Compare commits

..

8 Commits

Author SHA1 Message Date
rakshasa cf1ba60b67 Merge branch 'branch-0.9' of github.com:rakshasa/rtorrent into branch-0.9 2015-09-04 04:03:45 +09:00
rakshasa b283f51cad Bumped to version 0.9.6. 2015-09-04 04:01:30 +09:00
rakshasa 301926172a Bumped to version 0.9.5. 2015-07-02 07:30:41 +09:00
rakshasa 78a0fb3e85 Fixed cherry-picked patch tr1 usage. 2014-11-05 22:46:45 +09:00
rakshasa 145ad4fe0f Minor changes for branch-0.9 tr1 usage. 2014-11-05 00:21:08 +09:00
rakshasa ae5f37dbf0 Added 'log.open_file_pid' and 'log.open_gz_file_pid' commands that appends the pid automatically.
Conflicts:
	src/command_local.cc
2014-11-04 23:44:11 +09:00
rakshasa 368a629804 Use a generic function for logging and allow output groups to be appended.
log.open_file = "instrumentation_memory.log", "/foo/instrumentation_memory.log", "instrumentation_memory", ...
2014-11-04 23:43:18 +09:00
rakshasa 3d2fb6afbc Moved logging commands to a separate file.
Conflicts:
	src/command_local.cc
2014-11-04 23:43:07 +09:00
325 changed files with 17654 additions and 51592 deletions
-33
View File
@@ -1,33 +0,0 @@
---
BasedOnStyle: LLVM
Standard: c++14
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AlwaysBreakAfterReturnType: TopLevelDefinitions
BinPackArguments: false
BinPackParameters: false
BreakConstructorInitializers: AfterColon
BreakStringLiterals: false
ColumnLimit: 0
ContinuationIndentWidth: 2
IndentCaseLabels: false
IndentWidth: 2
PenaltyReturnTypeOnItsOwnLine: 130
PointerAlignment: Left
AlignEscapedNewlines: Right
AlignConsecutiveDeclarations:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
AlignConsecutiveMacros:
Enabled: true
AlignConsecutiveAssignments:
Enabled: true
IncludeCategories:
- Regex: "^(config|globals)\\.h"
Priority: -1
- Regex: "^torrent/.*"
Priority: 1
-16
View File
@@ -1,16 +0,0 @@
---
Checks: '-*,readability-identifier-naming'
FormatStyle: 'file'
CheckOptions:
- key: readability-identifier-naming.LocalVariableCase
value: lower_case
- key: readability-identifier-naming.ParameterCase
value: lower_case
- key: readability-identifier-naming.FunctionCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: m_
- key: readability-identifier-naming.PrivateMemberCase
value: lower_case
- key: readability-identifier-naming.ClassConstantCase
value: lower_case
-7
View File
@@ -1,7 +0,0 @@
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((c++-mode
(flycheck-clang-language-standard . "c++11")
(flycheck-gcc-language-standard . "c++11")))
-13
View File
@@ -1,13 +0,0 @@
# These are supported funding model platforms
github: [rakshasa]
patreon: rtorrent
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ['https://rakshasa.github.io/rtorrent/donate.html']
-65
View File
@@ -1,65 +0,0 @@
name: "Lint Commit Message Size"
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
check-commit-bounds:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate Line Count, Width, and Spacing
run: |
# Fetch commit hashes unique to this PR branch
COMMITS=$(git log --no-merges --pretty=format:"%H" origin/${{ github.base_ref }}..HEAD)
MAX_LINES=3
MAX_CHARS=90
FAILED=0
for commit in $COMMITS; do
SUBJECT=$(git log --format="%s" -n 1 $commit)
# Extract clean commit message, trimming trailing blank lines
RAW_MSG=$(git log --format="%B" -n 1 $commit)
CLEAN_MSG=$(echo "$RAW_MSG" | awk '{msg[NR]=$0} END {while(NR>0 && msg[NR]=="") NR--; for(i=1;i<=NR;i++) print msg[i]}')
# 1. Check total line count
LINE_COUNT=$(echo "$CLEAN_MSG" | wc -l)
if [ "$LINE_COUNT" -gt "$MAX_LINES" ]; then
echo "❌ Error: Commit message has too many lines ($LINE_COUNT/$MAX_LINES)."
echo " Commit: '$SUBJECT'"
FAILED=1
fi
# 2. Check for multiple consecutive blank lines
# This regex looks for 2 or more empty lines anywhere in the message
if echo "$CLEAN_MSG" | grep -pz '(\r?\n){3,}'; then
echo "❌ Error: Commit message contains multiple consecutive line breaks."
echo " Commit: '$SUBJECT'"
FAILED=1
fi
# 3. Check maximum width of any individual line
while IFS= read -r line; do
LINE_LENGTH=${#line}
if [ "$LINE_LENGTH" -gt "$MAX_CHARS" ]; then
echo "❌ Error: Line length exceeds limit ($LINE_LENGTH / $MAX_CHARS chars)."
echo " Offending line: '$line'"
FAILED=1
fi
done <<< "$CLEAN_MSG"
done
# Fail the job if any check failed
if [ "$FAILED" -ne 0 ]; then
exit 1
fi
echo "✅ All commit messages passed style rules!"
@@ -1,96 +0,0 @@
# Secure workflow with access to repository secrets and GitHub token for posting analysis results
name: Post the static analysis results
on:
workflow_run:
workflows: [ "Static analysis" ]
types: [ completed ]
jobs:
clang-tidy-results:
# Trigger the job only if the previous (insecure) workflow completed successfully
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-22.04
permissions:
pull-requests: write
# OPTIONAL: auto-closing conversations requires the `contents` permission
contents: read
steps:
- name: Sleep for 30 seconds
run: sleep 30s
shell: bash
- name: Download analysis results
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
const matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "clang-tidy-result"
})[0];
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
const fs = require("fs");
fs.writeFileSync("${{ github.workspace }}/clang-tidy-result.zip", Buffer.from(download.data));
- name: Extract analysis results
run: |
mkdir clang-tidy-result
unzip -j clang-tidy-result.zip -d clang-tidy-result
- name: Set environment variables
uses: actions/github-script@v7
with:
script: |
const assert = require("node:assert").strict;
const fs = require("fs");
function exportVar(varName, fileName, regEx) {
const val = fs.readFileSync("${{ github.workspace }}/clang-tidy-result/" + fileName, {
encoding: "ascii"
}).trimEnd();
assert.ok(regEx.test(val), "Invalid value format for " + varName);
core.exportVariable(varName, val);
}
exportVar("PR_ID", "pr-id.txt", /^[0-9]+$/);
exportVar("PR_HEAD_REPO", "pr-head-repo.txt", /^[-./0-9A-Z_a-z]+$/);
exportVar("PR_HEAD_SHA", "pr-head-sha.txt", /^[0-9A-Fa-f]+$/);
- uses: actions/checkout@v4
with:
repository: ${{ env.PR_HEAD_REPO }}
ref: ${{ env.PR_HEAD_SHA }}
persist-credentials: false
- name: Redownload analysis results
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
const matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "clang-tidy-result"
})[0];
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
const fs = require("fs");
fs.writeFileSync("${{ github.workspace }}/clang-tidy-result.zip", Buffer.from(download.data));
- name: Extract analysis results
run: |
mkdir clang-tidy-result
unzip -j clang-tidy-result.zip -d clang-tidy-result
- name: Run clang-tidy-pr-comments action
uses: platisd/clang-tidy-pr-comments@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
clang_tidy_fixes: clang-tidy-result/fixes.yml
pull_request_id: ${{ env.PR_ID }}
-84
View File
@@ -1,84 +0,0 @@
name: Static analysis
on: pull_request
jobs:
clang-tidy:
runs-on: ubuntu-22.04
steps:
- name: Update Packages
run: |
sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
bear \
clang-tidy \
libcurl4-openssl-dev \
zlib1g-dev
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
- name: Build libtorrent
run: |
cd libtorrent
libtoolize
aclocal -I scripts
autoconf -i
autoheader
automake --add-missing
./configure
make
sudo make install
cd ..
rm -rf libtorrent
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Fetch base branch
run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
- name: Configure Project
run: |
libtoolize
aclocal -I scripts
autoconf -i
autoheader
automake --add-missing
./configure
- name: Prepare compile_commands.json
run: |
bear -- make
- name: Create results directory
run: |
mkdir clang-tidy-result
- name: Analyze
run: |
git diff -U0 "$(git merge-base HEAD "upstream/${{ github.event.pull_request.base.ref }}")" | clang-tidy-diff -p1 -path build -export-fixes clang-tidy-result/fixes.yml "-extra-arg=-include/${PWD}/config.h"
- name: Save PR metadata
run: |
echo "${{ github.event.number }}" > clang-tidy-result/pr-id.txt
echo "${{ github.event.pull_request.head.repo.full_name }}" > clang-tidy-result/pr-head-repo.txt
echo "${{ github.event.pull_request.head.sha }}" > clang-tidy-result/pr-head-sha.txt
- uses: actions/upload-artifact@v4
with:
name: clang-tidy-result
path: clang-tidy-result/
# - name: Run clang-tidy-pr-comments action
# uses: platisd/clang-tidy-pr-comments@v1
# with:
# # The GitHub token (or a personal access token)
# github_token: ${{ secrets.GITHUB_TOKEN }}
# # The path to the clang-tidy fixes generated previously
# clang_tidy_fixes: clang-tidy-result/fixes.yml
# # Optionally set to true if you want the Action to request
# # changes in case warnings are found
# request_changes: true
# # Optionally set the number of comments per review
# # to avoid GitHub API timeouts for heavily loaded
# # pull requests
# suggestions_per_comment: 10
-107
View File
@@ -1,107 +0,0 @@
name: Static analysis
on: pull_request
jobs:
ubuntu-base:
runs-on: ubuntu-22.04
steps:
- name: Update Packages
run: |
sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
zlib1g-dev \
libcurl4-openssl-dev
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
- name: Build libtorrent
run: |
cd libtorrent
autoreconf -fiv
./configure
make
sudo make install DESTDIR=$GITHUB_WORKSPACE/libtorrent-dist
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: installed-libtorrent
path: libtorrent-dist/
unit-tests-default:
runs-on: ubuntu-22.04
needs: ubuntu-base
steps:
- name: Update Packages
run: |
sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
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: |
autoreconf -fiv
./configure
make
ls /usr/local/lib/
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: Update Packages
run: |
sudo apt-get update
- 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 -7
View File
@@ -18,8 +18,6 @@
.libs
Makefile
aclocal.m4
actmp.*
ar-lib
autom4te.cache
compile
config.h
@@ -34,8 +32,6 @@ libtool
ltmain.sh
missing
stamp-h1
src/rtorrent
scripts/libtool.m4
scripts/lt*.m4
@@ -60,7 +56,6 @@ scripts/lt*.m4
# OS generated files #
######################
.DS_Store?
.dirstamp
ehthumbs.db
Icon?
Thumbs.db
@@ -69,6 +64,6 @@ TAGS
# rTorrent specific files
###########################
src/rtorrent
test/rtorrent_Test*
test/test-suite.log.tmp
test/rtorrentTest
test-driver
test/rtorrentTest.trs
+1 -1
View File
@@ -1 +1 @@
Jari Sundell <sundell.software@gmail.com>
Jari Sundell <jaris@ifi.uio.no>
View File
+115 -254
View File
@@ -1,109 +1,81 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
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 warranty of any kind.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell command './configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the 'README' file for
instructions specific to this package. Some packages provide this
'INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
These are generic installation instructions.
The 'configure' shell script attempts to guess correct values for
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a 'Makefile' in each directory of the package.
It may also create one or more '.h' files containing system-dependent
definitions. Finally, it creates a shell script 'config.status' that
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file 'config.log' containing compiler output (useful mainly for
debugging 'configure').
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called 'config.cache' and
enabled with '--cache-file=config.cache' or simply '-C') that saves the
results of its tests to speed up reconfiguring. Caching is disabled by
default to prevent problems with accidental use of stale cache files.
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how 'configure' could check whether to do them, and mail
diffs or instructions to the address given in the 'README' so they can
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point 'config.cache' contains results you don't want to keep, you
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file 'configure.ac' (or 'configure.in') is used to create
'configure' by a program called 'autoconf'. You need 'configure.ac' if
you want to change it or regenerate 'configure' using a newer version of
'autoconf'.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
The simplest way to compile this package is:
1. 'cd' to the directory containing the package's source code and type
'./configure' to configure the package for your system.
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running 'configure' might take a while. While running, it prints
some messages telling which features it is checking for.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type 'make' to compile the package.
2. Type `make' to compile the package.
3. Optionally, type 'make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type 'make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the 'make install' phase executed with root
privileges.
4. Type `make install' to install the programs and any data files and
documentation.
5. Optionally, type 'make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior 'make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing 'make clean'. To also remove the
files that 'configure' created (so you can compile the package for
a different kind of computer), type 'make distclean'. There is
also a 'make maintainer-clean' target, but that is intended mainly
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type 'make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide 'make
distcheck', which can by used by developers to test that all other
targets like 'make install' and 'make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the 'configure' script does not know about. Run './configure --help'
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give 'configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here is
an example:
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
@@ -112,257 +84,146 @@ Compiling For Multiple Architectures
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU 'make'. 'cd' to the
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the 'configure' script. 'configure' automatically checks for the source
code in the directory that 'configure' is in and in '..'. This is known
as a "VPATH" build.
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU 'make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use 'make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple '-arch' options to the
compiler but only a single '-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the 'lipo' tool if you have problems.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, 'make install' installs the package's commands under
'/usr/local/bin', include files under '/usr/local/include', etc. You
can specify an installation prefix other than '/usr/local' by giving
'configure' the option '--prefix=PREFIX', where PREFIX must be an
absolute file name.
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like '--bindir=DIR' to specify different values for particular
kinds of files. Run 'configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the default
for these options is expressed in terms of '${prefix}', so that
specifying just '--prefix' will affect all of the other directory
specifications that were not explicitly provided.
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
The most portable way to affect installation locations is to pass the
correct locations to 'configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
'make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, 'make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
'${prefix}'. Any directories that were specified during 'configure',
but not in terms of '${prefix}', must each be overridden at install time
for the entire installation to be relocated. The approach of makefile
variable overrides for each directory variable is required by the GNU
Coding Standards, and ideally causes no recompilation. However, some
platforms have known limitations with the semantics of shared libraries
that end up requiring recompilation when using this method, particularly
noticeable in packages that use GNU Libtool.
The second method involves providing the 'DESTDIR' variable. For
example, 'make install DESTDIR=/alternate/directory' will prepend
'/alternate/directory' before all installation names. The approach of
'DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of '${prefix}'
at 'configure' time.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving 'configure' the
option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
Some packages pay attention to '--enable-FEATURE' options to
'configure', where FEATURE indicates an optional part of the package.
They may also pay attention to '--with-PACKAGE' options, where PACKAGE
is something like 'gnu-as' or 'x' (for the X Window System). The
'README' should mention any '--enable-' and '--with-' options that the
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, 'configure' can usually
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the 'configure' options '--x-includes=DIR' and
'--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of 'make' will be. For these packages, running './configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with 'make V=1'; while running './configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with 'make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX 'make' updates targets which have the same time stamps as their
prerequisites, which makes it generally unusable when shipped generated
files such as 'configure' are involved. Use GNU 'make' instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
workaround. If GNU CC is not installed, it is therefore recommended to
try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
in your 'PATH', put it _after_ '/usr/bin'.
On Haiku, software installed for all users goes in '/boot/common',
not '/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features 'configure' cannot figure out
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, 'configure' can figure that out, but if it prints
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
'--build=TYPE' option. TYPE can either be a short name for the system
type, such as 'sun4', or a canonical name which has the form:
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
OS KERNEL-OS
See the file 'config.sub' for the possible values of each field. If
'config.sub' isn't included in this package, then this package doesn't
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option '--target=TYPE' to select the type of system they will
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with '--host=TYPE'.
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for 'configure' scripts to share,
you can create a site shell script called 'config.site' that gives
default values for variables like 'CC', 'cache_file', and 'prefix'.
'configure' looks for 'PREFIX/share/config.site' if it exists, then
'PREFIX/etc/config.site' if it exists. Or, you can set the
'CONFIG_SITE' environment variable to the location of the site script.
A warning: not all 'configure' scripts look for a site script.
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to 'configure'. However, some packages may run
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the 'configure' command line, using 'VAR=value'. For example:
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified 'gcc' to be used as the C compiler (unless it is
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
Autoconf limitation. Until the limitation is lifted, you can use this
workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
'configure' Invocation
`configure' Invocation
======================
'configure' recognizes the following options to control how it
`configure' recognizes the following options to control how it
operates.
'--help'
'-h'
Print a summary of all of the options to 'configure', and exit.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
'--help=short'
'--help=recursive'
Print a summary of the options unique to this package's
'configure', and exit. The 'short' variant lists options used only
in the top level, while the 'recursive' variant lists options also
present in any nested packages.
'--version'
'-V'
Print the version of Autoconf used to generate the 'configure'
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
'--cache-file=FILE'
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally 'config.cache'. FILE defaults to '/dev/null' to
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
'--config-cache'
'-C'
Alias for '--cache-file=config.cache'.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
'--quiet'
'--silent'
'-q'
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to '/dev/null' (any error
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
'--srcdir=DIR'
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
'configure' can determine that directory automatically.
`configure' can determine that directory automatically.
'--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names:: for
more details, including other options available for fine-tuning the
installation locations.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
'--no-create'
'-n'
Run the configure checks, but stop before creating any output
files.
'configure' also accepts some other, not widely useful, options. Run
'configure --help' for more details.
+18 -3
View File
@@ -3,10 +3,25 @@ SUBDIRS = \
src \
test
nobase_dist_pkgdata_DATA = \
lua/rtorrent.lua
EXTRA_DIST= \
autogen.sh \
rak/address_info.h \
rak/algorithm.h \
rak/allocators.h \
rak/error_number.h \
rak/file_stat.h \
rak/fs_stat.h \
rak/functional.h \
rak/functional_fun.h \
rak/path.h \
rak/partial_queue.h \
rak/priority_queue.h \
rak/priority_queue_default.h \
rak/regex.h \
rak/socket_address.h \
rak/string_manip.h \
rak/timer.h \
rak/unordered_vector.h \
scripts/checks.m4 \
scripts/common.m4 \
scripts/attributes.m4
View File
+36
View File
@@ -0,0 +1,36 @@
BUILDING
Run "./autogen.sh" to generate the configure scripts if
nessesary. The man page "doc/rtorrent.1" must be generated with
"docbook2man rtorrent.1.xml" if it is missing.
Note that rtorrent follows the development of libtorrent closely, and
thus the versions must be in sync. This should not be nessesary in the
future, when the library API stabilizes.
USAGE
See the man page or website for instructions.
LICENSE
GNU GPL, see COPYING. "libtorrent/src/utils/sha_fast.{cc,h}" is
originally from the Mozilla NSS and is under a triple license; MPL,
LGPL and GPL. An exception to non-NSS code has been added for linking
to OpenSSL as requested by Debian, though the author considers that
library to be part of the Operative System and thus linking is allowed
according to the GPL.
Use whatever fits your purpose, the code required to compile with
Mozilla's NSS implementation of SHA1 has been retained and can be
compiled if the user wishes to avoid using OpenSSL.
DEPENDENCIES
libcurl >= 7.12.0
ncurses
CONTACT
Send bug reports, suggestions and patches to <jaris@ifi.uio.no> or
to the mailinglist.
-88
View File
@@ -1,88 +0,0 @@
RTorrent BitTorrent Client
========
Introduction
------------
A ncurses-based command line torrent client for high performance.
To learn how to use rTorrent visit the [Wiki](https://github.com/rakshasa/rtorrent/wiki).
Download the [latest stable release](https://github.com/rakshasa/rtorrent/releases/latest)
Related Projects
----------------
* [https://github.com/rakshasa/rbedit](https://github.com/rakshasa/rbedit): A dependency-free bencode editor.
Donate to rTorrent development
------------------------------
* [Paypal](https://paypal.me/jarisundellno)
* [Patreon](https://www.patreon.com/rtorrent)
* [SubscribeStar](https://www.subscribestar.com/rtorrent)
* Bitcoin: 1MpmXm5AHtdBoDaLZstJw8nupJJaeKu8V8
* Ethereum: 0x9AB1e3C3d8a875e870f161b3e9287Db0E6DAfF78
* Litecoin: LdyaVR67LBnTf6mAT4QJnjSG2Zk67qxmfQ
* Cardano: addr1qytaslmqmk6dspltw06sp0zf83dh09u79j49ceh5y26zdcccgq4ph7nmx6kgmzeldauj43254ey97f3x4xw49d86aguqwfhlte
Help keep rTorrent development going by donating to its creator.
BUILDING
--------
Jump into the github cloned directory
```
cd rtorrent
```
## Install build dependencies
Install [libtorrent](https://github.com/rakshasa/libtorrent) with the same version rTorrent.
Generate configure scripts:
```
autoreconf -ivf
```
Optionally, generate man pages:
```
docbook2man rtorrent.1.xml
```
Man pages output to "doc/rtorrent.1".
RTorrent follows the development of [libtorrent](https://github.com/rakshasa/libtorrent) closely, and thus the versions must be in sync.
## USAGE
Refer to User Guide: https://github.com/rakshasa/rtorrent/wiki/User-Guide
## LICENSE
GNU GPL, see COPYING. "libtorrent/src/utils/sha_fast.{cc,h}" is
originally from the Mozilla NSS and is under a triple license; MPL,
LGPL and GPL. An exception to non-NSS code has been added for linking to OpenSSL as requested by Debian, though the author considers that library to be part of the Operative System and thus linking is allowed according to the GPL.
Use whatever fits your purpose, the code required to compile with
Mozilla's NSS implementation of SHA1 has been retained and can be
compiled if the user wishes to avoid using OpenSSL.
## DEPENDENCIES
* libcurl >= 7.12.0
* libtorrent = (same version)
* ncurses
## BUILD DEPENDENCIES
* libtoolize
* aclocal
* autoconf
* autoheader
* automake
Executable
+51
View File
@@ -0,0 +1,51 @@
#! /bin/sh
echo aclocal...
(aclocal --version) < /dev/null > /dev/null 2>&1 || {
echo aclocal not found
exit 1
}
aclocal -I ./scripts -I . ${ACLOCAL_FLAGS} || exit 1
echo autoheader...
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
echo autoheader not found
exit 1
}
autoheader || exit 1
echo -n "libtoolize... "
if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then
echo "using glibtoolize"
glibtoolize --automake --copy --force || exit 1
elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then
echo "using libtoolize"
libtoolize --automake --copy --force || exit 1
else
echo "libtoolize nor glibtoolize not found"
exit 1
fi
echo automake...
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo automake not found
exit 1
}
automake --add-missing --copy --gnu || exit 1
echo autoconf...
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo autoconf not found
exit 1
}
autoconf || exit 1
echo ready to configure
exit 0
+57 -63
View File
@@ -1,85 +1,79 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT(rtorrent, 0.9.6, sundell.software@gmail.com)
AC_INIT([rtorrent],[0.16.19],[sundell.software@gmail.com])
AC_DEFINE(API_VERSION, 9, api version)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([scripts])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AM_PROG_AR
LT_INIT
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS(config.h)
AM_PATH_CPPUNIT(1.9.6)
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
AC_PROG_LIBTOOL
PKG_PROG_PKG_CONFIG
TORRENT_CHECK_CXXFLAGS()
TORRENT_ENABLE_DEBUG()
TORRENT_ENABLE_EXTRA_DEBUG()
TORRENT_ENABLE_WERROR()
TORRENT_ENABLE_TR1()
TORRENT_ENABLE_CXX11()
AC_DEFINE([API_VERSION], [24], [api version])
TORRENT_DISABLE_IPV6
RAK_CHECK_CFLAGS
RAK_CHECK_CXXFLAGS
RAK_ENABLE_DEBUG
RAK_ENABLE_EXTRA_DEBUG
RAK_ENABLE_WERROR
AC_SYS_LARGEFILE
AC_ARG_ENABLE(execinfo,
AS_HELP_STRING([--disable-execinfo],
[disable libexecinfo [[default=enable]]]),
[
if test "$enableval" = "yes"; then
AX_EXECINFO
fi
],[
AX_EXECINFO
])
TORRENT_CHECK_EXECINFO()
TORRENT_OTFD()
TORRENT_ENABLE_ARCH
TORRENT_WITH_SYSROOT
TORRENT_WITHOUT_VARIABLE_FDSET()
TORRENT_WITHOUT_STATVFS()
TORRENT_WITHOUT_STATFS()
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
AX_WITH_CURSES()
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
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
fi
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([ZLIB], [zlib])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.19])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS"
LIBS="$PTHREAD_LIBS $CURSES_LIB $LIBS"
PKG_CHECK_MODULES([libcurl], libcurl >= 7.15.4,
CXXFLAGS="$CXXFLAGS $libcurl_CFLAGS";
LIBS="$LIBS $libcurl_LIBS")
PKG_CHECK_MODULES([libtorrent], libtorrent >= 0.13.6,
CXXFLAGS="$CXXFLAGS $libtorrent_CFLAGS";
LIBS="$LIBS $libtorrent_LIBS")
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])
AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included)
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
TORRENT_WITH_LUA
TORRENT_WITH_TINYXML2
TORRENT_WITH_SYSTEMD
AC_CHECK_FUNCS(posix_memalign)
TORRENT_CHECK_CACHELINE()
TORRENT_CHECK_POPCOUNT()
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
CC_ATTRIBUTE_UNUSED(
AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
)
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 $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_CACHELINE
TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP
AC_CONFIG_FILES([
Makefile
doc/Makefile
src/Makefile
test/Makefile
AC_OUTPUT([
Makefile
doc/Makefile
src/Makefile
src/core/Makefile
src/display/Makefile
src/input/Makefile
src/rpc/Makefile
src/ui/Makefile
src/utils/Makefile
test/Makefile
])
AC_OUTPUT
+4 -14
View File
@@ -4,30 +4,20 @@
# log.open_file = "log name", "file path"
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
A newly opened log file is not connected to any logging events.
Some control over formatting will be provided at a later date.
## Appending to log files
log.append_file = "rtorrent.log", "/tmp/rtorrent.log"
The `log.open_file` clears any existing contents of the file. If you'd
prefer to have a single log file that persists across application
restarts, you can use the `log.append_file` in place of the
`log.open_file` configuration key.
## Adding outputs to events
# log.add_output = "logging event", "log name"
log.add_output = "info", "rtorrent.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
log.add_output = "dht_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
Each log handle can be added to multiple different logging events.
@@ -41,7 +31,7 @@ Each log handle can be added to multiple different logging events.
"debug"
The above events receive logging events from all the sub-groups
displayed below, and each event also receiving events from the event
displayed below, and each event also reciving events from the event
above in importance.
Thus some high-volume sub-group events such as “tracker\_debug” are not
+3 -4
View File
@@ -5,7 +5,7 @@
\begin{verbatim}
# log.open_file = "log name", "file path"
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
\end{verbatim}
A newly opened log file is not connected to any logging events.
@@ -20,9 +20,8 @@ Some control over formatting will be provided at a later date.
log.add_output = "info", "rtorrent.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
log.add_output = "dht_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
\end{verbatim}
Each log handle can be added to multiple different logging events.
+6 -5
View File
@@ -52,7 +52,7 @@ Decrease the download throttle by 1/5/50 KB.
\fB->\fR
View download.
.TP
\fB0 - 9\fR
\fB1 - 7\fR
Change view.
.TP
\fB^S\fR
@@ -99,9 +99,6 @@ Delete the file the torrent is tied to, and clear the association.
.TP
\fBI\fR
Toggle whether torrent ignores ratio settings.
.TP
\fBF\fR
Add a temporary name based regex filter to the current view.
.SS "DOWNLOAD VIEW KEYS"
.TP
\fB->\fR
@@ -499,6 +496,10 @@ Number of attempts to check the hash while using the mincore status,
before forcing. Overworked systems might need lower values to get a
decent hash checking rate.
.TP
\fBsafe_sync = \fIyes|no\fB\fR
Always use MS_SYNC rather than MS_ASYNC when syncing chunks. This may
be nessesary in case of filesystem bugs like NFS in linux ~2.6.13.
.TP
\fBmax_open_files = \fIvalue\fB\fR
Number of files to simultaneously keep open. LibTorrent dynamically
opens and closes files as necessary when mapping files to
@@ -556,4 +557,4 @@ log messages, but may be useful to debug connection problems.
.SH "AUTHORS"
.PP
Jari "Rakshasa" Sundell
Jari "Rakshasa" Sundell <jaris@ifi.uio.no>
+12 -9
View File
@@ -122,7 +122,7 @@ View download.
</varlistentry>
<varlistentry>
<term>0 - 9</term>
<term>1 - 7</term>
<listitem><para>
Change view.
</para></listitem>
@@ -225,13 +225,6 @@ Toggle whether torrent ignores ratio settings.
</para></listitem>
</varlistentry>
<varlistentry>
<term>F</term>
<listitem><para>
Add a temporary name based regex filter to the current view.
</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
@@ -978,6 +971,16 @@ decent hash checking rate.
</para></listitem>
</varlistentry>
<varlistentry>
<term>safe_sync = <replaceable>yes|no</replaceable></term>
<listitem><para>
Always use MS_SYNC rather than MS_ASYNC when syncing chunks. This may
be nessesary in case of filesystem bugs like NFS in linux ~2.6.13.
</para></listitem>
</varlistentry>
<varlistentry>
<term>max_open_files = <replaceable>value</replaceable></term>
<listitem><para>
@@ -1112,7 +1115,7 @@ log messages, but may be useful to debug connection problems.
<para>
<simplelist type="vert">
<member>Jari "Rakshasa" Sundell <email>sundell.software@gmail.com</email></member>
<member>Jari "Rakshasa" Sundell <email>jaris@ifi.uio.no</email></member>
</simplelist>
</para>
@@ -1,7 +1,7 @@
#/bin/bash
gnuplot << EOF
set terminal png size 1024 * 1, 768 enhanced
set terminal png size 1024,768 enhanced
set xdata time
set timefmt "%s"
set format x "%H:%M"
@@ -14,17 +14,17 @@ set format y2 "%.0f"
set output "output_$1_incore_sync.png"
plot \
"instrumentation_mincore.log.$1" using 1:6 title 'success' with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:7 title 'failed' with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:8 title 'not synced' with lines lw 4 axis x1y2,\
"instrumentation_mincore.log.$1" using 1:9 title 'not deallocated' with lines lw 4 axis x1y2
"instrumentation_mincore.log.$1" using 1:6 title 'success' smooth sbezier with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:7 title 'failed' smooth sbezier with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:8 title 'not synced' smooth sbezier with lines lw 4 axis x1y2,\
"instrumentation_mincore.log.$1" using 1:9 title 'not deallocated' smooth sbezier with lines lw 4 axis x1y2
set format y "%.0g"
set output "output_$1_incore_alloc.png"
plot \
"instrumentation_mincore.log.$1" using 1:12 title 'allocations' with lines lw 2 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:13 title 'deallocations' with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:10 title 'alloc failed' with lines lw 2 axis x1y2
"instrumentation_mincore.log.$1" using 1:12 title 'allocations' smooth sbezier with lines lw 2 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:13 title 'deallocations' smooth sbezier with lines lw 4 axis x1y1,\
"instrumentation_mincore.log.$1" using 1:10 title 'alloc failed' smooth sbezier with lines lw 2 axis x1y2
EOF
+45 -101
View File
@@ -1,140 +1,84 @@
#############################################################################
# This is an (old) example resource file for rTorrent.
# Copy to ~/.rtorrent.rc and enable/modify the options as needed.
# Remember to uncomment the options you wish to enable.
#
# See 'rtorrent.rc-example' for a newer, basic configuration.
#
# Sample: https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
# Complete: https://rtorrent-docs.readthedocs.io/en/latest/cmd-ref.html
# Useful: https://rtorrent-docs.readthedocs.io/en/latest/use-cases.html
# Manual: https://rtorrent-docs.readthedocs.io/en/latest/
# Convert: https://github.com/rakshasa/rtorrent/wiki/rTorrent-0.9-Comprehensive-Command-list-(WIP)
# Handbook: https://media.readthedocs.org/pdf/rtorrent-docs/latest/rtorrent-docs.pdf
# File: https://github.com/rakshasa/rtorrent/blob/master/doc/rtorrent.rc
#############################################################################
# This is an example resource file for rTorrent. Copy to
# ~/.rtorrent.rc and enable/modify the options as needed. Remember to
# uncomment the options you wish to enable.
# Maximum and minimum number of peers to connect to per torrent.
#
#throttle.min_peers.normal.set = 40
#throttle.max_peers.normal.set = 100
#min_peers = 40
#max_peers = 100
# Same as above but for seeding completed torrents.
# "-1" = same as downloading.
#
#throttle.min_peers.seed.set = 10
#throttle.max_peers.seed.set = 50
# Same as above but for seeding completed torrents (-1 = same as downloading)
#min_peers_seed = 10
#max_peers_seed = 50
# Maximum number of simultaneous uploads per torrent.
#
#throttle.max_uploads.set = 15
# Maximum number of simultanious uploads per torrent.
#max_uploads = 15
# Global upload and download rate in KiB.
# "0" for unlimited.
#
#throttle.global_down.max_rate.set_kb = 0
#throttle.global_up.max_rate.set_kb = 0
# Global upload and download rate in KiB. "0" for unlimited.
#download_rate = 0
#upload_rate = 0
# Default directory to save the downloaded torrents.
#
#directory.default.set = ./
#directory = ./
# Default session directory. Make sure you don't run multiple instance
# of rTorrent using the same session directory. Perhaps using a
# of rtorrent using the same session directory. Perhaps using a
# relative path?
#
#session.path.set = ./session
#session = ./session
# Watch a directory for new torrents, and stop those that have been
# 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
# deleted.
#schedule = watch_directory,5,5,load_start=./watch/*.torrent
#schedule = untied_directory,5,5,stop_untied=
# Close torrents when disk-space is low.
#
#schedule2 = low_diskspace,5,60,close_low_diskspace=100M
# Close torrents when diskspace is low.
#schedule = low_diskspace,5,60,close_low_diskspace=100M
# The IP address reported to the tracker.
#
#network.local_address.set = 127.0.0.1
#network.local_address.set = rakshasa.no
# The ip address reported to the tracker.
#ip = 127.0.0.1
#ip = rakshasa.no
# The IP address the listening socket and outgoing connections is
# The ip address the listening socket and outgoing connections is
# bound to.
#
#network.bind_address.set = 127.0.0.1
#network.bind_address.set = rakshasa.no
#bind = 127.0.0.1
#bind = rakshasa.no
# Port range to use for listening.
#
#network.port_range.set = 6890-6999
#port_range = 6890-6999
# Start opening ports at a random position within the port range.
#
#network.port_random.set = no
#port_random = no
# Set RPC type
#network.rpc.use_xmlrpc.set = true
#network.rpc.use_jsonrpc.set = true
# Check hash for finished torrents. Might be useful until the bug is
# fixed that causes lack of disk-space not to be properly reported.
#
#pieces.hash.on_completion.set = no
# Check hash for finished torrents. Might be usefull until the bug is
# fixed that causes lack of diskspace not to be properly reported.
#check_hash = no
# Set whether the client should try to connect to UDP trackers.
#
#trackers.use_udp.set = yes
#use_udp_trackers = yes
# Alternative calls to bind and IP that should handle dynamic IP's.
#
#schedule2 = ip_tick,0,1800,ip=rakshasa
#schedule2 = bind_tick,0,1800,bind=rakshasa
# Alternative calls to bind and ip that should handle dynamic ip's.
#schedule = ip_tick,0,1800,ip=rakshasa
#schedule = bind_tick,0,1800,bind=rakshasa
# Encryption options, set to none (default) or any combination of the following:
# allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext
#
# The example value allows incoming encrypted connections, starts unencrypted
# outgoing connections but retries with encryption if they fail, preferring
# plain-text to RC4 encryption after the encrypted handshake.
# plaintext to RC4 encryption after the encrypted handshake
#
# protocol.encryption.set = allow_incoming,enable_retry,prefer_plaintext
# encryption = allow_incoming,enable_retry,prefer_plaintext
# Enable DHT support for trackerless torrents or when all trackers are down.
# May be set to "disable" (completely disable DHT), "off" (do not start DHT),
# "auto" (start and stop DHT as needed), or "on" (start DHT immediately).
# The default is "off". For DHT to work, a session directory must be defined.
#
# dht.mode.set = auto
#
# dht = auto
# UDP port to use for DHT.
#
#dht.port.set = 6881
# UDP port to use for DHT.
#
# dht_port = 6881
# Enable peer exchange (for torrents not marked private).
# Enable peer exchange (for torrents not marked private)
#
#protocol.pex.set = yes
# Set download list layout style ("full", "compact").
#
#ui.torrent_list.layout.set = "full"
# Set navigation keymap style ("vi", "emacs"). Default is "emacs".
#
#ui.keymap.style.set = "emacs"
# Run rTorrent as a daemon, controlled via XMLRPC.
#
#system.daemon.set = false
# SCGI Connectivity (for alternative rtorrent interfaces, XMLRPC)
# Use a IP socket with scgi_port, or a Unix socket with scgi_local.
# schedule can be used to set permissions on the unix socket.
#
#network.scgi.open_port = "127.0.0.1:5000"
#network.scgi.open_local = (cat,(session.path),/rpc.sock)
#schedule2 = socket_chmod, 0, 0, "execute.nothrow=chmod,770,(cat,(session.path),/rpc.sock)"
# peer_exchange = yes
-111
View File
@@ -1,111 +0,0 @@
#############################################################################
# A minimal rTorrent configuration that provides the basic features
# you want to have in addition to the built-in defaults.
#
# See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
# for an up-to-date version.
#############################################################################
# Instance layout (base paths)
method.insert = cfg.basedir, private|const|string, (cat,"/home/USERNAME/rtorrent/")
method.insert = cfg.download, private|const|string, (cat,(cfg.basedir),"download/")
method.insert = cfg.logs, private|const|string, (cat,(cfg.basedir),"log/")
method.insert = cfg.logfile, private|const|string, (cat,(cfg.logs),"rtorrent-",(system.time),".log")
method.insert = cfg.session, private|const|string, (cat,(cfg.basedir),".session/")
method.insert = cfg.watch, private|const|string, (cat,(cfg.basedir),"watch/")
# Create instance directories
execute.throw = sh, -c, (cat,\
"mkdir -p \"",(cfg.download),"\" ",\
"\"",(cfg.logs),"\" ",\
"\"",(cfg.session),"\" ",\
"\"",(cfg.watch),"/load\" ",\
"\"",(cfg.watch),"/start\" ")
# Listening port for incoming peer traffic (fixed; you can also randomize it)
network.port_range.set = 50000-50000
network.port_random.set = no
# Tracker-less torrent and UDP tracker support
# (conservative settings for 'private' trackers, change for 'public')
dht.mode.set = disable
protocol.pex.set = no
trackers.use_udp.set = no
# Peer settings
throttle.max_uploads.set = 100
throttle.max_uploads.global.set = 250
throttle.min_peers.normal.set = 20
throttle.max_peers.normal.set = 60
throttle.min_peers.seed.set = 30
throttle.max_peers.seed.set = 80
trackers.numwant.set = 80
protocol.encryption.set = allow_incoming,try_outgoing,enable_retry
# Limits for file handle resources, this is optimized for
# an `ulimit` of 1024 (a common default). You MUST leave
# a ceiling of handles reserved for rTorrent's internal needs!
network.http.max_open.set = 50
network.max_open_files.set = 600
network.max_open_sockets.set = 300
# Memory resource usage (increase if you have a large number of items loaded,
# and/or the available resources to spend)
pieces.memory.max.set = 1800M
network.xmlrpc.size_limit.set = 4M
# Basic operational settings (no need to change these)
session.path.set = (cat, (cfg.session))
directory.default.set = (cat, (cfg.download))
log.execute = (cat, (cfg.logs), "execute.log")
##log.xmlrpc = (cat, (cfg.logs), "xmlrpc.log")
execute.nothrow = sh, -c, (cat, "echo >",\
(session.path), "rtorrent.pid", " ", (system.pid))
# Other operational settings (check & adapt)
encoding.add = utf8
system.umask.set = 0027
system.cwd.set = (directory.default)
network.http.dns_cache_timeout.set = 25
schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M))
##pieces.hash.on_completion.set = no
##view.sort_current = seeding, greater=d.ratio=
##keys.layout.set = qwerty
##network.http.capath.set = "/etc/ssl/certs"
##network.http.ssl_verify_peer.set = 0
##network.http.ssl_verify_host.set = 0
#network.rpc.use_xmlrpc.set = true
#network.rpc.use_jsonrpc.set = true
# Some additional values and commands
method.insert = system.startup_time, value|const, (system.time)
method.insert = d.data_path, simple,\
"if=(d.is_multi_file),\
(cat, (d.directory), /),\
(cat, (d.directory), /, (d.name))"
method.insert = d.session_file, simple, "cat=(session.path), (d.hash), .torrent"
# Watch directories (add more as you like, but use unique schedule names)
schedule2 = watch_start, 10, 10, ((load.start_verbose, (cat, (cfg.watch), "start/*.torrent")))
schedule2 = watch_load, 11, 10, ((load.verbose, (cat, (cfg.watch), "load/*.torrent")))
# Run the rTorrent process as a daemon in the background
# (and control via XMLRPC sockets)
#system.daemon.set = true
#network.scgi.open_local = (cat,(session.path),rtorrent.sock)
#execute.nothrow = chmod,770,(cat,(session.path),rtorrent.sock)
# Logging:
# Levels = critical error warn notice info debug
# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
print = (cat, "Logging to ", (cfg.logfile))
log.open_file = "log", (cfg.logfile)
log.add_output = "info", "log"
#log.add_output = "tracker_events", "log"
#log.add_output = "tracker_requests", "log"
### END of rtorrent.rc ###
-142
View File
@@ -1,142 +0,0 @@
--[[
A minimal rTorrent configuration that provides the basic features
you want to have in addition to the built-in defaults.
See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
for an up-to-date version.
How to use this file:
1. Copy to destination, remove '-example' suffix
2. Create rtorrent.rc, containing single command, which executes THIS file.
For example:
lua.execute = (cat, (system.env, HOME), "/.config/rtorrent/rtorrent.rc.lua")
]]--
--[[ Bootstrap START ]]--
local rtorrent = require('rtorrent')
rc = rtorrent.autocall
--[[ Helper functions ]]--
local function makeArgs(cmdline)
return 'sh', '-c', "'"..table.concat(cmdline, "' '").."'"
end
-- Instance layout (base paths)
local home = os.getenv('HOME')
local cfg = {}
cfg.basedir = home..'/rtorrent/'
cfg.download = cfg.basedir..'download/'
cfg.logs = cfg.basedir..'log/'
cfg.logfile = cfg.logs..'rtorrent-'..rc.system.time()..'.log'
cfg.session = cfg.basedir..'.session/'
cfg.watch = cfg.basedir..'watch/'
rc.method.insert('cfg.download', 'private|const|string', cfg.download)
rc.method.insert('cfg.logs', 'private|const|string', cfg.logs)
rc.method.insert('cfg.logfile', 'private|const|string', cfg.logfile)
rc.method.insert('cfg.session', 'private|const|string', cfg.session)
rc.method.insert('cfg.watch', 'private|const|string', cfg.watch)
-- Create instance directories
rc.execute.throw(
makeArgs({'mkdir', '-p',
cfg.download,
cfg.logs,
cfg.session,
cfg.watch..'/load',
cfg.watch..'/start'}))
-- Listening port for incoming peer traffic (fixed; you can also randomize it)
rc.network.port_range = '50000-50000'
rc.network.port_random = false
-- Tracker-less torrent and UDP tracker support
-- (conservative settings for 'private' trackers, change for 'public')
rc.dht.mode = 'disable'
rc.protocol.pex = false
rc.trackers.use_udp = false
-- Peer settings
rc.throttle.max_uploads = 100
rc.throttle.max_uploads.global = 250
rc.throttle.min_peers.normal = 20
rc.throttle.max_peers.normal = 60
rc.throttle.min_peers.seed = 30
rc.throttle.max_peers.seed = 80
rc.trackers.numwant = 80
rc.protocol.encryption.set('allow_incoming', 'try_outgoing', 'enable_retry')
-- Limits for file handle resources, this is optimized for
-- an `ulimit` of 1024 (a common default). You MUST leave
-- a ceiling of handles reserved for rTorrent's internal needs!
rc.network.http.max_open = 50
rc.network.max_open_files = 600
rc.network.max_open_sockets = 300
-- Memory resource usage (increase if you have a large number of items loaded,
-- and/or the available resources to spend)
rc.pieces.memory.max = '1800M'
rc.network.xmlrpc.size_limit = '4M'
-- Basic operational settings (no need to change these)
rc.session.path = cfg.session
rc.directory.default = cfg.download
rc.log.execute(cfg.logs.."execute.log")
--rc.log.xmlrpc(cfg.logs.."xmlrpc.log")
rc.execute.nothrow(
"sh", "-c", table.concat(
{"echo >", rc.session.path(), "rtorrent.pid", " ", rc.system.pid()
}))
-- Other operational settings (check & adapt)
rc.encoding.add('utf8')
rc.system.umask = 0027
rc.system.cwd = rc.directory.default()
rc.network.http.dns_cache_timeout = 25
rc.schedule2('monitor_diskspace', '15', '60', 'close_low_diskspace=1000M')
--rc.pieces.hash.on_completion = false
--rc.view.sort_current('seeding', 'greater=d.ratio=')
--rc.keys.layout = 'qwerty'
--rc.network.http.capath = '/etc/ssl/certs'
--rc.network.http.ssl_verify_peer = 0
--rc.network.http.ssl_verify_host = 0
--rc.network.rpc.use_xmlrpc = true
--rc.network.rpc.use_jsonrpc = true
-- Some additional values and commands
-- NOTE: just common names, not commands
rc.method.insert('system.startup_time', 'value|const', rc.system.time())
rc.method.insert('d.data_path', 'simple',
[[if=(d.is_multi_file),
(cat, (d.directory), /),
(cat, (d.directory), /, (d.name))]])
rc.method.insert('d.session_file', 'simple', 'cat=(session.path), (d.hash), .torrent')
-- Watch directories (add more as you like, but use unique schedule names)
rc.schedule2('watch_start', '10', '10', 'load.start_verbose=(cat, (cfg.watch), "start/*.torrent")')
rc.schedule2('watch_load', '11', '10', 'load.verbose=(cat, (cfg.watch), "load/*.torrent")')
-- Run the rTorrent process as a daemon in the background
-- (and control via XMLRPC sockets)
--rc.system.daemon = true
--rc.network.scgi.open_local(cfg.session..'rtorrent.sock')
--rc.execute.nothrow('chmod', '770', cfg.session..'rtorrent.sock')
-- Logging:
-- Levels = critical error warn notice info debug
-- Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
rc.print('Logging to '..rc.cfg.logfile())
rc.log.open_file('log', rc.cfg.logfile())
rc.log.add_output('info', 'log')
--rc.log.add_output('tracker_events', 'log')
--rc.log.add_output('tracker_requests', 'log')
--[[ END of rtorrent.rc.lua ]]--
+2 -5
View File
@@ -85,7 +85,7 @@ foreach my $f (0..$#files) {
my $mtime = (stat "$d$files[$f]")[9];
# Compute number of chunks per file
my $fsize = (exists $t->{info}{files}) ? $t->{info}{files}[$f]{length} : 1;
my $fsize = $t->{info}{files}[$f]{length};
my $fchunks = ($pmod ? 1 : 0);
if ($pmod >= $fsize) { ($fsize, $pmod ) = (0, $pmod-$fsize); }
else { ($pmod, $fsize) = (0, $fsize-$pmod); }
@@ -101,10 +101,7 @@ foreach my $f (0..$#files) {
$t->{libtorrent_resume}{'uncertain_pieces.timestamp'} = time;
# Some extra information to re-enforce the fact that this is a finished torrent
if (exists $t->{info}{files}) {
$d .= $t->{info}{name};
}
$d .= $t->{info}{name};
$t->{rtorrent} = {
state => 1, # started
state_changed => time,
-164
View File
@@ -1,164 +0,0 @@
#!/bin/bash
#############
###<Notes>###
#############
# This script depends on screen.
# For the stop function to work, you must set an
# explicit session directory using absolute paths (no, ~ is not absolute) in your rtorrent.rc.
# If you typically just start rtorrent with just "rtorrent" on the
# command line, all you need to change is the "user" option.
# Attach to the screen session as your user with
# "screen -dr rtorrent". Change "rtorrent" with srnname option.
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
##############
###</Notes>###
##############
#######################
##Start Configuration##
#######################
# You can specify your configuration in a different file
# (so that it is saved with upgrades, saved in your home directory,
# or whatever reason you want to)
# by commenting out/deleting the configuration lines and placing them
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
# have written them here (you can leave the comments if you desire
# and then uncommenting the following line correcting the path/filename
# for the one you used. note the space after the ".".
# . /etc/rtorrent.init.conf
#Do not put a space on either side of the equal signs e.g.
# user = user
# will not work
# system user to run as (can only use one)
user="user"
# system user to run as # not implemented, see d_start for beginning implementation
# group=$(id -ng "$user")
# the full path to the filename where you store your rtorrent configuration
# must keep parentheses around the entire statement, quotations around each config file
config=("$(su -c 'echo $HOME' $user)/.rtorrent.rc")
# Examples:
# config=("/home/user/.rtorrent.rc")
# config=("/home/user/.rtorrent.rc" "/mnt/some/drive/.rtorrent2.rc")
# config=("/home/user/.rtorrent.rc"
# "/mnt/some/drive/.rtorrent2.rc"
# "/mnt/another/drive/.rtorrent3.rc")
# set of options to run with each instance, separated by a new line
# must keep parentheses around the entire statement
#if no special options, specify with: ""
options=("")
# Examples:
# starts one instance, sourcing both .rtorrent.rc and .rtorrent2.rc
# options=("-o import=~/.rtorrent2.rc")
# starts two instances, ignoring .rtorrent.rc for both, and using
# .rtorrent2.rc for the first, and .rtorrent3.rc for the second
# we do not check for valid options
# options=("-n -o import=~/.rtorrent2.rc" "-n -o import=~/rtorrent3.rc")
# default directory for screen, needs to be an absolute path
base=$(su -c 'echo $HOME' $user)
# name of screen session
srnname="rtorrent"
# file to log to (makes for easier debugging if something goes wrong)
logfile="/var/log/rtorrentInit.log"
#######################
###END CONFIGURATION###
#######################
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
DESC="rtorrent"
NAME=rtorrent
DAEMON=$NAME
SCRIPTNAME=/etc/init.d/$NAME
checkcnfg() {
exists=0
for i in `echo "$PATH" | tr ':' '\n'` ; do
if [ -f $i/$NAME ] ; then
exists=1
break
fi
done
if [ $exists -eq 0 ] ; then
echo "cannot find $NAME binary in PATH: $PATH" | tee -a "$logfile" >&2
exit 3
fi
for (( i=0 ; i < ${#config[@]} ; i++ )) ; do
if ! [ -r "${config[i]}" ] ; then
echo "cannot find readable config ${config[i]}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2
exit 3
fi
session=$(getsession "${config[i]}")
if ! [ -d "${session}" ] ; then
echo "cannot find readable session directory ${session} from config ${config[i]}. check permissions" | tee -a "$logfile" >&2
exit 3
fi
done
}
d_start() {
[ -d "${base}" ] && cd "${base}"
stty stop undef && stty start undef
su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
# this works for the screen command, but starting rtorrent below adopts screen session gid
# even if it is not the screen session we started (e.g. running under an undesirable gid
#su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2
for (( i=0 ; i < ${#options[@]} ; i++ )) ; do
sleep 3
su -c "screen -S "${srnname}" -X screen rtorrent ${options[i]} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
done
}
d_stop() {
for (( i=0 ; i < ${#config[@]} ; i++ )) ; do
session=$(getsession "${config[i]}")
if ! [ -s ${session}/rtorrent.lock ] ; then
return
fi
pid=$(cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g")
# make sure the pid doesn't belong to another process
if ps -A | grep -sq ${pid}.*rtorrent ; then
kill -s INT ${pid}
fi
done
}
getsession() {
session=$(cat "$1" | grep "^[[:space:]]*session.path.set[[:space:]]*=" | sed "s/^[[:space:]]*session.path.set[[:space:]]*=[[:space:]]*//" )
#session=${session/#~/`getent passwd ${user}|cut -d: -f6`}
echo $session
}
checkcnfg
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
restart|force-reload)
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
-137
View File
@@ -1,137 +0,0 @@
#!/bin/sh
#############
###<Notes>###
#############
# This script depends on screen.
# For the stop function to work, you must set an
# explicit session directory using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc.
# If you typically just start rtorrent with just "rtorrent" on the
# command line, all you need to change is the "user" option.
# Attach to the screen session as your user with
# "screen -dr rtorrent". Change "rtorrent" with srnname option.
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
##############
###</Notes>###
##############
#######################
##Start Configuration##
#######################
# You can specify your configuration in a different file
# (so that it is saved with upgrades, saved in your home directory,
# or whateve reason you want to)
# by commenting out/deleting the configuration lines and placing them
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
# have written them here (you can leave the comments if you desire
# and then uncommenting the following line correcting the path/filename
# for the one you used. note the space after the ".".
# . /etc/rtorrent.init.conf
#Do not put a space on either side of the equal signs e.g.
# user = user
# will not work
# system user to run as
user="user"
# the system group to run as, not implemented, see d_start for beginning implementation
# group=`id -ng "$user"`
# the full path to the filename where you store your rtorrent configuration
config="`su -c 'echo $HOME' $user`/.rtorrent.rc"
# set of options to run with
options=""
# default directory for screen, needs to be an absolute path
base="`su -c 'echo $HOME' $user`"
# name of screen session
srnname="rtorrent"
# file to log to (makes for easier debugging if something goes wrong)
logfile="/var/log/rtorrentInit.log"
#######################
###END CONFIGURATION###
#######################
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
DESC="rtorrent"
NAME=rtorrent
DAEMON=$NAME
SCRIPTNAME=/etc/init.d/$NAME
checkcnfg() {
exists=0
for i in `echo "$PATH" | tr ':' '\n'` ; do
if [ -f $i/$NAME ] ; then
exists=1
break
fi
done
if [ $exists -eq 0 ] ; then
echo "cannot find rtorrent binary in PATH $PATH" | tee -a "$logfile" >&2
exit 3
fi
if ! [ -r "${config}" ] ; then
echo "cannot find readable config ${config}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2
exit 3
fi
session=`getsession "$config"`
if ! [ -d "${session}" ] ; then
echo "cannot find readable session directory ${session} from config ${config}. check permissions" | tee -a "$logfile" >&2
exit 3
fi
}
d_start() {
[ -d "${base}" ] && cd "${base}"
stty stop undef && stty start undef
su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "screen -dm -S ${srnname} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
# this works for the screen command, but starting rtorrent below adopts screen session gid
# even if it is not the screen session we started (e.g. running under an undesirable gid
#su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2
su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
}
d_stop() {
session=`getsession "$config"`
if ! [ -s ${session}/rtorrent.lock ] ; then
return
fi
pid=`cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"`
if ps -A | grep -sq ${pid}.*rtorrent ; then # make sure the pid doesn't belong to another process
kill -s INT ${pid}
fi
}
getsession() {
session=`cat "$1" | grep "^[[:space:]]*session.path.set[[:space:]]*=" | sed "s/^[[:space:]]*session.path.set[[:space:]]*=[[:space:]]*//" `
echo $session
}
checkcnfg
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
restart|force-reload)
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
-166
View File
@@ -1,166 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: rtorrent_autostart
# Required-Start: $local_fs $remote_fs $network $syslog $netdaemons
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: rtorrent script using tmux
# Description: rtorrent script using tmux
### END INIT INFO
#############
###<Notes>###
#############
# This script depends on tmux and is based on 'rtorrentInitScreen.sh' script
# with the following enhancements:
# - init script 'start' option can be called without breaking anything
# - init script 'status' option can be used in scripts to determine whether rtorrent is running or not
# - auto removes damaged/stuck 'rtorrent.lock' file if necessary
# - saves session (just in case) before stopping with 'rtxmlrp' if it exists
# - provides examples how to script tmux windows
#
# For the stop function to work, you must set an explicit session directory
# using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc and with
# "sessiondir" option.
# If you typically just start rtorrent with just "rtorrent" on the
# command line, all you need to change is the "user" and "sessiondir" option.
# Attach to the tmux session as your user with
# "tmux -2u new-session -A -s rtorrent". Change "rtorrent" with "tmuxname" option.
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
##############
###</Notes>###
##############
#######################
##Start Configuration##
#######################
# You can specify your configuration in a different file.
# (so that it is saved with upgrades, saved in your home directory,
# or whatever reason you want to)
# by commenting out/deleting the configuration lines and placing them
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
# have written them here (you can leave the comments if you desire
# and then uncommenting the following line correcting the path/filename.
# for the one you used. note the space after the ".".
# . /etc/rtorrent.init.conf
# system user to run as
user="username"
# default directory for tmux, needs to be an absolute path
base=$(su -c 'echo $HOME' $user)
# the full path to the filename where you store your rtorrent configuration
config="$base/.rtorrent.rc"
# the full path to the session directory of rtorrent
sessiondir="/mnt/Torrents/.rtorrent/.session"
# options to pass to rtorrent; e.g. don't read config from $HOME but load alternate
#options="-n -O import=$config"
options=""
# name of tmux session
tmuxname="rtorrent"
# name of window in tmux session
tmuxwindowname="rT"
#######################
###END CONFIGURATION###
#######################
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
NAME=rtorrent
DAEMON=$NAME
SCRIPTNAME=/etc/init.d/$NAME
RTXMLRPCBIN="$base/bin/rtxmlrpc"
checkcnfg() {
if [ -z "$(which $DAEMON)" ] ; then
echo "Cannot find $DAEMON binary in PATH: $PATH"
exit 3
fi
if ! [ -r "$config" ] ; then
echo "Cannot find readable config $config. Check that it is there and permissions are appropriate"
exit 3
fi
if ! [ -d "$sessiondir" ] ; then
echo "Cannot find readable session directory $sessiondir from config $config. Check permissions"
exit 3
fi
}
status() {
if [ -e "${sessiondir}/rtorrent.lock" ] ; then
pid=`cat ${sessiondir}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"`
# make sure the pid isn't empty and doesn't belong to another process : this will match lines containing rtorrent, which grep '[r]torrent' does not!
# if there is no process as the 'pid' suggests then delete the stuck "rtorrent.lock" file (to be able to start rtorrent)
[[ -n "$pid" ]] && ps aux | grep -sq ${pid}.*[r]torrent && echo -e ${pid} || rm -f "${sessiondir}/rtorrent.lock"
fi
}
d_start() {
[ -d "$base" ] && cd "$base"
# if STDIN is a terminal (we are using interactive mode)
[ -t 0 ] && stty stop undef && stty start undef
# start the default 2 tmux window (bash and mc) if there isn't tmux session called "tmuxname" option (rtorrent)
if ! su -c "tmux ls | grep -sq ${tmuxname}: " $user ; then
# 1st window (0): split it into 3 panes, display 'date' in the last one
su -c "tmux -2u new-session -d -s ${tmuxname} -n 'shell1'" $user
su -c "tmux -2u split-window -v -t ${tmuxname}:0 'bash'" $user
su -c "tmux -2u split-window -h -t ${tmuxname}:0 'date; bash'" $user
# 2nd window (1): start 'mc' if it exists
su -c "tmux -2u new-window -t ${tmuxname}:1 -n 'mc1' 'command which mc && mc ~/; bash'" $user
fi
# start rtorrent always in the 3rd tmux window (2) if it's not running and leave shell behind to be able to see reason of a crash
if [ "$(status)" == "" ]; then
su -c "tmux -2u list-panes -t ${tmuxname}:2 &>/dev/null && tmux -2u respawn-pane -t ${tmuxname}:2 -k \"${DAEMON} ${options}; bash\" || tmux -2u new-window -t ${tmuxname}:2 -n ${tmuxwindowname} \"${DAEMON} ${options}; bash\"" $user
fi
}
d_stop() {
pid=$(status)
if [ "$pid" != "" ]; then
# save session before stopping explicitly (just in case) if rtxmlrpc util exists then wait for 5 seconds to be able to complete it
[ -L "$RTXMLRPCBIN" ] && "$RTXMLRPCBIN" session.save &>/dev/null && sleep 5
# INT (2, Interrupt from keyboard): normal shutdown
kill -s INT $pid
fi
}
checkcnfg
case "$1" in
start)
echo -n "Starting $tmuxwindowname: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $tmuxwindowname: $NAME"
d_stop
echo "."
;;
restart|force-reload)
echo -n "Restarting $tmuxwindowname: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
status)
status
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
-23
View File
@@ -1,23 +0,0 @@
#!/usr/bin/env bash
PORT_NUMBER=${1:-5001}
echo "Option Strings"
echo "=============="
echo
echo "Introduction"
echo "------------"
echo
echo "Client version: " `xmlrpc2scgi.py -p scgi://127.0.0.1:${PORT_NUMBER} system.client_version`
echo
echo "Generated by 'rtorrent/doc/scripts/print_option_string.sh' on `date -u`."
for i in strings.choke_heuristics strings.choke_heuristics.upload strings.choke_heuristics.download strings.connection_type strings.encryption strings.ip_filter strings.ip_tos strings.log_group strings.tracker_event strings.tracker_mode; do
echo
echo $i
echo `echo $i | tr 'a-z_.' '-'`
echo
echo '```'
xmlrpc2scgi.py -p scgi://127.0.0.1:${PORT_NUMBER} $i | tr , '\n' | tr '[' ' ' | tr ']' ' '
echo '```'
done
File diff suppressed because it is too large Load Diff
-1
View File
@@ -1 +0,0 @@
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
@@ -1,343 +0,0 @@
{
<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
}
-127
View File
@@ -1,127 +0,0 @@
-- The "rtorrent" table is passed in by the C++ code, modify and
-- return it for loading.
local args = {...}
local rtorrent = args[1]
local math = require('math')
-- Autocall
-- Passes an empty first argument implicitly, as "".
-- Allows syntax like:
-- - `rtorrent.autocall.system.hostname()` or
-- - `rtorrent.autocall.session.directory.set("/tmp/")`
-- Has assignment operator, syntax sugar for `.set()` with single argument
-- - `rtorrent.autocall.session.directory = "/tmp/"`
-- Autocall-chains can be reused as aliases:
-- ```lua
-- a = rtorrent.autocall.system
-- a.hostname() -- same as `rtorrent.autocall.system.hostname()`
-- a.pid() -- same as `rtorrent.autocall.system.pid()`
local mt = {}
function mt.__call (t, ...)
name = table.concat(rawget(t, "__namestack"), ".")
tg = rawget(t, "__target") or ""
success, ret = pcall(rtorrent.call, name, tg, ...)
if not success then error(name..": "..ret, 2) end
return ret
end
function mt.__index (t, key)
ns = {table.unpack(rawget(t, "__namestack") or {})}
tg = rawget(t, "__target") or nil
table.insert(ns, key)
return setmetatable({__namestack=ns, __target=tg}, mt)
end
function mt.__newindex (t, key, value)
t[key].set(value)
end
rtorrent["autocall"] = setmetatable({}, mt)
-- Target-object
-- Sets first argment for Autocall, for commands that require target.
-- Second argument allows to add prefix to command.
-- Allows syntax like:
-- - `rtorrent.Target("some_infohash").d.name()` or
-- - `rtorrent.Target:new("some_infohash").d.name()`
-- Also can be stored as variable
local Target = setmetatable({
new = function (self, target, prefix)
return self(target, prefix)
end;
}, {
__call = function (self, target, prefix)
return setmetatable(
{__namestack={prefix}, __target=target}, mt)
end
})
rtorrent["Target"] = Target
-- Some aliases for Target-commands
for i, p in ipairs({ "d", "f", "p", "t", "load" }) do
rtorrent[p] = function (target) return Target(target, p) end
end
-- Insert Lua method
-- Allow insert global lua-finction `func_name` at rtorrent slot `name`
-- @param name string rtorrent's slot
-- @param func_name string name of global lua-function
-- @param method_args number|string[]|number[]
-- rtorrent's arguments like `(d.name)` to be passed to lua-function when it be
-- called by rtorrent:
--
-- 1) non-negative integer - number of first arguments to be passed
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', 1)
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.0
--
-- 2) table (array) of strings - concrete rtorrent strings, passed in specified
-- order
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { '$argument.0=' })
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.0
--
-- 3) table (array) of non-negative integer - indexes, converted to
-- $argument.0, $argument.1 ..., passed in specified order
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { 1, 0 })
-- or:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { [1]=1, [2]=0 })
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.1,$argument.0
--
-- NOTE: first argement of func_name is always target, may be empty string
rtorrent["insert_lua_method"] = function (name, func_name, method_args)
local args = {}
if method_args == nil then method_args = 0 end
if math.type(method_args) == 'integer' and method_args >= 0 then
for i = 1, method_args do
args[i] = "$argument." .. i-1 .. "="
end
elseif type(method_args) == 'table' then
for i, v in ipairs(method_args) do
if type(v) == 'string' then
args[i] = v
elseif math.type(v) == 'integer' and v >= 0 then
args[i] = "$argument." .. v .. "="
else
error("Incorrect arguments")
end
end
else
error("Incorrect arguments")
end
local arg_str = table.concat(args, ",")
if #arg_str > 0 then arg_str = ","..arg_str end
rtorrent.autocall.method.insert(name, "simple", 'lua.execute.str="return '..func_name..'(...)"'..arg_str)
end
return rtorrent
+98
View File
@@ -0,0 +1,98 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// 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 <rak/socket_address.h>
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; }
socket_address* address() { return reinterpret_cast<socket_address*>(m_addrinfo.ai_addr); }
addrinfo* c_addrinfo() { return &m_addrinfo; }
const addrinfo* c_addrinfo() const { return &m_addrinfo; }
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
+181
View File
@@ -0,0 +1,181 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_ALGORITHM_H
#define RAK_ALGORITHM_H
#include <algorithm>
#include <functional>
#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 : public std::binary_function<_Value, _Value, bool> {
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
if (std::numeric_limits<T>::digits <= std::numeric_limits<unsigned int>::digits)
return __builtin_popcount(t);
else
return __builtin_popcountll(t);
#else
#error __builtin_popcount not found.
unsigned int count = 0;
while (t) {
count += t & 0x1;
t >> 1;
}
return count;
#endif
}
}
#endif
+110
View File
@@ -0,0 +1,110 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// Some allocators for cacheline aligned chunks of memory, etc.
#ifndef RAK_ALLOCATORS_H
#define RAK_ALLOCATORS_H
#include <cstddef>
#include <limits>
#include <stdlib.h>
#include <sys/types.h>
namespace rak {
template <class T = void*>
class cacheline_allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef const void* const_void_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
cacheline_allocator() throw() { }
cacheline_allocator(const cacheline_allocator&) throw() { }
template <class U>
cacheline_allocator(const cacheline_allocator<U>&) throw() { }
~cacheline_allocator() throw() { }
template <class U>
struct rebind { typedef cacheline_allocator<U> other; };
// return address of values
pointer address (reference value) const { return &value; }
const_pointer address (const_reference value) const { return &value; }
size_type max_size () const throw() { return std::numeric_limits<size_t>::max() / sizeof(T); }
pointer allocate(size_type num, const_void_pointer hint = 0) { return alloc_size(num*sizeof(T)); }
static pointer alloc_size(size_type size) {
pointer ptr = NULL;
int __UNUSED result = posix_memalign((void**)&ptr, LT_SMP_CACHE_BYTES, size);
return ptr;
}
void construct (pointer p, const T& value) { new((void*)p)T(value); }
void destroy (pointer p) { p->~T(); }
void deallocate (pointer p, size_type num) { free((void*)p); }
};
template <class T1, class T2>
bool operator== (const cacheline_allocator<T1>&, const cacheline_allocator<T2>&) throw() {
return true;
}
template <class T1, class T2>
bool operator!= (const cacheline_allocator<T1>&, const cacheline_allocator<T2>&) throw() {
return false;
}
}
//
// Operator new with custom allocators:
//
template <typename T>
void* operator new(size_t s, rak::cacheline_allocator<T> a) { return a.alloc_size(s); }
#endif // namespace rak
+88
View File
@@ -0,0 +1,88 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_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
+77
View File
@@ -0,0 +1,77 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_FILE_STAT_H
#define RAK_FILE_STAT_H
#include <string>
#include <inttypes.h>
#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
+84
View File
@@ -0,0 +1,84 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_FS_STAT_H
#define RAK_FS_STAT_H
#include <string>
#include <inttypes.h>
#include <rak/error_number.h>
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
namespace rak {
class fs_stat {
public:
typedef FS_STAT_SIZE_TYPE blocksize_type;
typedef FS_STAT_COUNT_TYPE blockcount_type;
typedef FS_STAT_STRUCT fs_stat_type;
bool update(int fd) { return FS_STAT_FD; }
bool update(const char* fn) { return FS_STAT_FN; }
bool update(const std::string& filename) { return update(filename.c_str()); }
blocksize_type blocksize() { return FS_STAT_BLOCK_SIZE; }
blockcount_type blocks_avail() { return m_stat.f_bavail; }
int64_t bytes_avail() { return (int64_t) blocksize() * m_stat.f_bavail; }
private:
fs_stat_type m_stat;
};
}
#endif
+683
View File
@@ -0,0 +1,683 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_FUNCTIONAL_H
#define RAK_FUNCTIONAL_H
#include <cstddef>
#include <functional>
namespace rak {
template <typename Type>
struct reference_fix {
typedef Type type;
};
template <typename Type>
struct reference_fix<Type&> {
typedef Type type;
};
template <typename Type>
struct value_t {
value_t(Type v) : m_v(v) {}
Type operator () () const { return m_v; }
Type m_v;
};
template <typename Type>
inline value_t<Type>
value(Type v) {
return value_t<Type>(v);
}
template <typename Type, typename Ftor>
struct accumulate_t {
accumulate_t(Type t, Ftor f) : result(t), m_f(f) {}
template <typename Arg>
void operator () (const Arg& a) { result += m_f(a); }
Type result;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline accumulate_t<Type, Ftor>
accumulate(Type t, Ftor f) {
return accumulate_t<Type, Ftor>(t, f);
}
// Operators:
template <typename Type, typename Ftor>
struct equal_t {
typedef bool result_type;
equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t == m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline equal_t<Type, Ftor>
equal(Type t, Ftor f) {
return equal_t<Type, Ftor>(t, f);
}
template <typename Type, typename Ftor>
struct equal_ptr_t {
typedef bool result_type;
equal_ptr_t(Type* t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (const Arg& a) {
return *m_t == *m_f(a);
}
Type* m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline equal_ptr_t<Type, Ftor>
equal_ptr(Type* t, Ftor f) {
return equal_ptr_t<Type, Ftor>(t, f);
}
template <typename Type, typename Ftor>
struct not_equal_t {
typedef bool result_type;
not_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t != m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline not_equal_t<Type, Ftor>
not_equal(Type t, Ftor f) {
return not_equal_t<Type, Ftor>(t, f);
}
template <typename Type, typename Ftor>
struct less_t {
typedef bool result_type;
less_t(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t < m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline less_t<Type, Ftor>
less(Type t, Ftor f) {
return less_t<Type, Ftor>(t, f);
}
template <typename FtorA, typename FtorB>
struct less2_t : public std::binary_function<typename FtorA::argument_type, typename FtorB::argument_type, bool> {
less2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {}
bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) {
return m_f_a(a) < m_f_b(b);
}
FtorA m_f_a;
FtorB m_f_b;
};
template <typename FtorA, typename FtorB>
inline less2_t<FtorA, FtorB>
less2(FtorA f_a, FtorB f_b) {
return less2_t<FtorA,FtorB>(f_a,f_b);
}
template <typename Type, typename Ftor>
struct _greater {
typedef bool result_type;
_greater(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t > m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline _greater<Type, Ftor>
greater(Type t, Ftor f) {
return _greater<Type, Ftor>(t, f);
}
template <typename FtorA, typename FtorB>
struct greater2_t : public std::binary_function<typename FtorA::argument_type, typename FtorB::argument_type, bool> {
greater2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {}
bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) {
return m_f_a(a) > m_f_b(b);
}
FtorA m_f_a;
FtorB m_f_b;
};
template <typename FtorA, typename FtorB>
inline greater2_t<FtorA, FtorB>
greater2(FtorA f_a, FtorB f_b) {
return greater2_t<FtorA,FtorB>(f_a,f_b);
}
template <typename Type, typename Ftor>
struct less_equal_t {
typedef bool result_type;
less_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t <= m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline less_equal_t<Type, Ftor>
less_equal(Type t, Ftor f) {
return less_equal_t<Type, Ftor>(t, f);
}
template <typename Type, typename Ftor>
struct greater_equal_t {
typedef bool result_type;
greater_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
template <typename Arg>
bool operator () (Arg& a) {
return m_t >= m_f(a);
}
Type m_t;
Ftor m_f;
};
template <typename Type, typename Ftor>
inline greater_equal_t<Type, Ftor>
greater_equal(Type t, Ftor f) {
return greater_equal_t<Type, Ftor>(t, f);
}
template<typename Tp>
struct invert : public std::unary_function<Tp, Tp> {
Tp
operator () (const Tp& x) const { return ~x; }
};
template <typename Src, typename Dest>
struct on_t : public std::unary_function<typename Src::argument_type, typename Dest::result_type> {
typedef typename Dest::result_type result_type;
on_t(Src s, Dest d) : m_dest(d), m_src(s) {}
result_type operator () (typename reference_fix<typename Src::argument_type>::type arg) {
return m_dest(m_src(arg));
}
Dest m_dest;
Src m_src;
};
template <typename Src, typename Dest>
inline on_t<Src, Dest>
on(Src s, Dest d) {
return on_t<Src, Dest>(s, d);
}
template <typename Src, typename Dest>
struct on2_t : public std::binary_function<typename Src::argument_type, typename Dest::second_argument_type, typename Dest::result_type> {
typedef typename Dest::result_type result_type;
on2_t(Src s, Dest d) : m_dest(d), m_src(s) {}
result_type operator () (typename reference_fix<typename Src::argument_type>::type first, typename reference_fix<typename Dest::second_argument_type>::type second) {
return m_dest(m_src(first), second);
}
Dest m_dest;
Src m_src;
};
template <typename Src, typename Dest>
inline on2_t<Src, Dest>
on2(Src s, Dest d) {
return on2_t<Src, Dest>(s, d);
}
// Creates a functor for accessing a member.
template <typename Class, typename Member>
struct mem_ptr_t : public std::unary_function<Class*, Member&> {
mem_ptr_t(Member Class::*m) : m_member(m) {}
Member& operator () (Class* c) {
return c->*m_member;
}
const Member& operator () (const Class* c) {
return c->*m_member;
}
Member Class::*m_member;
};
template <typename Class, typename Member>
inline mem_ptr_t<Class, Member>
mem_ptr(Member Class::*m) {
return mem_ptr_t<Class, Member>(m);
}
template <typename Class, typename Member>
struct mem_ref_t : public std::unary_function<Class&, Member&> {
mem_ref_t(Member Class::*m) : m_member(m) {}
Member& operator () (Class& c) {
return c.*m_member;
}
Member Class::*m_member;
};
template <typename Class, typename Member>
struct const_mem_ref_t : public std::unary_function<const Class&, const Member&> {
const_mem_ref_t(const Member Class::*m) : m_member(m) {}
const Member& operator () (const Class& c) {
return c.*m_member;
}
const Member Class::*m_member;
};
template <typename Class, typename Member>
inline mem_ref_t<Class, Member>
mem_ref(Member Class::*m) {
return mem_ref_t<Class, Member>(m);
}
template <typename Class, typename Member>
inline const_mem_ref_t<Class, Member>
const_mem_ref(const Member Class::*m) {
return const_mem_ref_t<Class, Member>(m);
}
template <typename Cond, typename Then>
struct if_then_t {
if_then_t(Cond c, Then t) : m_cond(c), m_then(t) {}
template <typename Arg>
void operator () (Arg& a) {
if (m_cond(a))
m_then(a);
}
Cond m_cond;
Then m_then;
};
template <typename Cond, typename Then>
inline if_then_t<Cond, Then>
if_then(Cond c, Then t) {
return if_then_t<Cond, Then>(c, t);
}
template <typename T>
struct call_delete : public std::unary_function<T*, void> {
void operator () (T* t) {
delete t;
}
};
template <typename T>
inline void
call_delete_func(T* t) {
delete t;
}
template <typename Operation>
class bind1st_t : public std::unary_function<typename Operation::second_argument_type, typename Operation::result_type> {
public:
typedef typename reference_fix<typename Operation::first_argument_type>::type value_type;
typedef typename reference_fix<typename Operation::second_argument_type>::type argument_type;
bind1st_t(const Operation& op, const value_type v) :
m_op(op), m_value(v) {}
typename Operation::result_type
operator () (const argument_type arg) {
return m_op(m_value, arg);
}
protected:
Operation m_op;
value_type m_value;
};
template <typename Operation, typename Type>
inline bind1st_t<Operation>
bind1st(const Operation& op, const Type& val) {
return bind1st_t<Operation>(op, val);
}
template <typename Operation>
class bind2nd_t : public std::unary_function<typename Operation::first_argument_type, typename Operation::result_type> {
public:
typedef typename reference_fix<typename Operation::first_argument_type>::type argument_type;
typedef typename reference_fix<typename Operation::second_argument_type>::type value_type;
bind2nd_t(const Operation& op, const value_type v) :
m_op(op), m_value(v) {}
typename Operation::result_type
operator () (argument_type arg) {
return m_op(arg, m_value);
}
protected:
Operation m_op;
value_type m_value;
};
template <typename Operation, typename Type>
inline bind2nd_t<Operation>
bind2nd(const Operation& op, const Type& val) {
return bind2nd_t<Operation>(op, val);
}
// Lightweight callback function including pointer to object. Should
// be replaced by TR1 stuff later. Requires an object to bind, instead
// of using a seperate functor for that.
template <typename Ret>
class ptr_fun0 {
public:
typedef Ret result_type;
typedef Ret (*Function)();
ptr_fun0() {}
ptr_fun0(Function f) : m_function(f) {}
bool is_valid() const { return m_function; }
Ret operator () () { return m_function(); }
private:
Function m_function;
};
template <typename Object, typename Ret>
class mem_fun0 {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)();
mem_fun0() : m_object(NULL) {}
mem_fun0(Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
Ret operator () () { return (m_object->*m_function)(); }
private:
Object* m_object;
Function m_function;
};
template <typename Object, typename Ret>
class const_mem_fun0 {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)() const;
const_mem_fun0() : m_object(NULL) {}
const_mem_fun0(const Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
Ret operator () () const { return (m_object->*m_function)(); }
private:
const Object* m_object;
Function m_function;
};
template <typename Object, typename Ret, typename Arg1>
class mem_fun1 {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)(Arg1);
mem_fun1() : m_object(NULL) {}
mem_fun1(Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
Ret operator () (Arg1 a1) { return (m_object->*m_function)(a1); }
private:
Object* m_object;
Function m_function;
};
template <typename Object, typename Ret, typename Arg1>
class const_mem_fun1 {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)(Arg1) const;
const_mem_fun1() : m_object(NULL) {}
const_mem_fun1(const Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
Ret operator () (Arg1 a1) const { return (m_object->*m_function)(a1); }
private:
const Object* m_object;
Function m_function;
};
template <typename Object, typename Ret, typename Arg1, typename Arg2>
class mem_fun2 : public std::binary_function<Arg1, Arg2, Ret> {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)(Arg1, Arg2);
typedef Object object_type;
mem_fun2() : m_object(NULL) {}
mem_fun2(Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
object_type* object() { return m_object; }
const object_type* object() const { return m_object; }
Ret operator () (Arg1 a1, Arg2 a2) { return (m_object->*m_function)(a1, a2); }
private:
Object* m_object;
Function m_function;
};
template <typename Object, typename Ret, typename Arg1, typename Arg2, typename Arg3>
class mem_fun3 {
public:
typedef Ret result_type;
typedef Ret (Object::*Function)(Arg1, Arg2, Arg3);
mem_fun3() : m_object(NULL) {}
mem_fun3(Object* o, Function f) : m_object(o), m_function(f) {}
bool is_valid() const { return m_object; }
Ret operator () (Arg1 a1, Arg2 a2, Arg3 a3) { return (m_object->*m_function)(a1, a2, a3); }
private:
Object* m_object;
Function m_function;
};
template <typename Ret>
inline ptr_fun0<Ret>
ptr_fun(Ret (*f)()) { return ptr_fun0<Ret>(f); }
template <typename Object, typename Ret>
inline mem_fun0<Object, Ret>
make_mem_fun(Object* o, Ret (Object::*f)()) {
return mem_fun0<Object, Ret>(o, f);
}
template <typename Object, typename Ret>
inline const_mem_fun0<Object, Ret>
make_mem_fun(const Object* o, Ret (Object::*f)() const) {
return const_mem_fun0<Object, Ret>(o, f);
}
template <typename Object, typename Ret, typename Arg1>
inline mem_fun1<Object, Ret, Arg1>
make_mem_fun(Object* o, Ret (Object::*f)(Arg1)) {
return mem_fun1<Object, Ret, Arg1>(o, f);
}
template <typename Object, typename Ret, typename Arg1>
inline const_mem_fun1<Object, Ret, Arg1>
make_mem_fun(const Object* o, Ret (Object::*f)(Arg1) const) {
return const_mem_fun1<Object, Ret, Arg1>(o, f);
}
template <typename Object, typename Ret, typename Arg1, typename Arg2>
inline mem_fun2<Object, Ret, Arg1, Arg2>
make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2)) {
return mem_fun2<Object, Ret, Arg1, Arg2>(o, f);
}
template <typename Object, typename Ret, typename Arg1, typename Arg2, typename Arg3>
inline mem_fun3<Object, Ret, Arg1, Arg2, Arg3>
make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2, Arg3)) {
return mem_fun3<Object, Ret, Arg1, Arg2, Arg3>(o, f);
}
template <typename Container>
inline void
slot_list_call(const Container& slot_list) {
if (slot_list.empty())
return;
typename Container::const_iterator first = slot_list.begin();
typename Container::const_iterator next = slot_list.begin();
while (++next != slot_list.end()) {
(*first)();
first = next;
}
(*first)();
}
template <typename Container, typename Arg1>
inline void
slot_list_call(const Container& slot_list, Arg1 arg1) {
if (slot_list.empty())
return;
typename Container::const_iterator first = slot_list.begin();
typename Container::const_iterator next = slot_list.begin();
while (++next != slot_list.end()) {
(*first)(arg1);
first = next;
}
(*first)(arg1);
}
template <typename Container, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
inline void
slot_list_call(const Container& slot_list, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
if (slot_list.empty())
return;
typename Container::const_iterator first = slot_list.begin();
typename Container::const_iterator next = slot_list.begin();
while (++next != slot_list.end()) {
(*first)(arg1, arg2, arg3, arg4);
first = next;
}
(*first)(arg1, arg2, arg3, arg4);
}
}
#endif
+656
View File
@@ -0,0 +1,656 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// This file contains functors that wrap function pointers and member
// function pointers.
//
// 'fn' functors are polymorphic and derives from 'rak::function' and
// thus is less strict about types, this adds the cost of calling a
// virtual function.
//
// 'fun' functors are non-polymorphic and thus cheaper, but requires
// the target object's type in the functor's template arguments.
//
// This should be replaced with TR1 stuff when it becomes widely
// available. At the moment it behaves like std::auto_ptr, so be
// careful when copying.
#ifndef RAK_FUNCTIONAL_FUN_H
#define RAK_FUNCTIONAL_FUN_H
#include <memory>
#include <functional>
#include <tr1/functional>
#include <tr1/memory>
namespace rak {
template <typename Result>
class function_base0 {
public:
virtual ~function_base0() {}
virtual Result operator () () = 0;
};
template <typename Result, typename Arg1>
class function_base1 : public std::unary_function<Arg1, Result> {
public:
virtual ~function_base1() {}
virtual Result operator () (Arg1 arg1) = 0;
};
template <typename Result, typename Arg1, typename Arg2>
class function_base2 : public std::binary_function<Arg1, Arg2, Result> {
public:
virtual ~function_base2() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2) = 0;
};
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
class function_base3 {
public:
virtual ~function_base3() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) = 0;
};
template <typename Result>
class function0 {
public:
typedef Result result_type;
typedef function_base0<Result> base_type;
bool is_valid() const { return m_base.get() != NULL; }
void set(base_type* base) { m_base = std::tr1::shared_ptr<base_type>(base); }
base_type* release() { return m_base.release(); }
Result operator () () { return (*m_base)(); }
private:
std::tr1::shared_ptr<base_type> m_base;
};
template <typename Result, typename Arg1>
class function1 {
public:
typedef Result result_type;
typedef function_base1<Result, Arg1> base_type;
bool is_valid() const { return m_base.get() != NULL; }
void set(base_type* base) { m_base = std::tr1::shared_ptr<base_type>(base); }
base_type* release() { return m_base.release(); }
Result operator () (Arg1 arg1) { return (*m_base)(arg1); }
private:
std::tr1::shared_ptr<base_type> m_base;
};
template <typename Result, typename Arg1, typename Arg2>
class function2 {
public:
typedef Result result_type;
typedef function_base2<Result, Arg1, Arg2> base_type;
bool is_valid() const { return m_base.get() != NULL; }
void set(base_type* base) { m_base = std::tr1::shared_ptr<base_type>(base); }
base_type* release() { return m_base.release(); }
Result operator () (Arg1 arg1, Arg2 arg2) { return (*m_base)(arg1, arg2); }
private:
std::tr1::shared_ptr<base_type> m_base;
};
template <typename Result, typename Arg2>
class function2<Result, void, Arg2> {
public:
typedef Result result_type;
typedef function_base1<Result, Arg2> base_type;
bool is_valid() const { return m_base.get() != NULL; }
void set(base_type* base) { m_base = std::tr1::shared_ptr<base_type>(base); }
base_type* release() { return m_base.release(); }
Result operator () (Arg2 arg2) { return (*m_base)(arg2); }
template <typename Discard>
Result operator () (Discard discard, Arg2 arg2) { return (*m_base)(arg2); }
private:
std::tr1::shared_ptr<base_type> m_base;
};
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
class function3 {
public:
typedef Result result_type;
typedef function_base3<Result, Arg1, Arg2, Arg3> base_type;
bool is_valid() const { return m_base.get() != NULL; }
void set(base_type* base) { m_base = std::tr1::shared_ptr<base_type>(base); }
base_type* release() { return m_base.release(); }
Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (*m_base)(arg1, arg2, arg3); }
private:
std::tr1::shared_ptr<base_type> m_base;
};
template <typename Result>
class ptr_fn0_t : public function_base0<Result> {
public:
typedef Result (*Func)();
ptr_fn0_t(Func func) : m_func(func) {}
virtual ~ptr_fn0_t() {}
virtual Result operator () () { return m_func(); }
private:
Func m_func;
};
template <typename Result, typename Arg1>
class ptr_fn1_t : public function_base1<Result, Arg1> {
public:
typedef Result (*Func)(Arg1);
ptr_fn1_t(Func func) : m_func(func) {}
virtual ~ptr_fn1_t() {}
virtual Result operator () (Arg1 arg1) { return m_func(arg1); }
private:
Func m_func;
};
template <typename Result, typename Arg1, typename Arg2>
class ptr_fn2_t : public function_base2<Result, Arg1, Arg2> {
public:
typedef Result (*Func)(Arg1, Arg2);
ptr_fn2_t(Func func) : m_func(func) {}
virtual ~ptr_fn2_t() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2) { return m_func(arg1, arg2); }
private:
Func m_func;
};
template <typename Object, typename Result>
class mem_fn0_t : public function_base0<Result> {
public:
typedef Result (Object::*Func)();
mem_fn0_t(Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~mem_fn0_t() {}
virtual Result operator () () { return (m_object->*m_func)(); }
private:
Object* m_object;
Func m_func;
};
template <typename Object, typename Result, typename Arg1>
class mem_fn1_t : public function_base1<Result, Arg1> {
public:
typedef Result (Object::*Func)(Arg1);
mem_fn1_t(Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~mem_fn1_t() {}
virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); }
private:
Object* m_object;
Func m_func;
};
template <typename Object, typename Result, typename Arg1, typename Arg2, typename Arg3>
class mem_fn3_t : public function_base3<Result, Arg1, Arg2, Arg3> {
public:
typedef Result (Object::*Func)(Arg1, Arg2, Arg3);
mem_fn3_t(Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~mem_fn3_t() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (m_object->*m_func)(arg1, arg2, arg3); }
private:
Object* m_object;
Func m_func;
};
template <typename Object, typename Result, typename Arg1, typename Arg2>
class mem_fn2_t : public function_base2<Result, Arg1, Arg2> {
public:
typedef Result (Object::*Func)(Arg1, Arg2);
mem_fn2_t(Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~mem_fn2_t() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2) { return (m_object->*m_func)(arg1, arg2); }
private:
Object* m_object;
Func m_func;
};
template <typename Object, typename Result>
class const_mem_fn0_t : public function_base0<Result> {
public:
typedef Result (Object::*Func)() const;
const_mem_fn0_t(const Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~const_mem_fn0_t() {}
virtual Result operator () () { return (m_object->*m_func)(); }
private:
const Object* m_object;
Func m_func;
};
template <typename Object, typename Result, typename Arg1>
class const_mem_fn1_t : public function_base1<Result, Arg1> {
public:
typedef Result (Object::*Func)(Arg1) const;
const_mem_fn1_t(const Object* object, Func func) : m_object(object), m_func(func) {}
virtual ~const_mem_fn1_t() {}
virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); }
private:
const Object* m_object;
Func m_func;
};
// Unary functor with a bound argument.
template <typename Object, typename Result, typename Arg1>
class mem_fn0_b1_t : public function_base0<Result> {
public:
typedef Result (Object::*Func)(Arg1);
mem_fn0_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {}
virtual ~mem_fn0_b1_t() {}
virtual Result operator () () { return (m_object->*m_func)(m_arg1); }
private:
Object* m_object;
Func m_func;
const Arg1 m_arg1;
};
template <typename Object, typename Result, typename Arg1, typename Arg2>
class mem_fn1_b1_t : public function_base1<Result, Arg2> {
public:
typedef Result (Object::*Func)(Arg1, Arg2);
mem_fn1_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {}
virtual ~mem_fn1_b1_t() {}
virtual Result operator () (const Arg2 arg2) { return (m_object->*m_func)(m_arg1, arg2); }
private:
Object* m_object;
Func m_func;
const Arg1 m_arg1;
};
template <typename Object, typename Result, typename Arg1, typename Arg2>
class mem_fn1_b2_t : public function_base1<Result, Arg1> {
public:
typedef Result (Object::*Func)(Arg1, Arg2);
mem_fn1_b2_t(Object* object, Func func, const Arg2 arg2) : m_object(object), m_func(func), m_arg2(arg2) {}
virtual ~mem_fn1_b2_t() {}
virtual Result operator () (const Arg1 arg1) { return (m_object->*m_func)(arg1, m_arg2); }
private:
Object* m_object;
Func m_func;
const Arg2 m_arg2;
};
template <typename Result, typename Arg1>
class ptr_fn0_b1_t : public function_base0<Result> {
public:
typedef Result (*Func)(Arg1);
ptr_fn0_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
virtual ~ptr_fn0_b1_t() {}
virtual Result operator () () { return m_func(m_arg1); }
private:
Func m_func;
Arg1 m_arg1;
};
template <typename Result, typename Arg1, typename Arg2>
class ptr_fn1_b1_t : public function_base1<Result, Arg2> {
public:
typedef Result (*Func)(Arg1, Arg2);
ptr_fn1_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
virtual ~ptr_fn1_b1_t() {}
virtual Result operator () (Arg2 arg2) { return m_func(m_arg1, arg2); }
private:
Func m_func;
Arg1 m_arg1;
};
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
class ptr_fn2_b1_t : public function_base2<Result, Arg2, Arg3> {
public:
typedef Result (*Func)(Arg1, Arg2, Arg3);
ptr_fn2_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
virtual ~ptr_fn2_b1_t() {}
virtual Result operator () (Arg2 arg2, Arg3 arg3) { return m_func(m_arg1, arg2, arg3); }
private:
Func m_func;
Arg1 m_arg1;
};
template <typename Ftor>
class ftor_fn1_t : public function_base1<typename Ftor::result_type, typename Ftor::argument_type> {
public:
typedef typename Ftor::result_type result_type;
typedef typename Ftor::argument_type argument_type;
ftor_fn1_t(Ftor ftor) : m_ftor(ftor) {}
virtual ~ftor_fn1_t() {}
virtual result_type operator () (argument_type arg1) { return m_ftor(arg1); }
private:
Ftor m_ftor;
};
template <typename Ftor>
class ftor_fn2_t : public function_base2<typename Ftor::result_type, typename Ftor::first_argument_type, typename Ftor::second_argument_type> {
public:
typedef typename Ftor::result_type result_type;
typedef typename Ftor::first_argument_type first_argument_type;
typedef typename Ftor::second_argument_type second_argument_type;
ftor_fn2_t(Ftor ftor) : m_ftor(ftor) {}
virtual ~ftor_fn2_t() {}
virtual result_type operator () (first_argument_type arg1, second_argument_type arg2) { return m_ftor(arg1, arg2); }
private:
Ftor m_ftor;
};
template <typename Result>
class value_fn0_t : public function_base0<Result> {
public:
value_fn0_t(const Result& val) : m_value(val) {}
virtual Result operator () () { return m_value; }
private:
Result m_value;
};
template <typename Result, typename SrcResult>
class convert_fn0_t : public function_base0<Result> {
public:
typedef function0<SrcResult> src_type;
convert_fn0_t(typename src_type::base_type* object) { m_object.set(object); }
virtual ~convert_fn0_t() {}
virtual Result operator () () {
return m_object();
}
private:
src_type m_object;
};
template <typename Result, typename Arg1, typename SrcResult, typename SrcArg1>
class convert_fn1_t : public function_base1<Result, Arg1> {
public:
typedef function1<SrcResult, SrcArg1> src_type;
convert_fn1_t(typename src_type::base_type* object) { m_object.set(object); }
virtual ~convert_fn1_t() {}
virtual Result operator () (Arg1 arg1) {
return m_object(arg1);
}
private:
src_type m_object;
};
template <typename Result, typename Arg1, typename Arg2, typename SrcResult, typename SrcArg1, typename SrcArg2>
class convert_fn2_t : public function_base2<Result, Arg1, Arg2> {
public:
typedef function2<SrcResult, SrcArg1, SrcArg2> src_type;
convert_fn2_t(typename src_type::base_type* object) { m_object.set(object); }
virtual ~convert_fn2_t() {}
virtual Result operator () (Arg1 arg1, Arg2 arg2) {
return m_object(arg1, arg2);
}
private:
src_type m_object;
};
template <typename Result>
inline function_base0<Result>*
ptr_fn(Result (*func)()) {
return new ptr_fn0_t<Result>(func);
}
template <typename Arg1, typename Result>
inline function_base1<Result, Arg1>*
ptr_fn(Result (*func)(Arg1)) {
return new ptr_fn1_t<Result, Arg1>(func);
}
template <typename Arg1, typename Arg2, typename Result>
inline function_base2<Result, Arg1, Arg2>*
ptr_fn(Result (*func)(Arg1, Arg2)) {
return new ptr_fn2_t<Result, Arg1, Arg2>(func);
}
template <typename Result, typename Object>
inline function_base0<Result>*
mem_fn(Object* object, Result (Object::*func)()) {
return new mem_fn0_t<Object, Result>(object, func);
}
template <typename Arg1, typename Result, typename Object>
inline function_base1<Result, Arg1>*
mem_fn(Object* object, Result (Object::*func)(Arg1)) {
return new mem_fn1_t<Object, Result, Arg1>(object, func);
}
template <typename Arg1, typename Arg2, typename Result, typename Object>
inline function_base2<Result, Arg1, Arg2>*
mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2)) {
return new mem_fn2_t<Object, Result, Arg1, Arg2>(object, func);
}
template <typename Arg1, typename Arg2, typename Arg3, typename Result, typename Object>
inline function_base3<Result, Arg1, Arg2, Arg3>*
mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2, Arg3)) {
return new mem_fn3_t<Object, Result, Arg1, Arg2, Arg3>(object, func);
}
template <typename Result, typename Object>
inline function_base0<Result>*
mem_fn(const Object* object, Result (Object::*func)() const) {
return new const_mem_fn0_t<Object, Result>(object, func);
}
template <typename Arg1, typename Result, typename Object>
inline function_base1<Result, Arg1>*
mem_fn(const Object* object, Result (Object::*func)(Arg1) const) {
return new const_mem_fn1_t<Object, Result, Arg1>(object, func);
}
template <typename Arg1, typename Result, typename Object>
inline function_base0<Result>*
bind_mem_fn(Object* object, Result (Object::*func)(Arg1), const Arg1 arg1) {
return new mem_fn0_b1_t<Object, Result, Arg1>(object, func, arg1);
}
template <typename Arg1, typename Arg2, typename Result, typename Object>
inline function_base1<Result, Arg2>*
bind_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg1 arg1) {
return new mem_fn1_b1_t<Object, Result, Arg1, Arg2>(object, func, arg1);
}
template <typename Arg1, typename Arg2, typename Result, typename Object>
inline function_base1<Result, Arg1>*
bind2_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg2 arg2) {
return new mem_fn1_b2_t<Object, Result, Arg1, Arg2>(object, func, arg2);
}
template <typename Arg1, typename Result>
inline function_base0<Result>*
bind_ptr_fn(Result (*func)(Arg1), const Arg1 arg1) {
return new ptr_fn0_b1_t<Result, Arg1>(func, arg1);
}
template <typename Arg1, typename Arg2, typename Result>
inline function_base1<Result, Arg2>*
bind_ptr_fn(Result (*func)(Arg1, Arg2), const Arg1 arg1) {
return new ptr_fn1_b1_t<Result, Arg1, Arg2>(func, arg1);
}
template <typename Arg1, typename Arg2, typename Arg3, typename Result>
inline function_base2<Result, Arg2, Arg3>*
bind_ptr_fn(Result (*func)(Arg1, Arg2, Arg3), const Arg1 arg1) {
return new ptr_fn2_b1_t<Result, Arg1, Arg2, Arg3>(func, arg1);
}
template <typename Ftor>
inline function_base1<typename Ftor::result_type, typename Ftor::argument_type>*
ftor_fn1(Ftor ftor) {
return new ftor_fn1_t<Ftor>(ftor);
}
template <typename Ftor>
inline function_base2<typename Ftor::result_type, typename Ftor::first_argument_type, typename Ftor::second_argument_type>*
ftor_fn2(Ftor ftor) {
return new ftor_fn2_t<Ftor>(ftor);
}
template <typename Result>
inline function_base0<Result>*
value_fn(const Result& val) {
return new value_fn0_t<Result>(val);
}
template <typename A, typename B>
struct equal_types_t {
typedef A first_type;
typedef B second_type;
const static int result = 0;
};
template <typename A>
struct equal_types_t<A, A> {
typedef A first_type;
typedef A second_type;
const static int result = 1;
};
template <typename Result, typename SrcResult>
inline function_base0<Result>*
convert_fn(function_base0<SrcResult>* src) {
if (equal_types_t<function_base0<Result>, function_base0<SrcResult> >::result)
// The pointer cast never gets done if the types are different,
// but needs to be here to pleasant the compiler.
return reinterpret_cast<typename equal_types_t<function_base0<Result>, function_base0<SrcResult> >::first_type*>(src);
else
return new convert_fn0_t<Result, SrcResult>(src);
}
template <typename Result, typename Arg1, typename SrcResult, typename SrcArg1>
inline function_base1<Result, Arg1>*
convert_fn(function_base1<SrcResult, SrcArg1>* src) {
if (equal_types_t<function_base1<Result, Arg1>, function_base1<SrcResult, SrcArg1> >::result)
// The pointer cast never gets done if the types are different,
// but needs to be here to pleasant the compiler.
return reinterpret_cast<typename equal_types_t<function_base1<Result, Arg1>, function_base1<SrcResult, SrcArg1> >::first_type*>(src);
else
return new convert_fn1_t<Result, Arg1, SrcResult, SrcArg1>(src);
}
template <typename Result, typename Arg1, typename Arg2, typename SrcResult, typename SrcArg1, typename SrcArg2>
inline function_base2<Result, Arg1, Arg2>*
convert_fn(function_base2<SrcResult, SrcArg1, SrcArg2>* src) {
if (equal_types_t<function_base2<Result, Arg1, Arg2>, function_base2<SrcResult, SrcArg1, SrcArg2> >::result)
// The pointer cast never gets done if the types are different,
// but needs to be here to pleasant the compiler.
return reinterpret_cast<typename equal_types_t<function_base2<Result, Arg1, Arg2>, function_base2<SrcResult, SrcArg1, SrcArg2> >::first_type*>(src);
else
return new convert_fn2_t<Result, Arg1, Arg2, SrcResult, SrcArg1, SrcArg2>(src);
}
}
#endif
+198
View File
@@ -0,0 +1,198 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_PARTIAL_QUEUE_H
#define RAK_PARTIAL_QUEUE_H
#include <cstring>
#include <stdexcept>
#include <inttypes.h>
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;
size_pair_type m_layers[num_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);
std::memset(m_layers, 0, num_layers * sizeof(size_pair_type));
}
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
+107
View File
@@ -0,0 +1,107 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// 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
+144
View File
@@ -0,0 +1,144 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// priority_queue is a priority queue implemented using a binary
// heap. It can contain multiple instances of a value.
#ifndef RAK_PRIORITY_QUEUE_H
#define RAK_PRIORITY_QUEUE_H
#include <algorithm>
#include <functional>
#include <vector>
namespace rak {
template <typename Value, typename Compare, typename Equal, typename Alloc = std::allocator<Value> >
class priority_queue : public std::vector<Value, Alloc> {
public:
typedef std::vector<Value, Alloc> base_type;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::value_type value_type;
using base_type::begin;
using base_type::end;
using base_type::size;
using base_type::empty;
priority_queue(Compare l = Compare(), Equal e = Equal())
: m_compare(l), m_equal(e) {}
const_reference top() const {
return base_type::front();
}
void pop() {
std::pop_heap(begin(), end(), m_compare);
base_type::pop_back();
}
void push(const value_type& value) {
base_type::push_back(value);
std::push_heap(begin(), end(), m_compare);
}
template <typename Key>
iterator find(const Key& key) {
return std::find_if(begin(), end(), std::bind2nd(m_equal, key));
}
template <typename Key>
bool erase(const Key& key) {
iterator itr = find(key);
if (itr == end())
return false;
erase(itr);
return true;
}
// Removes 'itr' from the queue. This assumes 'itr' has been
// modified such that it has a higher priority than any other
// element in the queue.
void erase(iterator itr) {
// std::push_heap(begin(), ++itr, m_compare);
// pop();
base_type::erase(itr);
std::make_heap(begin(), end(), m_compare);
}
private:
Compare m_compare;
Equal m_equal;
};
// Iterate while the top node has higher priority, as 'Compare'
// returns false.
template <typename Queue, typename Compare>
class queue_pop_iterator
: public std::iterator<std::forward_iterator_tag, void, void, void, void> {
public:
typedef Queue container_type;
queue_pop_iterator() : m_queue(NULL) {}
queue_pop_iterator(Queue* q, Compare c) : m_queue(q), m_compare(c) {}
queue_pop_iterator& operator ++ () { m_queue->pop(); return *this; }
queue_pop_iterator& operator ++ (int) { m_queue->pop(); return *this; }
typename container_type::const_reference operator * () { return m_queue->top(); }
bool operator != (const queue_pop_iterator& itr) { return !m_queue->empty() && !m_compare(m_queue->top()); }
bool operator == (const queue_pop_iterator& itr) { return m_queue->empty() || m_compare(m_queue->top()); }
private:
Queue* m_queue;
Compare m_compare;
};
template <typename Queue, typename Compare>
inline queue_pop_iterator<Queue, Compare>
queue_popper(Queue& queue, Compare comp) {
return queue_pop_iterator<Queue, Compare>(&queue, comp);
}
}
#endif
+142
View File
@@ -0,0 +1,142 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_PRIORITY_QUEUE_DEFAULT_H
#define RAK_PRIORITY_QUEUE_DEFAULT_H
#include <tr1/functional>
#include <rak/allocators.h>
#include <rak/priority_queue.h>
#include <rak/timer.h>
#include "torrent/exceptions.h"
namespace rak {
class priority_item {
public:
typedef std::tr1::function<void (void)> slot_void;
priority_item() {}
~priority_item() {
if (is_queued())
throw torrent::internal_error("priority_item::~priority_item() called on a queued item.");
m_time = timer();
m_slot = slot_void();
}
bool is_valid() const { return (bool)m_slot; }
bool is_queued() const { return m_time != timer(); }
slot_void& slot() { return m_slot; }
const timer& time() const { return m_time; }
void clear_time() { m_time = timer(); }
void set_time(const timer& t) { m_time = t; }
bool compare(const timer& t) const { return m_time > t; }
private:
priority_item(const priority_item&);
void operator = (const priority_item&);
timer m_time;
slot_void m_slot;
};
struct priority_compare {
bool operator () (const priority_item* const p1, const priority_item* const p2) const {
return p1->time() > p2->time();
}
};
typedef std::equal_to<priority_item*> priority_equal;
typedef priority_queue<priority_item*, priority_compare, priority_equal,
cacheline_allocator<priority_item*> > priority_queue_default;
inline void
priority_queue_perform(priority_queue_default* queue, timer t) {
while (!queue->empty() && queue->top()->time() <= t) {
priority_item* v = queue->top();
queue->pop();
v->clear_time();
v->slot()();
}
}
inline void
priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) {
if (t == timer())
throw torrent::internal_error("priority_queue_insert(...) received a bad timer.");
if (!item->is_valid())
throw torrent::internal_error("priority_queue_insert(...) called on an invalid item.");
if (item->is_queued())
throw torrent::internal_error("priority_queue_insert(...) called on an already queued item.");
if (queue->find(item) != queue->end())
throw torrent::internal_error("priority_queue_insert(...) item found in queue.");
item->set_time(t);
queue->push(item);
}
inline void
priority_queue_erase(priority_queue_default* queue, priority_item* item) {
if (!item->is_queued())
return;
// Check is_valid() after is_queued() so that it is safe to call
// erase on untouched instances.
if (!item->is_valid())
throw torrent::internal_error("priority_queue_erase(...) called on an invalid item.");
// Clear time before erasing to force it to the top.
item->clear_time();
if (!queue->erase(item))
throw torrent::internal_error("priority_queue_erase(...) could not find item in queue.");
if (queue->find(item) != queue->end())
throw torrent::internal_error("priority_queue_erase(...) item still in queue.");
}
}
#endif
+111
View File
@@ -0,0 +1,111 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// This is a hacked up whole string pattern matching. Replace with
// TR1's regex when that becomes widely available. It is intended for
// small strings.
#ifndef RAK_REGEX_H
#define RAK_REGEX_H
#include <sys/types.h>
#include <algorithm>
#include <functional>
#include <string>
#include <list>
namespace rak {
class regex : public std::unary_function<std::string, bool> {
public:
regex() {}
regex(const std::string& p) : m_pattern(p) {}
const std::string& pattern() const { return m_pattern; }
bool operator () (const std::string& p) const;
private:
std::string m_pattern;
};
// This isn't optimized, or very clean. A simple hack that should work.
inline bool
regex::operator () (const std::string& text) const {
if (m_pattern.empty() ||
text.empty() ||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
return false;
// Replace with unordered_vector?
std::list<unsigned int> paths;
paths.push_front(0);
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
unsigned int next = *itrPaths + 1;
if (m_pattern[*itrPaths] != '*')
itrPaths = paths.erase(itrPaths);
else
itrPaths++;
// When we reach the end of 'm_pattern', we don't have a whole
// match of 'text'.
if (next == m_pattern.size())
continue;
// Push to the back so that '*' will match zero length strings.
if (m_pattern[next] == '*')
paths.push_back(next);
if (m_pattern[next] == *itrText)
paths.push_front(next);
}
if (paths.empty())
return false;
}
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
}
}
#endif
+411
View File
@@ -0,0 +1,411 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// Wrappers for the various sockaddr types with focus on zero-copy
// casting between the original type and the wrapper class.
//
// The default ctor does not initialize any data.
//
// _n suffixes indicate that the argument or return value is in
// network byte order, _h that they are in hardware byte order.
// Add define for inet6 scope id?
#ifndef RAK_SOCKET_ADDRESS_H
#define RAK_SOCKET_ADDRESS_H
#include <cstring>
#include <string>
#include <stdexcept>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
namespace rak {
class socket_address_inet;
class socket_address_inet6;
class socket_address {
public:
static const sa_family_t af_inet = AF_INET;
static const int pf_inet = PF_INET;
static const sa_family_t af_inet6 = AF_INET6;
static const int pf_inet6 = PF_INET6;
static const sa_family_t af_unspec = AF_UNSPEC;
static const int pf_unspec = PF_UNSPEC;
#ifdef AF_LOCAL
static const sa_family_t af_local = AF_LOCAL;
static const int pf_local = PF_LOCAL;
#else
static const sa_family_t af_local = AF_UNIX;
static const int pf_local = PF_UNIX;
#endif
bool is_valid() const;
bool is_bindable() const;
bool is_address_any() const;
// Should we need to set AF_UNSPEC?
void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); }
sa_family_t family() const { return m_sockaddr.sa_family; }
void set_family() { m_sockaddr.sa_family = af_unspec; }
uint16_t port() const;
void set_port(uint16_t p);
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;
// Attemts to set it as an inet, then an inet6 address. It will
// never set anything but net addresses, no local/unix.
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);
uint32_t length() const;
socket_address_inet* sa_inet() { return reinterpret_cast<socket_address_inet*>(this); }
const socket_address_inet* sa_inet() const { return reinterpret_cast<const socket_address_inet*>(this); }
sockaddr* c_sockaddr() { return &m_sockaddr; }
sockaddr_in* c_sockaddr_inet() { return &m_sockaddrInet; }
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
#ifdef RAK_USE_INET6
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
#endif
// Copy a socket address which has the length 'length. Zero out any
// extranous bytes and ensure it does not go beyond the size of this
// struct.
void copy(const socket_address& src, size_t length);
static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast<socket_address*>(sa); }
static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast<const socket_address*>(sa); }
// The different families will be sorted according to the
// sa_family_t's numeric value.
bool operator == (const socket_address& rhs) const;
bool operator < (const socket_address& rhs) const;
bool operator == (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
bool operator == (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
bool operator < (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
bool operator < (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
private:
union {
sockaddr m_sockaddr;
sockaddr_in m_sockaddrInet;
#ifdef RAK_USE_INET6
sockaddr_in6 m_sockaddrInet6;
#endif
};
};
// Remeber to set the AF_INET.
class socket_address_inet {
public:
bool is_any() const { return is_port_any() && is_address_any(); }
bool is_valid() const { return !is_port_any() && !is_address_any(); }
bool is_port_any() const { return port() == 0; }
bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }
void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }
uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
uint16_t port_n() const { return m_sockaddr.sin_port; }
void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); }
void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; }
// Should address() return the uint32_t?
in_addr address() const { return m_sockaddr.sin_addr; }
uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); }
uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;
void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; }
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);
void set_address_any() { set_port(0); set_address_h(INADDR_ANY); }
sa_family_t family() const { return m_sockaddr.sin_family; }
void set_family() { m_sockaddr.sin_family = AF_INET; }
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
bool operator == (const socket_address_inet& rhs) const;
bool operator < (const socket_address_inet& rhs) const;
private:
struct sockaddr_in m_sockaddr;
};
// Unique key for the address, excluding port numbers etc.
class socket_address_key {
public:
// socket_address_host_key() {}
socket_address_key(const socket_address& sa) {
*this = sa;
}
socket_address_key& operator = (const socket_address& sa) {
if (sa.family() == 0) {
std::memset(this, 0, sizeof(socket_address_key));
} else if (sa.family() == socket_address::af_inet) {
// Using hardware order as we use operator < to compare when
// using inet only.
m_addr.s_addr = sa.sa_inet()->address_h();
} else {
// When we implement INET6 handling, embed the ipv4 address in
// the ipv6 address.
throw std::logic_error("socket_address_key(...) received an unsupported protocol family.");
}
return *this;
}
// socket_address_key& operator = (const socket_address_key& sa) {
// }
bool operator < (const socket_address_key& sa) const {
// Compare the memory area instead.
return m_addr.s_addr < sa.m_addr.s_addr;
}
private:
union {
in_addr m_addr;
// #ifdef RAK_USE_INET6
// in_addr6 m_addr6;
// #endif
};
};
inline bool
socket_address::is_valid() const {
switch (family()) {
case af_inet:
return sa_inet()->is_valid();
// case af_inet6:
// return sa_inet6().is_valid();
default:
return false;
}
}
inline bool
socket_address::is_bindable() const {
switch (family()) {
case af_inet:
return !sa_inet()->is_address_any();
default:
return false;
}
}
inline bool
socket_address::is_address_any() const {
switch (family()) {
case af_inet:
return sa_inet()->is_address_any();
default:
return true;
}
}
inline uint16_t
socket_address::port() const {
switch (family()) {
case af_inet:
return sa_inet()->port();
default:
return 0;
}
}
inline void
socket_address::set_port(uint16_t p) {
switch (family()) {
case af_inet:
return sa_inet()->set_port(p);
default:
break;
}
}
inline std::string
socket_address::address_str() const {
switch (family()) {
case af_inet:
return sa_inet()->address_str();
default:
return std::string();
}
}
inline bool
socket_address::address_c_str(char* buf, socklen_t size) const {
switch (family()) {
case af_inet:
return sa_inet()->address_c_str(buf, size);
default:
return false;
}
}
inline bool
socket_address::set_address_c_str(const char* a) {
if (sa_inet()->set_address_c_str(a)) {
sa_inet()->set_family();
return true;
} else {
return false;
}
}
// Is the zero length really needed, should we require some length?
inline uint32_t
socket_address::length() const {
switch(family()) {
case af_inet:
return sizeof(sockaddr_in);
default:
return 0;
}
}
inline void
socket_address::copy(const socket_address& src, size_t length) {
length = std::min(length, sizeof(socket_address));
// Does this get properly optimized?
std::memset(this, 0, sizeof(socket_address));
std::memcpy(this, &src, length);
}
// Should we be able to compare af_unspec?
inline bool
socket_address::operator == (const socket_address& rhs) const {
if (family() != rhs.family())
return false;
switch (family()) {
case af_inet:
return *sa_inet() == *rhs.sa_inet();
// case af_inet6:
// return *sa_inet6() == *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
}
}
inline bool
socket_address::operator < (const socket_address& rhs) const {
if (family() != rhs.family())
return family() < rhs.family();
switch (family()) {
case af_inet:
return *sa_inet() < *rhs.sa_inet();
// case af_inet6:
// return *sa_inet6() < *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
}
}
inline std::string
socket_address_inet::address_str() const {
char buf[INET_ADDRSTRLEN];
if (!address_c_str(buf, INET_ADDRSTRLEN))
return std::string();
return std::string(buf);
}
inline bool
socket_address_inet::address_c_str(char* buf, socklen_t size) const {
return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size);
}
inline bool
socket_address_inet::set_address_c_str(const char* a) {
return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
}
inline bool
socket_address_inet::operator == (const socket_address_inet& rhs) const {
return
m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
m_sockaddr.sin_port == rhs.m_sockaddr.sin_port;
}
inline bool
socket_address_inet::operator < (const socket_address_inet& rhs) const {
return
m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr ||
(m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
}
}
#endif
+376
View File
@@ -0,0 +1,376 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_STRING_MANIP_H
#define RAK_STRING_MANIP_H
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <iterator>
#include <locale>
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 == (__UNUSED const split_iterator_t& itr) const { return m_pos == m_seq->end(); }
bool operator != (__UNUSED const split_iterator_t& itr) 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(__UNUSED const Sequence& seq) {
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) {
Sequence s;
s.reserve(length);
std::generate_n(std::back_inserter(s), length, &::random);
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());
}
}
#endif
+110
View File
@@ -0,0 +1,110 @@
// libTorrent - BitTorrent library
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_TIMER_H
#define RAK_TIMER_H
#include <limits>
#include <inttypes.h>
#include <sys/time.h>
namespace rak {
// Don't convert negative Timer to timeval and then back to Timer, that will bork.
class timer {
public:
timer(int64_t usec = 0) : m_time(usec) {}
timer(timeval tv) : m_time((int64_t)(uint32_t)tv.tv_sec * 1000000 + (int64_t)(uint32_t)tv.tv_usec % 1000000) {}
bool is_zero() const { return m_time == 0; }
bool is_not_zero() const { return m_time != 0; }
int32_t seconds() const { return m_time / 1000000; }
int32_t seconds_ceiling() const { return (m_time + 1000000 - 1) / 1000000; }
int64_t usec() const { return m_time; }
timer round_seconds() const { return (m_time / 1000000) * 1000000; }
timer round_seconds_ceiling() const { return ((m_time + 1000000 - 1) / 1000000) * 1000000; }
timeval tval() const {
timeval val;
val.tv_sec = m_time / 1000000;
val.tv_usec = m_time % 1000000;
return val;
}
static timer current();
static int64_t current_seconds() { return current().seconds(); }
static int64_t current_usec() { return current().usec(); }
static timer from_minutes(uint32_t minutes) { return rak::timer((uint64_t)minutes * 60 * 1000000); }
static timer from_seconds(uint32_t seconds) { return rak::timer((uint64_t)seconds * 1000000); }
static timer from_milliseconds(uint32_t msec) { return rak::timer((uint64_t)msec * 1000); }
static timer max() { return std::numeric_limits<int64_t>::max(); }
bool operator < (const timer& t) const { return m_time < t.m_time; }
bool operator > (const timer& t) const { return m_time > t.m_time; }
bool operator <= (const timer& t) const { return m_time <= t.m_time; }
bool operator >= (const timer& t) const { return m_time >= t.m_time; }
bool operator == (const timer& t) const { return m_time == t.m_time; }
bool operator != (const timer& t) const { return m_time != t.m_time; }
timer operator - (const timer& t) const { return timer(m_time - t.m_time); }
timer operator + (const timer& t) const { return timer(m_time + t.m_time); }
timer operator * (int64_t t) const { return timer(m_time * t); }
timer operator / (int64_t t) const { return timer(m_time / t); }
timer operator -= (int64_t t) { m_time -= t; return *this; }
timer operator -= (const timer& t) { m_time -= t.m_time; return *this; }
timer operator += (int64_t t) { m_time += t; return *this; }
timer operator += (const timer& t) { m_time += t.m_time; return *this; }
private:
int64_t m_time;
};
inline timer
timer::current() {
timeval t;
gettimeofday(&t, 0);
return timer(t);
}
}
#endif
+109
View File
@@ -0,0 +1,109 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_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
+19
View File
@@ -107,6 +107,25 @@ AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
fi
])
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
AC_CACHE_CHECK([if compiler supports __attribute__((unused))],
[cc_cv_attribute_unused],
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
void some_function(void *foo, __attribute__((unused)) void *bar);
])],
[cc_cv_attribute_unused=yes],
[cc_cv_attribute_unused=no])
])
if test "x$cc_cv_attribute_unused" = "xyes"; then
AC_DEFINE([SUPPORT_ATTRIBUTE_UNUSED], 1, [Define this if the compiler supports the unused attribute])
$1
else
true
$2
fi
])
AC_DEFUN([CC_FUNC_EXPECT], [
AC_CACHE_CHECK([if compiler has __builtin_expect function],
[cc_cv_func_expect],
-141
View File
@@ -1,141 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_zlib.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_ZLIB([action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# This macro searches for an installed zlib library. If nothing was
# specified when calling configure, it searches first in /usr/local and
# then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified,
# it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If
# --without-zlib is specified, the library is not searched at all.
#
# If either the header file (zlib.h) or the library (libz) is not found,
# shell commands 'action-if-not-found' is run. If 'action-if-not-found' is
# not specified, the configuration exits on error, asking for a valid zlib
# installation directory or --without-zlib.
#
# If both header file and library are found, shell commands
# 'action-if-found' is run. If 'action-if-found' is not specified, the
# default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends
# '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls
# AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition
# for this symbol in a config.h file. Sample usage in a C/C++ source is as
# follows:
#
# #ifdef HAVE_LIBZ
# #include <zlib.h>
# #endif /* HAVE_LIBZ */
#
# LICENSE
#
# Copyright (c) 2008 Loic Dachary <loic@senga.org>
# Copyright (c) 2010 Bastien Chevreux <bach@chevreux.org>
#
# 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, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 16
AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB])
AC_DEFUN([AX_CHECK_ZLIB],
#
# Handle user hints
#
[AC_MSG_CHECKING(if zlib is wanted)
zlib_places="/usr/local /usr /opt/local /sw"
AC_ARG_WITH([zlib],
[ --with-zlib=DIR root directory path of zlib installation @<:@defaults to
/usr/local or /usr if not found in /usr/local@:>@
--without-zlib to disable zlib usage completely],
[if test "$withval" != no ; then
AC_MSG_RESULT(yes)
if test -d "$withval"
then
zlib_places="$withval $zlib_places"
else
AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])
fi
else
zlib_places=
AC_MSG_RESULT(no)
fi],
[AC_MSG_RESULT(yes)])
#
# Locate zlib, if wanted
#
if test -n "${zlib_places}"
then
# check the user supplied or any other more or less 'standard' place:
# Most UNIX systems : /usr/local and /usr
# MacPorts / Fink on OSX : /opt/local respectively /sw
for ZLIB_HOME in ${zlib_places} ; do
if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi
ZLIB_HOME=""
done
ZLIB_OLD_LDFLAGS=$LDFLAGS
ZLIB_OLD_CPPFLAGS=$CPPFLAGS
if test -n "${ZLIB_HOME}"; then
LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
fi
AC_LANG_PUSH([C])
AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no])
AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no])
AC_LANG_POP([C])
if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes"
then
#
# If both library and header were found, action-if-found
#
m4_ifblank([$1],[
CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
LIBS="-lz $LIBS"
AC_DEFINE([HAVE_LIBZ], [1],
[Define to 1 if you have `z' library (-lz)])
],[
# Restore variables
LDFLAGS="$ZLIB_OLD_LDFLAGS"
CPPFLAGS="$ZLIB_OLD_CPPFLAGS"
$1
])
else
#
# If either header or library was not found, action-if-not-found
#
m4_default([$2],[
AC_MSG_ERROR([either specify a valid zlib installation with --with-zlib=DIR or disable zlib usage with --without-zlib])
])
fi
fi
])
File diff suppressed because it is too large Load Diff
-67
View File
@@ -1,67 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_execinfo.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_EXECINFO([ACTION-IF-EXECINFO-H-IS-FOUND], [ACTION-IF-EXECINFO-H-IS-NOT-FOUND], [ADDITIONAL-TYPES-LIST])
#
# DESCRIPTION
#
# Checks for execinfo.h header and if the len parameter/return type can be
# found from a list, also define backtrace_size_t to that type.
#
# By default the list of types to try contains int and size_t, but should
# some yet undiscovered system use e.g. unsigned, the 3rd argument can be
# used for extensions. I'd like to hear of further suggestions.
#
# Executes ACTION-IF-EXECINFO-H-IS-FOUND when present and the execinfo.h
# header is found or ACTION-IF-EXECINFO-H-IS-NOT-FOUND in case the header
# seems unavailable.
#
# Also adds -lexecinfo to LIBS on BSD if needed.
#
# LICENSE
#
# Copyright (c) 2014 Thomas Jahns <jahns@dkrz.de>
#
# 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 2
AC_DEFUN([AX_EXECINFO],
[AC_CHECK_HEADERS([execinfo.h])
AS_IF([test x"$ac_cv_header_execinfo_h" = xyes],
[AC_CACHE_CHECK([size parameter type for backtrace()],
[ax_cv_proto_backtrace_type],
[AC_LANG_PUSH([C])
for ax_cv_proto_backtrace_type in size_t int m4_ifnblank([$3],[$3 ])none; do
AS_IF([test "${ax_cv_proto_backtrace_type}" = none],
[ax_cv_proto_backtrace_type= ; break])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <execinfo.h>
extern
${ax_cv_proto_backtrace_type} backtrace(void **addrlist, ${ax_cv_proto_backtrace_type} len);
char **backtrace_symbols(void *const *buffer, ${ax_cv_proto_backtrace_type} size);
])],
[break])
done
AC_LANG_POP([C])])])
AS_IF([test x${ax_cv_proto_backtrace_type} != x],
[AC_DEFINE_UNQUOTED([backtrace_size_t], [$ax_cv_proto_backtrace_type],
[Defined to return type of backtrace().])])
AC_SEARCH_LIBS([backtrace],[execinfo])
AS_IF([test x"${ax_cv_proto_backtrace_type}" != x -a x"$ac_cv_header_execinfo_h" = xyes -a x"$ac_cv_search_backtrace" != xno],
[AC_DEFINE([HAVE_BACKTRACE],[1],
[Defined if backtrace() could be fully identified.])
]m4_ifnblank([$1],[$1
]),m4_ifnblank([$2],[$2
]))])
dnl
dnl Local Variables:
dnl mode: autoconf
dnl End:
dnl
-710
View File
@@ -1,710 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_lua.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
#
# DESCRIPTION
#
# Detect a Lua interpreter, optionally specifying a minimum and maximum
# version number. Set up important Lua paths, such as the directories in
# which to install scripts and modules (shared libraries).
#
# Also detect Lua headers and libraries. The Lua version contained in the
# 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, 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
# these macros without needing to modify configure.ac. Care has been taken
# to preserve each macro's behavior, but there are some differences:
#
# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
# AX_PROG_LUA with no arguments.
#
# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h
# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
# unnecessary, so it is deprecated and does not expand to anything.
#
# 3) The configure flag --with-lua-suffix no longer exists; the user
# should instead specify the LUA precious variable on the command line.
# See the AX_PROG_LUA description for details.
#
# Please read the macro descriptions below for more information.
#
# This file was inspired by Andrew Dalke's and James Henstridge's
# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
# (serial 17). Basically, this file is a mash-up of those two files. I
# like to think it combines the best of the two!
#
# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
# paths. Adds precious variable LUA, which may contain the path of the Lua
# 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
# version number greater or equal to MINIMUM-VERSION and less than
# TOO-BIG-VERSION will be accepted.
#
# The Lua version number, LUA_VERSION, is found from the interpreter, and
# substituted. LUA_PLATFORM is also found, but not currently supported (no
# standard representation).
#
# Finally, the macro finds four paths:
#
# luadir Directory to install Lua scripts.
# pkgluadir $luadir/$PACKAGE
# luaexecdir Directory to install Lua modules.
# pkgluaexecdir $luaexecdir/$PACKAGE
#
# These paths are found based on $prefix, $exec_prefix, Lua's
# package.path, and package.cpath. The first path of package.path
# beginning with $prefix is selected as luadir. The first path of
# package.cpath beginning with $exec_prefix is used as luaexecdir. This
# should work on all reasonable Lua installations. If a path cannot be
# determined, a default path is used. Of course, the user can override
# these later when invoking make.
#
# luadir Default: $prefix/share/lua/$LUA_VERSION
# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION
#
# These directories can be used by Automake as install destinations. The
# variable name minus 'dir' needs to be used as a prefix to the
# 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 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.
#
# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
# expanded before this macro. Adds precious variable LUA_INCLUDE, which
# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
# LUA_INCLUDE is blank, then this macro will attempt to find suitable
# flags.
#
# LUA_INCLUDE can be used by Automake to compile Lua modules or
# executables with embedded interpreters. The *_CPPFLAGS variables should
# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
#
# This macro searches for the header lua.h (and others). The search is
# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
# If the search is unsuccessful, then some common directories are tried.
# If the headers are then found, then LUA_INCLUDE is set accordingly.
#
# The paths automatically searched are:
#
# * /usr/include/luaX.Y
# * /usr/include/lua/X.Y
# * /usr/include/luaXY
# * /usr/local/include/luaX.Y
# * /usr/local/include/lua-X.Y
# * /usr/local/include/lua/X.Y
# * /usr/local/include/luaXY
#
# (Where X.Y is the Lua version number, e.g. 5.1.)
#
# The Lua version number found in the headers is always checked to match
# the Lua interpreter's version number. Lua headers with mismatched
# version numbers are not accepted.
#
# If headers are found, then ACTION-IF-FOUND is 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,
# set the action to ':'.
#
# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
# expanded before this macro. Adds precious variable LUA_LIB, which may
# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
# then this macro will attempt to find suitable flags.
#
# LUA_LIB can be used by Automake to link Lua modules or executables with
# embedded interpreters. The *_LIBADD and *_LDADD variables should be used
# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
#
# This macro searches for the Lua library. More technically, it searches
# for a library containing the function lua_load. The search is performed
# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
#
# If the search determines that some linker flags are missing, then those
# flags will be added to LUA_LIB.
#
# If libraries are found, then ACTION-IF-FOUND is 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,
# set the action to ':'.
#
# AX_LUA_READLINE: Search for readline headers and libraries. Requires the
# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
# Autoconf Archive.
#
# If a readline compatible library is found, then ACTION-IF-FOUND is
# performed, otherwise ACTION-IF-NOT-FOUND is performed.
#
# 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>
#
# 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 3 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, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 47
dnl =========================================================================
dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_PROG_LUA],
[
dnl Check for required tools.
AC_REQUIRE([AC_PROG_GREP])
AC_REQUIRE([AC_PROG_SED])
dnl Make LUA a precious variable.
AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
dnl Find a Lua interpreter.
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], [:])])
ax_display_LUA='lua'
AS_IF([test "x$LUA" != 'x:'],
[ dnl At least check if this is a Lua interpreter.
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
_AX_LUA_CHK_IS_INTRP([$LUA],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([not a Lua interpreter])
])
])
],
[ dnl A version check is needed.
AS_IF([test "x$LUA" != 'x'],
[ dnl Check if this is a Lua interpreter.
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
_AX_LUA_CHK_IS_INTRP([$LUA],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([not a Lua interpreter])
])
dnl Check the version.
m4_if([$2], [],
[_ax_check_text="whether $LUA version >= $1"],
[_ax_check_text="whether $LUA version >= $1, < $2"])
AC_MSG_CHECKING([$_ax_check_text])
_AX_LUA_CHK_VER([$LUA], [$1], [$2],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([version is out of range for specified LUA])])
ax_display_LUA=$LUA
],
[ dnl Try each interpreter until we find one that satisfies VERSION.
m4_if([$2], [],
[_ax_check_text="for a Lua interpreter with version >= $1"],
[_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
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])
done
])
dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
[LUA=':'],
[AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
ax_display_LUA=$ax_cv_pathless_LUA
])
])
AS_IF([test "x$LUA" = 'x:'],
[ dnl Run any user-specified action, or abort.
m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
],
[ dnl Query Lua for its version number.
AC_CACHE_CHECK([for $ax_display_LUA version],
[ax_cv_lua_version],
[ dnl Get the interpreter version in X.Y format. This should work for
dnl interpreters version 5.0 and beyond.
ax_cv_lua_version=[`$LUA -e '
-- return a version number in X.Y format
local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
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.
AC_CACHE_CHECK([for $ax_display_LUA platform],
[ax_cv_lua_platform],
[ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]])
AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
dnl variables so they can be overridden if need be. However, the general
dnl consensus is that you shouldn't need this ability.
AC_SUBST([LUA_PREFIX], ['${prefix}'])
AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
dnl Lua provides no way to query the script directory, and instead
dnl provides LUA_PATH. However, we should be able to make a safe educated
dnl guess. If the built-in search path contains a directory which is
dnl prefixed by $prefix, then we can store scripts there. The first
dnl matching path will be used.
AC_CACHE_CHECK([for $ax_display_LUA script directory],
[ax_cv_lua_luadir],
[ AS_IF([test "x$prefix" = 'xNONE'],
[ax_lua_prefix=$ac_default_prefix],
[ax_lua_prefix=$prefix])
dnl Initialize to the default path.
ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
dnl Try to find a path with the prefix.
_AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script])
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
[ dnl Fix the prefix.
_ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'`
ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
$SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"`
])
])
AC_SUBST([luadir], [$ax_cv_lua_luadir])
AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
dnl Lua provides no way to query the module directory, and instead
dnl provides LUA_PATH. However, we should be able to make a safe educated
dnl guess. If the built-in search path contains a directory which is
dnl prefixed by $exec_prefix, then we can store modules there. The first
dnl matching path will be used.
AC_CACHE_CHECK([for $ax_display_LUA module directory],
[ax_cv_lua_luaexecdir],
[ AS_IF([test "x$exec_prefix" = 'xNONE'],
[ax_lua_exec_prefix=$ax_lua_prefix],
[ax_lua_exec_prefix=$exec_prefix])
dnl Initialize to the default path.
ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
dnl Try to find a path with the prefix.
_AX_LUA_FND_PRFX_PTH([$LUA],
[$ax_lua_exec_prefix], [module])
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
[ dnl Fix the prefix.
_ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'`
ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
$SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"`
])
])
AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
dnl Run any user specified action.
$3
])
])
dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
AC_DEFUN([AX_WITH_LUA],
[
AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]])
AX_PROG_LUA
])
dnl =========================================================================
dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl =========================================================================
AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
[
dnl A minimal Lua factorial to prove this is an interpreter. This should work
dnl for Lua interpreters version 5.0 and beyond.
_ax_lua_factorial=[`$1 2>/dev/null -e '
-- a simple factorial
function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end
print("fact(5) is " .. fact(5))'`]
AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'],
[$2], [$3])
])
dnl =========================================================================
dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl =========================================================================
AC_DEFUN([_AX_LUA_CHK_VER],
[
dnl Check that the Lua version is within the bounds. Only the major and minor
dnl version numbers are considered. This should work for Lua interpreters
dnl version 5.0 and beyond.
_ax_lua_good_version=[`$1 -e '
-- a script to compare versions
function verstr2num(verstr)
local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)")
if majorver and minorver then
return tonumber(majorver) * 100 + tonumber(minorver)
end
end
local minver = verstr2num("$2")
local _, _, trimver = string.find(_VERSION, "^Lua (.*)")
local ver = verstr2num(trimver)
local maxver = verstr2num("$3") or 1e9
if minver <= ver and ver < maxver then
print("yes")
else
print("no")
end'`]
AS_IF([test "x$_ax_lua_good_version" = "xyes"],
[$4], [$5])
])
dnl =========================================================================
dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR)
dnl =========================================================================
AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
[
dnl Get the script or module directory by querying the Lua interpreter,
dnl filtering on the given prefix, and selecting the shallowest path. If no
dnl path is found matching the prefix, the result will be an empty string.
dnl The third argument determines the type of search, it can be 'script' or
dnl 'module'. Supplying 'script' will perform the search with package.path
dnl and LUA_PATH, and supplying 'module' will search with package.cpath and
dnl LUA_CPATH. This is done for compatibility with Lua 5.0.
ax_lua_prefixed_path=[`$1 -e '
-- get the path based on search type
local searchtype = "$3"
local paths = ""
if searchtype == "script" then
paths = (package and package.path) or LUA_PATH
elseif searchtype == "module" then
paths = (package and package.cpath) or LUA_CPATH
end
-- search for the prefix
local prefix = "'$2'"
local minpath = ""
local mindepth = 1e9
string.gsub(paths, "(@<:@^;@:>@+)",
function (path)
path = string.gsub(path, "%?.*$", "")
path = string.gsub(path, "/@<:@^/@:>@*$", "")
if string.find(path, prefix) then
local depth = string.len(string.gsub(path, "@<:@^/@:>@", ""))
if depth < mindepth then
minpath = path
mindepth = depth
end
end
end)
print(minpath)'`]
])
dnl =========================================================================
dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_HEADERS],
[
dnl Check for LUA_VERSION.
AC_MSG_CHECKING([if LUA_VERSION is defined])
AS_IF([test "x$LUA_VERSION" != 'x'],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
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.
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$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
test ! -d "$_ax_include_path" && continue
AC_MSG_CHECKING([for Lua headers in])
AC_MSG_RESULT([$_ax_include_path])
AS_UNSET([ac_cv_header_lua_h])
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'],
[ LUA_INCLUDE="-I$_ax_include_path"
break
])
done
])
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
[ dnl Make a program to print LUA_VERSION defined in the header.
dnl TODO It would be really nice if we could do this without compiling a
dnl program, then it would work when cross compiling. But I'm not sure how
dnl to do this reliably. For now, assume versions match when cross compiling.
AS_IF([test "x$cross_compiling" != 'xyes'],
[ AC_CACHE_CHECK([for Lua header version],
[ax_cv_lua_header_version],
[ _ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
AC_COMPUTE_INT(ax_cv_lua_header_version_major,[LUA_VERSION_NUM/100],[AC_INCLUDES_DEFAULT
#include <lua.h>
],[ax_cv_lua_header_version_major=unknown])
AC_COMPUTE_INT(ax_cv_lua_header_version_minor,[LUA_VERSION_NUM%100],[AC_INCLUDES_DEFAULT
#include <lua.h>
],[ax_cv_lua_header_version_minor=unknown])
AS_IF([test "x$ax_cv_lua_header_version_major" = xunknown || test "x$ax_cv_lua_header_version_minor" = xunknown],[
ax_cv_lua_header_version=unknown
],[
ax_cv_lua_header_version="$ax_cv_lua_header_version_major.$ax_cv_lua_header_version_minor"
])
CPPFLAGS=$_ax_lua_saved_cppflags
])
dnl Compare this to the previously found LUA_VERSION.
AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
[ AC_MSG_RESULT([yes])
ax_header_version_match='yes'
],
[ AC_MSG_RESULT([no])
ax_header_version_match='no'
])
],
[ AC_MSG_WARN([cross compiling so assuming header version number matches])
ax_header_version_match='yes'
])
])
dnl Was LUA_INCLUDE specified?
AS_IF([test "x$ax_header_version_match" != 'xyes' &&
test "x$LUA_INCLUDE" != 'x'],
[AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
dnl Test the final result and run user code.
AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
])
dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
AC_DEFUN([AX_LUA_HEADERS_VERSION],
[
AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]])
])
dnl =========================================================================
dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_LIBS],
[
dnl TODO Should this macro also check various -L flags?
dnl Check for LUA_VERSION.
AC_MSG_CHECKING([if LUA_VERSION is defined])
AS_IF([test "x$LUA_VERSION" != 'x'],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
])
dnl Make LUA_LIB a precious variable.
AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
AS_IF([test "x$LUA_LIB" != 'x'],
[ dnl Check that LUA_LIBS works.
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([lua_load], [],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'])
LIBS=$_ax_lua_saved_libs
dnl Check the result.
AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
[AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
],
[ dnl First search for extra libs.
_ax_lua_extra_libs=''
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([exp], [m])
AC_SEARCH_LIBS([dlopen], [dl])
LIBS=$_ax_lua_saved_libs
AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
test "x$ac_cv_search_exp" != 'xnone required'],
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
test "x$ac_cv_search_dlopen" != 'xnone required'],
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
dnl Try to find the Lua libs.
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
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' &&
test "x$ac_cv_search_lua_load" != 'xnone required'],
[LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
])
dnl Test the result and run user code.
AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
])
dnl =========================================================================
dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_READLINE],
[
AX_LIB_READLINE
AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
test "x$ac_cv_header_readline_history_h" != 'x'],
[ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
$1
],
[$2])
])
+122 -335
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
@@ -14,28 +14,24 @@
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
# needed for multi-threaded programs (defaults to the value of CC
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
# special cc_r/CC_r compiler alias.)
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also to link with them as well. For example, you might link with
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threaded programs, you may wish to use these
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
# CXX="$PTHREAD_CXX"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
@@ -59,7 +55,6 @@
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
#
# 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
@@ -72,7 +67,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -87,41 +82,35 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 31
#serial 17
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_PROG_SED])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on Tru64 or Sequent).
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
ax_pthread_save_CC="$CC"
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = "xno"; then
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
CC="$ax_pthread_save_CC"
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
@@ -129,14 +118,12 @@ fi
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items with a "," contain both
# C compiler flags (before ",") and linker flags (after ","). Other items
# starting with a "-" are C compiler flags, and remaining items are
# library names, except for "none" which indicates that we try without
# any flags at all, and "pthread-config" which is a program returning
# the flags for the Pth emulation library.
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
ax_pthread_flags="none pthreads -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
@@ -145,163 +132,68 @@ ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
# (Note: HP C rejects this with "bad form for `-t' option")
# -pthreads: Solaris/gcc (Note: HP C also rejects)
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads and
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
# is present but should not be used directly; and before -mthreads,
# because the compiler interprets this as "-mt" + "-hreads")
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case $host_os in
freebsd*)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
;;
hpux*)
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
# multi-threading and also sets -lpthread."
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
;;
openedition*)
# IBM z/OS requires a feature-test macro to be defined in order to
# enable POSIX threads at all, so give the user a hint if this is
# not set. (We don't define these ourselves, as they can affect
# other portions of the system API in unpredictable ways.)
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
[
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
AX_PTHREAD_ZOS_MISSING
# endif
],
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
;;
solaris*)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (N.B.: The stubs are missing
# pthread_cleanup_push, or rather a function called by this macro,
# so we could check for that, but who knows whether they'll stub
# that too in a future libc.) So we'll check first for the
# standard Solaris way of linking pthreads (-mt -lpthread).
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
*-darwin*)
ax_pthread_flags="none -pthread $ax_pthread_flags"
;;
esac
# Are we compiling with Clang?
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
AC_CACHE_CHECK([whether $CC is Clang],
[ax_cv_PTHREAD_CLANG],
[ax_cv_PTHREAD_CLANG=no
# Note that Autoconf sets GCC=yes for Clang as well as GCC
if test "x$GCC" = "xyes"; then
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
# if defined(__clang__) && defined(__llvm__)
AX_PTHREAD_CC_IS_CLANG
# endif
],
[ax_cv_PTHREAD_CLANG=yes])
fi
])
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
# Note that for GCC and Clang -pthread generally implies -lpthread,
# except when -nostdlib is passed.
# This is problematic using libtool to build C++ shared libraries with pthread:
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
# To solve this, first try -pthread together with -lpthread for GCC
AS_IF([test "x$GCC" = "xyes"],
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
AS_IF([test "x$ax_pthread_clang" = "xyes"],
[ax_pthread_flags="-pthread,-lpthread -pthread"])
# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
ax_pthread_check_macro="_REENTRANT"
;;
aix*)
ax_pthread_check_macro="_THREAD_SAFE"
;;
*)
ax_pthread_check_macro="--"
;;
esac
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
[ax_pthread_check_cond=0],
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
if test "x$ax_pthread_ok" = "xno"; then
for ax_pthread_try_flag in $ax_pthread_flags; do
case $ax_pthread_try_flag in
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
*,*)
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
PTHREAD_CFLAGS="$ax_pthread_try_flag"
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
PTHREAD_LIBS="-l$ax_pthread_try_flag"
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
@@ -312,18 +204,8 @@ for ax_pthread_try_flag in $ax_pthread_flags; do
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
# if $ax_pthread_check_cond
# error "$ax_pthread_check_macro must be defined"
# endif
static void *some_global = NULL;
static void routine(void *a)
{
/* To avoid any unused-parameter or
unused-but-set-parameter warning. */
some_global = a;
}
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
@@ -331,188 +213,93 @@ for ax_pthread_try_flag in $ax_pthread_flags; do
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
[ax_pthread_ok=yes],
[])
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT([$ax_pthread_ok])
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way
if test "x$ax_pthread_clang" = "xyes"; then
# Clang takes -pthread; it has never supported any other flag
# (Note 1: This will need to be revisited if a system that Clang
# supports has POSIX threads in a separate library. This tends not
# to be the way of modern systems, but it's conceivable.)
# (Note 2: On some systems, notably Darwin, -pthread is not needed
# to get POSIX threads support; the API is always present and
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
# -pthread does define _REENTRANT, and while the Darwin headers
# ignore this macro, third-party headers might not.)
# However, older versions of Clang make a point of warning the user
# that, in an invocation where only linking and no compilation is
# taking place, the -pthread option has no effect ("argument unused
# during compilation"). They expect -pthread to be passed in only
# when source code is being compiled.
#
# Problem is, this is at odds with the way Automake and most other
# C build frameworks function, which is that the same flags used in
# compilation (CFLAGS) are also used in linking. Many systems
# supported by AX_PTHREAD require exactly this for POSIX threads
# support, and in fact it is often not straightforward to specify a
# flag that is used only in the compilation phase and not in
# linking. Such a scenario is extremely rare in practice.
#
# Even though use of the -pthread flag in linking would only print
# a warning, this can be a nuisance for well-run software projects
# that build with -Werror. So if the active version of Clang has
# this misfeature, we search for an option to squash it.
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
# Create an alternate version of $ac_link that compiles and
# links in two steps (.c -> .o, .o -> exe) instead of one
# (.c -> exe), because the warning occurs only in the second
# step
ax_pthread_save_ac_link="$ac_link"
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
ax_pthread_save_CFLAGS="$CFLAGS"
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
ac_link="$ax_pthread_save_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[ac_link="$ax_pthread_2step_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[break])
])
done
ac_link="$ax_pthread_save_ac_link"
CFLAGS="$ax_pthread_save_CFLAGS"
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
])
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
no | unknown) ;;
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
esac
fi # $ax_pthread_clang = yes
# Various other checks:
if test "x$ax_pthread_ok" = "xyes"; then
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_CACHE_CHECK([for joinable pthread attribute],
[ax_cv_PTHREAD_JOINABLE_ATTR],
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $ax_pthread_attr; return attr /* ; */])],
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
[])
done
])
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
[$ax_cv_PTHREAD_JOINABLE_ATTR],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
ax_pthread_joinable_attr_defined=yes
])
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_CACHE_CHECK([whether more special flags are required for pthreads],
[ax_cv_PTHREAD_SPECIAL_FLAGS],
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
case $host_os in
solaris*)
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
;;
esac
])
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
test "x$ax_pthread_special_flags_added" != "xyes"],
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
ax_pthread_special_flags_added=yes])
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*-osf* | *-hpux*) flag="-D_REENTRANT";;
*solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
[[int i = PTHREAD_PRIO_INHERIT;
return i;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
ax_cv_PTHREAD_PRIO_INHERIT, [
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
ax_pthread_prio_inherit_defined=yes
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: compile with *_r variant
if test "x$GCC" != "xyes"; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
],
[
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
]
)
])
;;
esac
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
else
PTHREAD_CC="$CC"
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
AC_SUBST([PTHREAD_CXX])
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test "x$ax_pthread_ok" = "xyes"; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
-37
View File
@@ -1,37 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# 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 2
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED
+69 -105
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_with_curses.html
# http://www.gnu.org/software/autoconf-archive/ax_with_curses.html
# ===========================================================================
#
# SYNOPSIS
@@ -12,9 +12,7 @@
# present, along with the associated header file. The NcursesW
# (wide-character) library is searched for first, followed by Ncurses,
# then the system-default plain Curses. The first library found is the
# one returned. Finding libraries will first be attempted by using
# pkg-config, and should the pkg-config files not be available, will
# fallback to combinations of known flags itself.
# one returned.
#
# The following options are understood: --with-ncursesw, --with-ncurses,
# --without-ncursesw, --without-ncurses. The "--with" options force the
@@ -54,29 +52,23 @@
#
# (These preprocessor symbols are discussed later in this document.)
#
# The following output variables are defined by this macro; they are
# precious and may be overridden on the ./configure command line:
# The following output variable is defined by this macro; it is precious
# and may be overridden on the ./configure command line:
#
# CURSES_LIBS - library to add to xxx_LDADD
# CURSES_CFLAGS - include paths to add to xxx_CPPFLAGS
# CURSES_LIB - library to add to xxx_LDADD
#
# In previous versions of this macro, the flags CURSES_LIB and
# CURSES_CPPFLAGS were defined. These have been renamed, in keeping with
# AX_WITH_CURSES's close bigger brother, PKG_CHECK_MODULES, which should
# eventually supersede the use of AX_WITH_CURSES. Neither the library
# listed in CURSES_LIBS, nor the flags in CURSES_CFLAGS are added to LIBS,
# respectively CPPFLAGS, by default. You need to add both to the
# appropriate xxx_LDADD/xxx_CPPFLAGS line in your Makefile.am. For
# example:
# The library listed in CURSES_LIB is NOT added to LIBS by default. You
# need to add CURSES_LIB to the appropriate xxx_LDADD line in your
# Makefile.am. For example:
#
# prog_LDADD = @CURSES_LIBS@
# prog_CPPFLAGS = @CURSES_CFLAGS@
# prog_LDADD = @CURSES_LIB@
#
# If CURSES_LIBS is set on the configure command line (such as by running
# "./configure CURSES_LIBS=-lmycurses"), then the only header searched for
# is <curses.h>. If the user needs to specify an alternative path for a
# library (such as for a non-standard NcurseW), the user should use the
# LDFLAGS variable.
# If CURSES_LIB is set on the configure command line (such as by running
# "./configure CURSES_LIB=-lmycurses"), then the only header searched for
# is <curses.h>. The user may use the CPPFLAGS precious variable to
# override the standard #include search path. If the user needs to
# specify an alternative path for a library (such as for a non-standard
# NcurseW), the user should use the LDFLAGS variable.
#
# The following shell variables may be defined by this macro:
#
@@ -96,7 +88,7 @@
#
# 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])
# AX_MSG_ERROR([requires either NcursesW or Ncurses library])
# fi
#
# If any Curses library will do (but one must be present and must support
@@ -175,7 +167,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -190,66 +182,11 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 18
# internal function to factorize common code that is used by both ncurses
# and ncursesw
AC_DEFUN([_FIND_CURSES_FLAGS], [
AC_MSG_CHECKING([for $1 via pkg-config])
AX_REQUIRE_DEFINED([PKG_CHECK_EXISTS])
_PKG_CONFIG([_ax_cv_$1_libs], [libs], [$1])
_PKG_CONFIG([_ax_cv_$1_cppflags], [cflags], [$1])
AS_IF([test "x$pkg_failed" = "xyes" || test "x$pkg_failed" = "xuntried"],[
AC_MSG_RESULT([no])
# No suitable .pc file found, have to find flags via fallback
AC_CACHE_CHECK([for $1 via fallback], [ax_cv_$1], [
AS_ECHO()
pkg_cv__ax_cv_$1_libs="-l$1"
pkg_cv__ax_cv_$1_cppflags="-D_GNU_SOURCE $CURSES_CFLAGS"
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags"
AC_MSG_CHECKING([for initscr() with $pkg_cv__ax_cv_$1_libs])
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
[
AC_MSG_RESULT([yes])
AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs])
AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[
ax_cv_$1=yes
],[
AC_MSG_RESULT([no])
m4_if(
[$1],[ncursesw],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfow"],
[$1],[ncurses],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfo"]
)
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs])
AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[
ax_cv_$1=yes
],[
ax_cv_$1=no
])
])
],[
ax_cv_$1=no
])
])
],[
AC_MSG_RESULT([yes])
# Found .pc file, using its information
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags"
ax_cv_$1=yes
])
])
#serial 13
AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES])
AC_DEFUN([AX_WITH_CURSES], [
AC_ARG_VAR([CURSES_LIBS], [linker library for Curses, e.g. -lcurses])
AC_ARG_VAR([CURSES_CFLAGS], [preprocessor flags for Curses, e.g. -I/usr/include/ncursesw])
AC_ARG_VAR([CURSES_LIB], [linker library for Curses, e.g. -lcurses])
AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses],
[force the use of Ncurses or NcursesW])],
[], [with_ncurses=check])
@@ -258,17 +195,20 @@ AC_DEFUN([AX_WITH_CURSES], [
[], [with_ncursesw=check])
ax_saved_LIBS=$LIBS
ax_saved_CPPFLAGS=$CPPFLAGS
AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes],
[ax_with_plaincurses=no], [ax_with_plaincurses=check])
ax_cv_curses_which=no
# Test for NcursesW
AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncursesw" != xno], [
_FIND_CURSES_FLAGS([ncursesw])
AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncursesw" != xno], [
LIBS="$ax_saved_LIBS -lncursesw"
AC_CACHE_CHECK([for NcursesW wide-character library], [ax_cv_ncursesw], [
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
[ax_cv_ncursesw=yes], [ax_cv_ncursesw=no])
])
AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [
AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library])
])
@@ -276,8 +216,7 @@ AC_DEFUN([AX_WITH_CURSES], [
AS_IF([test "x$ax_cv_ncursesw" = xyes], [
ax_cv_curses=yes
ax_cv_curses_which=ncursesw
CURSES_LIBS="$pkg_cv__ax_cv_ncursesw_libs"
CURSES_CFLAGS="$pkg_cv__ax_cv_ncursesw_cppflags"
CURSES_LIB="-lncursesw"
AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present])
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
@@ -377,15 +316,46 @@ AC_DEFUN([AX_WITH_CURSES], [
AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [
AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h])
])
dnl Test if we need to explicitly link against -ltinfow.
AC_CACHE_CHECK([if curses tinfo library is linked properly], [ax_cv_ncurses_compiled], [
LIBS="$ax_saved_LIBS $CURSES_LIB"
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_ncurses_compiled=yes], [ax_cv_ncurses_compiled=no])
LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfo"
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfo_compiled=yes], [ax_cv_tinfo_compiled=no])
LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfow"
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfow_compiled=yes], [ax_cv_tinfow_compiled=no])
LIBS=$ax_saved_LIBS
])
AS_IF([test "x$ax_cv_ncurses_compiled" = xno], [
AS_IF(
[test "x$ax_cv_tinfo_compiled" = xyes], [
AC_MSG_RESULT([adding libtinfo])
CURSES_LIB="$CURSES_LIB -ltinfo"
],
[test "x$ax_cv_tinfow_compiled" = xyes], [
AC_MSG_RESULT([adding libtinfow])
CURSES_LIB="$CURSES_LIB -ltinfow"
], [
AC_MSG_ERROR([no])
])
])
])
])
unset pkg_cv__ax_cv_ncursesw_libs
unset pkg_cv__ax_cv_ncursesw_cppflags
# Test for Ncurses
AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [
_FIND_CURSES_FLAGS([ncurses])
AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [
LIBS="$ax_saved_LIBS -lncurses"
AC_CACHE_CHECK([for Ncurses library], [ax_cv_ncurses], [
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
[ax_cv_ncurses=yes], [ax_cv_ncurses=no])
])
AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [
AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library])
])
@@ -393,8 +363,7 @@ AC_DEFUN([AX_WITH_CURSES], [
AS_IF([test "x$ax_cv_ncurses" = xyes], [
ax_cv_curses=yes
ax_cv_curses_which=ncurses
CURSES_LIBS="$pkg_cv__ax_cv_ncurses_libs"
CURSES_CFLAGS="$pkg_cv__ax_cv_ncurses_cppflags"
CURSES_LIB="-lncurses"
AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present])
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
@@ -449,13 +418,12 @@ AC_DEFUN([AX_WITH_CURSES], [
])
])
])
unset pkg_cv__ax_cv_ncurses_libs
unset pkg_cv__ax_cv_ncurses_cppflags
# Test for plain Curses (or if CURSES_LIBS was set by user)
# Test for plain Curses (or if CURSES_LIB was set by user)
AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [
AS_IF([test "x$CURSES_LIBS" != x], [
LIBS="$ax_saved_LIBS $CURSES_LIBS"
AS_IF([test "x$CURSES_LIB" != x], [
LIBS="$ax_saved_LIBS $CURSES_LIB"
], [
LIBS="$ax_saved_LIBS -lcurses"
])
@@ -468,8 +436,8 @@ AC_DEFUN([AX_WITH_CURSES], [
AS_IF([test "x$ax_cv_plaincurses" = xyes], [
ax_cv_curses=yes
ax_cv_curses_which=plaincurses
AS_IF([test "x$CURSES_LIBS" = x], [
CURSES_LIBS="-lcurses"
AS_IF([test "x$CURSES_LIB" = x], [
CURSES_LIB="-lcurses"
])
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
@@ -575,8 +543,4 @@ AC_DEFUN([AX_WITH_CURSES], [
AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no])
LIBS=$ax_saved_LIBS
CPPFLAGS=$ax_saved_CPPFLAGS
unset ax_saved_LIBS
unset ax_saved_CPPFLAGS
])dnl
+362 -173
View File
@@ -1,3 +1,48 @@
AC_DEFUN([TORRENT_CHECK_XFS], [
AC_MSG_CHECKING(for XFS support)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <xfs/libxfs.h>
#include <sys/ioctl.h>
int main() {
struct xfs_flock64 l;
ioctl(0, XFS_IOC_RESVSP64, &l);
return 0;
}
])],
[
AC_DEFINE(USE_XFS, 1, Use XFS filesystem stuff.)
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_WITHOUT_XFS], [
AC_ARG_WITH(xfs,
AC_HELP_STRING([--without-xfs], [do not check for XFS filesystem support]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_XFS
fi
], [
TORRENT_CHECK_XFS
])
])
AC_DEFUN([TORRENT_WITH_XFS], [
AC_ARG_WITH(xfs,
AC_HELP_STRING([--with-xfs], [check for XFS filesystem support]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_XFS
fi
])
])
AC_DEFUN([TORRENT_CHECK_EPOLL], [
AC_MSG_CHECKING(for epoll support)
@@ -9,8 +54,6 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
}
])],
[
use_epoll=yes
AC_DEFINE(USE_EPOLL, 1, Use epoll.)
AC_MSG_RESULT(yes)
], [
@@ -20,7 +63,7 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
AC_DEFUN([TORRENT_WITHOUT_EPOLL], [
AC_ARG_WITH(epoll,
AS_HELP_STRING([--without-epoll],[do not check for epoll support]),
AC_HELP_STRING([--without-epoll], [do not check for epoll support]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_EPOLL
@@ -43,8 +86,6 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
}
])],
[
use_kqueue=yes
AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
AC_MSG_RESULT(yes)
], [
@@ -52,13 +93,51 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
])
])
AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
AC_MSG_CHECKING(whether kqueue supports pipes and ptys)
AC_RUN_IFELSE([AC_LANG_SOURCE([
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/event.h>
#include <sys/time.h>
int main() {
struct kevent ev@<:@2@:>@, ev_out@<:@2@:>@;
struct timespec ts = { 0, 0 };
int pfd@<:@2@:>@, pty@<:@2@:>@, kfd, n;
char buffer@<:@9001@:>@;
if (pipe(pfd) == -1) return 1;
if (fcntl(pfd@<:@1@:>@, F_SETFL, O_NONBLOCK) == -1) return 2;
while ((n = write(pfd@<:@1@:>@, buffer, sizeof(buffer))) == sizeof(buffer));
if ((pty@<:@0@:>@=posix_openpt(O_RDWR | O_NOCTTY)) == -1) return 3;
if ((pty@<:@1@:>@=grantpt(pty@<:@0@:>@)) == -1) return 4;
EV_SET(ev+0, pfd@<:@1@:>@, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
EV_SET(ev+1, pty@<:@1@:>@, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
if ((kfd = kqueue()) == -1) return 5;
if ((n = kevent(kfd, ev, 2, NULL, 0, NULL)) == -1) return 6;
if (ev_out@<:@0@:>@.flags & EV_ERROR) return 7;
if (ev_out@<:@1@:>@.flags & EV_ERROR) return 8;
read(pfd@<:@0@:>@, buffer, sizeof(buffer));
if ((n = kevent(kfd, NULL, 0, ev_out, 2, &ts)) < 1) return 9;
return 0;
}
])],
[
AC_MSG_RESULT(yes)
], [
AC_DEFINE(KQUEUE_SOCKET_ONLY, 1, kqueue only supports sockets.)
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_WITH_KQUEUE], [
AC_ARG_WITH(kqueue,
AS_HELP_STRING([--with-kqueue],[enable kqueue [[default=no]]]),
AC_HELP_STRING([--with-kqueue], [enable kqueue [[default=no]]]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_KQUEUE
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
fi
])
])
@@ -66,20 +145,197 @@ AC_DEFUN([TORRENT_WITH_KQUEUE], [
AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
AC_ARG_WITH(kqueue,
AS_HELP_STRING([--without-kqueue],[do not check for kqueue support]),
AC_HELP_STRING([--without-kqueue], [do not check for kqueue support]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_KQUEUE
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
fi
], [
TORRENT_CHECK_KQUEUE
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
])
])
AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
AC_ARG_WITH(variable-fdset,
AC_HELP_STRING([--without-variable-fdset], [do not use non-portable variable sized fd_set's]),
[
if test "$withval" = "yes"; then
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
fi
], [
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
])
])
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
AC_MSG_CHECKING(for fallocate)
AC_TRY_LINK([#include <fcntl.h>
#include <linux/falloc.h>
],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
],
[
AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.)
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
AC_MSG_CHECKING(for posix_fallocate)
AC_TRY_LINK([#include <fcntl.h>
],[ posix_fallocate(0, 0, 0);
],
[
AC_DEFINE(USE_POSIX_FALLOCATE, 1, posix_fallocate supported.)
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
AC_ARG_WITH(posix-fallocate,
AC_HELP_STRING([--with-posix-fallocate], [check for and use posix_fallocate to allocate files]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_POSIX_FALLOCATE
fi
])
])
AC_DEFUN([TORRENT_CHECK_STATVFS], [
AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h)
AC_MSG_CHECKING(for statvfs)
AC_TRY_LINK(
[
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
],[
struct statvfs s; fsblkcnt_t c;
statvfs("", &s);
fstatvfs(0, &s);
],
[
AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],
[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_CHECK_STATFS], [
AC_CHECK_HEADERS(sys/statfs.h sys/param.h sys/mount.h)
AC_MSG_CHECKING(for statfs)
AC_TRY_LINK(
[
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
],[
struct statfs s;
statfs("", &s);
fstatfs(0, &s);
],
[
AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],
[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_DISABLED_STATFS], [
AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size)
AC_MSG_RESULT(No filesystem stats available)
])
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
AC_ARG_WITH(statvfs,
AC_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,
AC_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-or-32768mb]]),
AC_HELP_STRING([--with-address-space=MB], [change the default address space size [[default=1024mb]]]),
[
if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
@@ -91,48 +347,102 @@ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
AC_CHECK_SIZEOF(long)
if test $ac_cv_sizeof_long = 8; then
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 32768, Default address space size.)
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 4096, Default address space size.)
else
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 1024, Default address space size.)
fi
])
])
AC_DEFUN([TORRENT_CHECK_ATOMIC], [
AC_MSG_CHECKING([whether 64-bit atomic operations require -latomic])
AC_DEFUN([TORRENT_CHECK_TR1], [
AC_LANG_PUSH(C++)
AC_MSG_CHECKING(for TR1 support)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cstdint>
#include <atomic>]],
[[std::atomic<uint64_t> x(0);
return x.load();]])],
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <tr1/unordered_map>
class Foo;
typedef std::tr1::unordered_map<Foo*, int> Bar;
])],
[
AC_MSG_RESULT([no])
ATOMIC_LIBS=""
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_TR1, 1, Define to 1 if your C++ library supports the extensions from Technical Report 1)
],
[
save_LIBS="$LIBS"
LIBS="$LIBS -latomic"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cstdint>
#include <atomic>]],
[[std::atomic<uint64_t> x(0);
return x.load();]])],
[
AC_MSG_RESULT([yes])
ATOMIC_LIBS="-latomic"
],
[
AC_MSG_RESULT([unsupported])
AC_MSG_ERROR([Compiler target lacks proper 64-bit atomic support.])
])
LIBS="$save_LIBS"
])
AC_MSG_RESULT(no)
]
)
AC_LANG_POP(C++)
AC_SUBST([ATOMIC_LIBS])
])
AC_DEFUN([TORRENT_CHECK_CXX11], [
AC_LANG_PUSH(C++)
AC_MSG_CHECKING(for C++11 support)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <functional>
#include <unordered_map>
class Foo;
typedef std::unordered_map<Foo*, int> Bar;
union test { Bar b1; };
])],
[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_CXX11, 1, Define to 1 if your C++ compiler has support for C++11.)
],
[
AC_MSG_RESULT(no)
]
)
AC_LANG_POP(C++)
])
AC_DEFUN([TORRENT_WITH_FASTCGI], [
AC_ARG_WITH(fastcgi,
AC_HELP_STRING([--with-fastcgi=PATH], [enable FastCGI RPC support (DO NOT USE)]),
[
AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
elif test "$withval" = "yes"; then
CXXFLAGS="$CXXFLAGS"
LIBS="$LIBS -lfcgi"
AC_TRY_LINK(
[ #include <fcgiapp.h>
],[ FCGX_Init(); ],
[
AC_MSG_RESULT(ok)
],
[
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Could not compile FastCGI test.)
])
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
else
CXXFLAGS="$CXXFLAGS -I$withval/include"
LIBS="$LIBS -lfcgi -L$withval/lib"
AC_TRY_LINK(
[ #include <fcgiapp.h>
],[ FCGX_Init(); ],
[
AC_MSG_RESULT(ok)
],
[
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Could not compile FastCGI test.)
])
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
fi
])
])
@@ -140,7 +450,7 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
AC_MSG_CHECKING(for XMLRPC-C)
AC_ARG_WITH(xmlrpc-c,
AS_HELP_STRING([--with-xmlrpc-c=PATH],[enable XMLRPC-C support]),
AC_HELP_STRING([--with-xmlrpc-c=PATH], [enable XMLRPC-C support]),
[
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
@@ -151,15 +461,17 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
else
xmlrpc_cc_prg="$withval"
fi
if eval $xmlrpc_cc_prg --version 2>/dev/null >/dev/null; then
CXXFLAGS="$CXXFLAGS `$xmlrpc_cc_prg --cflags server-util`"
LIBS="$LIBS `$xmlrpc_cc_prg server-util --libs`"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <xmlrpc-c/server.h>
]], [[ xmlrpc_registry_new(NULL); ]])],[
AC_TRY_LINK(
[ #include <xmlrpc-c/server.h>
],[ xmlrpc_registry_new(NULL); ],
[
AC_MSG_RESULT(ok)
],[
], [
AC_MSG_RESULT(failed)
AC_MSG_ERROR(Could not compile XMLRPC-C test.)
])
@@ -178,67 +490,17 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
])
AC_DEFUN([TORRENT_WITH_TINYXML2], [
AC_MSG_CHECKING(for tinyxml2)
AC_ARG_WITH(xmlrpc-tinyxml2,
AS_HELP_STRING([--with-xmlrpc-tinyxml2],[enable XMLRPC support via tinyxml2]),
[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_XMLRPC_TINYXML2, 1, Support for XMLRPC via tinyxml2.)
],[
AC_MSG_RESULT(ignored)
])
])
AC_DEFUN([TORRENT_WITH_LUA], [
AC_ARG_WITH(lua,
AS_HELP_STRING([--with-lua],[enable LUA support]),
[
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
else
AX_PROG_LUA
# 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])
AC_CHECK_HEADERS([sys/inotify.h mcheck.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(USE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(failed)]
)
@@ -246,30 +508,28 @@ AC_DEFUN([TORRENT_WITH_INOTIFY], [
AC_LANG_POP(C++)
])
AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
AC_CHECK_HEADERS(pthread.h)
AC_MSG_CHECKING(for pthread_setname_np type)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#define _GNU_SOURCE
AC_TRY_LINK([
#include <pthread.h>
#include <sys/types.h>
]], [[
],[
pthread_t t;
pthread_setname_np(t, "foo");
]])],[
],[
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_GENERIC, 1, The function to set pthread name has a pthread_t argumet.)
AC_MSG_RESULT(generic)
],[
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_LINK([
#include <pthread.h>
#include <sys/types.h>
]],[[
],[
pthread_t t;
pthread_setname_np("foo");
]])],[
],[
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_DARWIN, 1, The function to set pthread name has no pthread argument.)
AC_MSG_RESULT(darwin)
],[
@@ -277,74 +537,3 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
])
])
])
AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
AC_MSG_CHECKING([for pthread_setname_no])
AC_ARG_ENABLE(pthread-setname-np,
AS_HELP_STRING([--disable-pthread-setname-np],[disable pthread_setname_np]),
[
if test "$enableval" = "no"; then
AC_MSG_RESULT(disabled)
else
AC_MSG_RESULT(checking)
TORRENT_CHECK_PTHREAD_SETNAME_NP
fi
], [
TORRENT_CHECK_PTHREAD_SETNAME_NP
]
)
])
AC_DEFUN([TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP], [
AC_MSG_CHECKING(for posix_spawn_file_actions_addclosefrom_np)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#define _GNU_SOURCE
#include <spawn.h>
]], [[
posix_spawn_file_actions_t actions;
posix_spawn_file_actions_addclosefrom_np(&actions, 3);
]])],[
AC_DEFINE(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP, 1, [Define if posix_spawn_file_actions_addclosefrom_np is available.])
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
AC_ARG_WITH(systemd,
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
[
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])
])
+240 -179
View File
@@ -1,3 +1,120 @@
AC_DEFUN([TORRENT_CHECK_CXXFLAGS], [
AC_MSG_CHECKING([for user-defined CXXFLAGS])
if test -n "$CXXFLAGS"; then
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
else
CXXFLAGS="-O2 -Wall"
AC_MSG_RESULT([default "$CXXFLAGS"])
fi
])
AC_DEFUN([TORRENT_ENABLE_DEBUG], [
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]),
[
if test "$enableval" = "yes"; then
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
else
CXXFLAGS="$CXXFLAGS -DNDEBUG"
fi
],[
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
])
])
AC_DEFUN([TORRENT_ENABLE_WERROR], [
AC_ARG_ENABLE(werror,
AC_HELP_STRING([--enable-werror], [enable the -Werror and -Wall flag [[default=no]]]),
[
if test "$enableval" = "yes"; then
CXXFLAGS="$CXXFLAGS -Werror -Wall"
fi
])
])
AC_DEFUN([TORRENT_ENABLE_EXTRA_DEBUG], [
AC_ARG_ENABLE(extra-debug,
AC_HELP_STRING([--enable-extra-debug], [enable extra debugging checks [[default=no]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
fi
])
])
AC_DEFUN([TORRENT_WITH_SYSROOT], [
AC_ARG_WITH(sysroot,
AC_HELP_STRING([--with-sysroot=PATH], [compile and link with a specific sysroot]),
[
AC_MSG_CHECKING(for sysroot)
if test "$withval" = "no"; then
AC_MSG_RESULT(no)
elif test "$withval" = "yes"; then
AC_MSG_RESULT(not a path)
AC_MSG_ERROR(The sysroot option must point to a directory, like f.ex "/Developer/SDKs/MacOSX10.4u.sdk".)
else
AC_MSG_RESULT($withval)
CXXFLAGS="$CXXFLAGS -isysroot $withval"
LDFLAGS="$LDFLAGS -Wl,-syslibroot,$withval"
fi
])
])
AC_DEFUN([TORRENT_ENABLE_ARCH], [
AC_ARG_ENABLE(arch,
AC_HELP_STRING([--enable-arch=ARCH], [comma seprated list of architectures to compile for]),
[
AC_MSG_CHECKING(for target architectures)
if test "$enableval" = "yes"; then
AC_MSG_ERROR(no arch supplied)
elif test "$enableval" = "no"; then
AC_MSG_RESULT(using default)
else
AC_MSG_RESULT($enableval)
for i in `IFS=,; echo $enableval`; do
CFLAGS="$CFLAGS -march=$i"
CXXFLAGS="$CXXFLAGS -march=$i"
LDFLAGS="$LDFLAGS -march=$i"
done
fi
])
])
AC_DEFUN([TORRENT_OTFD], [
AC_LANG_PUSH(C++)
AC_MSG_CHECKING(for proper overloaded template function disambiguation)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
template <typename T> void f(T&) {}
template <typename T> void f(T*) {}
int main() { int *i = 0; f(*i); f(i); }
])],
[
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
AC_MSG_ERROR([your compiler does not properly handle overloaded template function disambiguation])
])
AC_LANG_POP(C++)
])
AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
AC_LANG_PUSH(C++)
AC_MSG_CHECKING(signedness of mincore parameter)
@@ -26,7 +143,7 @@ AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
AC_MSG_RESULT(signed)
],
[
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32 or OpenBSD.])
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32.])
])
])
@@ -35,8 +152,7 @@ AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
AC_DEFUN([TORRENT_MINCORE], [
AC_ARG_ENABLE(mincore,
AS_HELP_STRING([--disable-mincore],
[disable mincore check [[default=enable]]]),
AC_HELP_STRING([--disable-mincore], [disable mincore check [[default=enable]]]),
[
if test "$enableval" = "yes"; then
TORRENT_MINCORE_SIGNEDNESS()
@@ -55,7 +171,7 @@ AC_DEFUN([TORRENT_CHECK_MADVISE], [
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <sys/types.h>
#include <sys/mman.h>
void f() { static char test@<:@1024@:>@; madvise((void *)test, sizeof(test), MADV_NORMAL); }
void f() { static char test@<:@1024@:>@; madvise((void *)test, sizeof(test), MADV_NORMAL); }
])],
[
AC_MSG_RESULT(yes)
@@ -65,218 +181,163 @@ AC_DEFUN([TORRENT_CHECK_MADVISE], [
])
])
AC_DEFUN([TORRENT_CHECK_POSIX_FADVISE], [
AC_MSG_CHECKING(for posix_fadvise)
AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
AC_MSG_CHECKING(for __builtin_popcount)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <fcntl.h>
void f() { posix_fadvise(0, 0, 0, POSIX_FADV_RANDOM); }
])],
int f() { return __builtin_popcount(0); }
])],
[
AC_MSG_RESULT(yes)
AC_DEFINE(USE_POSIX_FADVISE, 1, Use posix_fadvise)
AC_DEFINE(USE_BUILTIN_POPCOUNT, 1, Use __builtin_popcount.)
], [
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_MSG_CHECKING([for target cacheline size])
AC_MSG_CHECKING(for cacheline)
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])
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.])
;;
riscv32*|riscv64*)
AC_MSG_RESULT([linux fallback RISC-V 64 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux RISC-V hardware.])
;;
loongarch32*|loongarch64*)
AC_MSG_RESULT([linux fallback LoongArch 64 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux LoongArch hardware.])
;;
*)
AC_MSG_RESULT([unrecognized CPU arch on Linux header fallback])
AC_MSG_FAILURE([Unrecognized CPU architecture ($host_cpu) on Linux fallback path. Aborting build.])
;;
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_CUSTOM_ENDIAN64], [
AC_CHECK_HEADERS([endian.h sys/endian.h libkern/OSByteOrder.h])
AC_C_BIGENDIAN
AH_TEMPLATE([CUSTOM_ENDIAN_HEADER], [The system header to include for endian conversions.])
AH_TEMPLATE([custom_ntohll], [Convert 64-bit integer from network to host byte order.])
AH_TEMPLATE([custom_htonll], [Convert 64-bit integer from host to network byte order.])
dnl 1. Initialize our header variable tracking
endian_header_file='<stdint.h>'
dnl 2. Test if native be64toh works natively via <endian.h> (Standard Linux/glibc)
AC_MSG_CHECKING([for native be64toh via endian.h])
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <stdint.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif
int main() { uint64_t x = be64toh(1); return 0; }
])],
[has_native_be64=yes; endian_header_file='<endian.h>'],
[has_native_be64=no]
)
AC_MSG_RESULT([$has_native_be64])
dnl 3. If missing, test if it works via <sys/endian.h> (True BSD systems like FreeBSD)
if test "$has_native_be64" = "no"; then
AC_MSG_CHECKING([for native be64toh via sys/endian.h])
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <stdint.h>
#ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
int main() { uint64_t x = be64toh(1); return 0; }
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); }
])],
[has_native_be64=yes; endian_header_file='<sys/endian.h>'],
[has_native_be64=no]
)
AC_MSG_RESULT([$has_native_be64])
fi
[
AC_MSG_RESULT(found builtin)
dnl AC_DEFINE(LT_SMP_CACHE_BYTES, SMP_CACHE_BYTES, Largest L1 cache size we know of, should work on all archs.)
dnl AC_DEFINE(lt_cacheline_aligned, __cacheline_aligned, LibTorrent defined cacheline aligned.)
dnl 4. Route definitions cleanly based on actual testing results
if test "$has_native_be64" = "yes"; then
dnl Linux or true BSD environment
AC_DEFINE_UNQUOTED([CUSTOM_ENDIAN_HEADER], [$endian_header_file], [The header containing native endian macros.])
AC_DEFINE([custom_ntohll(x)], [(be64toh(x))], [Use native platform be64toh])
AC_DEFINE([custom_htonll(x)], [(htobe64(x))], [Use native platform htobe64])
else
dnl Fallback block: Check if we are on macOS using Apple's optimized hardware libraries
if test "$ac_cv_header_libkern_OSByteOrder_h" = "yes"; then
AC_DEFINE([CUSTOM_ENDIAN_HEADER], [<libkern/OSByteOrder.h>], [The header containing native endian macros.])
AC_DEFINE([custom_ntohll(x)], [(OSSwapBigToHostInt64(x))], [Map missing be64toh to macOS native swap])
AC_DEFINE([custom_htonll(x)], [(OSSwapHostToBigInt64(x))], [Map missing htobe64 to macOS native swap])
else
dnl Fallback for platforms with no built-in architecture macros (compiler built-ins)
AC_DEFINE([CUSTOM_ENDIAN_HEADER], [<stdint.h>], [The header containing native endian macros.])
if test "$ac_cv_c_bigendian" = "yes"; then
AC_DEFINE([custom_ntohll(x)], [((uint64_t)(x))], [Fallback 64-bit conversion.])
AC_DEFINE([custom_htonll(x)], [((uint64_t)(x))], [Fallback 64-bit conversion.])
else
AC_DEFINE([custom_ntohll(x)], [(__builtin_bswap64((uint64_t)(x)))], [Fallback 64-bit conversion.])
AC_DEFINE([custom_htonll(x)], [(__builtin_bswap64((uint64_t)(x)))], [Fallback 64-bit conversion.])
fi
fi
fi
dnl Need to fix this so that it uses the stuff defined by the system.
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.)
], [
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.)
AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.)
])
])
AC_DEFUN([TORRENT_CHECK_EXECINFO], [
AC_MSG_CHECKING(for execinfo.h)
AC_RUN_IFELSE([AC_LANG_SOURCE([
#include <execinfo.h>
int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
])],
[
AC_MSG_RESULT(yes)
AC_DEFINE(USE_EXECINFO, 1, Use execinfo.h)
], [
AC_MSG_RESULT(no)
])
])
AC_DEFUN([TORRENT_CHECK_ALIGNED], [
AC_MSG_CHECKING(the byte alignment)
AC_RUN_IFELSE([AC_LANG_SOURCE([
#include <inttypes.h>
int main() {
char buf@<:@8@:>@ = { 0, 0, 0, 0, 1, 0, 0, 0 };
int i;
for (i = 1; i < 4; ++i)
if (*(uint32_t*)(buf + i) == 0) return -1;
return 0;
}
])],
[
AC_MSG_RESULT(none needed)
], [
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
AC_MSG_RESULT(required)
])
])
AC_DEFUN([TORRENT_ENABLE_INSTRUMENTATION], [
AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
AC_ARG_ENABLE(aligned,
AC_HELP_STRING([--enable-aligned], [enable alignment safe code [[default=check]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
fi
],[
TORRENT_CHECK_ALIGNED
])
])
AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
AC_MSG_CHECKING([if instrumentation should be included])
AC_ARG_ENABLE(instrumentation,
AS_HELP_STRING([--enable-instrumentation],
[enable instrumentation [[default=disabled]]]),
AC_HELP_STRING([--disable-instrumentation], [disable instrumentation [[default=enabled]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
AC_MSG_RESULT(yes)
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_RESULT(no)
fi
],[
AC_MSG_RESULT(no)
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
AC_MSG_RESULT(yes)
])
])
AC_DEFUN([TORRENT_ENABLE_CUSTOM_STACK_SIZE], [
AC_ARG_ENABLE([pthread-setstacksize],
[AS_HELP_STRING([--enable-pthread-setstacksize], [explicitly set pthread stack size (auto-enabled for musl)])],
[enable_pthread_setstacksize=$enableval],
[enable_pthread_setstacksize=auto])
AC_CANONICAL_HOST
if test "x$enable_pthread_setstacksize" = "xauto"; then
case "$host" in
*-musl*)
enable_pthread_setstacksize=yes
;;
*)
enable_pthread_setstacksize=no
;;
esac
fi
if test "x$enable_pthread_setstacksize" = "xyes"; then
AC_DEFINE([USE_PTHREAD_SETSTACKSIZE], [1], [Use explicit pthread stack size])
AC_DEFINE([DEFAULT_PTHREAD_STACKSIZE], [(8 * 1024 * 1024)], [Default pthread stack size in bytes])
fi
AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [
AC_ARG_ENABLE(interrupt-socket,
AC_HELP_STRING([--enable-interrupt-socket], [enable interrupt socket [[default=no]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(USE_INTERRUPT_SOCKET, 1, Use interrupt socket instead of pthread_kill)
fi
]
)
])
AC_DEFUN([TORRENT_DISABLE_IPV6], [
AC_ARG_ENABLE(ipv6,
AS_HELP_STRING([--enable-ipv6],
[enable ipv6 [[default=no]]]),
AC_HELP_STRING([--enable-ipv6], [enable ipv6 [[default=no]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(RAK_USE_INET6, 1, enable ipv6 stuff)
fi
])
])
AC_DEFUN([TORRENT_ENABLE_TR1], [
AC_ARG_ENABLE(std_tr1,
AC_HELP_STRING([--disable-std_tr1], [disable check for support for TR1 [[default=enable]]]),
[
if test "$enableval" = "yes"; then
TORRENT_CHECK_TR1()
else
AC_MSG_CHECKING(for TR1 support)
AC_MSG_RESULT(disabled)
fi
],[
TORRENT_CHECK_TR1()
])
])
AC_DEFUN([TORRENT_ENABLE_CXX11], [
AC_ARG_ENABLE(std_c++11,
AC_HELP_STRING([--disable-std_c++11], [disable check for support for C++11 [[default=enable]]]),
[
if test "$enableval" = "yes"; then
TORRENT_CHECK_CXX11()
else
AC_MSG_CHECKING(for C++11 support)
AC_MSG_RESULT(disabled)
fi
],[
TORRENT_CHECK_CXX11()
]
)
])
-63
View File
@@ -1,63 +0,0 @@
AC_DEFUN([RAK_CHECK_CFLAGS], [
AC_MSG_CHECKING([for user-defined CFLAGS])
if test "$CFLAGS" = ""; then
unset CFLAGS
AC_MSG_RESULT([undefined])
else
AC_MSG_RESULT([user-defined "$CFLAGS"])
fi
])
AC_DEFUN([RAK_CHECK_CXXFLAGS], [
AC_MSG_CHECKING([for user-defined CXXFLAGS])
if test "$CXXFLAGS" = ""; then
unset CXXFLAGS
AC_MSG_RESULT([undefined])
else
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
fi
])
AC_DEFUN([RAK_ENABLE_DEBUG], [
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],[enable debug information [[default=yes]]]),
[
if test "$enableval" = "yes"; then
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
else
CXXFLAGS="$CXXFLAGS -DNDEBUG"
fi
],[
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
])
])
AC_DEFUN([RAK_ENABLE_WERROR], [
AC_ARG_ENABLE(werror,
AS_HELP_STRING([--enable-werror],[enable the -Werror and -Wall flags [[default -Wall only]]]),
[
if test "$enableval" = "yes"; then
CXXFLAGS="$CXXFLAGS -Werror -Wall"
fi
],[
CXXFLAGS="$CXXFLAGS -Wall"
])
])
AC_DEFUN([RAK_ENABLE_EXTRA_DEBUG], [
AC_ARG_ENABLE(extra-debug,
AS_HELP_STRING([--enable-extra-debug],[enable extra debugging checks [[default=no]]]),
[
if test "$enableval" = "yes"; then
AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
fi
])
])
-38
View File
@@ -1,38 +0,0 @@
AC_DEFUN([TORRENT_CHECK_OPENSSL],
[
PKG_CHECK_MODULES(OPENSSL, libcrypto,
CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
LIBS="$LIBS $OPENSSL_LIBS")
AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
]
)
AC_DEFUN([TORRENT_ARG_OPENSSL],
[
AC_ARG_ENABLE(openssl,
[ --disable-openssl Don't use OpenSSL's SHA1 implementation.],
[
if test "$enableval" = "yes"; then
TORRENT_CHECK_OPENSSL
else
AC_DEFINE(USE_NSS_SHA, 1, Using Mozilla's SHA1 implementation.)
fi
],[
TORRENT_CHECK_OPENSSL
])
]
)
AC_DEFUN([TORRENT_ARG_CYRUS_RC4],
[
AC_ARG_ENABLE(cyrus-rc4,
[ --enable-cyrus-rc4=PFX Use Cyrus RC4 implementation.],
[
CXXFLAGS="$CXXFLAGS -I${enableval}/include";
LIBS="$LIBS -lrc4 -L${enableval}/lib"
AC_DEFINE(USE_CYRUS_RC4, 1, Using Cyrus RC4 implementation.)
])
]
)
+27 -185
View File
@@ -1,184 +1,14 @@
noinst_LIBRARIES = libsub_root.a
bin_PROGRAMS = rtorrent
SUBDIRS = \
core \
display \
input \
rpc \
ui \
utils
rtorrent_LDADD = libsub_root.a @PTHREAD_LIBS@
rtorrent_SOURCES = main.cc
noinst_LIBRARIES = libsub_root.a
libsub_root_a_SOURCES = \
core/dht_manager.cc \
core/dht_manager.h \
core/download.cc \
core/download.h \
core/download_factory.cc \
core/download_factory.h \
core/download_list.cc \
core/download_list.h \
core/http_queue.cc \
core/http_queue.h \
core/manager.cc \
core/manager.h \
core/range_map.h \
core/view.cc \
core/view.h \
core/view_manager.cc \
core/view_manager.h \
\
display/attributes.h \
display/canvas.cc \
display/canvas.h \
display/color_map.h \
display/frame.cc \
display/frame.h \
display/manager.cc \
display/manager.h \
display/utils.cc \
display/utils.h \
display/text_element.h \
display/text_element_list.cc \
display/text_element_list.h \
display/text_element_string.cc \
display/text_element_string.h \
display/text_element_value.cc \
display/text_element_value.h \
display/window.cc \
display/window.h \
display/window_download_chunks_seen.cc \
display/window_download_chunks_seen.h \
display/window_download_list.cc \
display/window_download_list.h \
display/window_download_statusbar.cc \
display/window_download_statusbar.h \
display/window_download_transfer_list.cc \
display/window_download_transfer_list.h \
display/window_file_list.cc \
display/window_file_list.h \
display/window_http_queue.cc \
display/window_http_queue.h \
display/window_input.cc \
display/window_input.h \
display/window_log.cc \
display/window_log.h \
display/window_log_complete.cc \
display/window_log_complete.h \
display/window_peer_list.cc \
display/window_peer_list.h \
display/window_statusbar.cc \
display/window_statusbar.h \
display/window_string_list.cc \
display/window_string_list.h \
display/window_text.cc \
display/window_text.h \
display/window_title.cc \
display/window_title.h \
display/window_tracker_list.cc \
display/window_tracker_list.h \
\
input/bindings.cc \
input/bindings.h \
input/input_event.cc \
input/input_event.h \
input/manager.cc \
input/manager.h \
input/path_input.cc \
input/path_input.h \
input/text_input.cc \
input/text_input.h \
\
rpc/command.h \
rpc/command.cc \
rpc/command_impl.h \
rpc/command_map.cc \
rpc/command_map.h \
rpc/command_scheduler.cc \
rpc/command_scheduler.h \
rpc/command_scheduler_item.cc \
rpc/command_scheduler_item.h \
rpc/exec_file.cc \
rpc/exec_file.h \
rpc/fixed_key.h \
rpc/ip_table_list.h \
rpc/lua.h \
rpc/lua.cc \
rpc/jsonrpc.cc \
rpc/jsonrpc.h \
rpc/rpc_manager.cc \
rpc/rpc_manager.h \
rpc/object_storage.cc \
rpc/object_storage.h \
rpc/parse.cc \
rpc/parse.h \
rpc/parse_commands.cc \
rpc/parse_commands.h \
rpc/parse_options.cc \
rpc/parse_options.h \
rpc/scgi.cc \
rpc/scgi.h \
rpc/scgi_task.cc \
rpc/scgi_task.h \
rpc/xmlrpc.h \
rpc/xmlrpc.cc \
rpc/xmlrpc_c.cc \
rpc/xmlrpc_tinyxml2.cc \
rpc/tinyxml2/tinyxml2.h \
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 \
ui/download_list.h \
ui/element_base.h \
ui/element_base.cc \
ui/element_chunks_seen.cc \
ui/element_chunks_seen.h \
ui/element_download_list.cc \
ui/element_download_list.h \
ui/element_file_list.cc \
ui/element_file_list.h \
ui/element_log_complete.cc \
ui/element_log_complete.h \
ui/element_menu.cc \
ui/element_menu.h \
ui/element_peer_list.cc \
ui/element_peer_list.h \
ui/element_string_list.cc \
ui/element_string_list.h \
ui/element_text.cc \
ui/element_text.h \
ui/element_tracker_list.cc \
ui/element_tracker_list.h \
ui/element_transfer_list.cc \
ui/element_transfer_list.h \
ui/root.cc \
ui/root.h \
\
utils/base64.cc \
utils/base64.h \
utils/directory.cc \
utils/directory.h \
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/waitpid_queue.cc \
utils/waitpid_queue.h \
utils/watch_ready_queue.cc \
utils/watch_ready_queue.h \
\
command_download.cc \
command_dynamic.cc \
command_events.cc \
@@ -201,14 +31,26 @@ libsub_root_a_SOURCES = \
globals.h \
option_parser.cc \
option_parser.h \
setup.cc \
setup.h \
signal_handler.cc \
signal_handler.h
signal_handler.h \
thread_base.cc \
thread_base.h \
thread_worker.cc \
thread_worker.h
bin_PROGRAMS = rtorrent
if NO_NCURSES
libsub_root_a_SOURCES += display/curses_stub.cc display/curses_stub.h
endif
rtorrent_LDADD = \
libsub_root.a \
ui/libsub_ui.a \
core/libsub_core.a \
display/libsub_display.a \
input/libsub_input.a \
rpc/libsub_rpc.a \
utils/libsub_utils.a \
@PTHREAD_LIBS@
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
rtorrent_SOURCES = \
main.cc
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
+280 -425
View File
File diff suppressed because it is too large Load Diff
+191 -207
View File
@@ -1,36 +1,48 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <algorithm>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "command_helpers.h"
#include "control.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "rpc/parse.h"
#include "rpc/parse_options.h"
static std::vector<std::pair<const char*, int>> object_storage_flags = {
{"multi", rpc::object_storage::flag_multi_type},
{"simple", rpc::object_storage::flag_function_type},
{"value", rpc::object_storage::flag_value_type},
{"bool", rpc::object_storage::flag_bool_type},
{"string", rpc::object_storage::flag_string_type},
{"list", rpc::object_storage::flag_list_type},
{"static", rpc::object_storage::flag_static},
{"private", rpc::object_storage::flag_private},
{"const", rpc::object_storage::flag_constant},
{"rlookup", rpc::object_storage::flag_rlookup}};
static int
object_storage_parse_flag(const std::string& flag) {
for (auto [n, f] : object_storage_flags)
if (n == flag)
return f;
throw torrent::input_error("unknown flag");
}
std::string
system_method_generate_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
@@ -72,7 +84,7 @@ system_method_generate_command2(torrent::Object* object, torrent::Object::list_c
if (first + 1 == last) {
if (!first->is_dict_key())
throw torrent::input_error("New command of wrong type.");
*object = *first;
uint32_t flags = object->flags() & torrent::Object::mask_function;
@@ -85,9 +97,9 @@ system_method_generate_command2(torrent::Object* object, torrent::Object::list_c
while (first != last) {
if (!first->is_dict_key())
throw torrent::input_error("New command of wrong type.");
object->as_list().push_back(*first++);
uint32_t flags = object->as_list().back().flags() & torrent::Object::mask_function;
object->as_list().back().unset_flags(torrent::Object::mask_function);
object->as_list().back().set_flags((flags >> 1) & torrent::Object::mask_function);
@@ -97,32 +109,20 @@ system_method_generate_command2(torrent::Object* object, torrent::Object::list_c
// torrent::Object
// system_method_insert_function(const torrent::Object::list_type& args, int flags) {
// }
// This is only used by tinyxml2, xmlrpc-c intercepts the call internally
torrent::Object
system_listMethods() {
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
result.push_back("system.multicall"); // Handled directly by the XMLRPC code
for (auto itr : rpc::commands) {
result.push_back(itr.first);
}
return resultRaw;
}
torrent::Object
system_method_insert_object(const torrent::Object::list_type& args, int flags) {
if (args.empty())
throw torrent::input_error("Invalid argument count.");
torrent::Object::list_const_iterator itrArgs = args.begin();
const std::string& raw_key = (itrArgs++)->as_string();
const std::string& rawKey = (itrArgs++)->as_string();
if (raw_key.empty() ||
control->object_storage()->find_raw_string(torrent::raw_string::from_string(raw_key)) != control->object_storage()->end() ||
rpc::commands.has(raw_key) || rpc::commands.has(raw_key + ".set"))
if (rawKey.empty() ||
control->object_storage()->find_local(torrent::raw_string::from_string(rawKey)) != control->object_storage()->end(0) ||
rpc::commands.has(rawKey) || rpc::commands.has(rawKey + ".set"))
throw torrent::input_error("Invalid key.");
torrent::Object value;
@@ -138,8 +138,6 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
case rpc::object_storage::flag_function_type:
system_method_generate_command2(&value, itrArgs, args.end());
break;
case rpc::object_storage::flag_list_type:
break;
case rpc::object_storage::flag_multi_type:
break;
default:
@@ -151,96 +149,67 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
if (!(flags & rpc::object_storage::flag_static))
cmd_flags |= rpc::CommandMap::flag_modifiable;
if (!(flags & rpc::object_storage::flag_private))
cmd_flags |= rpc::CommandMap::flag_public_rpc;
cmd_flags |= rpc::CommandMap::flag_public_xmlrpc;
if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_list_type) {
torrent::Object valueList = torrent::Object::create_list();
torrent::Object::list_type& valueListType = valueList.as_list();
if ((itrArgs)->is_list())
valueListType = (itrArgs)->as_list();
control->object_storage()->insert_str(raw_key, valueList, flags);
} else {
control->object_storage()->insert_str(raw_key, value, flags);
}
control->object_storage()->insert_str(rawKey, value, flags);
if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_function_type ||
(flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_multi_type) {
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type>>::type>(
raw_key,
std::bind(&rpc::object_storage::call_function_str, control->object_storage(), raw_key, std::placeholders::_1, std::placeholders::_2),
&rpc::command_base_call<rpc::target_type>,
cmd_flags,
NULL,
NULL);
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type> >::type>
(create_new_key(rawKey),
tr1::bind(&rpc::object_storage::call_function_str, control->object_storage(),
rawKey, tr1::placeholders::_1, tr1::placeholders::_2),
&rpc::command_base_call<rpc::target_type>,
cmd_flags, NULL, NULL);
} else {
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type>>::type>(
raw_key,
std::bind(&rpc::object_storage::get_str, control->object_storage(), raw_key),
&rpc::command_base_call<rpc::target_type>,
cmd_flags,
NULL,
NULL);
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type> >::type>
(create_new_key(rawKey),
tr1::bind(&rpc::object_storage::get_str, control->object_storage(), rawKey),
&rpc::command_base_call<rpc::target_type>,
cmd_flags, NULL, NULL);
}
// Not the right argument.
// if (flags & rpc::object_storage::flag_rlookup) {
// rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_string<rpc::target_type> >::type>
// (create_new_key<9>(raw_key, ".rlookup"),
// std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), raw_key),
// (create_new_key<9>(rawKey, ".rlookup"),
// tr1::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), rawKey),
// &rpc::command_base_call_string<rpc::target_type>,
// cmd_flags, NULL, NULL);
// }
// TODO: Next... Make test class for this.
// // Ehm... no proper handling if these throw.
// // Ehm... no proper handling if these throw.
if (!(flags & rpc::object_storage::flag_constant)) {
switch (flags & rpc::object_storage::mask_type) {
case rpc::object_storage::flag_bool_type:
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type>>::type>(
raw_key + ".set",
std::bind(&rpc::object_storage::set_str_bool, control->object_storage(), raw_key, std::placeholders::_2),
&rpc::command_base_call_value<rpc::target_type>,
cmd_flags,
NULL,
NULL);
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type> >::type>
(create_new_key<5>(rawKey, ".set"),
tr1::bind(&rpc::object_storage::set_str_bool, control->object_storage(), rawKey, tr1::placeholders::_2),
&rpc::command_base_call_value<rpc::target_type>,
cmd_flags, NULL, NULL);
break;
case rpc::object_storage::flag_value_type:
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type>>::type>(
raw_key + ".set",
std::bind(&rpc::object_storage::set_str_value, control->object_storage(), raw_key, std::placeholders::_2),
&rpc::command_base_call_value<rpc::target_type>,
cmd_flags,
NULL,
NULL);
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type> >::type>
(create_new_key<5>(rawKey, ".set"),
tr1::bind(&rpc::object_storage::set_str_value, control->object_storage(), rawKey, tr1::placeholders::_2),
&rpc::command_base_call_value<rpc::target_type>,
cmd_flags, NULL, NULL);
break;
case rpc::object_storage::flag_string_type:
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_string<rpc::target_type>>::type>(
raw_key + ".set",
std::bind(&rpc::object_storage::set_str_string, control->object_storage(), raw_key, std::placeholders::_2),
&rpc::command_base_call_string<rpc::target_type>,
cmd_flags,
NULL,
NULL);
break;
case rpc::object_storage::flag_list_type:
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_list<rpc::target_type>>::type>(
raw_key + ".set",
std::bind(&rpc::object_storage::set_str_list, control->object_storage(), raw_key, std::placeholders::_2),
&rpc::command_base_call_list<rpc::target_type>,
cmd_flags,
NULL,
NULL);
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_string<rpc::target_type> >::type>
(create_new_key<5>(rawKey, ".set"),
tr1::bind(&rpc::object_storage::set_str_string, control->object_storage(), rawKey, tr1::placeholders::_2),
&rpc::command_base_call_string<rpc::target_type>,
cmd_flags, NULL, NULL);
break;
case rpc::object_storage::flag_function_type:
case rpc::object_storage::flag_multi_type:
default:
break;
default: break;
}
}
@@ -268,32 +237,94 @@ system_method_insert(const torrent::Object::list_type& args) {
throw torrent::input_error("Invalid argument count.");
torrent::Object::list_const_iterator itrArgs = args.begin();
const std::string& raw_key = (itrArgs++)->as_string();
const std::string& rawKey = (itrArgs++)->as_string();
if (raw_key.empty() || rpc::commands.has(raw_key))
if (rawKey.empty() || rpc::commands.has(rawKey))
throw torrent::input_error("Invalid key.");
int new_flags = rpc::parse_option_flags(itrArgs->as_string(), std::bind(&object_storage_parse_flag, std::placeholders::_1));
int flags = rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc;
torrent::Object::list_type new_args;
new_args.push_back(raw_key);
const std::string& options = itrArgs->as_string();
if ((new_flags & rpc::object_storage::flag_function_type) ||
(new_flags & rpc::object_storage::flag_multi_type)) {
if (options.find("private") != std::string::npos)
flags &= ~rpc::CommandMap::flag_public_xmlrpc;
if (options.find("const") != std::string::npos)
flags &= ~rpc::CommandMap::flag_modifiable;
if (options.find("multi") != std::string::npos) {
torrent::Object::list_type new_args;
new_args.push_back(rawKey);
new_args.push_back(system_method_generate_command(++itrArgs, args.end()));
} else if ((new_flags & rpc::object_storage::flag_value_type) ||
(new_flags & rpc::object_storage::flag_bool_type) ||
(new_flags & rpc::object_storage::flag_string_type) ||
(new_flags & rpc::object_storage::flag_list_type)) {
int new_flags = rpc::object_storage::flag_multi_type;
if (options.find("static") != std::string::npos)
new_flags |= rpc::object_storage::flag_static;
if (options.find("private") != std::string::npos)
new_flags |= rpc::object_storage::flag_private;
if (options.find("const") != std::string::npos)
new_flags |= rpc::object_storage::flag_constant;
if (options.find("rlookup") != std::string::npos)
new_flags |= rpc::object_storage::flag_rlookup;
return system_method_insert_object(new_args, new_flags);
} else if (options.find("simple") != std::string::npos) {
torrent::Object::list_type new_args;
new_args.push_back(rawKey);
new_args.push_back(system_method_generate_command(++itrArgs, args.end()));
int new_flags = rpc::object_storage::flag_function_type;
if (options.find("static") != std::string::npos)
new_flags |= rpc::object_storage::flag_static;
if (options.find("private") != std::string::npos)
new_flags |= rpc::object_storage::flag_private;
if (options.find("const") != std::string::npos)
new_flags |= rpc::object_storage::flag_constant;
return system_method_insert_object(new_args, new_flags);
} else if (options.find("value") != std::string::npos ||
options.find("bool") != std::string::npos ||
options.find("string") != std::string::npos ||
options.find("list") != std::string::npos ||
options.find("simple") != std::string::npos) {
torrent::Object::list_type new_args;
new_args.push_back(rawKey);
if (++itrArgs != args.end())
new_args.insert(new_args.end(), itrArgs, args.end());
int new_flags;
if (options.find("value") != std::string::npos)
new_flags = rpc::object_storage::flag_value_type;
else if (options.find("bool") != std::string::npos)
new_flags = rpc::object_storage::flag_bool_type;
else if (options.find("string") != std::string::npos)
new_flags = rpc::object_storage::flag_string_type;
else if (options.find("list") != std::string::npos)
new_flags = rpc::object_storage::flag_list_type;
else if (options.find("simple") != std::string::npos)
new_flags = rpc::object_storage::flag_function_type;
else
throw torrent::input_error("No support for 'list' variable type.");
if (options.find("static") != std::string::npos)
new_flags |= rpc::object_storage::flag_static;
if (options.find("private") != std::string::npos)
new_flags |= rpc::object_storage::flag_private;
if (options.find("const") != std::string::npos)
new_flags |= rpc::object_storage::flag_constant;
return system_method_insert_object(new_args, new_flags);
} else {
throw torrent::input_error("No object type specified.");
// THROW.
}
return system_method_insert_object(new_args, new_flags);
return torrent::Object();
}
// method.erase <> {name}
@@ -324,7 +355,8 @@ system_method_redirect(const torrent::Object::list_type& args) {
std::string new_key = torrent::object_create_string(args.front());
std::string dest_key = torrent::object_create_string(args.back());
rpc::commands.create_redirect(new_key, dest_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_modifiable);
rpc::commands.create_redirect(create_new_key(new_key), create_new_key(dest_key),
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable);
return torrent::Object();
}
@@ -334,11 +366,11 @@ system_method_set_function(const torrent::Object::list_type& args) {
if (args.empty())
throw torrent::input_error("Invalid argument count.");
rpc::object_storage::iterator itr =
control->object_storage()->find_raw_string(torrent::raw_string::from_string(args.front().as_string()));
rpc::object_storage::local_iterator itr =
control->object_storage()->find_local(torrent::raw_string::from_string(args.front().as_string()));
if (itr == control->object_storage()->end() || itr->second.flags & rpc::object_storage::flag_constant)
throw torrent::input_error("Command is not modifiable.");
if (itr == control->object_storage()->end(0) || itr->second.flags & rpc::object_storage::flag_constant)
throw torrent::input_error("Command is not modifiable.");
return control->object_storage()->set_str_function(args.front().as_string(),
system_method_generate_command(++args.begin(), args.end()));
@@ -350,9 +382,9 @@ system_method_has_key(const torrent::Object::list_type& args) {
throw torrent::input_error("Invalid argument count.");
torrent::Object::list_const_iterator itrArgs = args.begin();
const std::string& key = (itrArgs++)->as_string();
const std::string& cmd_key = (itrArgs++)->as_string();
const std::string& key = (itrArgs++)->as_string();
const std::string& cmd_key = (itrArgs++)->as_string();
return control->object_storage()->has_str_multi_key(key, cmd_key);
}
@@ -362,9 +394,9 @@ system_method_set_key(const torrent::Object::list_type& args) {
throw torrent::input_error("Invalid argument count.");
torrent::Object::list_const_iterator itrArgs = args.begin();
const std::string& key = (itrArgs++)->as_string();
const std::string& cmd_key = (itrArgs++)->as_string();
const std::string& key = (itrArgs++)->as_string();
const std::string& cmd_key = (itrArgs++)->as_string();
if (itrArgs == args.end()) {
control->object_storage()->erase_str_multi_key(key, cmd_key);
return torrent::Object();
@@ -380,11 +412,13 @@ system_method_set_key(const torrent::Object::list_type& args) {
torrent::Object
system_method_list_keys(const torrent::Object::string_type& args) {
torrent::Object rawResult = torrent::Object::create_list();
torrent::Object::list_type& result = rawResult.as_list();
const torrent::Object::map_type& multi_cmd = control->object_storage()->get_str(args).as_map();
torrent::Object rawResult = torrent::Object::create_list();
torrent::Object::list_type& result = rawResult.as_list();
for (const auto& itr : control->object_storage()->get_str(args).as_map())
result.push_back(itr.first);
for (torrent::Object::map_const_iterator itr = multi_cmd.begin(), last = multi_cmd.end(); itr != last; itr++)
result.push_back(itr->first);
return rawResult;
}
@@ -400,88 +434,38 @@ cmd_catch(rpc::target_type target, const torrent::Object& args) {
}
#define CMD2_METHOD_INSERT(key, flags) \
CMD2_ANY_LIST(key, std::bind(&system_method_insert_object, std::placeholders::_2, flags));
CMD2_ANY_LIST(key, tr1::bind(&system_method_insert_object, tr1::placeholders::_2, flags));
void
initialize_command_dynamic() {
// clang-format off
#ifdef HAVE_XMLRPC_TINYXML2
CMD2_ANY ("system.listMethods", std::bind(&system_listMethods)); // only used by tinyxml2
#endif
CMD2_VAR_BOOL ("method.use_deprecated", true);
CMD2_VAR_VALUE ("method.use_intermediate", 1);
// Keep these for future use when we deprecate more commands.
CMD2_VAR_BOOL ("method.use_deprecated", false);
CMD2_VAR_VALUE ("method.use_intermediate", 3);
CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2));
CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_value_type));
CMD2_ANY_LIST ("method.insert.bool", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_bool_type));
CMD2_ANY_LIST ("method.insert.string", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_string_type));
CMD2_ANY_LIST ("method.insert.list", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_list_type));
CMD2_ANY_LIST ("method.insert", tr1::bind(&system_method_insert, tr1::placeholders::_2));
CMD2_ANY_LIST ("method.insert.value", tr1::bind(&system_method_insert_object, tr1::placeholders::_2, rpc::object_storage::flag_value_type));
CMD2_METHOD_INSERT("method.insert.simple", rpc::object_storage::flag_function_type);
CMD2_METHOD_INSERT("method.insert.c_simple", rpc::object_storage::flag_constant | rpc::object_storage::flag_function_type);
CMD2_METHOD_INSERT("method.insert.s_c_simple", rpc::object_storage::flag_static |
rpc::object_storage::flag_constant |rpc::object_storage::flag_function_type);
CMD2_ANY_STRING ("method.erase", std::bind(&system_method_erase, std::placeholders::_2));
CMD2_ANY_LIST ("method.redirect", std::bind(&system_method_redirect, std::placeholders::_2));
CMD2_ANY_STRING ("method.get", std::bind(&rpc::object_storage::get_str, control->object_storage(),
std::placeholders::_2));
CMD2_ANY_LIST ("method.set", std::bind(&system_method_set_function, std::placeholders::_2));
CMD2_ANY_STRING ("method.erase", tr1::bind(&system_method_erase, tr1::placeholders::_2));
CMD2_ANY_LIST ("method.redirect", tr1::bind(&system_method_redirect, tr1::placeholders::_2));
CMD2_ANY_STRING ("method.get", tr1::bind(&rpc::object_storage::get_str, control->object_storage(),
tr1::placeholders::_2));
CMD2_ANY_LIST ("method.set", tr1::bind(&system_method_set_function, tr1::placeholders::_2));
CMD2_ANY_STRING ("method.const", std::bind(&rpc::object_storage::has_flag_str, control->object_storage(),
std::placeholders::_2, rpc::object_storage::flag_constant));
CMD2_ANY_STRING_V("method.const.enable", std::bind(&rpc::object_storage::enable_flag_str, control->object_storage(),
std::placeholders::_2, rpc::object_storage::flag_constant));
CMD2_ANY_STRING ("method.const", tr1::bind(&rpc::object_storage::has_flag_str, control->object_storage(),
tr1::placeholders::_2, rpc::object_storage::flag_constant));
CMD2_ANY_STRING_V("method.const.enable", tr1::bind(&rpc::object_storage::enable_flag_str, control->object_storage(),
tr1::placeholders::_2, rpc::object_storage::flag_constant));
CMD2_ANY_LIST ("method.has_key", std::bind(&system_method_has_key, std::placeholders::_2));
CMD2_ANY_LIST ("method.set_key", std::bind(&system_method_set_key, std::placeholders::_2));
CMD2_ANY_STRING ("method.list_keys", std::bind(&system_method_list_keys, std::placeholders::_2));
CMD2_ANY_LIST ("method.has_key", tr1::bind(&system_method_has_key, tr1::placeholders::_2));
CMD2_ANY_LIST ("method.set_key", tr1::bind(&system_method_set_key, tr1::placeholders::_2));
CMD2_ANY_STRING ("method.list_keys", tr1::bind(&system_method_list_keys, tr1::placeholders::_2));
CMD2_ANY_STRING ("method.rlookup", std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), std::placeholders::_2));
CMD2_ANY_STRING_V("method.rlookup.clear", std::bind(&rpc::object_storage::rlookup_clear, control->object_storage(), std::placeholders::_2));
CMD2_ANY_STRING ("method.rlookup", tr1::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), tr1::placeholders::_2));
CMD2_ANY_STRING_V("method.rlookup.clear", tr1::bind(&rpc::object_storage::rlookup_clear, control->object_storage(), tr1::placeholders::_2));
CMD2_ANY ("catch", std::bind(&cmd_catch, std::placeholders::_1, std::placeholders::_2));
CMD2_ANY_STRING ("enum.log_group", [](auto, const auto& str) { return torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, str); });
CMD2_ANY ("strings.choke_heuristics", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS); });
CMD2_ANY ("strings.choke_heuristics.upload", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_UPLOAD); });
CMD2_ANY ("strings.choke_heuristics.download", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD); });
CMD2_ANY ("strings.connection_type", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CONNECTION_TYPE); });
CMD2_ANY ("strings.encryption", [](auto, auto) { return torrent::Object::create_list(); });
CMD2_ANY ("strings.encryption.handshake", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_HANDSHAKE); });
CMD2_ANY ("strings.encryption.stream", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_STREAM); });
CMD2_ANY ("strings.ip_filter", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_FILTER); });
CMD2_ANY ("strings.ip_tos", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_TOS); });
CMD2_ANY ("strings.log_group", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_LOG_GROUP); });
CMD2_ANY ("strings.tracker_event", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_EVENT); });
CMD2_ANY ("strings.tracker_mode", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_MODE); });
// 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("enum.log_group");
rpc::rpc.mark_safe("strings.choke_heuristics");
rpc::rpc.mark_safe("strings.choke_heuristics.upload");
rpc::rpc.mark_safe("strings.choke_heuristics.download");
rpc::rpc.mark_safe("strings.connection_type");
rpc::rpc.mark_safe("strings.encryption");
rpc::rpc.mark_safe("strings.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");
CMD2_ANY ("catch", tr1::bind(&cmd_catch, tr1::placeholders::_1, tr1::placeholders::_2));
}
+149 -192
View File
@@ -1,19 +1,50 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <functional>
#include <cstdio>
#include <string>
#include <vector>
#include <rak/file_stat.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/rate.h>
#include <torrent/hash_string.h>
#include <torrent/utils/log.h>
#include <torrent/utils/directory_events.h>
#include <torrent/utils/file_stat.h>
#include <torrent/utils/string_manip.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
@@ -21,58 +52,76 @@
#include "rpc/command_scheduler.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "utils/watch_ready_queue.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "thread_worker.h"
torrent::Object
apply_on_ratio(const torrent::Object& rawArgs) {
auto& group_name = rawArgs.as_string();
auto view_itr = control->view_manager()->find(rpc::commands.call("group." + group_name + ".view", rpc::make_target()).as_string());
const std::string& groupName = rawArgs.as_string();
if (view_itr == control->view_manager()->end())
char buffer[32 + groupName.size()];
sprintf(buffer, "group2.%s.view", groupName.c_str());
core::ViewManager::iterator viewItr = control->view_manager()->find(rpc::commands.call(buffer, rpc::make_target()).as_string());
if (viewItr == control->view_manager()->end())
throw torrent::input_error("Could not find view.");
char* bufferStart = buffer + sprintf(buffer, "group2.%s.ratio.", groupName.c_str());
// first argument: minimum ratio to reach
// second argument: minimum upload amount to reach [optional]
// third argument: maximum ratio to reach [optional]
int64_t min_ratio = rpc::commands.call("group." + group_name + ".ratio.min", rpc::make_target()).as_value();
int64_t max_ratio = rpc::commands.call("group." + group_name + ".ratio.max", rpc::make_target()).as_value();
int64_t min_upload = rpc::commands.call("group." + group_name + ".ratio.upload", rpc::make_target()).as_value();
std::strcpy(bufferStart, "min");
int64_t minRatio = rpc::commands.call(buffer, rpc::make_target()).as_value();
std::strcpy(bufferStart, "max");
int64_t maxRatio = rpc::commands.call(buffer, rpc::make_target()).as_value();
std::strcpy(bufferStart, "upload");
int64_t minUpload = rpc::commands.call(buffer, rpc::make_target()).as_value();
std::vector<core::Download*> downloads;
for (auto itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) {
for (core::View::iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
if (!(*itr)->is_seeding() || rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) != 0)
continue;
int64_t total_done = (*itr)->download()->bytes_done();
int64_t total_upload = (*itr)->info()->up_rate()->total();
// rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
if (!(total_upload >= min_upload && total_upload * 100 >= total_done * min_ratio) &&
!(max_ratio > 0 && total_upload * 100 > total_done * max_ratio))
int64_t totalDone = (*itr)->download()->bytes_done();
int64_t totalUpload = (*itr)->info()->up_rate()->total();
if (!(totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) &&
!(maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio))
continue;
downloads.push_back(*itr);
}
auto ratio_command = "group." + group_name + ".ratio.command";
sprintf(buffer, "group.%s.ratio.command", groupName.c_str());
for (const auto& download : downloads)
rpc::commands.call_catch(ratio_command, rpc::make_target(download), torrent::Object(), "Ratio reached, but command failed: ");
for (std::vector<core::Download*>::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) {
// rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: ");
}
return torrent::Object();
}
torrent::Object
apply_start_tied() {
for (const auto& download : *control->core()->download_list()) {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 1)
continue;
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
rak::file_stat fs;
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (!tied_to_file.empty() && fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_start=");
if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile)))
rpc::parse_command_single(rpc::make_target(*itr), "d.try_start=");
}
return torrent::Object();
@@ -80,15 +129,15 @@ apply_start_tied() {
torrent::Object
apply_stop_untied() {
for (const auto& download : *control->core()->download_list()) {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 0)
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 0)
continue;
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
rak::file_stat fs;
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_stop=");
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)))
rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop=");
}
return torrent::Object();
@@ -96,12 +145,12 @@ apply_stop_untied() {
torrent::Object
apply_close_untied() {
for (const auto& download : *control->core()->download_list()) {
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
rak::file_stat fs;
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(download)) == 0 && !tied_to_file.empty() && !fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_close=");
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)))
rpc::parse_command_single(rpc::make_target(*itr), "d.try_close=");
}
return torrent::Object();
@@ -109,11 +158,11 @@ apply_close_untied() {
torrent::Object
apply_remove_untied() {
for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) {
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) {
rak::file_stat fs;
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file))) {
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) {
// 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));
@@ -134,9 +183,9 @@ apply_schedule(const torrent::Object::list_type& args) {
torrent::Object::list_const_iterator itr = args.begin();
auto& arg1 = (itr++)->as_string();
auto& arg2 = (itr++)->as_string();
auto& arg3 = (itr++)->as_string();
const std::string& arg1 = (itr++)->as_string();
const std::string& arg2 = (itr++)->as_string();
const std::string& arg3 = (itr++)->as_string();
control->command_scheduler()->parse(arg1, arg2, arg3, *itr);
@@ -150,7 +199,7 @@ apply_load(const torrent::Object::list_type& args, int flags) {
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
const std::string& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
@@ -165,29 +214,28 @@ void apply_import(const std::string& path) { if (!rpc::parse_command_file(pa
void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); }
torrent::Object
apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
apply_close_low_diskspace(int64_t arg) {
core::DownloadList* downloadList = control->core()->download_list();
bool closed = false;
core::Manager::DListItr itr = downloadList->begin();
torrent::FileList::cache_list cache;
while ((itr = std::find_if(itr, downloadList->end(), std::mem_fun(&core::Download::is_downloading)))
!= downloadList->end()) {
if ((*itr)->file_list()->free_diskspace() < (uint64_t)arg) {
downloadList->close(*itr);
for (auto download : *control->core()->download_list()) {
if (!download->is_downloading())
continue;
if (download->priority() >= skip_priority)
continue;
if (download->file_list()->free_diskspace(cache) >= (uint64_t)arg)
continue;
(*itr)->set_hash_failed(true);
(*itr)->set_message(std::string("Low diskspace."));
control->core()->download_list()->close(download);
closed = true;
}
download->set_hash_failed(true);
download->set_message(std::string("Low diskspace."));
closed = true;
++itr;
}
if (closed)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Closed torrents due to low diskspace.");
lt_log_print(torrent::LOG_TORRENT_ERROR, "Closed torrents due to low diskspace.");
return torrent::Object();
}
@@ -197,23 +245,23 @@ apply_download_list(const torrent::Object::list_type& args) {
torrent::Object::list_const_iterator argsItr = args.begin();
core::ViewManager* viewManager = control->view_manager();
core::ViewManager::iterator view_itr;
core::ViewManager::iterator viewItr;
if (argsItr != args.end() && !argsItr->as_string().empty())
view_itr = viewManager->find((argsItr++)->as_string());
viewItr = viewManager->find((argsItr++)->as_string());
else
view_itr = viewManager->find("default");
viewItr = viewManager->find("default");
if (view_itr == viewManager->end())
if (viewItr == viewManager->end())
throw torrent::input_error("Could not find view.");
torrent::Object result = torrent::Object::create_list();
torrent::Object::list_type& resultList = result.as_list();
for (core::View::const_iterator itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) {
for (core::View::const_iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
const torrent::HashString* hashString = &(*itr)->info()->hash();
resultList.push_back(torrent::utils::transform_to_hex_str(*hashString));
resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end()));
}
return result;
@@ -225,156 +273,65 @@ d_multicall(const torrent::Object::list_type& args) {
throw torrent::input_error("Too few arguments.");
core::ViewManager* viewManager = control->view_manager();
core::ViewManager::iterator view_itr;
core::ViewManager::iterator viewItr;
if (!args.front().as_string().empty())
view_itr = viewManager->find(args.front().as_string());
viewItr = viewManager->find(args.front().as_string());
else
view_itr = viewManager->find("default");
viewItr = viewManager->find("default");
if (view_itr == viewManager->end())
if (viewItr == viewManager->end())
throw torrent::input_error("Could not find view.");
// Add some pre-parsing of the commands, so we don't spend time
// parsing and searching command map for every single call.
std::vector<core::Download*> dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
unsigned int dlist_size = (*viewItr)->size_visible();
core::Download* dlist[dlist_size];
std::copy((*viewItr)->begin_visible(), (*viewItr)->end_visible(), dlist);
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
for (auto download : dlist) {
for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) {
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
auto& cmd = cItr->as_string();
row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first);
const std::string& cmd = cItr->as_string();
row.push_back(rpc::parse_command(rpc::make_target(*vItr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
}
}
return resultRaw;
}
torrent::Object
d_multicall_filtered(const torrent::Object::list_type& args) {
if (args.size() < 2)
throw torrent::input_error("d.multicall.filtered requires at least 2 arguments.");
auto arg = args.begin();
// Find the given view
auto* viewManager = control->view_manager();
auto view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
if (view_itr == viewManager->end())
throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
// Make a filtered copy of the current item list
core::View::base_type dlist;
(*view_itr)->filter_by(*++arg, dlist);
// Generate result by iterating over all items
auto resultRaw = torrent::Object::create_list();
auto& result = resultRaw.as_list();
++arg; // skip to first command
for (const auto& item : dlist) {
// Add empty row to result
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
// Call the provided commands and assemble their results
for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) {
auto& cmdstr = command->as_string();
row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
}
}
return resultRaw;
}
static void
call_watch_command(const std::string& command, const std::string& path) {
rpc::commands.call_catch(command.c_str(), rpc::make_target(), path);
}
torrent::Object
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(std::strerror(errno)));
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", [](auto, auto& args) { return apply_on_ratio(args); });
CMD2_ANY_STRING ("on_ratio", tr1::bind(&apply_on_ratio, tr1::placeholders::_2));
CMD2_ANY ("start_tied", [](auto, auto) { return apply_start_tied(); });
CMD2_ANY ("stop_untied", [](auto, auto) { return apply_stop_untied(); });
CMD2_ANY ("close_untied", [](auto, auto) { return apply_close_untied(); });
CMD2_ANY ("remove_untied", [](auto, auto) { return apply_remove_untied(); });
CMD2_ANY ("start_tied", tr1::bind(&apply_start_tied));
CMD2_ANY ("stop_untied", tr1::bind(&apply_stop_untied));
CMD2_ANY ("close_untied", tr1::bind(&apply_close_untied));
CMD2_ANY ("remove_untied", tr1::bind(&apply_remove_untied));
CMD2_ANY_LIST ("schedule", [](auto, auto& args) { return apply_schedule(args); });
CMD2_ANY_STRING_V("schedule.remove", [](auto, auto& str) { return control->command_scheduler()->erase_str(str); });
CMD2_ANY_LIST ("schedule2", tr1::bind(&apply_schedule, tr1::placeholders::_2));
CMD2_ANY_STRING_V("schedule_remove2", tr1::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), tr1::placeholders::_2));
CMD2_ANY_STRING_V("import", [](auto, auto& str) { return apply_import(str); });
CMD2_ANY_STRING_V("try_import", [](auto, auto& str) { return apply_try_import(str); });
CMD2_ANY_STRING_V("import", tr1::bind(&apply_import, tr1::placeholders::_2));
CMD2_ANY_STRING_V("try_import", tr1::bind(&apply_try_import, tr1::placeholders::_2));
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied); });
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied); });
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.normal", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied));
CMD2_ANY_LIST ("load.verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_tied));
CMD2_ANY_LIST ("load.start", tr1::bind(&apply_load, tr1::placeholders::_2,
core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start));
CMD2_ANY_LIST ("load.start_verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_tied | core::Manager::create_start));
CMD2_ANY_LIST ("load.raw", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data));
CMD2_ANY_LIST ("load.raw_verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_raw_data));
CMD2_ANY_LIST ("load.raw_start", tr1::bind(&apply_load, tr1::placeholders::_2,
core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data));
CMD2_ANY_VALUE ("close_low_diskspace", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 99); });
CMD2_ANY_VALUE ("close_low_diskspace.normal", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 3); });
CMD2_ANY_VALUE ("close_low_diskspace", tr1::bind(&apply_close_low_diskspace, tr1::placeholders::_2));
CMD2_ANY_LIST ("download_list", [](auto, auto& args) { return apply_download_list(args); });
// TODO: Deprecate d.multicall2. (6/2026)
CMD2_ANY_LIST ("d.multicall", [](auto, auto& args) { return d_multicall(args); });
CMD2_ANY_LIST ("d.multicall.filtered", [](auto, auto& args) { return d_multicall_filtered(args); });
CMD2_ANY_LIST ("directory.watch.added", [](auto, auto& args) { return directory_watch_added(args); });
CMD2_ANY_LIST ("directory.watch.ready", [](auto, auto& args) { return directory_watch_ready(args); });
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.multicall");
rpc::rpc.mark_safe("d.multicall.filtered");
CMD2_ANY_LIST ("download_list", tr1::bind(&apply_download_list, tr1::placeholders::_2));
CMD2_ANY_LIST ("d.multicall2", tr1::bind(&d_multicall, tr1::placeholders::_2));
}
+81 -98
View File
@@ -1,5 +1,43 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#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>
@@ -15,7 +53,7 @@ apply_f_set_priority(torrent::File* file, uint32_t value) {
if (value > torrent::PRIORITY_HIGH)
throw torrent::input_error("Invalid value.");
file->set_priority(static_cast<torrent::priority_enum>(value));
file->set_priority((torrent::priority_t)value);
}
// TODO: Redundant.
@@ -24,34 +62,24 @@ apply_f_path(torrent::File* file) {
if (file->path()->empty())
return std::string();
torrent::Object result_raw(file->path()->begin()->str());
auto& result = result_raw.as_string();
torrent::Object resultRaw(*file->path()->begin());
torrent::Object::string_type& result = resultRaw.as_string();
for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++)
result += '/' + itr->str();
result += '/' + *itr;
return result_raw;
return resultRaw;
}
torrent::Object
apply_f_path_components(torrent::File* file, int output_type) {
auto result_raw = torrent::Object::create_list();
auto& result = result_raw.as_list();
apply_f_path_components(torrent::File* file) {
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
for (const auto& itr : *file->path()) {
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");
};
}
for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++)
result.push_back(*itr);
return result_raw;
return resultRaw;
}
torrent::Object
@@ -67,95 +95,50 @@ apply_fi_filename_last(torrent::FileListIterator* itr) {
if (itr->depth() >= itr->file()->path()->size())
return "ERROR";
return itr->file()->path()->at(itr->depth()).str();
return itr->file()->path()->at(itr->depth());
}
void
initialize_command_file() {
CMD2_FILE("f.is_created", std::bind(&torrent::File::is_created, std::placeholders::_1));
CMD2_FILE("f.is_open", std::bind(&torrent::File::is_open, std::placeholders::_1));
CMD2_FILE("f.is_created", tr1::bind(&torrent::File::is_created, tr1::placeholders::_1));
CMD2_FILE("f.is_open", tr1::bind(&torrent::File::is_open, tr1::placeholders::_1));
CMD2_FILE("f.is_create_queued", std::bind(&torrent::File::is_create_queued, std::placeholders::_1));
CMD2_FILE("f.is_resize_queued", std::bind(&torrent::File::is_resize_queued, std::placeholders::_1));
CMD2_FILE("f.is_create_queued", tr1::bind(&torrent::File::is_create_queued, tr1::placeholders::_1));
CMD2_FILE("f.is_resize_queued", tr1::bind(&torrent::File::is_resize_queued, tr1::placeholders::_1));
CMD2_FILE_VALUE_V("f.set_create_queued", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_create_queued));
CMD2_FILE_VALUE_V("f.set_resize_queued", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_resize_queued));
CMD2_FILE_VALUE_V("f.unset_create_queued", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_create_queued));
CMD2_FILE_VALUE_V("f.unset_resize_queued", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_resize_queued));
CMD2_FILE_VALUE_V("f.set_create_queued", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_create_queued));
CMD2_FILE_VALUE_V("f.set_resize_queued", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_resize_queued));
CMD2_FILE_VALUE_V("f.unset_create_queued", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_create_queued));
CMD2_FILE_VALUE_V("f.unset_resize_queued", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_resize_queued));
CMD2_FILE ("f.prioritize_first", std::bind(&torrent::File::has_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE_V("f.prioritize_first.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE_V("f.prioritize_first.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE ("f.prioritize_last", std::bind(&torrent::File::has_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
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.prioritize_first", tr1::bind(&torrent::File::has_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE_V("f.prioritize_first.enable", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE_V("f.prioritize_first.disable", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first));
CMD2_FILE ("f.prioritize_last", tr1::bind(&torrent::File::has_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last));
CMD2_FILE_V("f.prioritize_last.enable", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last));
CMD2_FILE_V("f.prioritize_last.disable", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last));
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.size_bytes", tr1::bind(&torrent::File::size_bytes, tr1::placeholders::_1));
CMD2_FILE("f.size_chunks", tr1::bind(&torrent::File::size_chunks, tr1::placeholders::_1));
CMD2_FILE("f.completed_chunks", tr1::bind(&torrent::File::completed_chunks, tr1::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.offset", tr1::bind(&torrent::File::offset, tr1::placeholders::_1));
CMD2_FILE("f.range_first", tr1::bind(&torrent::File::range_first, tr1::placeholders::_1));
CMD2_FILE("f.range_second", tr1::bind(&torrent::File::range_second, tr1::placeholders::_1));
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.priority", tr1::bind(&torrent::File::priority, tr1::placeholders::_1));
CMD2_FILE_VALUE_V("f.priority.set", tr1::bind(&apply_f_set_priority, tr1::placeholders::_1, tr1::placeholders::_2));
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.path", tr1::bind(&apply_f_path, tr1::placeholders::_1));
CMD2_FILE("f.path_components", tr1::bind(&apply_f_path_components, tr1::placeholders::_1));
CMD2_FILE("f.path_depth", tr1::bind(&apply_f_path_depth, tr1::placeholders::_1));
CMD2_FILE("f.frozen_path", tr1::bind(&torrent::File::frozen_path, tr1::placeholders::_1));
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));
CMD2_FILE("f.match_depth_prev", tr1::bind(&torrent::File::match_depth_prev, tr1::placeholders::_1));
CMD2_FILE("f.match_depth_next", tr1::bind(&torrent::File::match_depth_next, tr1::placeholders::_1));
CMD2_FILE("f.last_touched", std::bind(&torrent::File::last_touched, std::placeholders::_1));
CMD2_FILE("f.last_touched", tr1::bind(&torrent::File::last_touched, tr1::placeholders::_1));
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");
CMD2_FILEITR("fi.filename_last", tr1::bind(&apply_fi_filename_last, tr1::placeholders::_1));
CMD2_FILEITR("fi.is_file", tr1::bind(&torrent::FileListIterator::is_file, tr1::placeholders::_1));
}
+87 -103
View File
@@ -1,9 +1,44 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <torrent/download/resource_manager.h>
#include <torrent/download/choke_group.h>
#include <torrent/download/choke_queue.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "ui/root.h"
@@ -17,9 +52,6 @@
// For cg_d_group.
#include "core/download.h"
#define LT_LOG_SUBSYSTEM(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_TORRENT_INFO, "choke_queue", log_fmt, __VA_ARGS__);
// A hack to allow testing of the new choke_group API without the
// working parts present.
#define USE_CHOKE_GROUP 0
@@ -69,7 +101,7 @@ cg_d_group_set(core::Download* download, const torrent::Object& arg) {
torrent::Object
apply_cg_list() {
torrent::Object::list_type result;
for (torrent::ResourceManager::group_iterator
itr = torrent::resource_manager()->group_begin(),
last = torrent::resource_manager()->group_end(); itr != last; itr++)
@@ -90,22 +122,6 @@ apply_cg_insert(const std::string& arg) {
return torrent::Object();
}
torrent::Object
apply_cg_all_update_balance(bool is_up) {
LT_LOG_SUBSYSTEM("apply update balance: resource_manager is_up:%i", (int)is_up);
for (torrent::ResourceManager::group_iterator
itr = torrent::resource_manager()->group_begin(),
last = torrent::resource_manager()->group_end(); itr != last; itr++) {
if (is_up)
itr->up_queue()->balance();
else
itr->down_queue()->balance();
}
return torrent::Object();
}
//
// The hacked version:
//
@@ -121,7 +137,8 @@ cg_get_index(const torrent::Object& raw_args) {
if (arg.is_string()) {
if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) {
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg.as_string() == cg->name(); });
std::vector<torrent::choke_group*>::iterator itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(),
rak::equal(arg.as_string(), std::mem_fun(&torrent::choke_group::name)));
if (itr == cg_list_hack.end())
throw torrent::input_error("Choke group not found.");
@@ -153,26 +170,18 @@ cg_get_group(const torrent::Object& raw_args) {
}
int64_t cg_d_group(core::Download* download) { return download->group(); }
const std::string& cg_d_group_name(core::Download* download) {
return cg_list_hack.at(download->group())->name();
}
void cg_d_group_set(core::Download* download, const torrent::Object& arg) { download->set_group(cg_get_index(arg)); }
torrent::Object
apply_cg_list() {
torrent::Object::list_type result;
for (auto itr : cg_list_hack)
result.push_back(itr->name());
for (std::vector<torrent::choke_group*>::iterator itr = cg_list_hack.begin(), last = cg_list_hack.end(); itr != last; itr++)
result.push_back((*itr)->name());
return torrent::Object::from_list(result);
}
int
cg_get_can_unchoke(torrent::choke_queue* cq) {
return cq->max_unchoked_signed() - (int)cq->size_unchoked();
}
torrent::Object
apply_cg_insert(const std::string& arg) {
int64_t dummy;
@@ -180,21 +189,24 @@ apply_cg_insert(const std::string& arg) {
if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))
throw torrent::input_error("Cannot use a value string as choke group name.");
if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](auto cg) { return arg == cg->name(); }))
if (arg.empty() ||
std::find_if(cg_list_hack.begin(), cg_list_hack.end(),
rak::equal(arg, std::mem_fun(&torrent::choke_group::name))) != cg_list_hack.end())
throw torrent::input_error("Duplicate name for choke group.");
cg_list_hack.push_back(new torrent::choke_group());
cg_list_hack.back()->set_name(arg);
cg_list_hack.back()->up_queue()->set_heuristics(torrent::HEURISTICS_UPLOAD_LEECH);
cg_list_hack.back()->down_queue()->set_heuristics(torrent::HEURISTICS_DOWNLOAD_LEECH);
cg_list_hack.back()->up_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_UPLOAD_LEECH);
cg_list_hack.back()->down_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_DOWNLOAD_LEECH);
return torrent::Object();
}
torrent::Object
apply_cg_index_of(const std::string& arg) {
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg == cg->name(); });
std::vector<torrent::choke_group*>::iterator itr =
std::find_if(cg_list_hack.begin(), cg_list_hack.end(), rak::equal(arg, std::mem_fun(&torrent::choke_group::name)));
if (itr == cg_list_hack.end())
throw torrent::input_error("Choke group not found.");
@@ -202,20 +214,6 @@ apply_cg_index_of(const std::string& arg) {
return std::distance(cg_list_hack.begin(), itr);
}
torrent::Object
apply_cg_all_update_balance(bool is_up) {
LT_LOG_SUBSYSTEM("apply update balance: hack is_up:%i", (int)is_up);
for (auto itr : cg_list_hack) {
if (is_up)
itr->up_queue()->balance();
else
itr->down_queue()->balance();
}
return torrent::Object();
}
//
// End of choke group hack.
//
@@ -266,8 +264,8 @@ apply_cg_tracker_mode_set(const torrent::Object::list_type& args) {
return torrent::Object();
}
#define CG_GROUP_AT() std::bind(&cg_get_group, std::placeholders::_2)
#define CHOKE_GROUP(direction) std::bind(direction, CG_GROUP_AT())
#define CG_GROUP_AT() tr1::bind(&cg_get_group, tr1::placeholders::_2)
#define CHOKE_GROUP(direction) tr1::bind(direction, CG_GROUP_AT())
/*
@@ -337,69 +335,55 @@ options.
void
initialize_command_groups() {
CMD_ANY ("choke_group.list", std::bind(&apply_cg_list));
CMD_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
// Move somewhere else?
CMD2_ANY ("strings.choke_heuristics", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS));
CMD2_ANY ("strings.choke_heuristics.upload", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_UPLOAD));
CMD2_ANY ("strings.choke_heuristics.download", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD));
CMD2_ANY ("strings.tracker_mode", tr1::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
CMD2_ANY ("choke_group.list", tr1::bind(&apply_cg_list));
CMD2_ANY_STRING ("choke_group.insert", tr1::bind(&apply_cg_insert, tr1::placeholders::_2));
#if USE_CHOKE_GROUP
CMD_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
CMD_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
CMD2_ANY ("choke_group.size", tr1::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
CMD2_ANY_STRING ("choke_group.index_of", tr1::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), tr1::placeholders::_2));
#else
apply_cg_insert("default");
CMD_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
CMD_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
CMD2_ANY ("choke_group.size", tr1::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
CMD2_ANY_STRING ("choke_group.index_of", tr1::bind(&apply_cg_index_of, tr1::placeholders::_2));
#endif
// Commands specific for a group. Supports as the first argument the
// name, the index or a negative index.
CMD_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
CMD2_ANY ("choke_group.general.size", tr1::bind(&torrent::choke_group::size, CG_GROUP_AT()));
CMD_ANY ("choke_group.tracker.mode", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_TRACKER_MODE, cg_get_group(arg)->tracker_mode()); });
CMD_ANY_LIST ("choke_group.tracker.mode.set", [](auto, auto arg) { return apply_cg_tracker_mode_set(arg); });
CMD2_ANY ("choke_group.tracker.mode", tr1::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE,
tr1::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT())));
CMD2_ANY_LIST ("choke_group.tracker.mode.set", tr1::bind(&apply_cg_tracker_mode_set, tr1::placeholders::_2));
CMD_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
CMD_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
CMD2_ANY ("choke_group.up.rate", tr1::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
CMD2_ANY ("choke_group.down.rate", tr1::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
CMD_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
CMD_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
CMD2_ANY ("choke_group.up.max.unlimited", tr1::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD2_ANY ("choke_group.up.max", tr1::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD2_ANY_LIST ("choke_group.up.max.set", tr1::bind(&apply_cg_max_set, tr1::placeholders::_2, true));
CMD_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
CMD2_ANY ("choke_group.up.total", tr1::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD2_ANY ("choke_group.up.queued", tr1::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD2_ANY ("choke_group.up.unchoked", tr1::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD2_ANY ("choke_group.up.heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
tr1::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue))));
CMD2_ANY_LIST ("choke_group.up.heuristics.set", tr1::bind(&apply_cg_heuristics_set, tr1::placeholders::_2, true));
CMD_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
CMD_ANY ("choke_group.up.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->up_queue()->heuristics()); });
CMD_ANY_LIST ("choke_group.up.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, true); });
CMD2_ANY ("choke_group.down.max.unlimited", tr1::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD2_ANY ("choke_group.down.max", tr1::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD2_ANY_LIST ("choke_group.down.max.set", tr1::bind(&apply_cg_max_set, tr1::placeholders::_2, false));
CMD_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
CMD_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD_ANY ("choke_group.down.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->down_queue()->heuristics()); });
CMD_ANY_LIST ("choke_group.down.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, false); });
rpc::rpc.mark_safe("choke_group.list");
rpc::rpc.mark_safe("choke_group.size");
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");
CMD2_ANY ("choke_group.down.total", tr1::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD2_ANY ("choke_group.down.queued", tr1::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD2_ANY ("choke_group.down.unchoked", tr1::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
CMD2_ANY ("choke_group.down.heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
tr1::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
CMD2_ANY_LIST ("choke_group.down.heuristics.set", tr1::bind(&apply_cg_heuristics_set, tr1::placeholders::_2, false));
}
+36
View File
@@ -1,3 +1,39 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <torrent/exceptions.h>
+95 -52
View File
@@ -1,3 +1,39 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_UTILS_COMMAND_HELPERS_H
#define RTORRENT_UTILS_COMMAND_HELPERS_H
@@ -5,34 +41,17 @@
#include "rpc/parse_commands.h"
#include "rpc/object_storage.h"
namespace tr1 { using namespace std::tr1; }
void initialize_commands();
//
// Aliases with CMD_* for the below
//
#define CMD_ANY(key, slot) CMD2_ANY(key, slot)
#define CMD_ANY_P(key, slot) CMD2_ANY_P(key, slot)
#define CMD_REDIRECT(key, slot) CMD2_REDIRECT(key, slot)
#define CMD_REDIRECT_NO_EXPORT(key, slot) CMD2_REDIRECT_NO_EXPORT(key, slot)
#define CMD_ANY_STRING(key, slot) CMD2_ANY_STRING(key, slot)
#define CMD_ANY_STRING_V(key, slot) CMD2_ANY_STRING_V(key, slot)
#define CMD_ANY_LIST(key, slot) CMD2_ANY_LIST(key, slot)
#define CMD_VAR_VALUE(key, value) CMD2_VAR_VALUE(key, value)
#define CMD_VAR_BOOL(key, value) CMD2_VAR_BOOL(key, value)
#define CMD_VAR_STRING(key, value) CMD2_VAR_STRING(key, value)
#define CMD_VAR_C_STRING(key, value) CMD2_VAR_C_STRING(key, value)
#define CMD_VAR_LIST(key) CMD2_VAR_LIST(key)
#define CMD_ANY_V(key, slot) CMD2_ANY_V(key, slot)
#define CMD_ANY_VALUE_V(key, slot) CMD2_ANY_VALUE_V(key, slot)
//
// New std::function based command_base helper functions:
//
#define CMD2_A_FUNCTION(key, function, slot, parm, doc) \
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_rpc, NULL, NULL);
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL);
#define CMD2_A_FUNCTION_PRIVATE(key, function, slot, parm, doc) \
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
@@ -75,64 +94,68 @@ void initialize_commands();
#define CMD2_PEER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Peer*>, object_convert_void(slot), "i:", "")
#define CMD2_PEER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::Peer*>, object_convert_void(slot), "i:i", "")
#define CMD2_TRACKER(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::tracker::Tracker*>, slot, "i:", "")
#define CMD2_TRACKER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::tracker::Tracker*>, object_convert_void(slot), "i:", "")
#define CMD2_TRACKER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::tracker::Tracker*>, object_convert_void(slot), "i:i", "")
#define CMD2_TRACKER(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Tracker*>, slot, "i:", "")
#define CMD2_TRACKER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Tracker*>, object_convert_void(slot), "i:", "")
#define CMD2_TRACKER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::Tracker*>, object_convert_void(slot), "i:i", "")
#define CMD2_VAR_BOOL(key, value) \
control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_bool_type); \
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \
torrent::raw_string::from_c_str(key))); \
CMD2_ANY_VALUE(key ".set", std::bind(&rpc::object_storage::set_bool, control->object_storage(), \
torrent::raw_string::from_c_str(key), std::placeholders::_2));
CMD2_ANY_VALUE(key ".set", tr1::bind(&rpc::object_storage::set_bool, control->object_storage(), \
torrent::raw_string::from_c_str(key), tr1::placeholders::_2));
#define CMD2_VAR_VALUE(key, value) \
control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_value_type); \
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \
torrent::raw_string::from_c_str(key))); \
CMD2_ANY_VALUE(key ".set", std::bind(&rpc::object_storage::set_value, control->object_storage(), \
torrent::raw_string::from_c_str(key), std::placeholders::_2));
CMD2_ANY_VALUE(key ".set", tr1::bind(&rpc::object_storage::set_value, control->object_storage(), \
torrent::raw_string::from_c_str(key), tr1::placeholders::_2));
#define CMD2_VAR_STRING(key, value) \
control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \
torrent::raw_string::from_c_str(key))); \
CMD2_ANY_STRING(key ".set", std::bind(&rpc::object_storage::set_string, control->object_storage(), \
torrent::raw_string::from_c_str(key), std::placeholders::_2));
CMD2_ANY_STRING(key ".set", tr1::bind(&rpc::object_storage::set_string, control->object_storage(), \
torrent::raw_string::from_c_str(key), tr1::placeholders::_2));
#define CMD2_VAR_C_STRING(key, value) \
control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \
torrent::raw_string::from_c_str(key)));
#define CMD2_VAR_LIST(key) \
control->object_storage()->insert_c_str(key, torrent::Object::create_list(), rpc::object_storage::flag_list_type); \
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \
torrent::raw_string::from_c_str(key))); \
CMD2_ANY_LIST(key ".set", std::bind(&rpc::object_storage::set_list, control->object_storage(), \
torrent::raw_string::from_c_str(key), std::placeholders::_2)); \
CMD2_ANY_VOID(key ".push_back", std::bind(&rpc::object_storage::list_push_back, control->object_storage(), \
torrent::raw_string::from_c_str(key), std::placeholders::_2));
CMD2_ANY_LIST(key ".set", tr1::bind(&rpc::object_storage::set_list, control->object_storage(), \
torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); \
CMD2_ANY_VOID(key ".push_back", tr1::bind(&rpc::object_storage::list_push_back, control->object_storage(), \
torrent::raw_string::from_c_str(key), tr1::placeholders::_2));
#define CMD2_FUNC_SINGLE(key, cmds) \
CMD2_ANY(key, std::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \
std::placeholders::_1, std::placeholders::_2));
CMD2_ANY(key, tr1::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \
tr1::placeholders::_1, tr1::placeholders::_2));
#define CMD2_REDIRECT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_MUTABLE(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc);
#define CMD2_REDIRECT_STR(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc);
#define CMD2_REDIRECT_STR_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, 0);
#define CMD2_REDIRECT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_GENERIC(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_GENERIC_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_FILE(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_TRACKER(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_GENERIC_STR(from_key, to_key) \
rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key);
#define CMD2_REDIRECT_GENERIC_STR_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \
rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key);
//
// Conversion of return types:
@@ -167,4 +190,24 @@ template <typename T>
object_convert_type<T, void>
object_convert_void(T f) { return f; }
//
// Key creation:
//
template <int postfix_size>
inline const char*
create_new_key(const std::string& key, const char postfix[postfix_size]) {
char *buffer = new char[key.size() + std::max(postfix_size, 1)];
std::memcpy(buffer, key.c_str(), key.size() + 1);
std::memcpy(buffer + key.size(), postfix, postfix_size);
return buffer;
}
inline const char*
create_new_key(const std::string& key) {
char *buffer = new char[key.size() + 1];
std::memcpy(buffer, key.c_str(), key.size() + 1);
return buffer;
}
#endif
+144 -225
View File
@@ -1,12 +1,43 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <rak/path.h>
#include <torrent/peer/peer_list.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
@@ -14,7 +45,42 @@
#include "globals.h"
#include "command_helpers.h"
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
void
ipv4_filter_parse(const char* address, int value) {
uint32_t ip_values[4] = { 0, 0, 0, 0 };
unsigned int block = rpc::ipv4_table::mask_bits;
char ip_dot;
int values_read;
if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u",
ip_values + 0, &ip_dot,
ip_values + 1, &ip_dot,
ip_values + 2, &ip_dot,
ip_values + 3,
&block)) < 2 ||
// Make sure the dot is included.
(values_read < 7 && values_read % 2) ||
ip_values[0] >= 256 ||
ip_values[1] >= 256 ||
ip_values[2] >= 256 ||
ip_values[3] >= 256 ||
block > rpc::ipv4_table::mask_bits)
throw torrent::input_error("Invalid address format.");
// E.g. '10.10.' will be '10.10.0.0/16'.
if (values_read < 7)
block = 8 * (values_read / 2);
lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %u.%u.%u.%u/%u.",
ip_values[0], ip_values[1], ip_values[2], ip_values[3], block);
torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
rpc::ipv4_table::mask_bits - block, value);
}
torrent::Object
apply_ip_tables_insert_table(const std::string& args) {
@@ -29,11 +95,10 @@ 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();
return size;
return itr->table.sizeof_data();
}
torrent::Object
@@ -45,21 +110,20 @@ apply_ip_tables_get(const torrent::Object::list_type& args) {
const std::string& name = (args_itr++)->as_string();
const std::string& address = (args_itr++)->as_string();
uint32_t address_start;
uint32_t address_end;
// Move to a helper function, add support for addresses.
uint32_t ip_values[4];
if (sscanf(address.c_str(), "%u.%u.%u.%u",
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
throw torrent::input_error("Invalid address format.");
rpc::ip_table_list::iterator table_itr = ip_tables.find(name);
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))
throw torrent::input_error("Invalid address format.");
if(!table_itr->table.defined(address_start, address_end))
throw torrent::input_error("No value defined for specified IP(s).");
return table_itr->table.at(address_start, address_end);
return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
}
torrent::Object
@@ -72,6 +136,15 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
const std::string& name = (args_itr++)->as_string();
const std::string& address = (args_itr++)->as_string();
const std::string& value_str = (args_itr++)->as_string();
// Move to a helper function, add support for addresses.
uint32_t ip_values[4];
unsigned int block = rpc::ipv4_table::mask_bits;
if (sscanf(address.c_str(), "%u.%u.%u.%u/%u",
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 ||
block > rpc::ipv4_table::mask_bits)
throw torrent::input_error("Invalid address format.");
int value;
@@ -85,13 +158,8 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
if (table_itr == ip_tables.end())
throw torrent::input_error("Could not find ip table.");
uint32_t address_start;
uint32_t address_end;
if (ipv4_range_parse(address.c_str(), &address_start, &address_end))
table_itr->table.insert(address_start, address_end, value);
else
throw torrent::input_error("Invalid address format.");
table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
rpc::ipv4_table::mask_bits - block, value);
return torrent::Object();
}
@@ -100,163 +168,6 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
// IPv4 filter functions:
//
///////////////////////////////////////////////////////////
// IPV4_RANGE_PARSE parses string into an ip range
//
// should be compatible with lines in p2p files
// everything in address before colon is ignored
//
// ip range can be single ip in which case start=end
// ip range can be cidr notation a.b.c.d/e
// ip range can be explicit range like in p2p line a.b.c.d-w.x.y.z
//
// returns false if line does not contain valid ip or ip range
// address_start and address_end will contain start and end ip
//
// addresses parsed are returned in host byte order
// to get network byte order call htonl(address)
///////////////////////////////////////////////////////////
bool
ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end) {
// same length as buffer used to do reads so no worries about overflow
char address_copy[4096];
bool valid = false;
char address_start_str[20];
int address_start_index=0;
struct sockaddr_in sa_start;
*address_start=0;
*address_end=0;
// get rid of everything after '#' comments
// copy everything up to '#' to address_copy and work from there
while(address[address_start_index] != '#' && address[address_start_index] != '\r' &&
address[address_start_index] != '\n' && address[address_start_index] != '\0' &&
address_start_index < 4096 ) {
address_copy[address_start_index] = address[address_start_index];
address_start_index++;
}
address_copy[address_start_index] = '\0';
address_start_index=0;
// skip everything up to and including last ':' character and whitespace
const char* addr = strrchr(address_copy, ':');
addr = (addr == NULL) ? address_copy : addr + 1;
while(addr[0] == ' ' || addr[0] == '\t')
addr++;
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_start_index < 19) {
address_start_str[address_start_index] = addr[0];
address_start_index++;
addr++;
}
address_start_str[address_start_index] = '\0';
if(strchr(addr, '-') != NULL) {
// explicit range
char address_end_str[20];
int address_end_index=0;
struct sockaddr_in sa_end;
while(addr[0] == '-' || addr[0] == ' ' || addr[0] == '\t')
addr++;
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_end_index < 19) {
address_end_str[address_end_index] = addr[0];
address_end_index++;
addr++;
}
address_end_str[address_end_index] = '\0';
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && inet_pton(AF_INET, address_end_str, &(sa_end.sin_addr)) != 0) {
*address_start = ntohl(sa_start.sin_addr.s_addr);
*address_end = ntohl(sa_end.sin_addr.s_addr);
if(*address_start <= *address_end)
valid=true;
}
} else if(strchr(addr, '/') != NULL) {
// cidr range
char mask_bits_str[20];
int mask_bits_index=0;
uint32_t mask_bits;
while(addr[0] == '/' || addr[0] == ' ' || addr[0] == '\t')
addr++;
while( (addr[0] >= '0' && addr[0] <= '9') && mask_bits_index < 19) {
mask_bits_str[mask_bits_index] = addr[0];
mask_bits_index++;
addr++;
}
mask_bits_str[mask_bits_index] = '\0';
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && sscanf(mask_bits_str, "%u", &mask_bits) != 0) {
if(mask_bits <=32) {
uint32_t ip=ntohl(sa_start.sin_addr.s_addr);
uint32_t mask=0;
uint32_t end_mask=0;
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;
*address_end = (ip & mask) | end_mask;
valid=true;
}
}
} else {
// single ip
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0) {
*address_start = ntohl(sa_start.sin_addr.s_addr);
*address_end = *address_start;
valid=true;
}
}
return valid;
}
///////////////////////////////////////////////////////////
// IPV4_FILTER_PARSE
//
// should now be compatible with lines in p2p files
//
// addresses in table MUST be in host byte order
// ntohl is called after parsing ip address(es)
///////////////////////////////////////////////////////////
void
ipv4_filter_parse(const char* address, int value) {
uint32_t address_start;
uint32_t address_end;
if (ipv4_range_parse(address, &address_start, &address_end) ) {
torrent::PeerList::ipv4_filter()->insert(address_start, address_end, value);
char start_str[INET_ADDRSTRLEN];
char end_str[INET_ADDRSTRLEN];
uint32_t net_start = htonl(address_start);
uint32_t net_end = htonl(address_end);
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
lt_log_print(torrent::LOG_CONNECTION_FILTER, "Adding ip filter for %s-%s.", start_str, end_str);
}
}
torrent::Object
apply_ipv4_filter_size_data() {
return torrent::PeerList::ipv4_filter()->sizeof_data();
@@ -264,16 +175,14 @@ apply_ipv4_filter_size_data() {
torrent::Object
apply_ipv4_filter_get(const std::string& args) {
uint32_t address_start;
uint32_t address_end;
// Move to a helper function, add support for addresses.
uint32_t ip_values[4];
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
if (sscanf(args.c_str(), "%u.%u.%u.%u",
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
throw torrent::input_error("Invalid address format.");
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
throw torrent::input_error("No value defined for specified IP(s).");
return torrent::PeerList::ipv4_filter()->at(address_start, address_end);
return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
}
torrent::Object
@@ -295,8 +204,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(expand_path(filename).c_str(), std::ios::in);
std::fstream file(rak::path_expand(filename).c_str(), std::ios::in);
if (!file.is_open())
throw torrent::input_error("Could not open ip filter file: " + filename);
@@ -322,7 +231,7 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
throw torrent::input_error(buffer);
}
lt_log_print(torrent::LOG_CONNECTION_FILTER, "loaded %u %s address blocks (%u kb in-memory) from '%s'",
lt_log_print(torrent::LOG_CONNECTION_INFO, "Loaded %u %s address blocks (%u kb in-memory) from '%s'.",
lineNumber,
value_name.c_str(),
torrent::PeerList::ipv4_filter()->sizeof_data() / 1024,
@@ -331,48 +240,58 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
return torrent::Object();
}
static void
append_table(torrent::ipv4_table::base_type* extent, torrent::Object::list_type& result) {
torrent::ipv4_table::table_type::iterator first = extent->table.begin();
torrent::ipv4_table::table_type::iterator last = extent->table.end();
while (first != last) {
if (first->first != NULL) {
// Do something more here?...
append_table(first->first, result);
} else if (first->second != 0) {
uint32_t position = extent->partition_pos(first);
char buffer[256];
snprintf(buffer, 256, "%u.%u.%u.%u/%u %s",
(position >> 24) & 0xff,
(position >> 16) & 0xff,
(position >> 8) & 0xff,
(position >> 0) & 0xff,
extent->mask_bits,
torrent::option_as_string(torrent::OPTION_IP_FILTER, first->second));
result.push_back((std::string)buffer);
}
first++;
}
}
torrent::Object
apply_ipv4_filter_dump() {
torrent::Object raw_result = torrent::Object::create_list();
torrent::Object::list_type& result = raw_result.as_list();
torrent::ipv4_table::range_map_type range_map = torrent::PeerList::ipv4_filter()->range_map;
torrent::ipv4_table::range_map_type::iterator iter = range_map.begin();
while(iter != range_map.end()) {
char buffer[64];
uint32_t address_start = iter->first;
uint32_t address_end = (iter->second).first;
int value = (iter->second).second;
char start_str[INET_ADDRSTRLEN];
char end_str[INET_ADDRSTRLEN];
uint32_t net_start = htonl(address_start);
uint32_t net_end = htonl(address_end);
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_to_c_str_or_throw(torrent::OPTION_IP_FILTER, value));
result.push_back((std::string)buffer);
iter++;
}
append_table(torrent::PeerList::ipv4_filter()->data(), result);
return raw_result;
}
void
initialize_command_ip() {
CMD2_ANY_STRING ("ip_tables.insert_table", std::bind(&apply_ip_tables_insert_table, std::placeholders::_2));
CMD2_ANY_STRING ("ip_tables.size_data", std::bind(&apply_ip_tables_size_data, std::placeholders::_2));
CMD2_ANY_LIST ("ip_tables.get", std::bind(&apply_ip_tables_get, std::placeholders::_2));
CMD2_ANY_LIST ("ip_tables.add_address", std::bind(&apply_ip_tables_add_address, std::placeholders::_2));
CMD2_ANY ("strings.ip_filter", tr1::bind(&torrent::option_list_strings, torrent::OPTION_IP_FILTER));
CMD2_ANY ("strings.ip_tos", tr1::bind(&torrent::option_list_strings, torrent::OPTION_IP_TOS));
CMD2_ANY ("ipv4_filter.size_data", std::bind(&apply_ipv4_filter_size_data));
CMD2_ANY_STRING ("ipv4_filter.get", std::bind(&apply_ipv4_filter_get, std::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.add_address", std::bind(&apply_ipv4_filter_add_address, std::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.load", std::bind(&apply_ipv4_filter_load, std::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.dump", std::bind(&apply_ipv4_filter_dump));
CMD2_ANY_STRING ("ip_tables.insert_table", tr1::bind(&apply_ip_tables_insert_table, tr1::placeholders::_2));
CMD2_ANY_STRING ("ip_tables.size_data", tr1::bind(&apply_ip_tables_size_data, tr1::placeholders::_2));
CMD2_ANY_LIST ("ip_tables.get", tr1::bind(&apply_ip_tables_get, tr1::placeholders::_2));
CMD2_ANY_LIST ("ip_tables.add_address", tr1::bind(&apply_ip_tables_add_address, tr1::placeholders::_2));
CMD2_ANY ("ipv4_filter.size_data", tr1::bind(&apply_ipv4_filter_size_data));
CMD2_ANY_STRING ("ipv4_filter.get", tr1::bind(&apply_ipv4_filter_get, tr1::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.add_address", tr1::bind(&apply_ipv4_filter_add_address, tr1::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.load", tr1::bind(&apply_ipv4_filter_load, tr1::placeholders::_2));
CMD2_ANY_LIST ("ipv4_filter.dump", tr1::bind(&apply_ipv4_filter_dump));
}
+161 -210
View File
@@ -1,31 +1,65 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#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/runtime/memory_manager.h>
#include <torrent/runtime/socket_manager.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"
#include "rpc/lua.h"
#include "control.h"
#include "command_helpers.h"
@@ -35,23 +69,15 @@ typedef torrent::FileManager FM_t;
torrent::Object
apply_pieces_stats_total_size() {
uint64_t size = 0;
core::DownloadList* d_list = control->core()->download_list();
for (const auto& d : *control->core()->download_list())
if (d->is_active())
size += d->file_list()->size_bytes();
for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++)
if ((*itr)->is_active())
size += (*itr)->file_list()->size_bytes();
return size;
}
torrent::Object
system_env(const torrent::Object::string_type& arg) {
if (arg.empty())
throw torrent::input_error("system.env: Missing variable name.");
char* val = getenv(arg.c_str());
return std::string(val ? val : "");
}
torrent::Object
system_hostname() {
char buffer[1024];
@@ -96,15 +122,11 @@ post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object:
inline const std::string&
check_name(const std::string& str) {
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.");
if (!rak::is_all_name(str))
throw torrent::input_error("Non-alphanumeric characters found.");
return str;
}
}
torrent::Object
group_insert(const torrent::Object::list_type& args) {
@@ -115,24 +137,40 @@ group_insert(const torrent::Object::list_type& args) {
const std::string& view = check_name(post_increment(itr, last)->as_string());
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.enable", "simple",
"schedule=group." + name + ".ratio,5,60,on_ratio=" + name));
"schedule2=group." + name + ".ratio,5,60,on_ratio=" + name));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple",
"schedule.remove=group." + name + ".ratio"));
"schedule_remove2=group." + name + ".ratio"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
"d.try_close= ;d.ignore_commands.set=1"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".view", "string", view));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.min", "value", (int64_t)200));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.max", "value", (int64_t)300));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.upload", "value", (int64_t)20 << 20));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".view", "string", view));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.min", "value", (int64_t)200));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.max", "value", (int64_t)300));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.upload", "value", (int64_t)20 << 20));
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") == 1) {
// Deprecated in 0.7.0:
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view", "group2." + name + ".view");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view.set", "group2." + name + ".view.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
} if (rpc::call_command_value("method.use_intermediate") == 2) {
// Deprecated in 0.7.0:
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view", "group2." + name + ".view");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view.set", "group2." + name + ".view.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
}
return name;
}
@@ -148,7 +186,7 @@ file_print_list(torrent::Object::list_const_iterator first, torrent::Object::lis
fprintf(output, (const char*)" %s" + !(flags & file_print_use_space), first->as_string().c_str());
break;
case torrent::Object::TYPE_VALUE:
fprintf(output, (const char*)" %" PRIi64 + !(flags & file_print_use_space), first->as_value());
fprintf(output, (const char*)" %lli" + !(flags & file_print_use_space), first->as_value());
break;
case torrent::Object::TYPE_LIST:
file_print_list(first->as_list().begin(), first->as_list().end(), output, 0);
@@ -168,211 +206,124 @@ torrent::Object
cmd_file_append(const torrent::Object::list_type& args) {
if (args.empty())
throw torrent::input_error("Invalid number of arguments.");
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);
try {
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
fprintf(output, "\n");
} catch (...) {
fclose(output);
throw;
}
fprintf(output, "\n");
fclose(output);
return torrent::Object();
}
void
initialize_command_local() {
core::DownloadList* dList = control->core()->download_list();
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
torrent::FileManager* fileManager = torrent::file_manager();
core::DownloadList* dList = control->core()->download_list();
core::DownloadStore* dStore = control->core()->download_store();
CMD_ANY ("system.hostname", std::bind(&system_hostname));
CMD_ANY ("system.pid", std::bind(&getpid));
CMD2_ANY ("system.hostname", tr1::bind(&system_hostname));
CMD2_ANY ("system.pid", tr1::bind(&getpid));
CMD_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
CMD_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
CMD_VAR_C_STRING("system.library_version", torrent::runtime::version());
CMD2_VAR_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_VALUE ("system.file.allocate", 0);
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)128 << 30);
CMD2_VAR_VALUE ("system.file.split_size", -1);
CMD2_VAR_STRING ("system.file.split_suffix", ".part");
CMD_VAR_VALUE ("system.file.allocate", 0);
CMD_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
CMD_VAR_VALUE ("system.file.split_size", -1);
CMD_VAR_STRING ("system.file.split_suffix", ".part");
CMD_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
CMD2_ANY ("system.file_status_cache.size", tr1::bind(&utils::FileStatusCache::size,
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
CMD_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
CMD2_ANY_V ("system.file_status_cache.prune", tr1::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
CMD_VAR_BOOL ("file.prioritize_toc", 0);
CMD_VAR_LIST ("file.prioritize_toc.first");
CMD_VAR_LIST ("file.prioritize_toc.last");
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
CMD2_VAR_LIST ("file.prioritize_toc.first");
CMD2_VAR_LIST ("file.prioritize_toc.last");
CMD_ANY ("system.files.advise_random", std::bind(&FM_t::advise_random, fileManager));
CMD_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
CMD_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
CMD_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
CMD_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
CMD_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
CMD2_ANY ("system.files.opened_counter", tr1::bind(&FM_t::files_opened_counter, fileManager));
CMD2_ANY ("system.files.closed_counter", tr1::bind(&FM_t::files_closed_counter, fileManager));
CMD2_ANY ("system.files.failed_counter", tr1::bind(&FM_t::files_failed_counter, fileManager));
CMD_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
CMD_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
CMD_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
CMD2_ANY ("system.time", tr1::bind(&rak::timer::seconds, &cachedTime));
CMD2_ANY ("system.time_seconds", tr1::bind(&rak::timer::current_seconds));
CMD2_ANY ("system.time_usec", tr1::bind(&rak::timer::current_usec));
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
CMD2_ANY_VALUE_V ("system.umask.set", tr1::bind(&umask, tr1::placeholders::_2));
CMD_ANY ("system.time", [](auto, auto) { return torrent::this_thread::cached_seconds().count(); });
CMD_ANY ("system.time_seconds", [](auto, auto) { return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count(); });
CMD_ANY ("system.time_usec", [](auto, auto) { return torrent::utils::time_since_epoch().count(); });
CMD2_ANY ("system.cwd", tr1::bind(&system_get_cwd));
CMD2_ANY_STRING ("system.cwd.set", tr1::bind(&system_set_cwd, tr1::placeholders::_2));
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
CMD2_ANY ("pieces.sync.always_safe", tr1::bind(&CM_t::safe_sync, chunkManager));
CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", tr1::bind(&CM_t::set_safe_sync, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.sync.safe_free_diskspace", tr1::bind(&CM_t::safe_free_diskspace, chunkManager));
CMD2_ANY ("pieces.sync.timeout", tr1::bind(&CM_t::timeout_sync, chunkManager));
CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", tr1::bind(&CM_t::set_timeout_sync, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.sync.timeout_safe", tr1::bind(&CM_t::timeout_safe_sync, chunkManager));
CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", tr1::bind(&CM_t::set_timeout_safe_sync, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.sync.queue_size", tr1::bind(&CM_t::sync_queue_size, chunkManager));
CMD_VAR_BOOL ("system.daemon", false);
CMD2_ANY ("pieces.preload.type", tr1::bind(&CM_t::preload_type, chunkManager));
CMD2_ANY_VALUE_V ("pieces.preload.type.set", tr1::bind(&CM_t::set_preload_type, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.preload.min_size", tr1::bind(&CM_t::preload_min_size, chunkManager));
CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", tr1::bind(&CM_t::set_preload_min_size, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.preload.min_rate", tr1::bind(&CM_t::preload_required_rate, chunkManager));
CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", tr1::bind(&CM_t::set_preload_required_rate, chunkManager, tr1::placeholders::_2));
CMD_ANY_V ("system.shutdown.normal", [](auto, auto) { control->receive_normal_shutdown(); });
CMD_ANY_V ("system.shutdown.quick", [](auto, auto) { control->receive_quick_shutdown(); });
CMD2_ANY ("pieces.memory.current", tr1::bind(&CM_t::memory_usage, chunkManager));
CMD2_ANY ("pieces.memory.sync_queue", tr1::bind(&CM_t::sync_queue_memory_usage, chunkManager));
CMD2_ANY ("pieces.memory.block_count", tr1::bind(&CM_t::memory_block_count, chunkManager));
CMD2_ANY ("pieces.memory.max", tr1::bind(&CM_t::max_memory_usage, chunkManager));
CMD2_ANY_VALUE_V ("pieces.memory.max.set", tr1::bind(&CM_t::set_max_memory_usage, chunkManager, tr1::placeholders::_2));
CMD2_ANY ("pieces.stats_preloaded", tr1::bind(&CM_t::stats_preloaded, chunkManager));
CMD2_ANY ("pieces.stats_not_preloaded", tr1::bind(&CM_t::stats_not_preloaded, chunkManager));
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
CMD2_ANY ("pieces.stats.total_size", tr1::bind(&apply_pieces_stats_total_size));
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
CMD2_ANY ("pieces.hash.queue_size", tr1::bind(&torrent::hash_queue_size));
CMD2_VAR_BOOL ("pieces.hash.on_completion", true);
CMD_ANY ("system.sockets.size", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
CMD_ANY ("system.sockets.max_size", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
CMD_ANY_VALUE_V ("system.sockets.max_size.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
CMD_ANY_V ("system.sockets.adjust_alloc", [](auto, auto) { torrent::runtime::socket_manager()->adjust_allocation(); });
CMD2_VAR_STRING ("directory.default", "./");
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
CMD2_VAR_STRING ("session.name", "");
CMD2_VAR_BOOL ("session.use_lock", true);
CMD2_VAR_BOOL ("session.on_completion", true);
CMD_ANY (category_name + ".size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_managed_size(category); });
CMD_ANY (category_name + ".max_size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_size(category); });
CMD2_ANY ("session.path", tr1::bind(&core::DownloadStore::path, dStore));
CMD2_ANY_STRING_V("session.path.set", tr1::bind(&core::DownloadStore::set_path, dStore, tr1::placeholders::_2));
if (i == 0)
continue;
CMD2_ANY_V ("session.save", tr1::bind(&core::DownloadList::session_save, dList));
CMD_ANY (category_name + ".min_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_min_allocation(category); });
CMD_ANY (category_name + ".max_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_allocation(category); });
CMD_ANY_VALUE_V(category_name + ".min_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_min_allocation(category, value); });
CMD_ANY_VALUE_V(category_name + ".max_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_max_allocation(category, value); });
}
#define CMD2_EXECUTE(key, flags) \
CMD2_ANY(key, tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, tr1::placeholders::_2, flags));
CMD_ANY ("pieces.sync.always_safe", [](auto, auto) { return torrent::runtime::memory_manager()->safe_sync(); });
CMD_ANY_VALUE_V ("pieces.sync.always_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_safe_sync(value); });
CMD_ANY ("pieces.sync.safe_free_diskspace", [](auto, auto) { return torrent::runtime::memory_manager()->sync_safe_free_diskspace(); });
CMD_ANY ("pieces.sync.timeout", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_sync().count(); });
CMD_ANY_VALUE_V ("pieces.sync.timeout.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_sync(value); });
// CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_safe_sync(); });
// CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_safe_sync(value); });
CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return 0; });
CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto) { });
CMD_ANY ("pieces.sync.queue_size", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_block_count(); });
CMD2_EXECUTE ("execute2", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
CMD2_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
CMD2_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
CMD2_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
CMD2_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
CMD2_EXECUTE ("execute.raw_nothrow", 0);
CMD2_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
CMD2_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
CMD2_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
CMD_ANY ("pieces.preload.type", [](auto, auto) { return torrent::runtime::memory_manager()->preload_type(); });
CMD_ANY_VALUE_V ("pieces.preload.type.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_type(value); });
CMD_ANY ("pieces.preload.min_size", [](auto, auto) { return torrent::runtime::memory_manager()->preload_min_size(); });
CMD_ANY_VALUE_V ("pieces.preload.min_size.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_min_size(value); });
CMD_ANY ("pieces.preload.min_rate", [](auto, auto) { return torrent::runtime::memory_manager()->preload_required_rate(); });
CMD_ANY_VALUE_V ("pieces.preload.min_rate.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_required_rate(value); });
CMD_ANY ("pieces.stats_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_preloaded(); });
CMD_ANY ("pieces.stats_not_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_not_preloaded(); });
CMD_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
CMD_ANY ("pieces.memory.current", [](auto, auto) { return torrent::runtime::memory_manager()->memory_usage(); });
CMD_ANY ("pieces.memory.sync_queue", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_memory_usage(); });
CMD_ANY ("pieces.memory.block_count", [](auto, auto) { return torrent::runtime::memory_manager()->memory_block_count(); });
CMD_ANY ("pieces.memory.max", [](auto, auto) { return torrent::runtime::memory_manager()->max_memory_usage(); });
CMD_ANY_VALUE_V ("pieces.memory.max.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_max_memory_usage(value); });
CMD_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
CMD_VAR_BOOL ("pieces.hash.on_completion", true);
CMD_VAR_STRING ("directory.default", "./");
CMD_VAR_STRING ("session.name", "");
CMD_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
CMD_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
CMD_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
CMD_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
CMD_VAR_BOOL ("session.on_completion", true);
CMD_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
CMD_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
CMD_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
#ifdef HAVE_LUA
rpc::LuaEngine* lua_engine = control->lua_engine();
CMD_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
CMD_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
#endif
#define CMD_EXECUTE(key, flags) \
CMD_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
CMD_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
CMD_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
CMD_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
CMD_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
CMD_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
CMD_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
CMD_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
CMD_EXECUTE ("execute.raw_nothrow", 0);
CMD_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
CMD_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
CMD_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
CMD2_ANY_LIST ("file.append", tr1::bind(&cmd_file_append, tr1::placeholders::_2));
// TODO: Convert to new command types:
*rpc::command_base::argument(0) = "placeholder.0";
*rpc::command_base::argument(1) = "placeholder.1";
*rpc::command_base::argument(2) = "placeholder.2";
*rpc::command_base::argument(3) = "placeholder.3";
CMD_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
CMD_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
CMD_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
CMD_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
CMD2_ANY_P("argument.0", tr1::bind(&rpc::command_base::argument_ref, 0));
CMD2_ANY_P("argument.1", tr1::bind(&rpc::command_base::argument_ref, 1));
CMD2_ANY_P("argument.2", tr1::bind(&rpc::command_base::argument_ref, 2));
CMD2_ANY_P("argument.3", tr1::bind(&rpc::command_base::argument_ref, 3));
CMD_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
rpc::rpc.mark_safe("system.api_version");
rpc::rpc.mark_safe("system.client_version");
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("system.sockets.size");
rpc::rpc.mark_safe("system.sockets.max_size");
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
rpc::rpc.mark_safe(category_name + ".size");
rpc::rpc.mark_safe(category_name + ".max_size");
if (i == 0)
continue;
rpc::rpc.mark_safe(category_name + ".min_alloc");
rpc::rpc.mark_safe(category_name + ".max_alloc");
}
rpc::rpc.mark_safe("directory.default");
rpc::rpc.mark_safe("session.path");
rpc::rpc.mark_safe("session.use_lock");
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");
CMD2_ANY_LIST ("group.insert", tr1::bind(&group_insert, tr1::placeholders::_2));
}
+90 -65
View File
@@ -1,7 +1,42 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <fcntl.h>
#include <iterator>
#include <stdio.h>
#include <unistd.h>
#include <torrent/data/chunk_utils.h>
@@ -9,24 +44,50 @@
#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 "rpc/parse.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;
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& raw_args) {
std::vector<std::string> args;
apply_log_open(int output_flags, const torrent::Object::list_type& args) {
if (args.size() < 2)
throw torrent::input_error("Invalid number of arguments.");
torrent::Object::list_const_iterator itr = args.begin();
for (const auto& arg : raw_args)
args.push_back(arg.as_string());
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;
}
if ((output_flags & log_flag_use_gz))
torrent::log_open_gz_file_output(output_id.c_str(), file_name.c_str());
else
torrent::log_open_file_output(output_id.c_str(), file_name.c_str());
while (itr != args.end())
log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str());
apply_log_open_str(output_flags, args);
return torrent::Object();
}
@@ -34,35 +95,10 @@ 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();
}
torrent::Object
apply_log_print(const torrent::Object::list_type& args) {
if (args.size() < 2)
throw torrent::input_error("Invalid number of arguments.");
torrent::Object::value_type group;
if (args.front().is_value())
group = args.front().as_value();
else if (args.front().is_string())
group = torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, args.front().as_string());
else
throw torrent::input_error("Invalid log group.");
if (group < 0 || group >= torrent::LOG_GROUP_MAX_SIZE)
throw torrent::input_error("Invalid log group.");
std::string message;
for (auto itr = std::next(args.begin()); itr != args.end(); ++itr)
rpc::print_object_std(&message, &*itr, 0);
torrent::log_groups[group].internal_print(message);
return torrent::Object();
}
@@ -83,7 +119,7 @@ apply_log(const torrent::Object::string_type& arg, int logType) {
}
if (!arg.empty()) {
int logFd = open(expand_path(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
if (logFd < 0)
throw torrent::input_error("Could not open execute log file.");
@@ -105,21 +141,19 @@ apply_log(const torrent::Object::string_type& arg, int logType) {
torrent::Object
log_vmmap_dump(const std::string& str) {
core::DownloadList* d_list = control->core()->download_list();
std::vector<torrent::vm_mapping> all_mappings;
for (const auto& d : *control->core()->download_list()) {
std::vector<torrent::vm_mapping> tmp_mappings = torrent::chunk_list_mapping(d->download());
for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++) {
std::vector<torrent::vm_mapping> tmp_mappings = torrent::chunk_list_mapping((*itr)->download());
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
}
FILE* log_file = fopen(str.c_str(), "w");
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));
for (std::vector<torrent::vm_mapping>::iterator itr = all_mappings.begin(), last = all_mappings.end(); itr != last; itr++) {
fprintf(log_file, "%8p-%8p [%5llxk]\n", itr->ptr, (char*)itr->ptr + itr->length, (long long unsigned int)(itr->length / 1024));
}
fclose(log_file);
@@ -128,23 +162,14 @@ 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_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_LIST ("log.open_file", tr1::bind(&apply_log_open, 0, tr1::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file", tr1::bind(&apply_log_open, log_flag_use_gz, tr1::placeholders::_2));
CMD2_ANY_LIST ("log.open_file_pid", tr1::bind(&apply_log_open, log_flag_append_pid, tr1::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file_pid", tr1::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, tr1::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", tr1::bind(&apply_log_add_output, tr1::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_LIST ("log.print", std::bind(&apply_log_print, std::placeholders::_2));
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
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
CMD2_ANY_STRING ("log.execute", tr1::bind(&apply_log, tr1::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", tr1::bind(&log_vmmap_dump, tr1::placeholders::_2));
CMD2_ANY_STRING_V("log.xmlrpc", tr1::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, tr1::placeholders::_2));
}
+179 -326
View File
@@ -1,27 +1,56 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <functional>
#include <cstdio>
#include <unistd.h>
#include <rak/address_info.h>
#include <rak/path.h>
#include <torrent/connection_manager.h>
#include <torrent/tracker.h>
#include <torrent/tracker_list.h>
#include <torrent/torrent.h>
#include <torrent/rate.h>
#include <torrent/data/file_manager.h>
#include <torrent/download/resource_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/socket_address.h>
#include <torrent/runtime/client_config.h>
#include <torrent/runtime/network_config.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/runtime/proxy_manager.h>
#include <torrent/runtime/runtime.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/scgi.h"
@@ -29,121 +58,28 @@
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#ifdef HAVE_SYSTEMD
#include <sys/socket.h>
#include <systemd/sd-daemon.h>
#endif
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
torrent::Object
listen_port_range() {
auto port_range = torrent::runtime::client_config()->listen_port_range();
return std::to_string(port_range.first) + "-" + std::to_string(port_range.second);
}
void
set_listen_port_range(const std::string& arg) {
unsigned int port_first{}, port_last{};
if (std::sscanf(arg.c_str(), "%i-%i", &port_first, &port_last) != 2)
throw torrent::input_error("Invalid port_range argument.");
if (port_first >= (1 << 16) || port_last >= (1 << 16))
throw torrent::input_error("Port range out-of-bounds.");
torrent::runtime::client_config()->set_listen_port_range(port_first, port_last);
}
torrent::Object
get_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_HANDSHAKE, encryption_modes.first) + "," +
torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_STREAM, encryption_modes.second);
}
torrent::Object
get_handshake_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.first);
}
torrent::Object
get_stream_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.second);
}
torrent::Object
apply_obsolete_encryption(const torrent::Object::list_type& args) {
torrent::encryption_mode handshake_mode{torrent::ENCRYPTION_MODE_ALLOW};
torrent::encryption_mode stream_mode{torrent::ENCRYPTION_MODE_ALLOW};
for (auto& itr : args) {
auto arg = itr.as_string();
if (arg == "none") {
handshake_mode = torrent::ENCRYPTION_MODE_DENY;
stream_mode = torrent::ENCRYPTION_MODE_DENY;
break;
} else if (arg == "allow_incoming") {
} else if (arg == "try_outgoing") {
} else if (arg == "require") {
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
} else if (arg == "require_RC4" || arg == "require_rc4") {
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
stream_mode = torrent::ENCRYPTION_MODE_REQUIRE;
break;
} else if (arg == "enable_retry") {
} else if (arg == "prefer_plaintext") {
} else {
throw torrent::input_error("Invalid encryption option: '" + arg + "'");
}
}
lt_log_print(torrent::LOG_WARN, "Obsolete encryption options used, use 'handshake_{deny,allow,prefer,require}, stream_{deny,allow,prefer,require}' instead.");
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
return {};
}
namespace tr1 { using namespace std::tr1; }
torrent::Object
apply_encryption(const torrent::Object::list_type& args) {
if (args.empty())
throw torrent::input_error("No encryption options specified.");
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
torrent::encryption_mode encryption_mode, handshake_mode, stream_mode;
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, itr->as_string().c_str());
if (args.size() == 1) {
try {
encryption_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_MODE, args.front().as_string()));
} catch (torrent::input_error& e) {
return apply_obsolete_encryption(args);
}
torrent::runtime::network_config()->set_encryption_modes(encryption_mode, encryption_mode);
return {};
if (opt == torrent::ConnectionManager::encryption_none)
options_mask = torrent::ConnectionManager::encryption_none;
else
options_mask |= opt;
}
if (args.size() != 2)
return apply_obsolete_encryption(args);
torrent::connection_manager()->set_encryption_options(options_mask);
try {
handshake_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_HANDSHAKE, args.front().as_string()));
stream_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_STREAM, args.back().as_string()));
} catch (torrent::input_error& e) {
return apply_obsolete_encryption(args);
}
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
return {};
return torrent::Object();
}
torrent::Object
@@ -153,62 +89,97 @@ 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::runtime::network_config()->set_priority(value);
torrent::connection_manager()->set_priority(value);
return torrent::Object();
}
torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); }
torrent::File*
xmlrpc_find_file(core::Download* download, uint32_t index) {
if (index >= download->file_list()->size_files())
return NULL;
return (*download->file_list())[index];
}
// Ergh... time to update the Tracker API to allow proper ptrs.
torrent::Tracker*
xmlrpc_find_tracker(core::Download* download, uint32_t index) {
if (index >= download->tracker_list()->size())
return NULL;
return download->tracker_list()->at(index);
}
torrent::Peer*
xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) {
torrent::ConnectionList::iterator itr = download->connection_list()->find(hash.c_str());
if (itr == download->connection_list()->end())
return NULL;
return *itr;
}
void
initialize_rpc_handlers() {
rpc::rpc.initialize_handlers();
initialize_xmlrpc() {
rpc::xmlrpc.initialize();
rpc::xmlrpc.slot_find_download() = tr1::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), tr1::placeholders::_1);
rpc::xmlrpc.slot_find_file() = tr1::bind(&xmlrpc_find_file, tr1::placeholders::_1, tr1::placeholders::_2);
rpc::xmlrpc.slot_find_tracker() = tr1::bind(&xmlrpc_find_tracker, tr1::placeholders::_1, tr1::placeholders::_2);
rpc::xmlrpc.slot_find_peer() = tr1::bind(&xmlrpc_find_peer, tr1::placeholders::_1, tr1::placeholders::_2);
unsigned int count = 0;
for (const auto& [name, cmd] : rpc::commands) {
if (!(cmd.m_flags & rpc::CommandMap::flag_public_rpc))
for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++, count++) {
if (!(itr->second.m_flags & rpc::CommandMap::flag_public_xmlrpc))
continue;
rpc::rpc.insert_command(name.c_str(), cmd.m_parm, cmd.m_doc);
++count;
rpc::xmlrpc.insert_command(itr->first, itr->second.m_parm, itr->second.m_doc);
}
lt_log_print(torrent::LOG_RPC_EVENTS, "RPC manager initialized with %u functions.", count);
lt_log_print(torrent::LOG_RPC_EVENTS, "XMLRPC initialized with %u functions.", count);
}
torrent::Object
apply_scgi(const std::string& arg, int type) {
if (scgi_thread::scgi() != nullptr)
if (worker_thread->scgi() != NULL)
throw torrent::input_error("SCGI already enabled.");
initialize_rpc_handlers();
if (!rpc::xmlrpc.is_valid())
initialize_xmlrpc();
torrent::sa_unique_ptr sa;
rpc::SCgi* scgi = new rpc::SCgi;
auto scgi = std::make_unique<rpc::SCgi>();
rak::address_info* ai = NULL;
rak::socket_address sa;
rak::socket_address* saPtr;
try {
int port{};
char dummy{};
int port, err;
char dummy;
char address[1024];
std::string path;
switch (type) {
case 1:
if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) {
sa = torrent::sa_make_inet();
sa.sa_inet()->clear();
saPtr = &sa;
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is open to any address and is a security risk");
lt_log_print(torrent::LOG_RPC_EVENTS,
"The SCGI socket has not been bound to any address and likely poses a security risk.");
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) {
if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");
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()));
}
saPtr = ai->address();
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
lt_log_print(torrent::LOG_RPC_EVENTS,
"The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'.");
} else {
throw torrent::input_error("Could not parse address.");
@@ -217,82 +188,33 @@ apply_scgi(const std::string& arg, int type) {
if (port <= 0 || port >= (1 << 16))
throw torrent::input_error("Invalid port number.");
torrent::sap_set_port(sa, port);
scgi->open_port(sa.get(), torrent::sap_length(sa), rpc::call_command_value("network.scgi.dont_route"));
saPtr->set_port(port);
scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route"));
break;
case 2:
default:
path = expand_path(arg);
path = rak::path_expand(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());
}
scgi_thread::set_scgi(scgi.release());
worker_thread->set_scgi(scgi);
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;
@@ -306,148 +228,79 @@ apply_xmlrpc_dialect(const std::string& arg) {
else
value = -1;
rpc::rpc.set_dialect(value);
rpc::xmlrpc.set_dialect(value);
return torrent::Object();
}
void
initialize_command_network() {
auto file_manager = torrent::file_manager();
auto http_stack = torrent::net_thread::http_stack();
auto nw_config = torrent::runtime::network_config();
torrent::ConnectionManager* cm = torrent::connection_manager();
torrent::FileManager* fileManager = torrent::file_manager();
core::CurlStack* httpStack = control->core()->http_stack();
CMD_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::network_manager()->listen_port(); });
CMD_ANY_VALUE_V ("network.listen.port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_listen_port(value); });
CMD_ANY ("network.listen.port.random", [](auto, auto) { return torrent::runtime::client_config()->listen_port_random(); });
CMD_ANY_VALUE_V ("network.listen.port.random.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_listen_port_random(value); });
CMD_ANY ("network.listen.port.range", [](auto, auto) { return listen_port_range(); });
CMD_ANY_STRING_V("network.listen.port.range.set", [](auto, auto& value) { return set_listen_port_range(value); });
CMD_ANY ("network.listen.backlog", [](auto, auto) { return torrent::runtime::network_config()->listen_backlog(); });
CMD_ANY_VALUE_V ("network.listen.backlog.set", [](auto, auto& value) { return torrent::runtime::network_config()->set_listen_backlog(value); });
CMD2_ANY ("strings.connection_type", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CONNECTION_TYPE));
CMD2_ANY ("strings.encryption", tr1::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION));
CMD_ANY ("protocol.pex", [](auto, auto) { return torrent::runtime::client_config()->is_pex_enabled(); });
CMD_ANY_VALUE_V ("protocol.pex.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_pex_enabled(value); });
// CMD2_ANY_STRING ("encoding_list", tr1::bind(&apply_encoding_list, tr1::placeholders::_2));
CMD2_ANY_STRING ("encoding.add", tr1::bind(&apply_encoding_list, tr1::placeholders::_2));
CMD_ANY_LIST ("protocol.encryption", [](auto, auto) { return get_encryption(); });
CMD_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
CMD_ANY_LIST ("protocol.encryption.handshake", [](auto, auto) { return get_handshake_encryption(); });
CMD_ANY_LIST ("protocol.encryption.stream", [](auto, auto) { return get_stream_encryption(); });
// Isn't port_open used?
CMD2_VAR_BOOL ("network.port_open", true);
CMD2_VAR_BOOL ("network.port_random", true);
CMD2_VAR_STRING ("network.port_range", "6881-6999");
CMD_VAR_STRING ("protocol.connection.leech", "leech");
CMD_VAR_STRING ("protocol.connection.seed", "seed");
CMD2_ANY ("network.listen.port", tr1::bind(&torrent::ConnectionManager::listen_port, cm));
CMD2_ANY ("network.listen.backlog", tr1::bind(&torrent::ConnectionManager::listen_backlog, cm));
CMD2_ANY_VALUE_V ("network.listen.backlog.set", tr1::bind(&torrent::ConnectionManager::set_listen_backlog, cm, tr1::placeholders::_2));
CMD_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
CMD_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
CMD_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
CMD_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
CMD2_VAR_BOOL ("protocol.pex", true);
CMD2_ANY_LIST ("protocol.encryption.set", tr1::bind(&apply_encryption, tr1::placeholders::_2));
CMD_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
CMD_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
CMD_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
CMD_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
CMD_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
CMD_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
CMD_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
CMD_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
CMD_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
CMD_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
CMD_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
CMD_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
CMD_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
CMD_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
CMD_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
CMD_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
CMD_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); });
CMD_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); });
CMD_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); });
CMD_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); });
CMD_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); });
CMD2_ANY ("network.http.capath", tr1::bind(&core::CurlStack::http_capath, httpStack));
CMD2_ANY_STRING_V("network.http.capath.set", tr1::bind(&core::CurlStack::set_http_capath, httpStack, tr1::placeholders::_2));
CMD2_ANY ("network.http.cacert", tr1::bind(&core::CurlStack::http_cacert, httpStack));
CMD2_ANY_STRING_V("network.http.cacert.set", tr1::bind(&core::CurlStack::set_http_cacert, httpStack, tr1::placeholders::_2));
CMD2_ANY ("network.http.proxy_address", tr1::bind(&core::CurlStack::http_proxy, httpStack));
CMD2_ANY_STRING_V("network.http.proxy_address.set", tr1::bind(&core::CurlStack::set_http_proxy, httpStack, tr1::placeholders::_2));
CMD2_ANY ("network.http.max_open", tr1::bind(&core::CurlStack::max_active, httpStack));
CMD2_ANY_VALUE_V ("network.http.max_open.set", tr1::bind(&core::CurlStack::set_max_active, httpStack, tr1::placeholders::_2));
CMD2_ANY ("network.http.ssl_verify_peer", tr1::bind(&core::CurlStack::ssl_verify_peer, httpStack));
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", tr1::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, tr1::placeholders::_2));
CMD2_ANY ("network.http.dns_cache_timeout", tr1::bind(&core::CurlStack::dns_timeout, httpStack));
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", tr1::bind(&core::CurlStack::set_dns_timeout, httpStack, tr1::placeholders::_2));
CMD_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); });
CMD_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); });
CMD_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); });
CMD_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); });
CMD_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); });
CMD_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); });
CMD2_ANY ("network.send_buffer.size", tr1::bind(&torrent::ConnectionManager::send_buffer_size, cm));
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", tr1::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, tr1::placeholders::_2));
CMD2_ANY ("network.receive_buffer.size", tr1::bind(&torrent::ConnectionManager::receive_buffer_size, cm));
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", tr1::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, tr1::placeholders::_2));
CMD2_ANY_STRING ("network.tos.set", tr1::bind(&apply_tos, tr1::placeholders::_2));
CMD_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
CMD_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
CMD_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
CMD_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
CMD_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
CMD_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); });
CMD2_ANY ("network.bind_address", tr1::bind(&core::Manager::bind_address, control->core()));
CMD2_ANY_STRING_V("network.bind_address.set", tr1::bind(&core::Manager::set_bind_address, control->core(), tr1::placeholders::_2));
CMD2_ANY ("network.local_address", tr1::bind(&core::Manager::local_address, control->core()));
CMD2_ANY_STRING_V("network.local_address.set", tr1::bind(&core::Manager::set_local_address, control->core(), tr1::placeholders::_2));
CMD2_ANY ("network.proxy_address", tr1::bind(&core::Manager::proxy_address, control->core()));
CMD2_ANY_STRING_V("network.proxy_address.set", tr1::bind(&core::Manager::set_proxy_address, control->core(), tr1::placeholders::_2));
CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); });
CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); });
CMD_ANY ("network.proxy.http", [](auto, auto) { return torrent::runtime::proxy_manager()->http_proxy_url(); });
CMD_ANY_STRING_V("network.proxy.http.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_http_proxy_url(str); });
CMD2_ANY ("network.max_open_files", tr1::bind(&torrent::FileManager::max_open_files, fileManager));
CMD2_ANY_VALUE_V ("network.max_open_files.set", tr1::bind(&torrent::FileManager::set_max_open_files, fileManager, tr1::placeholders::_2));
CMD2_ANY ("network.open_sockets", tr1::bind(&torrent::ConnectionManager::size, cm));
CMD2_ANY ("network.max_open_sockets", tr1::bind(&torrent::ConnectionManager::max_size, cm));
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", tr1::bind(&torrent::ConnectionManager::set_max_size, cm, tr1::placeholders::_2));
CMD_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
CMD_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
CMD_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
CMD2_ANY_STRING ("network.scgi.open_port", tr1::bind(&apply_scgi, tr1::placeholders::_2, 1));
CMD2_ANY_STRING ("network.scgi.open_local", tr1::bind(&apply_scgi, tr1::placeholders::_2, 2));
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
CMD_ANY_STRING ("network.scgi.open_port", [](auto, auto& arg) { return apply_scgi(arg, 1); });
CMD_ANY_STRING ("network.scgi.open_local", [](auto, auto& arg) { return apply_scgi(arg, 2); });
CMD_VAR_BOOL ("network.scgi.dont_route", false);
CMD_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
CMD_ANY ("network.scgi.use_gzip", [](auto, auto) { return rpc::rpc.scgi_allow_compression(); });
CMD_ANY_VALUE_V ("network.scgi.use_gzip.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
CMD_ANY ("network.scgi.gzip.min_size", [](auto, auto) { return rpc::rpc.scgi_min_compress_size(); });
CMD_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
CMD_ANY_STRING ("network.xmlrpc.dialect.set", [](auto, auto& arg) { return apply_xmlrpc_dialect(arg); })
CMD_ANY ("network.xmlrpc.size_limit", [](auto, auto) { return rpc::rpc.size_limit(); });
CMD_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](auto, auto& arg) { return rpc::rpc.set_size_limit(arg); });
CMD_ANY ("network.rpc.use_xmlrpc", [](auto, auto) { return rpc::rpc.use_xmlrpc(); });
CMD_ANY_VALUE_V ("network.rpc.use_xmlrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_xmlrpc(arg); });
CMD_ANY ("network.rpc.use_jsonrpc", [](auto, auto) { return rpc::rpc.use_jsonrpc(); });
CMD_ANY_VALUE_V ("network.rpc.use_jsonrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_jsonrpc(arg); });
CMD_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); });
CMD_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); });
CMD_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); });
CMD_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); });
CMD_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); });
CMD_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); });
CMD_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); });
CMD_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); });
CMD_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); });
CMD_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); });
rpc::rpc.mark_safe("network.port_open");
rpc::rpc.mark_safe("network.port_random");
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.total_handshakes");
rpc::rpc.mark_safe("network.open_files");
rpc::rpc.mark_safe("network.max_open_files");
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.proxy.global");
rpc::rpc.mark_safe("network.proxy.http");
rpc::rpc.mark_safe("network.scgi.dont_route");
rpc::rpc.mark_safe("protocol.pex");
rpc::rpc.mark_safe("network.rpc.use_xmlrpc");
rpc::rpc.mark_safe("network.rpc.use_jsonrpc");
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", tr1::bind(&apply_xmlrpc_dialect, tr1::placeholders::_2));
CMD2_ANY ("network.xmlrpc.size_limit", tr1::bind(&rpc::XmlRpc::size_limit));
CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", tr1::bind(&rpc::XmlRpc::set_size_limit, tr1::placeholders::_2));
}
+89 -65
View File
@@ -1,28 +1,80 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/socket_address.h>
#include <rak/string_manip.h>
#include <torrent/bitfield.h>
#include <torrent/rate.h>
#include <torrent/net/socket_address.h>
#include <torrent/peer/connection_list.h>
#include <torrent/peer/peer.h>
#include <torrent/peer/peer_info.h>
#include <torrent/utils/string_manip.h>
#include "globals.h"
#include "command_helpers.h"
#include "control.h"
#include "core/manager.h"
#include "display/utils.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());
}
torrent::Object
retrieve_p_address(torrent::Peer* peer) {
auto sa = peer->peer_info()->socket_address();
auto addr_str = torrent::sa_addr_str(sa);
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
}
if (sa->sa_family == AF_INET6)
return "[" + addr_str + "]";
return addr_str;
torrent::Object
retrieve_p_port(torrent::Peer* peer) {
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port();
}
torrent::Object
@@ -35,75 +87,47 @@ retrieve_p_client_version(torrent::Peer* peer) {
torrent::Object
retrieve_p_options_str(torrent::Peer* peer) {
return torrent::utils::transform_to_hex_str(peer->peer_info()->options(), peer->peer_info()->options() + 8);
return rak::transform_hex(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", [](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.id", tr1::bind(&retrieve_p_id, tr1::placeholders::_1));
CMD2_PEER("p.id_html", tr1::bind(&retrieve_p_id_html, tr1::placeholders::_1));
CMD2_PEER("p.client_version", tr1::bind(&retrieve_p_client_version, tr1::placeholders::_1));
CMD2_PEER("p.options_str", std::bind(&retrieve_p_options_str, std::placeholders::_1));
CMD2_PEER("p.options_str", tr1::bind(&retrieve_p_options_str, tr1::placeholders::_1));
CMD2_PEER("p.is_encrypted", std::bind(&torrent::Peer::is_encrypted, std::placeholders::_1));
CMD2_PEER("p.is_incoming", std::bind(&torrent::Peer::is_incoming, std::placeholders::_1));
CMD2_PEER("p.is_obfuscated", std::bind(&torrent::Peer::is_obfuscated, std::placeholders::_1));
CMD2_PEER("p.is_snubbed", std::bind(&torrent::Peer::is_snubbed, std::placeholders::_1));
CMD2_PEER("p.is_encrypted", tr1::bind(&torrent::Peer::is_encrypted, tr1::placeholders::_1));
CMD2_PEER("p.is_incoming", tr1::bind(&torrent::Peer::is_incoming, tr1::placeholders::_1));
CMD2_PEER("p.is_obfuscated", tr1::bind(&torrent::Peer::is_obfuscated, tr1::placeholders::_1));
CMD2_PEER("p.is_snubbed", tr1::bind(&torrent::Peer::is_snubbed, tr1::placeholders::_1));
CMD2_PEER("p.is_unwanted", std::bind(&torrent::PeerInfo::is_unwanted, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
CMD2_PEER("p.is_preferred", std::bind(&torrent::PeerInfo::is_preferred, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
CMD2_PEER("p.is_unwanted", tr1::bind(&torrent::PeerInfo::is_unwanted, tr1::bind(&torrent::Peer::peer_info, tr1::placeholders::_1)));
CMD2_PEER("p.is_preferred", tr1::bind(&torrent::PeerInfo::is_preferred, tr1::bind(&torrent::Peer::peer_info, tr1::placeholders::_1)));
CMD2_PEER("p.address", std::bind(&retrieve_p_address, std::placeholders::_1));
CMD2_PEER("p.port", [](auto* peer, auto) { return torrent::sa_port(peer->peer_info()->socket_address()); });
CMD2_PEER("p.address", tr1::bind(&retrieve_p_address, tr1::placeholders::_1));
CMD2_PEER("p.port", tr1::bind(&retrieve_p_port, tr1::placeholders::_1));
CMD2_PEER("p.completed_percent", std::bind(&retrieve_p_completed_percent, std::placeholders::_1));
CMD2_PEER("p.completed_percent", tr1::bind(&retrieve_p_completed_percent, tr1::placeholders::_1));
CMD2_PEER("p.up_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::up_rate, std::placeholders::_1)));
CMD2_PEER("p.up_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::up_rate, std::placeholders::_1)));
CMD2_PEER("p.down_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::down_rate, std::placeholders::_1)));
CMD2_PEER("p.down_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::down_rate, std::placeholders::_1)));
CMD2_PEER("p.peer_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::peer_rate, std::placeholders::_1)));
CMD2_PEER("p.peer_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::peer_rate, std::placeholders::_1)));
CMD2_PEER("p.up_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::up_rate, tr1::placeholders::_1)));
CMD2_PEER("p.up_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::up_rate, tr1::placeholders::_1)));
CMD2_PEER("p.down_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::down_rate, tr1::placeholders::_1)));
CMD2_PEER("p.down_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::down_rate, tr1::placeholders::_1)));
CMD2_PEER("p.peer_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::peer_rate, tr1::placeholders::_1)));
CMD2_PEER("p.peer_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::peer_rate, tr1::placeholders::_1)));
CMD2_PEER ("p.snubbed", std::bind(&torrent::Peer::is_snubbed, std::placeholders::_1));
CMD2_PEER_VALUE_V("p.snubbed.set", std::bind(&torrent::Peer::set_snubbed, std::placeholders::_1, std::placeholders::_2));
CMD2_PEER ("p.banned", std::bind(&torrent::Peer::is_banned, std::placeholders::_1));
CMD2_PEER_VALUE_V("p.banned.set", std::bind(&torrent::Peer::set_banned, std::placeholders::_1, std::placeholders::_2));
CMD2_PEER ("p.snubbed", tr1::bind(&torrent::Peer::is_snubbed, tr1::placeholders::_1));
CMD2_PEER_VALUE_V("p.snubbed.set", tr1::bind(&torrent::Peer::set_snubbed, tr1::placeholders::_1, tr1::placeholders::_2));
CMD2_PEER ("p.banned", tr1::bind(&torrent::Peer::is_banned, tr1::placeholders::_1));
CMD2_PEER_VALUE_V("p.banned.set", tr1::bind(&torrent::Peer::set_banned, tr1::placeholders::_1, tr1::placeholders::_2));
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");
CMD2_PEER_V("p.disconnect", tr1::bind(&torrent::Peer::disconnect, tr1::placeholders::_1, 0));
CMD2_PEER_V("p.disconnect_delayed", tr1::bind(&torrent::Peer::disconnect, tr1::placeholders::_1, torrent::ConnectionList::disconnect_delayed));
}
+44 -6
View File
@@ -1,3 +1,39 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <sys/types.h>
@@ -16,7 +52,7 @@ torrent::Object
cmd_scheduler_simple_added(core::Download* download) {
unsigned int numActive = (*control->view_manager()->find("active"))->size_visible();
int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
if (numActive < (uint64_t)maxActive)
control->core()->download_list()->resume(download);
@@ -47,7 +83,7 @@ cmd_scheduler_simple_removed(core::Download* download) {
}
torrent::Object
cmd_scheduler_simple_update([[maybe_unused]] core::Download* download) {
cmd_scheduler_simple_update(core::Download* download) {
core::View* viewActive = *control->view_manager()->find("active");
core::View* viewStarted = *control->view_manager()->find("started");
@@ -55,6 +91,7 @@ cmd_scheduler_simple_update([[maybe_unused]] core::Download* download) {
uint64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
if (viewActive->size_visible() < maxActive) {
for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) {
if ((*itr)->is_active())
continue;
@@ -65,7 +102,8 @@ cmd_scheduler_simple_update([[maybe_unused]] core::Download* download) {
break;
}
} else {
} else if (viewActive->size_visible() > maxActive) {
while (viewActive->size_visible() > maxActive)
control->core()->download_list()->pause(*viewActive->begin_visible());
}
@@ -77,7 +115,7 @@ void
initialize_command_scheduler() {
CMD2_VAR_VALUE("scheduler.max_active", int64_t(-1));
CMD2_DL("scheduler.simple.added", std::bind(&cmd_scheduler_simple_added, std::placeholders::_1));
CMD2_DL("scheduler.simple.removed", std::bind(&cmd_scheduler_simple_removed, std::placeholders::_1));
CMD2_DL("scheduler.simple.update", std::bind(&cmd_scheduler_simple_update, std::placeholders::_1));
CMD2_DL("scheduler.simple.added", tr1::bind(&cmd_scheduler_simple_added, tr1::placeholders::_1));
CMD2_DL("scheduler.simple.removed", tr1::bind(&cmd_scheduler_simple_removed, tr1::placeholders::_1));
CMD2_DL("scheduler.simple.update", tr1::bind(&cmd_scheduler_simple_update, tr1::placeholders::_1));
}
+107 -131
View File
@@ -1,10 +1,46 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <cstdio>
#include <rak/address_info.h>
#include <torrent/throttle.h>
#include <torrent/rate.h>
#include <torrent/download/resource_manager.h>
#include <torrent/net/socket_address.h>
#include "core/manager.h"
#include "ui/root.h"
@@ -20,47 +56,35 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
unsigned int prefixWidth, ret;
char dummy;
char host[1024];
torrent::sa_unique_ptr sa;
rak::address_info* ai;
ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy);
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()));
}
if (ret < 1 || rak::address_info::get_address_info(host, PF_INET, SOCK_STREAM, &ai) != 0)
throw torrent::input_error("Could not resolve host.");
uint32_t begin, end;
auto sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
begin = end = sa_addr;
rak::socket_address sa;
sa.copy(*ai->address(), ai->length());
begin = end = sa.sa_inet()->address_h();
rak::address_info::free_address_info(ai);
if (ret == 2) {
if (++itr != args.end())
throw torrent::input_error("Cannot specify both network and range end.");
uint32_t netmask = std::numeric_limits<uint32_t>::max() << (32 - prefixWidth);
if (prefixWidth >= 32 || sa_addr & ~netmask)
if (prefixWidth >= 32 || sa.sa_inet()->address_h() & ~netmask)
throw torrent::input_error("Invalid address/prefix.");
end = sa_addr | ~netmask;
end = sa.sa_inet()->address_h() | ~netmask;
} else if (++itr != args.end()) {
try {
sa = torrent::sa_copy(torrent::sa_lookup_address(itr->as_string(), AF_INET).get());
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.");
} catch (torrent::input_error& e) {
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
}
sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
end = sa_addr;
sa.copy(*ai->address(), ai->length());
rak::address_info::free_address_info(ai);
end = sa.sa_inet()->address_h();
}
// convert to [begin, end) making sure the end doesn't overflow
@@ -70,35 +94,30 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
torrent::Object
apply_throttle(const torrent::Object::list_type& args, bool up) {
auto arg_itr = args.begin();
torrent::Object::list_const_iterator argItr = args.begin();
if (arg_itr == args.end())
throw torrent::input_error("Missing throttle name.");
const std::string& name = arg_itr->as_string();
const std::string& name = argItr->as_string();
if (name.empty() || name == "NULL")
throw torrent::input_error("Invalid throttle name '" + name + "'.");
throw torrent::input_error("Invalid throttle name.");
if (++arg_itr == args.end() || arg_itr->as_string().empty())
throw torrent::input_error("Missing throttle rate for '" + name + "'.");
if ((++argItr)->as_string().empty())
return torrent::Object();
int64_t rate;
rpc::parse_whole_value_nothrow(arg_itr->as_string().c_str(), &rate);
rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate);
if (rate < 0)
throw torrent::input_error("Throttle rate must be non-negative.");
auto itr = control->core()->throttles().find(name);
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
if (itr == control->core()->throttles().end())
itr = control->core()->throttles().insert(std::make_pair(name, core::ThrottlePair(nullptr, nullptr))).first;
itr = control->core()->throttles().insert(std::make_pair(name, torrent::ThrottlePair(NULL, NULL))).first;
auto*& throttle = up ? itr->second.first : itr->second.second;
if (rate != 0 && throttle == nullptr)
torrent::Throttle*& throttle = up ? itr->second.first : itr->second.second;
if (rate != 0 && throttle == NULL)
throttle = (up ? torrent::up_throttle_global() : torrent::down_throttle_global())->create_slave();
if (throttle != nullptr)
if (throttle != NULL)
throttle->set_max_rate(rate * 1024);
return torrent::Object();
@@ -111,10 +130,10 @@ static const int throttle_info_rate = (1 << 3);
torrent::Object
retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
auto itr = control->core()->throttles().find(name);
auto throttles = (itr == control->core()->throttles().end()) ? core::ThrottlePair(nullptr, nullptr) : itr->second;
auto* throttle = flags & throttle_info_down ? throttles.second : throttles.first;
auto* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global();
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
torrent::ThrottlePair throttles = itr == control->core()->throttles().end() ? torrent::ThrottlePair(NULL, NULL) : itr->second;
torrent::Throttle* throttle = flags & throttle_info_down ? throttles.second : throttles.first;
torrent::Throttle* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global();
if (throttle == NULL && name.empty())
throttle = global;
@@ -129,6 +148,20 @@ retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
return (int64_t)throttle->max_rate();
}
torrent::Object
apply_address_throttle(const torrent::Object::list_type& args) {
if (args.size() < 2 || args.size() > 3)
throw torrent::input_error("Incorrect number of arguments.");
std::pair<uint32_t, uint32_t> range = parse_address_range(args, ++args.begin());
core::ThrottleMap::iterator throttleItr = control->core()->throttles().find(args.begin()->as_string().c_str());
if (throttleItr == control->core()->throttles().end())
throw torrent::input_error("Throttle not found.");
control->core()->set_address_throttle(range.first, range.second, throttleItr->second);
return torrent::Object();
}
torrent::Object
throttle_update(const char* variable, int64_t value) {
rpc::commands.call_command(variable, value);
@@ -140,10 +173,8 @@ throttle_update(const char* variable, int64_t value) {
void
initialize_command_throttle() {
CMD2_ANY ("throttle.unchoked_uploads", std::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager()));
CMD2_ANY ("throttle.max_unchoked_uploads", std::bind(&torrent::ResourceManager::max_upload_unchoked, torrent::resource_manager()));
CMD2_ANY ("throttle.unchoked_downloads", std::bind(&torrent::ResourceManager::currently_download_unchoked, torrent::resource_manager()));
CMD2_ANY ("throttle.max_unchoked_downloads", std::bind(&torrent::ResourceManager::max_download_unchoked, torrent::resource_manager()));
CMD2_ANY ("throttle.unchoked_uploads", tr1::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager()));
CMD2_ANY ("throttle.unchoked_downloads", tr1::bind(&torrent::ResourceManager::currently_download_unchoked, torrent::resource_manager()));
CMD2_VAR_VALUE ("throttle.min_peers.normal", 100);
CMD2_VAR_VALUE ("throttle.max_peers.normal", 200);
@@ -160,91 +191,36 @@ initialize_command_throttle() {
CMD2_VAR_VALUE ("throttle.max_downloads.div._val", 1);
CMD2_VAR_VALUE ("throttle.max_downloads.global._val", 0);
CMD2_REDIRECT ("throttle.max_uploads.div", "throttle.max_uploads.div._val");
CMD2_REDIRECT ("throttle.max_uploads.global", "throttle.max_uploads.global._val");
CMD2_REDIRECT ("throttle.max_downloads.div", "throttle.max_downloads.div._val");
CMD2_REDIRECT ("throttle.max_downloads.global", "throttle.max_downloads.global._val");
CMD2_REDIRECT_GENERIC("throttle.max_uploads.div", "throttle.max_uploads.div._val");
CMD2_REDIRECT_GENERIC("throttle.max_uploads.global", "throttle.max_uploads.global._val");
CMD2_REDIRECT_GENERIC("throttle.max_downloads.div", "throttle.max_downloads.div._val");
CMD2_REDIRECT_GENERIC("throttle.max_downloads.global", "throttle.max_downloads.global._val");
CMD2_ANY_VALUE ("throttle.max_uploads.div.set", std::bind(&throttle_update, "throttle.max_uploads.div._val.set", std::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_uploads.global.set", std::bind(&throttle_update, "throttle.max_uploads.global._val.set", std::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_downloads.div.set", std::bind(&throttle_update, "throttle.max_downloads.div._val.set", std::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_downloads.global.set", std::bind(&throttle_update, "throttle.max_downloads.global._val.set", std::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_uploads.div.set", tr1::bind(&throttle_update, "throttle.max_uploads.div._val.set", tr1::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_uploads.global.set", tr1::bind(&throttle_update, "throttle.max_uploads.global._val.set", tr1::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_downloads.div.set", tr1::bind(&throttle_update, "throttle.max_downloads.div._val.set", tr1::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_downloads.global.set", tr1::bind(&throttle_update, "throttle.max_downloads.global._val.set", tr1::placeholders::_2));
// TODO: Move the logic into some libtorrent function.
CMD2_ANY ("throttle.global_up.rate", std::bind(&torrent::Rate::rate, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.total", std::bind(&torrent::Rate::total, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::up_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY ("throttle.global_down.rate", std::bind(&torrent::Rate::rate, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.total", std::bind(&torrent::Rate::total, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::down_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY ("throttle.global_up.rate", tr1::bind(&torrent::Rate::rate, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.total", tr1::bind(&torrent::Rate::total, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.max_rate", tr1::bind(&torrent::Throttle::max_rate, torrent::up_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", tr1::bind(&ui::Root::set_up_throttle_i64, control->ui(), tr1::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", tr1::bind(&ui::Root::set_up_throttle_i64, control->ui(), tr1::placeholders::_2));
CMD2_ANY ("throttle.global_down.rate", tr1::bind(&torrent::Rate::rate, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.total", tr1::bind(&torrent::Rate::total, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.max_rate", tr1::bind(&torrent::Throttle::max_rate, torrent::down_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", tr1::bind(&ui::Root::set_down_throttle_i64, control->ui(), tr1::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", tr1::bind(&ui::Root::set_down_throttle_i64, control->ui(), tr1::placeholders::_2));
// Temporary names, need to change this to accept real rates rather
// than kB.
CMD2_ANY_LIST ("throttle.up", std::bind(&apply_throttle, std::placeholders::_2, true));
CMD2_ANY_LIST ("throttle.down", std::bind(&apply_throttle, std::placeholders::_2, false));
CMD2_ANY_LIST ("throttle.up", tr1::bind(&apply_throttle, tr1::placeholders::_2, true));
CMD2_ANY_LIST ("throttle.down", tr1::bind(&apply_throttle, tr1::placeholders::_2, false));
CMD2_ANY_LIST ("throttle.ip", tr1::bind(&apply_address_throttle, tr1::placeholders::_2));
CMD2_ANY_STRING ("throttle.up.max", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_max));
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");
CMD2_ANY_STRING ("throttle.up.max", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_up | throttle_info_max));
CMD2_ANY_STRING ("throttle.up.rate", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_up | throttle_info_rate));
CMD2_ANY_STRING ("throttle.down.max", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_down | throttle_info_max));
CMD2_ANY_STRING ("throttle.down.rate", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_down | throttle_info_rate));
}
+109 -120
View File
@@ -1,14 +1,46 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <cassert>
#include <cstdio>
#include <netdb.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 <rak/address_info.h>
#include <rak/error_number.h>
#include <torrent/dht_manager.h>
#include <torrent/tracker.h>
#include <torrent/utils/log.h>
#include "core/download.h"
@@ -20,20 +52,37 @@
#include "core/dht_manager.h"
void
tracker_set_enabled(torrent::tracker::Tracker* tracker, bool state) {
tracker_set_enabled(torrent::Tracker* tracker, bool state) {
if (state)
tracker->enable();
else
tracker->disable();
}
struct call_add_node_t {
call_add_node_t(int port) : m_port(port) { }
void operator() (const sockaddr* sa, int err) {
if (sa == NULL) {
lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host.");
} else {
torrent::dht_manager()->add_node(sa, m_port);
}
}
int m_port;
};
torrent::Object
apply_dht_add_node(const std::string& arg) {
int port;
if (!torrent::dht_manager()->is_valid())
throw torrent::input_error("DHT not enabled.");
int port, ret;
char dummy;
char host[1024];
int ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
if (ret == 1)
port = 6881;
@@ -43,138 +92,78 @@ 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_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(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::runtime::network_manager()->dht_add_bootstrap_node(host_str.c_str(), port);
});
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port));
return torrent::Object();
}
torrent::Object
apply_enable_trackers(int64_t arg) {
if (arg == 0) {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) {
std::for_each((*itr)->tracker_list()->begin(), (*itr)->tracker_list()->end(),
arg ? std::mem_fun(&torrent::Tracker::enable) : std::mem_fun(&torrent::Tracker::disable));
} else {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
}
if (arg && !rpc::call_command_value("trackers.use_udp"))
(*itr)->enable_udp_trackers(false);
}
return torrent::Object();
}
void
initialize_command_tracker() {
CMD2_TRACKER ("t.is_busy", [](auto* tracker, auto) { return tracker->is_requesting(); });
CMD2_TRACKER ("t.is_enabled", [](auto* tracker, auto) { return tracker->is_enabled(); });
CMD2_TRACKER ("t.is_extra_tracker", [](auto* tracker, auto) { return tracker->is_extra_tracker(); });
CMD2_TRACKER ("t.is_open", [](auto* tracker, auto) { return tracker->is_requesting(); });
CMD2_TRACKER ("t.is_scrapable", [](auto* tracker, auto) { return tracker->is_scrapable(); });
CMD2_TRACKER ("t.is_usable", [](auto* tracker, auto) { return tracker->is_usable(); });
CMD2_TRACKER ("t.is_open", tr1::bind(&torrent::Tracker::is_busy, tr1::placeholders::_1));
CMD2_TRACKER ("t.is_enabled", tr1::bind(&torrent::Tracker::is_enabled, tr1::placeholders::_1));
CMD2_TRACKER ("t.is_usable", tr1::bind(&torrent::Tracker::is_usable, tr1::placeholders::_1));
CMD2_TRACKER ("t.is_busy", tr1::bind(&torrent::Tracker::is_busy, tr1::placeholders::_1));
CMD2_TRACKER ("t.is_extra_tracker", tr1::bind(&torrent::Tracker::is_extra_tracker, tr1::placeholders::_1));
CMD2_TRACKER ("t.can_scrape", tr1::bind(&torrent::Tracker::can_scrape, tr1::placeholders::_1));
// TODO: Deprecate.
CMD2_TRACKER ("t.can_scrape", [](auto* tracker, auto) { return tracker->is_scrapable(); });
CMD2_TRACKER_V ("t.enable", tr1::bind(&torrent::Tracker::enable, tr1::placeholders::_1));
CMD2_TRACKER_V ("t.disable", tr1::bind(&torrent::Tracker::disable, tr1::placeholders::_1));
CMD2_TRACKER_V ("t.enable", [](auto* tracker, auto) { tracker->enable(); });
CMD2_TRACKER_V ("t.disable", [](auto* tracker, auto) { tracker->disable(); });
CMD2_TRACKER_VALUE_V("t.is_enabled.set", tr1::bind(&tracker_set_enabled, tr1::placeholders::_1, tr1::placeholders::_2));
CMD2_TRACKER_VALUE_V("t.is_enabled.set", [](auto* tracker, auto& value) { return tracker_set_enabled(tracker, value); });
CMD2_TRACKER ("t.url", tr1::bind(&torrent::Tracker::url, tr1::placeholders::_1));
CMD2_TRACKER ("t.group", tr1::bind(&torrent::Tracker::group, tr1::placeholders::_1));
CMD2_TRACKER ("t.type", tr1::bind(&torrent::Tracker::type, tr1::placeholders::_1));
CMD2_TRACKER ("t.id", tr1::bind(&torrent::Tracker::tracker_id, tr1::placeholders::_1));
CMD2_TRACKER ("t.url", [](auto* tracker, auto) { return tracker->url(); });
CMD2_TRACKER ("t.group", [](auto* tracker, auto) { return tracker->group(); });
CMD2_TRACKER ("t.type", [](auto* tracker, auto) { return tracker->type(); });
CMD2_TRACKER ("t.id", [](auto* tracker, auto) { return tracker->tracker_id(); });
CMD2_TRACKER ("t.latest_event", tr1::bind(&torrent::Tracker::latest_event, tr1::placeholders::_1));
CMD2_TRACKER ("t.latest_new_peers", tr1::bind(&torrent::Tracker::latest_new_peers, tr1::placeholders::_1));
CMD2_TRACKER ("t.latest_sum_peers", tr1::bind(&torrent::Tracker::latest_sum_peers, tr1::placeholders::_1));
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(); });
// Time since last connection, connection attempt.
CMD2_TRACKER ("t.normal_interval", [](auto* tracker, auto) { return tracker->state().normal_interval().count(); });
CMD2_TRACKER ("t.min_interval", [](auto* tracker, auto) { return tracker->state().min_interval().count(); });
CMD2_TRACKER ("t.normal_interval", tr1::bind(&torrent::Tracker::normal_interval, tr1::placeholders::_1));
CMD2_TRACKER ("t.min_interval", tr1::bind(&torrent::Tracker::min_interval, tr1::placeholders::_1));
CMD2_TRACKER ("t.activity_time_next", [](auto* tracker, auto) { return tracker->state().activity_time_next().count(); });
CMD2_TRACKER ("t.activity_time_last", [](auto* tracker, auto) { return tracker->state().activity_time_last().count(); });
CMD2_TRACKER ("t.activity_time_next", tr1::bind(&torrent::Tracker::activity_time_next, tr1::placeholders::_1));
CMD2_TRACKER ("t.activity_time_last", tr1::bind(&torrent::Tracker::activity_time_last, tr1::placeholders::_1));
CMD2_TRACKER ("t.success_time_next", [](auto* tracker, auto) { return tracker->state().success_time_next().count(); });
CMD2_TRACKER ("t.success_time_last", [](auto* tracker, auto) { return tracker->state().success_time_last().count(); });
CMD2_TRACKER ("t.success_counter", [](auto* tracker, auto) { return tracker->state().success_counter(); });
CMD2_TRACKER ("t.success_time_next", tr1::bind(&torrent::Tracker::success_time_next, tr1::placeholders::_1));
CMD2_TRACKER ("t.success_time_last", tr1::bind(&torrent::Tracker::success_time_last, tr1::placeholders::_1));
CMD2_TRACKER ("t.success_counter", tr1::bind(&torrent::Tracker::success_counter, tr1::placeholders::_1));
CMD2_TRACKER ("t.failed_time_next", [](auto* tracker, auto) { return tracker->state().failed_time_next().count(); });
CMD2_TRACKER ("t.failed_time_last", [](auto* tracker, auto) { return tracker->state().failed_time_last().count(); });
CMD2_TRACKER ("t.failed_counter", [](auto* tracker, auto) { return tracker->state().failed_counter(); });
CMD2_TRACKER ("t.failed_time_next", tr1::bind(&torrent::Tracker::failed_time_next, tr1::placeholders::_1));
CMD2_TRACKER ("t.failed_time_last", tr1::bind(&torrent::Tracker::failed_time_last, tr1::placeholders::_1));
CMD2_TRACKER ("t.failed_counter", tr1::bind(&torrent::Tracker::failed_counter, tr1::placeholders::_1));
CMD2_TRACKER ("t.scrape_time_last", [](auto* tracker, auto) { return tracker->state().scrape_time_last().count(); });
CMD2_TRACKER ("t.scrape_counter", [](auto* tracker, auto) { return tracker->state().scrape_counter(); });
CMD2_TRACKER ("t.scrape_time_last", tr1::bind(&torrent::Tracker::scrape_time_last, tr1::placeholders::_1));
CMD2_TRACKER ("t.scrape_counter", tr1::bind(&torrent::Tracker::scrape_counter, tr1::placeholders::_1));
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_TRACKER ("t.scrape_complete", tr1::bind(&torrent::Tracker::scrape_complete, tr1::placeholders::_1));
CMD2_TRACKER ("t.scrape_incomplete", tr1::bind(&torrent::Tracker::scrape_incomplete, tr1::placeholders::_1));
CMD2_TRACKER ("t.scrape_downloaded", tr1::bind(&torrent::Tracker::scrape_downloaded, tr1::placeholders::_1));
CMD2_ANY_VALUE ("trackers.enable", [](auto, auto) { return apply_enable_trackers(1); });
CMD2_ANY_VALUE ("trackers.disable", [](auto, auto) { return apply_enable_trackers(0); });
CMD2_VAR_BOOL ("trackers.delay_scrape", false);
CMD2_VAR_VALUE ("trackers.numwant", -1);
CMD2_ANY_VALUE ("trackers.enable", tr1::bind(&apply_enable_trackers, int64_t(1)));
CMD2_ANY_VALUE ("trackers.disable", tr1::bind(&apply_enable_trackers, int64_t(0)));
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);
})
CMD2_ANY_STRING_V ("dht.mode.set", [](auto, auto& str) { return control->dht_manager()->set_mode_by_user(str); });
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", [](auto, auto) { return torrent::runtime::network_config()->override_dht_port(); });
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_dht_port(value); });
CMD2_ANY_STRING ("dht.add_node", [](auto, auto& str) { return apply_dht_add_node(str); });
CMD2_ANY ("dht.statistics", [](auto, auto) { return control->dht_manager()->dht_statistics(); });
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");
CMD2_ANY_STRING_V ("dht.mode.set", tr1::bind(&core::DhtManager::set_mode, control->dht_manager(), tr1::placeholders::_2));
CMD2_VAR_VALUE ("dht.port", int64_t(6881));
CMD2_ANY_STRING ("dht.add_node", tr1::bind(&apply_dht_add_node, tr1::placeholders::_2));
CMD2_ANY ("dht.statistics", tr1::bind(&core::DhtManager::dht_statistics, control->dht_manager()));
CMD2_ANY ("dht.throttle.name", tr1::bind(&core::DhtManager::throttle_name, control->dht_manager()));
CMD2_ANY_STRING_V ("dht.throttle.name.set", tr1::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), tr1::placeholders::_2));
}
+125 -484
View File
@@ -1,17 +1,51 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <sys/types.h>
#include <ctime>
#include <regex>
#include <torrent/utils/log.h>
#include <rak/functional.h>
#include <rak/functional_fun.h>
#include "core/manager.h"
#include "core/view_manager.h"
#include "display/canvas.h"
#include "ui/root.h"
#include "ui/download_list.h"
#include "display/color_map.h"
#include "rpc/parse.h"
#include "globals.h"
@@ -26,7 +60,7 @@ apply_view_filter_on(const torrent::Object::list_type& args) {
throw torrent::input_error("Too few arguments.");
const std::string& name = args.front().as_string();
if (name.empty())
throw torrent::input_error("First argument must be a string.");
@@ -74,8 +108,8 @@ apply_view_list() {
torrent::Object rawResult = torrent::Object::create_list();
torrent::Object::list_type& result = rawResult.as_list();
for (auto itr : *control->view_manager())
result.push_back(itr->name());
for (core::ViewManager::const_iterator itr = control->view_manager()->begin(), last = control->view_manager()->end(); itr != last; itr++)
result.push_back((*itr)->name());
return rawResult;
}
@@ -93,12 +127,11 @@ apply_view_set(const torrent::Object::list_type& args) {
// if (args.front().as_string() == "main")
// control->ui()->download_list()->set_view(*itr);
// else
throw torrent::input_error("No such target.");
throw torrent::input_error("No such target.");
}
torrent::Object
apply_print([[maybe_unused]] rpc::target_type target, const torrent::Object& rawArgs) {
apply_print(rpc::target_type target, const torrent::Object& rawArgs) {
char buffer[1024];
rpc::print_object(buffer, buffer + 1024, &rawArgs, 0);
@@ -107,48 +140,13 @@ apply_print([[maybe_unused]] rpc::target_type target, const torrent::Object& raw
}
torrent::Object
apply_cat([[maybe_unused]] rpc::target_type target, const torrent::Object& rawArgs) {
apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
std::string result;
rpc::print_object_std(&result, &rawArgs, 0);
return result;
}
torrent::Object
apply_value([[maybe_unused]] rpc::target_type target, const torrent::Object::list_type& args) {
if (args.size() < 1)
throw torrent::input_error("'value' takes at least a number argument!");
if (args.size() > 2)
throw torrent::input_error("'value' takes at most two arguments!");
torrent::Object::value_type val = 0;
if (args.front().is_value()) {
val = args.front().as_value();
} else {
int base = args.size() > 1 ? args.back().is_value() ?
args.back().as_value() : strtol(args.back().as_string().c_str(), NULL, 10) : 10;
char* endptr = 0;
val = strtoll(args.front().as_string().c_str(), &endptr, base);
while (*endptr == ' ' || *endptr == '\n') ++endptr;
if (*endptr)
throw torrent::input_error("Junk at end of number: " + args.front().as_string());
}
return val;
}
torrent::Object
apply_try(rpc::target_type target, const torrent::Object& args) {
try {
return rpc::call_object(args, target);
} catch (torrent::input_error& e) {
lt_log_print(torrent::LOG_RPC_EVENTS, "try command caught input_error: %s", e.what());
}
return torrent::Object();
}
// Move these boolean operators to a new file.
inline bool
@@ -183,7 +181,7 @@ apply_not(rpc::target_type target, const torrent::Object& rawArgs) {
}
torrent::Object
apply_false([[maybe_unused]] rpc::target_type target, [[maybe_unused]] const torrent::Object& rawArgs) {
apply_false(rpc::target_type target, const torrent::Object& rawArgs) {
return (int64_t)0;
}
@@ -192,18 +190,18 @@ apply_and(rpc::target_type target, const torrent::Object& rawArgs) {
if (rawArgs.type() != torrent::Object::TYPE_LIST)
return as_boolean(rawArgs);
for (const auto& itr : rawArgs.as_list())
if (itr.is_dict_key()) {
if (!as_boolean(rpc::commands.call_command(itr.as_dict_key().c_str(), itr.as_dict_obj(), target)))
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
if (itr->is_dict_key()) {
if (!as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
return (int64_t)false;
} else if (itr.is_value()) {
if (!itr.as_value())
} else if (itr->is_value()) {
if (!itr->as_value())
return (int64_t)false;
} else {
} else {
// TODO: Switch to new versions that only accept the new command syntax.
if (!as_boolean(rpc::parse_command_single(target, itr.as_string())))
if (!as_boolean(rpc::parse_command_single(target, itr->as_string())))
return (int64_t)false;
}
@@ -215,17 +213,17 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) {
if (rawArgs.type() != torrent::Object::TYPE_LIST)
return as_boolean(rawArgs);
for (const auto& itr : rawArgs.as_list())
if (itr.is_dict_key()) {
if (as_boolean(rpc::commands.call_command(itr.as_dict_key().c_str(), itr.as_dict_obj(), target)))
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
if (itr->is_dict_key()) {
if (as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
return (int64_t)true;
} else if (itr.is_value()) {
if (itr.as_value())
} else if (itr->is_value()) {
if (itr->as_value())
return (int64_t)true;
} else {
if (as_boolean(rpc::parse_command_single(target, itr.as_string())))
} else {
if (as_boolean(rpc::parse_command_single(target, itr->as_string())))
return (int64_t)true;
}
@@ -261,7 +259,7 @@ apply_cmp(rpc::target_type target, const torrent::Object::list_type& args) {
if (result1.type() != result2.type())
throw torrent::input_error("Type mismatch.");
switch (result1.type()) {
case torrent::Object::TYPE_VALUE: return result1.as_value() - result2.as_value();
case torrent::Object::TYPE_STRING: return result1.as_string().compare(result2.as_string());
@@ -284,103 +282,6 @@ torrent::Object apply_equal(rpc::target_type target, const torrent::Object::list
return result.is_value() ? result.as_value() == 0 : (int64_t)false;
}
torrent::Object
apply_compare(rpc::target_type target, const torrent::Object::list_type& args) {
if (!rpc::is_target_pair(target))
throw torrent::input_error("Can only compare a target pair.");
if (args.size() < 2)
throw torrent::input_error("Need at least order and one field.");
torrent::Object::list_const_iterator itr = args.begin();
std::string order = (itr++)->as_string();
const char* current = order.c_str();
torrent::Object result1;
torrent::Object result2;
for (torrent::Object::list_const_iterator last = args.end(); itr != last; itr++) {
std::string field = itr->as_string();
result1 = rpc::parse_command_single(rpc::get_target_left(target), field);
result2 = rpc::parse_command_single(rpc::get_target_right(target), field);
if (result1.type() != result2.type())
throw torrent::input_error(std::string("Type mismatch in compare of ") + field);
bool descending = *current == 'd' || *current == 'D' || *current == '-';
if (*current) {
if (!descending && !(*current == 'a' || *current == 'A' || *current == '+'))
throw torrent::input_error(std::string("Bad order '") + *current + "' in " + order);
++current;
}
switch (result1.type()) {
case torrent::Object::TYPE_VALUE:
if (result1.as_value() != result2.as_value())
return (int64_t) (descending ^ (result1.as_value() < result2.as_value()));
break;
case torrent::Object::TYPE_STRING:
if (result1.as_string() != result2.as_string())
return (int64_t) (descending ^ (result1.as_string() < result2.as_string()));
break;
default:
break; // treat unknown types as equal
}
}
// if all else is equal, ensure stable sort order based on memory location
return (int64_t) (target.second < target.third);
}
// Regexp based 'match' function.
// arg1: the text to match.
// arg2: the regexp pattern.
// eg: match{d.name=,.*linux.*iso}
torrent::Object apply_match(rpc::target_type target, const torrent::Object::list_type& args) {
if (args.size() != 2)
throw torrent::input_error("Wrong argument count for 'match': 2 arguments needed.");
// This really should be converted to using args flagged as
// commands, so that we can compare commands and statics values.
torrent::Object result1;
torrent::Object result2;
rpc::target_type target1 = rpc::is_target_pair(target) ? rpc::get_target_left(target) : target;
rpc::target_type target2 = rpc::is_target_pair(target) ? rpc::get_target_right(target) : target;
if (args.front().is_dict_key())
result1 = rpc::commands.call_command(args.front().as_dict_key().c_str(), args.front().as_dict_obj(), target1);
else
result1 = rpc::parse_command_single(target1, args.front().as_string());
if (args.back().is_dict_key())
result2 = rpc::commands.call_command(args.back().as_dict_key().c_str(), args.back().as_dict_obj(), target2);
else
result2 = args.back().as_string();
if (result1.type() != result2.type())
throw torrent::input_error("Type mismatch for 'match' arguments.");
std::string text = result1.as_string();
std::string pattern = result2.as_string();
std::transform(text.begin(), text.end(), text.begin(), ::tolower);
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
bool isAMatch = false;
try {
std::regex re(pattern);
isAMatch = std::regex_match(text, re);
} catch (const std::regex_error& exc) {
control->core()->push_log_std("regex_error: " + std::string(exc.what()));
}
return isAMatch ? (int64_t)true : (int64_t)false;
}
torrent::Object
apply_to_time(const torrent::Object& rawArgs, int flags) {
std::tm *u;
@@ -390,7 +291,7 @@ apply_to_time(const torrent::Object& rawArgs, int flags) {
u = std::localtime(&t);
else
u = std::gmtime(&t);
if (u == NULL)
return torrent::Object();
@@ -406,9 +307,7 @@ apply_to_time(const torrent::Object& rawArgs, int flags) {
torrent::Object
apply_to_elapsed_time(const torrent::Object& rawArgs) {
auto cached_seconds = torrent::this_thread::cached_seconds().count();
uint64_t arg = cached_seconds - rawArgs.as_value();
uint64_t arg = cachedTime.seconds() - rawArgs.as_value();
char buffer[48];
snprintf(buffer, 48, "%2d:%02d:%02d", (int)(arg / 3600), (int)((arg / 60) % 60), (int)(arg % 60));
@@ -435,7 +334,7 @@ apply_to_mb(const torrent::Object& rawArgs) {
torrent::Object
apply_to_xb(const torrent::Object& rawArgs) {
char buffer[48];
int64_t arg = rawArgs.as_value();
int64_t arg = rawArgs.as_value();
if (arg < (int64_t(1000) << 10))
snprintf(buffer, 48, "%5.1f KB", (double)arg / (int64_t(1) << 10));
@@ -451,7 +350,7 @@ apply_to_xb(const torrent::Object& rawArgs) {
torrent::Object
apply_to_throttle(const torrent::Object& rawArgs) {
int64_t arg = rawArgs.as_value();
int64_t arg = rawArgs.as_value();
if (arg < 0)
return "---";
else if (arg == 0)
@@ -472,14 +371,11 @@ apply_to_throttle(const torrent::Object& rawArgs) {
// if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 }
// <cond1>,<branch1>,<cond2>,<branch2>,<branch3>
torrent::Object
apply_if(rpc::target_type target, const torrent::Object& raw_args, int flags) {
auto& args = raw_args.as_list();
auto itr = args.begin();
apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
const torrent::Object::list_type& args = rawArgs.as_list();
torrent::Object::list_const_iterator itr = args.begin();
if (args.empty())
throw torrent::input_error("Empty argument list to " + std::string((flags & 0x1) ? "branch" : "if") + ".");
{
while (itr != args.end() && itr != --args.end()) {
torrent::Object tmp;
const torrent::Object* conditional;
@@ -503,44 +399,40 @@ apply_if(rpc::target_type target, const torrent::Object& raw_args, int flags) {
result = false;
break;
default:
throw torrent::input_error("Type not supported by " + std::string((flags & 0x1) ? "branch" : "if") + ".");
throw torrent::input_error("Type not supported by 'if'.");
};
itr++;
if (!result && itr != args.end())
itr++;
if (result)
break;
itr++;
}
if (itr == args.end())
return torrent::Object();
if (flags & 0x1) {
if (itr->is_string())
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
if (flags & 0x1 && itr->is_string()) {
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
if (itr->is_dict_key())
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
} else if (flags & 0x1 && itr->is_dict_key()) {
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
if (itr->is_list()) {
for (const auto& cmd_itr : itr->as_list()) {
if (cmd_itr.is_string())
rpc::parse_command(target, cmd_itr.as_string().c_str(), cmd_itr.as_string().c_str() + cmd_itr.as_string().size());
} else if (flags & 0x1 && itr->is_list()) {
// Move this into a special function or something. Also, might be
// nice to have a parse_command function that takes list
// iterator...
else if (cmd_itr.is_dict_key())
rpc::commands.call_command(cmd_itr.as_dict_key().c_str(), cmd_itr.as_dict_obj(), target);
for (torrent::Object::list_type::const_iterator cmdItr = itr->as_list().begin(), last = itr->as_list().end(); cmdItr != last; cmdItr++)
if (cmdItr->is_string())
rpc::parse_command(target, cmdItr->as_string().c_str(), cmdItr->as_string().c_str() + cmdItr->as_string().size());
else
throw torrent::input_error("Invalid command type in branch list.");
}
return torrent::Object();
return torrent::Object();
}
throw torrent::input_error("Invalid command type in branch.");
} else {
return *itr;
}
return *itr;
}
torrent::Object
@@ -556,7 +448,7 @@ cmd_view_size_not_visible(const torrent::Object::string_type& args) {
torrent::Object
cmd_view_persistent(const torrent::Object::string_type& args) {
core::View* view = *control->view_manager()->find_throw(args);
if (!view->get_filter().is_empty() || !view->event_added().is_empty() || !view->event_removed().is_empty())
throw torrent::input_error("Cannot set modified views as persitent.");
@@ -574,11 +466,6 @@ cmd_ui_set_view(const torrent::Object::string_type& args) {
return torrent::Object();
}
torrent::Object
cmd_ui_current_view() {
return control->ui()->download_list()->current_view()->name();
}
torrent::Object
cmd_ui_unfocus_download(core::Download* download) {
control->ui()->download_list()->unfocus_download(download);
@@ -613,9 +500,8 @@ apply_elapsed_less(const torrent::Object::list_type& args) {
throw torrent::input_error("Wrong argument count.");
int64_t start_time = rpc::convert_to_value(args.front());
auto cached_seconds = torrent::this_thread::cached_seconds().count();
return (int64_t)(start_time != 0 && cached_seconds - start_time < rpc::convert_to_value(args.back()));
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time < rpc::convert_to_value(args.back()));
}
torrent::Object
@@ -624,244 +510,49 @@ apply_elapsed_greater(const torrent::Object::list_type& args) {
throw torrent::input_error("Wrong argument count.");
int64_t start_time = rpc::convert_to_value(args.front());
auto cached_seconds = torrent::this_thread::cached_seconds().count();
return (int64_t)(start_time != 0 && cached_seconds - start_time > rpc::convert_to_value(args.back()));
}
inline std::vector<int64_t>
as_vector(const torrent::Object::list_type& args) {
if (args.size() == 0)
throw torrent::input_error("Wrong argument count in as_vector.");
std::vector<int64_t> result;
for (const auto& arg : args) {
if (arg.is_value()) {
result.push_back(arg.as_value());
} else if (arg.is_string()) {
result.push_back(rpc::convert_to_value(arg.as_string()));
} else if (arg.is_list()) {
std::vector<int64_t> subResult = as_vector(arg.as_list());
result.insert(result.end(), subResult.begin(), subResult.end());
} else {
throw torrent::input_error("Wrong type supplied to as_vector.");
}
}
return result;
}
template <typename Comp>
int64_t
apply_math_basic(const char* name, Comp op, const torrent::Object::list_type& args) {
int64_t val = 0, rhs = 0;
bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod");
if (args.size() == 0)
throw torrent::input_error(std::string(name) + ": No arguments provided!");
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
if (itr->is_value()) {
rhs = itr->as_value();
} else if (itr->is_string()) {
rhs = rpc::convert_to_value(itr->as_string());
} else if (itr->is_list()) {
rhs = apply_math_basic(name, op, itr->as_list());
} else {
throw torrent::input_error(std::string(name) + ": Wrong argument type");
}
if (divides && !rhs && itr != args.begin())
throw torrent::input_error(std::string(name) + ": Division by zero!");
val = itr == args.begin() ? rhs : op(val, rhs);
}
return val;
}
template <typename Comp>
int64_t
apply_arith_basic(Comp op, const torrent::Object::list_type& args) {
if (args.size() == 0)
throw torrent::input_error("Wrong argument count in apply_arith_basic.");
int64_t val = 0;
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
if (itr->is_value()) {
val = itr == args.begin() ? itr->as_value() : (op(val, itr->as_value()) ? val : itr->as_value());
} else if (itr->is_string()) {
int64_t cval = rpc::convert_to_value(itr->as_string());
val = itr == args.begin() ? cval : (op(val, cval) ? val : cval);
} else if (itr->is_list()) {
int64_t fval = apply_arith_basic(op, itr->as_list());
val = itr == args.begin() ? fval : (op(val, fval) ? val : fval);
} else {
throw torrent::input_error("Wrong type supplied to apply_arith_basic.");
}
}
return val;
}
int64_t
apply_arith_count(const torrent::Object::list_type& args) {
if (args.size() == 0)
throw torrent::input_error("Wrong argument count in apply_arith_count.");
int64_t val = 0;
for (const auto& arg : args) {
switch (arg.type()) {
case torrent::Object::TYPE_VALUE:
case torrent::Object::TYPE_STRING:
val++;
break;
case torrent::Object::TYPE_LIST:
val += apply_arith_count(arg.as_list());
break;
default:
throw torrent::input_error("Wrong type supplied to apply_arith_count.");
}
}
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)
throw torrent::input_error("Wrong argument count in apply_arith_other.");
if (strcmp(op, "average") == 0) {
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)median(result.begin(), result.end());
} else {
throw torrent::input_error("Wrong operation supplied to apply_arith_other.");
}
}
torrent::Object
cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
if (args.size() == 0)
return torrent::Object();
std::vector<std::string> throttle_name_list;
for (const auto& arg : args) {
if (arg.is_string())
throttle_name_list.push_back(arg.as_string());
}
if (up)
control->ui()->set_status_throttle_up_names(throttle_name_list);
else
control->ui()->set_status_throttle_down_names(throttle_name_list);
return torrent::Object();
}
torrent::Object
apply_set_color(int color_id, const torrent::Object::string_type& color_str) {
control->object_storage()->set_str_string(display::color_vars[color_id], color_str);
display::Canvas::build_colors();
return torrent::Object();
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back()));
}
void
initialize_command_ui() {
CMD2_VAR_STRING ("keys.layout", "qwerty");
CMD2_VAR_STRING("keys.layout", "qwerty");
CMD2_ANY_STRING ("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2)));
CMD2_ANY_STRING("view.add", object_convert_void(tr1::bind(&core::ViewManager::insert_throw, control->view_manager(), tr1::placeholders::_2)));
CMD2_ANY_L ("view.list", std::bind(&apply_view_list));
CMD2_ANY_LIST ("view.set", std::bind(&apply_view_set, std::placeholders::_2));
CMD2_ANY_L ("view.list", tr1::bind(&apply_view_list));
CMD2_ANY_LIST("view.set", tr1::bind(&apply_view_set, tr1::placeholders::_2));
CMD2_ANY_LIST ("view.filter", std::bind(&apply_view_event, &core::ViewManager::set_filter, std::placeholders::_2));
CMD2_ANY_LIST ("view.filter_on", std::bind(&apply_view_filter_on, std::placeholders::_2));
CMD2_ANY_LIST ("view.filter.temp", std::bind(&apply_view_event, &core::ViewManager::set_filter_temp, std::placeholders::_2));
CMD2_VAR_STRING ("view.filter.temp.excluded", "default,started,stopped");
CMD2_VAR_BOOL ("view.filter.temp.log", 0);
CMD2_ANY_LIST("view.filter", tr1::bind(&apply_view_event, &core::ViewManager::set_filter, tr1::placeholders::_2));
CMD2_ANY_LIST("view.filter_on", tr1::bind(&apply_view_filter_on, tr1::placeholders::_2));
CMD2_ANY_LIST ("view.sort", std::bind(&apply_view_sort, std::placeholders::_2));
CMD2_ANY_LIST ("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2));
CMD2_ANY_LIST ("view.sort_current", std::bind(&apply_view_event, &core::ViewManager::set_sort_current, std::placeholders::_2));
CMD2_ANY_LIST("view.sort", tr1::bind(&apply_view_sort, tr1::placeholders::_2));
CMD2_ANY_LIST("view.sort_new", tr1::bind(&apply_view_event, &core::ViewManager::set_sort_new, tr1::placeholders::_2));
CMD2_ANY_LIST("view.sort_current", tr1::bind(&apply_view_event, &core::ViewManager::set_sort_current, tr1::placeholders::_2));
CMD2_ANY_LIST ("view.event_added", std::bind(&apply_view_event, &core::ViewManager::set_event_added, std::placeholders::_2));
CMD2_ANY_LIST ("view.event_removed", std::bind(&apply_view_event, &core::ViewManager::set_event_removed, std::placeholders::_2));
CMD2_ANY_LIST("view.event_added", tr1::bind(&apply_view_event, &core::ViewManager::set_event_added, tr1::placeholders::_2));
CMD2_ANY_LIST("view.event_removed", tr1::bind(&apply_view_event, &core::ViewManager::set_event_removed, tr1::placeholders::_2));
CMD2_ANY_STRING ("view.size", std::bind(&cmd_view_size, std::placeholders::_2));
CMD2_ANY_STRING ("view.size_not_visible", std::bind(&cmd_view_size_not_visible, std::placeholders::_2));
CMD2_ANY_STRING ("view.persistent", std::bind(&cmd_view_persistent, std::placeholders::_2));
// Cleanup and add . to view.
CMD2_ANY_STRING_V("view.filter_all", std::bind(&core::View::filter, std::bind(&core::ViewManager::find_ptr_throw, control->view_manager(), std::placeholders::_2)));
CMD2_ANY_STRING("view.size", tr1::bind(&cmd_view_size, tr1::placeholders::_2));
CMD2_ANY_STRING("view.size_not_visible", tr1::bind(&cmd_view_size_not_visible, tr1::placeholders::_2));
CMD2_ANY_STRING("view.persistent", tr1::bind(&cmd_view_persistent, tr1::placeholders::_2));
CMD2_DL_STRING ("view.filter_download", std::bind(&cmd_view_filter_download, std::placeholders::_1, std::placeholders::_2));
CMD2_DL_STRING ("view.set_visible", std::bind(&cmd_view_set_visible, std::placeholders::_1, std::placeholders::_2));
CMD2_DL_STRING ("view.set_not_visible", std::bind(&cmd_view_set_not_visible, std::placeholders::_1, std::placeholders::_2));
CMD2_ANY_STRING_V("view.filter_all", tr1::bind(&core::View::filter, tr1::bind(&core::ViewManager::find_ptr_throw, control->view_manager(), tr1::placeholders::_2)));
CMD2_DL_STRING ("view.filter_download", tr1::bind(&cmd_view_filter_download, tr1::placeholders::_1, tr1::placeholders::_2));
CMD2_DL_STRING ("view.set_visible", tr1::bind(&cmd_view_set_visible, tr1::placeholders::_1, tr1::placeholders::_2));
CMD2_DL_STRING ("view.set_not_visible", tr1::bind(&cmd_view_set_not_visible, tr1::placeholders::_1, tr1::placeholders::_2));
// Commands that affect the default rtorrent UI.
CMD2_DL ("ui.unfocus_download", std::bind(&cmd_ui_unfocus_download, std::placeholders::_1));
CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view));
CMD2_ANY_STRING ("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2));
CMD2_ANY ("ui.input.history.size", std::bind(&ui::Root::get_input_history_size, control->ui()));
CMD2_ANY_VALUE_V ("ui.input.history.size.set", std::bind(&ui::Root::set_input_history_size, control->ui(), std::placeholders::_2));
CMD2_ANY_V ("ui.input.history.clear", std::bind(&ui::Root::clear_input_history, control->ui()));
CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5);
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
CMD2_VAR_VALUE ("ui.focus.page_size", 0);
CMD2_ANY_LIST ("ui.status.throttle.up.set", std::bind(&cmd_status_throttle_names, true, std::placeholders::_2));
CMD2_ANY_LIST ("ui.status.throttle.down.set", std::bind(&cmd_status_throttle_names, false, std::placeholders::_2));
CMD2_ANY ("ui.keymap.style", std::bind(&ui::Root::keymap_style, control->ui()));
CMD2_ANY_STRING_V("ui.keymap.style.set", std::bind(&ui::Root::set_keymap_style, control->ui(), std::placeholders::_2));
// TODO: Add 'option_string' for rtorrent-specific options.
CMD2_VAR_STRING ("ui.torrent_list.layout", "full");
CMD2_DL ("ui.unfocus_download", tr1::bind(&cmd_ui_unfocus_download, tr1::placeholders::_1));
CMD2_ANY_STRING("ui.current_view.set", tr1::bind(&cmd_ui_set_view, tr1::placeholders::_2));
// Move.
CMD2_ANY("print", &apply_print);
CMD2_ANY("cat", &apply_cat);
CMD2_ANY_LIST("value", &apply_value);
CMD2_ANY("try", &apply_try);
CMD2_ANY("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0));
CMD2_ANY("if", tr1::bind(&apply_if, tr1::placeholders::_1, tr1::placeholders::_2, 0));
CMD2_ANY("not", &apply_not);
CMD2_ANY("false", &apply_false);
CMD2_ANY("and", &apply_and);
@@ -869,72 +560,22 @@ initialize_command_ui() {
// A temporary command for handling stuff until we get proper
// support for seperation of commands and literals.
CMD2_ANY("branch", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 1));
CMD2_ANY("branch", tr1::bind(&apply_if, tr1::placeholders::_1, tr1::placeholders::_2, 1));
CMD2_ANY_LIST("less", &apply_less);
CMD2_ANY_LIST("greater", &apply_greater);
CMD2_ANY_LIST("equal", &apply_equal);
CMD2_ANY_LIST("compare", &apply_compare);
CMD2_ANY_LIST("match", &apply_match);
CMD2_ANY_VALUE("convert.gm_time", std::bind(&apply_to_time, std::placeholders::_2, 0));
CMD2_ANY_VALUE("convert.gm_date", std::bind(&apply_to_time, std::placeholders::_2, 0x2));
CMD2_ANY_VALUE("convert.time", std::bind(&apply_to_time, std::placeholders::_2, 0x1));
CMD2_ANY_VALUE("convert.date", std::bind(&apply_to_time, std::placeholders::_2, 0x1 | 0x2));
CMD2_ANY_VALUE("convert.elapsed_time", std::bind(&apply_to_elapsed_time, std::placeholders::_2));
CMD2_ANY_VALUE("convert.kb", std::bind(&apply_to_kb, std::placeholders::_2));
CMD2_ANY_VALUE("convert.mb", std::bind(&apply_to_mb, std::placeholders::_2));
CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2));
CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2));
CMD2_ANY_VALUE("convert.gm_time", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0));
CMD2_ANY_VALUE("convert.gm_date", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x2));
CMD2_ANY_VALUE("convert.time", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x1));
CMD2_ANY_VALUE("convert.date", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x1 | 0x2));
CMD2_ANY_VALUE("convert.elapsed_time", tr1::bind(&apply_to_elapsed_time, tr1::placeholders::_2));
CMD2_ANY_VALUE("convert.kb", tr1::bind(&apply_to_kb, tr1::placeholders::_2));
CMD2_ANY_VALUE("convert.mb", tr1::bind(&apply_to_mb, tr1::placeholders::_2));
CMD2_ANY_VALUE("convert.xb", tr1::bind(&apply_to_xb, tr1::placeholders::_2));
CMD2_ANY_VALUE("convert.throttle", tr1::bind(&apply_to_throttle, tr1::placeholders::_2));
CMD2_ANY_LIST("math.add", [](auto, const auto& args) { return apply_math_basic("math.add", std::plus(), args); });
CMD2_ANY_LIST("math.sub", [](auto, const auto& args) { return apply_math_basic("math.sub", std::minus(), args); });
CMD2_ANY_LIST("math.mul", [](auto, const auto& args) { return apply_math_basic("math.mul", std::multiplies(), args); });
CMD2_ANY_LIST("math.div", [](auto, const auto& args) { return apply_math_basic("math.div", std::divides(), args); });
CMD2_ANY_LIST("math.mod", [](auto, const auto& args) { return apply_math_basic("math.mod", std::modulus(), args); });
CMD2_ANY_LIST("math.min", [](auto, const auto& args) { return apply_arith_basic(std::less(), args); });
CMD2_ANY_LIST("math.max", [](auto, const auto& args) { return apply_arith_basic(std::greater(), args); });
CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2));
CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2));
CMD2_ANY_LIST("math.med", std::bind(&apply_arith_other, "median", std::placeholders::_2));
CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2));
CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2));
// Build set/get methods for all color definitions
for (int color_id = 1; color_id < display::RCOLOR_MAX; color_id++) {
control->object_storage()->insert_str(display::color_vars[color_id], "", rpc::object_storage::flag_string_type);
CMD2_ANY_STRING(std::string(display::color_vars[color_id]) + ".set", [color_id](const auto&, const auto& arg) {
return apply_set_color(color_id, arg);
});
CMD2_ANY(display::color_vars[color_id], [color_id](const auto&, const auto&) {
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");
CMD2_ANY_LIST ("elapsed.less", tr1::bind(&apply_elapsed_less, tr1::placeholders::_2));
CMD2_ANY_LIST ("elapsed.greater", tr1::bind(&apply_elapsed_greater, tr1::placeholders::_2));
}
+108 -93
View File
@@ -1,105 +1,137 @@
#include "config.h"
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "control.h"
#include "config.h"
#include <unistd.h>
#include <sys/stat.h>
#include <torrent/net/http_stack.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/runtime/runtime.h>
#include <torrent/utils/directory_events.h>
#include <torrent/connection_manager.h>
#include "core/manager.h"
#include "core/download_store.h"
#include "core/view_manager.h"
#include "core/dht_manager.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "core/view_manager.h"
#include "display/canvas.h"
#include "display/window.h"
#include "display/window_http_queue.h"
#include "display/window_input.h"
#include "display/window_statusbar.h"
#include "display/window_title.h"
#include "display/manager.h"
#include "input/manager.h"
#include "input/input_event.h"
#include "rpc/command_scheduler.h"
#include "rpc/lua.h"
#include "rpc/parse_commands.h"
#include "rpc/scgi.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()),
m_display(new display::Manager()),
m_input(new input::Manager()),
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
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_watch_ready_queue(new utils::WatchReadyQueue()) {
#include "control.h"
m_core = std::make_unique<core::Manager>();
m_view_manager = std::make_unique<core::ViewManager>();
m_dht_manager = std::make_unique<core::DhtManager>();
Control::Control() :
m_ui(new ui::Root()),
m_display(new display::Manager()),
m_input(new input::Manager()),
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
m_commandScheduler(new rpc::CommandScheduler()),
m_objectStorage(new rpc::object_storage()),
m_task_shutdown.slot() = [this] { handle_shutdown(); };
m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); };
m_tick(0),
m_shutdownReceived(false),
m_shutdownQuick(false) {
m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); });
m_core = new core::Manager();
m_viewManager = new core::ViewManager();
m_dhtManager = new core::DhtManager();
m_inputStdin->slot_pressed(std::tr1::bind(&input::Manager::pressed, m_input, std::tr1::placeholders::_1));
m_taskShutdown.slot() = std::tr1::bind(&Control::handle_shutdown, this);
m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log_std));
}
Control::~Control() {
m_view_manager.reset();
delete m_inputStdin;
delete m_input;
m_ui.reset();
m_display.reset();
delete m_viewManager;
delete m_ui;
delete m_display;
delete m_core;
delete m_dhtManager;
delete m_commandScheduler;
delete m_objectStorage;
}
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); });
display::Window::slot_adjust([this]() { m_display->adjust_layout(); });
display::Window::slot_schedule(rak::make_mem_fun(m_display, &display::Manager::schedule));
display::Window::slot_unschedule(rak::make_mem_fun(m_display, &display::Manager::unschedule));
display::Window::slot_adjust(rak::make_mem_fun(m_display, &display::Manager::adjust_layout));
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
m_core->http_stack()->set_user_agent(USER_AGENT);
m_core->initialize_second();
m_core->listen_open();
m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
m_core->set_hashing_view(*m_viewManager->find_throw("hashing"));
m_ui->init(this);
if(!display::Canvas::daemon())
m_inputStdin->insert();
m_inputStdin->insert(torrent::main_thread()->poll());
}
void
Control::cleanup() {
rpc::rpc.cleanup();
// delete m_scgi; m_scgi = NULL;
rpc::xmlrpc.cleanup();
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests);
priority_queue_erase(&taskScheduler, &m_taskShutdown);
if(!display::Canvas::daemon())
m_inputStdin->remove();
m_inputStdin->remove(torrent::main_thread()->poll());
m_directory_events->close();
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_core->download_store()->disable();
m_ui->cleanup();
m_core->cleanup();
display::Canvas::erase_std();
display::Canvas::refresh_std();
display::Canvas::do_update();
@@ -108,64 +140,47 @@ Control::cleanup() {
void
Control::cleanup_exception() {
// delete m_scgi; m_scgi = NULL;
display::Canvas::cleanup();
}
bool
Control::is_shutdown_completed() {
if (!m_shutdown_quick)
if (!m_shutdownQuick || worker_thread->is_active())
return false;
// Tracker requests can be disowned, so wait for these to
// finish. The edge case of torrent http downloads may delay
// shutdown.
// TODO: We keep http requests in the queue for a while after, so improve this check to ignore
// those.
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
if (!core()->http_stack()->empty() || !core()->http_queue()->empty())
return false;
return core()->is_download_shutdown_completed();
return torrent::is_inactive();
}
void
Control::handle_shutdown() {
m_watch_ready_queue->shutdown();
if (!m_shutdownQuick) {
// Temporary hack:
if (worker_thread->is_active())
worker_thread->queue_item(&ThreadBase::stop_thread);
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
if (scgi_thread::thread()->is_active())
scgi_thread::thread()->stop_thread_wait();
if (!m_shutdown_quick) {
torrent::runtime::network_manager()->listen_close();
torrent::runtime::shutdown();
m_directory_events->close();
torrent::connection_manager()->listen_close();
m_core->shutdown(false);
if (!m_task_shutdown.is_scheduled())
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
if (!m_taskShutdown.is_queued())
priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + rak::timer::from_seconds(5));
} else {
torrent::runtime::quick_shutdown();
// Temporary hack:
if (worker_thread->is_active())
worker_thread->queue_item(&ThreadBase::stop_thread);
m_core->shutdown(true);
}
if (!m_task_shutdown_clear_requests.is_scheduled())
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s);
m_shutdown_quick = true;
m_shutdown_received = false;
m_shutdownQuick = true;
m_shutdownReceived = false;
}
void
Control::handle_shutdown_clear_requests() {
torrent::net_thread::http_stack()->clear_requests();
// Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests.
if (m_clear_requests_count++ == 0)
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s);
else
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s);
}
+67 -54
View File
@@ -1,12 +1,47 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CONTROL_H
#define RTORRENT_CONTROL_H
#include <atomic>
#include <cinttypes>
#include <memory>
#include <inttypes.h>
#include <sys/types.h>
#include <rak/timer.h>
#include <rak/priority_queue_default.h>
#include <torrent/torrent.h>
#include <torrent/system/scheduler.h>
namespace ui {
class Root;
@@ -25,57 +60,43 @@ namespace display {
namespace input {
class InputEvent;
class Manager;
}
}
namespace rpc {
class CommandScheduler;
class XmlRpc;
class object_storage;
class LuaEngine;
}
namespace torrent {
class directory_events;
}
namespace utils {
class WatchReadyQueue;
}
class Control {
public:
Control();
~Control();
bool is_shutdown_completed();
bool is_shutdown_received() { return m_shutdown_received; }
bool is_shutdown_started() { return m_shutdown_quick; }
bool is_shutdown_received() { return m_shutdownReceived; }
bool is_shutdown_started() { return m_shutdownQuick; }
void initialize();
void cleanup();
void cleanup_exception();
void handle_shutdown();
void handle_shutdown_clear_requests();
void receive_normal_shutdown() { m_shutdown_received = true; }
void receive_quick_shutdown() { m_shutdown_received = true; m_shutdown_quick = true; }
void receive_normal_shutdown() { m_shutdownReceived = true; __sync_synchronize(); }
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; __sync_synchronize(); }
core::Manager* core() { return m_core.get(); }
core::ViewManager* view_manager() { return m_view_manager.get(); }
core::DhtManager* dht_manager() { return m_dht_manager.get(); }
core::Manager* core() { return m_core; }
core::ViewManager* view_manager() { return m_viewManager; }
core::DhtManager* dht_manager() { return m_dhtManager; }
ui::Root* ui() { return m_ui.get(); }
display::Manager* display() { return m_display.get(); }
input::Manager* input() { return m_input.get(); }
input::InputEvent* input_stdin() { return m_inputStdin.get(); }
ui::Root* ui() { return m_ui; }
display::Manager* display() { return m_display; }
input::Manager* input() { return m_input; }
input::InputEvent* input_stdin() { return m_inputStdin; }
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler.get(); }
rpc::object_storage* object_storage() { return m_objectStorage.get(); }
rpc::LuaEngine* lua_engine() { return m_lua_engine.get(); }
torrent::directory_events* directory_events() { return m_directory_events.get(); }
utils::WatchReadyQueue* watch_ready_queue() { return m_watch_ready_queue.get(); }
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; }
rpc::object_storage* object_storage() { return m_objectStorage; }
uint64_t tick() const { return m_tick; }
void inc_tick() { m_tick++; }
@@ -87,35 +108,27 @@ private:
Control(const Control&);
void operator = (const Control&);
std::unique_ptr<core::Manager> m_core;
std::unique_ptr<core::ViewManager> m_view_manager;
std::unique_ptr<core::DhtManager> m_dht_manager;
core::Manager* m_core;
core::ViewManager* m_viewManager;
core::DhtManager* m_dhtManager;
std::unique_ptr<ui::Root> m_ui;
std::unique_ptr<display::Manager> m_display;
std::unique_ptr<input::Manager> m_input;
std::unique_ptr<input::InputEvent> m_inputStdin;
ui::Root* m_ui;
display::Manager* m_display;
input::Manager* m_input;
input::InputEvent* m_inputStdin;
std::unique_ptr<rpc::CommandScheduler> m_commandScheduler;
std::unique_ptr<rpc::object_storage> m_objectStorage;
std::unique_ptr<rpc::LuaEngine> m_lua_engine;
std::unique_ptr<torrent::directory_events> m_directory_events;
std::unique_ptr<utils::WatchReadyQueue> m_watch_ready_queue;
rpc::CommandScheduler* m_commandScheduler;
rpc::object_storage* m_objectStorage;
uint64_t m_tick{};
uint64_t m_tick;
mode_t m_umask;
std::string m_workingDirectory;
torrent::system::SchedulerEntry m_task_shutdown;
torrent::system::SchedulerEntry m_task_shutdown_clear_requests;
rak::priority_item m_taskShutdown;
int m_clear_requests_count{};
align_cacheline
std::atomic<bool> m_shutdown_received{};
std::atomic<bool> m_shutdown_quick{};
bool m_shutdownReceived lt_cacheline_aligned;
bool m_shutdownQuick lt_cacheline_aligned;
};
#endif
+33
View File
@@ -0,0 +1,33 @@
noinst_LIBRARIES = libsub_core.a
libsub_core_a_SOURCES = \
curl_get.cc \
curl_get.h \
curl_socket.cc \
curl_socket.h \
curl_stack.cc \
curl_stack.h \
dht_manager.cc \
dht_manager.h \
download.cc \
download.h \
download_factory.cc \
download_factory.h \
download_list.cc \
download_list.h \
download_slot_map.h \
download_store.cc \
download_store.h \
http_queue.cc \
http_queue.h \
manager.cc \
manager.h \
poll_manager.cc \
poll_manager.h \
range_map.h \
view.cc \
view.h \
view_manager.cc \
view_manager.h
AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
+134
View File
@@ -0,0 +1,134 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <iostream>
#include <curl/curl.h>
#include <curl/easy.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "curl_get.h"
#include "curl_stack.h"
namespace core {
size_t
curl_get_receive_write(void* data, size_t size, size_t nmemb, void* handle) {
if (!((CurlGet*)handle)->stream()->write((const char*)data, size * nmemb).fail())
return size * nmemb;
else
return 0;
}
CurlGet::~CurlGet() {
close();
}
void
CurlGet::start() {
if (is_busy())
throw torrent::internal_error("Tried to call CurlGet::start on a busy object.");
if (m_stream == NULL)
throw torrent::internal_error("Tried to call CurlGet::start without a valid output stream.");
m_handle = curl_easy_init();
if (m_handle == NULL)
throw torrent::internal_error("Call to curl_easy_init() failed.");
curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &curl_get_receive_write);
curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
if (m_timeout != 0) {
curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, (long)60);
curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, (long)m_timeout);
// Normally libcurl should handle the timeout. But sometimes that doesn't
// work right so we do a fallback timeout that just aborts the transfer.
m_taskTimeout.slot() = std::tr1::bind(&CurlGet::receive_timeout, this);
priority_queue_erase(&taskScheduler, &m_taskTimeout);
priority_queue_insert(&taskScheduler, &m_taskTimeout, cachedTime + rak::timer::from_seconds(m_timeout + 5));
}
curl_easy_setopt(m_handle, CURLOPT_FORBID_REUSE, (long)1);
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
m_stack->add_get(this);
}
void
CurlGet::close() {
priority_queue_erase(&taskScheduler, &m_taskTimeout);
if (!is_busy())
return;
m_stack->remove_get(this);
curl_easy_cleanup(m_handle);
m_handle = NULL;
}
void
CurlGet::receive_timeout() {
return m_stack->transfer_done(m_handle, "Timed out");
}
double
CurlGet::size_done() {
double d = 0.0;
curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD, &d);
return d;
}
double
CurlGet::size_total() {
double d = 0.0;
curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
return d;
}
}
+87
View File
@@ -0,0 +1,87 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_CURL_GET_H
#define RTORRENT_CORE_CURL_GET_H
#include <iosfwd>
#include <string>
#include <curl/curl.h>
#include <torrent/http.h>
#include "rak/priority_queue_default.h"
namespace core {
class CurlStack;
class CurlGet : public torrent::Http {
public:
friend class CurlStack;
CurlGet(CurlStack* s) : m_active(false), m_handle(NULL), m_stack(s) {}
virtual ~CurlGet();
void start();
void close();
bool is_busy() const { return m_handle; }
bool is_active() const { return m_active; }
void set_active(bool a) { m_active = a; }
double size_done();
double size_total();
CURL* handle() { return m_handle; }
private:
CurlGet(const CurlGet&);
void operator = (const CurlGet&);
void receive_timeout();
bool m_active;
rak::priority_item m_taskTimeout;
CURL* m_handle;
CurlStack* m_stack;
};
}
#endif
+134
View File
@@ -0,0 +1,134 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2008, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <curl/curl.h>
#include <curl/multi.h>
#include <torrent/poll.h>
#include <torrent/exceptions.h>
#include <torrent/utils/thread_base.h>
#include "control.h"
#include "curl_socket.h"
#include "curl_stack.h"
namespace core {
int
CurlSocket::receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp) {
CurlStack* stack = (CurlStack*)userp;
CurlSocket* socket = (CurlSocket*)socketp;
if (what == CURL_POLL_REMOVE) {
// We also probably need the special code here as we're not
// guaranteed that the fd will be closed, afaik.
if (socket != NULL)
socket->close();
// TODO: Consider the possibility that we'll need to set the
// fd-associated pointer curl holds to NULL.
delete socket;
return 0;
}
if (socket == NULL) {
socket = stack->new_socket(fd);
torrent::main_thread()->poll()->open(socket);
// No interface for libcurl to signal when it's interested in error events.
// Assume that hence it must always be interested in them.
torrent::main_thread()->poll()->insert_error(socket);
}
if (what == CURL_POLL_NONE || what == CURL_POLL_OUT)
torrent::main_thread()->poll()->remove_read(socket);
else
torrent::main_thread()->poll()->insert_read(socket);
if (what == CURL_POLL_NONE || what == CURL_POLL_IN)
torrent::main_thread()->poll()->remove_write(socket);
else
torrent::main_thread()->poll()->insert_write(socket);
return 0;
}
CurlSocket::~CurlSocket() {
if (m_fileDesc != -1)
throw torrent::internal_error("CurlSocket::~CurlSocket() m_fileDesc != -1.");
}
void
CurlSocket::close() {
if (m_fileDesc == -1)
throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1.");
torrent::main_thread()->poll()->closed(this);
m_fileDesc = -1;
}
void
CurlSocket::event_read() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_IN);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_write() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_OUT);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_error() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_ERR);
#else
return m_stack->receive_action(this, 0);
#endif
}
}
+72
View File
@@ -0,0 +1,72 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2008, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_CURL_SOCKET_H
#define RTORRENT_CORE_CURL_SOCKET_H
#include <torrent/event.h>
#include "globals.h"
namespace core {
class CurlStack;
class CurlSocket : public torrent::Event {
public:
CurlSocket(int fd, CurlStack* stack) : m_stack(stack) { m_fileDesc = fd; }
~CurlSocket();
const char* type_name() const { return "curl"; }
void close();
static int receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp);
private:
CurlSocket(const CurlSocket&);
void operator = (const CurlSocket&);
virtual void event_read();
virtual void event_write();
virtual void event_error();
CurlStack* m_stack;
};
}
#endif
+254
View File
@@ -0,0 +1,254 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <algorithm>
#include <curl/multi.h>
#include <torrent/exceptions.h>
#include "rak/functional.h"
#include "curl_get.h"
#include "curl_socket.h"
#include "curl_stack.h"
namespace core {
CurlStack::CurlStack() :
m_handle((void*)curl_multi_init()),
m_active(0),
m_maxActive(32),
m_ssl_verify_peer(true),
m_dns_timeout(60) {
m_taskTimeout.slot() = std::tr1::bind(&CurlStack::receive_timeout, this);
#if (LIBCURL_VERSION_NUM >= 0x071000)
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
#endif
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
}
CurlStack::~CurlStack() {
while (!empty())
front()->close();
curl_multi_cleanup((CURLM*)m_handle);
priority_queue_erase(&taskScheduler, &m_taskTimeout);
}
CurlGet*
CurlStack::new_object() {
return new CurlGet(this);
}
CurlSocket*
CurlStack::new_socket(int fd) {
CurlSocket* socket = new CurlSocket(fd, this);
curl_multi_assign((CURLM*)m_handle, fd, socket);
return socket;
}
void
CurlStack::receive_action(CurlSocket* socket, int events) {
CURLMcode code;
do {
int count;
#if (LIBCURL_VERSION_NUM >= 0x071003)
code = curl_multi_socket_action((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
events,
&count);
#else
code = curl_multi_socket((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
&count);
#endif
if (code > 0)
throw torrent::internal_error("Error calling curl_multi_socket_action.");
// Socket might be removed when cleaning handles below, future
// calls should not use it.
socket = NULL;
events = 0;
if ((unsigned int)count != size()) {
while (process_done_handle())
; // Do nothing.
if (empty())
priority_queue_erase(&taskScheduler, &m_taskTimeout);
}
} while (code == CURLM_CALL_MULTI_PERFORM);
}
bool
CurlStack::process_done_handle() {
int remaining_msgs = 0;
CURLMsg* msg = curl_multi_info_read((CURLM*)m_handle, &remaining_msgs);
if (msg == NULL)
return false;
if (msg->msg != CURLMSG_DONE)
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
transfer_done(msg->easy_handle,
msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
return remaining_msgs != 0;
}
void
CurlStack::transfer_done(void* handle, const char* msg) {
iterator itr = std::find_if(begin(), end(), rak::equal(handle, std::mem_fun(&CurlGet::handle)));
if (itr == end())
throw torrent::internal_error("Could not find CurlGet with the right easy_handle.");
if (msg == NULL)
(*itr)->trigger_done();
else
(*itr)->trigger_failed(msg);
}
void
CurlStack::receive_timeout() {
receive_action(NULL, 0);
// Sometimes libcurl forgets to reset the timeout. Try to poll the value in that case, or use 10 seconds.
if (!empty() && !m_taskTimeout.is_queued()) {
long timeout;
curl_multi_timeout((CURLM*)m_handle, &timeout);
priority_queue_insert(&taskScheduler, &m_taskTimeout,
cachedTime + rak::timer::from_milliseconds(std::max<unsigned long>(timeout, 10000)));
}
}
void
CurlStack::add_get(CurlGet* get) {
if (!m_userAgent.empty())
curl_easy_setopt(get->handle(), CURLOPT_USERAGENT, m_userAgent.c_str());
if (!m_httpProxy.empty())
curl_easy_setopt(get->handle(), CURLOPT_PROXY, m_httpProxy.c_str());
if (!m_bindAddress.empty())
curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bindAddress.c_str());
if (!m_httpCaPath.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_httpCaPath.c_str());
if (!m_httpCaCert.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_httpCaCert.c_str());
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)m_ssl_verify_peer);
curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout);
base_type::push_back(get);
if (m_active >= m_maxActive)
return;
m_active++;
get->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
#if (LIBCURL_VERSION_NUM < 0x071000)
receive_timeout();
#endif
}
void
CurlStack::remove_get(CurlGet* get) {
iterator itr = std::find(begin(), end(), get);
if (itr == end())
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::remove.");
base_type::erase(itr);
// The CurlGet object was never activated, so we just skip this one.
if (!get->is_active())
return;
get->set_active(false);
if (curl_multi_remove_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_remove_handle.");
if (m_active == m_maxActive &&
(itr = std::find_if(begin(), end(), std::not1(std::mem_fun(&CurlGet::is_active)))) != end()) {
(*itr)->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
} else {
m_active--;
}
}
void
CurlStack::global_init() {
curl_global_init(CURL_GLOBAL_ALL);
}
void
CurlStack::global_cleanup() {
curl_global_cleanup();
}
// TODO: Is this function supposed to set a per-handle timeout, or is
// it the shortest timeout amongst all handles?
int
CurlStack::set_timeout(void* handle, long timeout_ms, void* userp) {
CurlStack* stack = (CurlStack*)userp;
priority_queue_erase(&taskScheduler, &stack->m_taskTimeout);
priority_queue_insert(&taskScheduler, &stack->m_taskTimeout, cachedTime + rak::timer::from_milliseconds(timeout_ms));
return 0;
}
}
+149
View File
@@ -0,0 +1,149 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_CURL_STACK_H
#define RTORRENT_CORE_CURL_STACK_H
#include <deque>
#include <string>
#include "rak/priority_queue_default.h"
namespace core {
class CurlGet;
class CurlSocket;
// By using a deque instead of vector we allow for cheaper removal of
// the oldest elements, those that will be first in the in the
// deque.
//
// This should fit well with the use-case of a http stack, thus
// we get most of the cache locality benefits of a vector with fast
// removal of elements.
class CurlStack : std::deque<CurlGet*> {
public:
friend class CurlGet;
typedef std::deque<CurlGet*> base_type;
using base_type::value_type;
using base_type::iterator;
using base_type::const_iterator;
using base_type::reverse_iterator;
using base_type::const_reverse_iterator;
using base_type::begin;
using base_type::end;
using base_type::rbegin;
using base_type::rend;
using base_type::back;
using base_type::front;
using base_type::size;
using base_type::empty;
CurlStack();
~CurlStack();
CurlGet* new_object();
CurlSocket* new_socket(int fd);
unsigned int active() const { return m_active; }
unsigned int max_active() const { return m_maxActive; }
void set_max_active(unsigned int a) { m_maxActive = a; }
const std::string& user_agent() const { return m_userAgent; }
const std::string& http_proxy() const { return m_httpProxy; }
const std::string& bind_address() const { return m_bindAddress; }
const std::string& http_capath() const { return m_httpCaPath; }
const std::string& http_cacert() const { return m_httpCaCert; }
void set_user_agent(const std::string& s) { m_userAgent = s; }
void set_http_proxy(const std::string& s) { m_httpProxy = s; }
void set_bind_address(const std::string& s) { m_bindAddress = s; }
void set_http_capath(const std::string& s) { m_httpCaPath = s; }
void set_http_cacert(const std::string& s) { m_httpCaCert = s; }
bool ssl_verify_peer() const { return m_ssl_verify_peer; }
void set_ssl_verify_peer(bool s) { m_ssl_verify_peer = s; }
long dns_timeout() const { return m_dns_timeout; }
void set_dns_timeout(long timeout) { m_dns_timeout = timeout; }
static void global_init();
static void global_cleanup();
void receive_action(CurlSocket* socket, int type);
static int set_timeout(void* handle, long timeout_ms, void* userp);
void transfer_done(void* handle, const char* msg);
protected:
void add_get(CurlGet* get);
void remove_get(CurlGet* get);
private:
CurlStack(const CurlStack&);
void operator = (const CurlStack&);
void receive_timeout();
bool process_done_handle();
void* m_handle;
unsigned int m_active;
unsigned int m_maxActive;
rak::priority_item m_taskTimeout;
std::string m_userAgent;
std::string m_httpProxy;
std::string m_bindAddress;
std::string m_httpCaPath;
std::string m_httpCaCert;
bool m_ssl_verify_peer;
long m_dns_timeout;
};
}
#endif
+137 -132
View File
@@ -1,136 +1,161 @@
#include "config.h"
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "dht_manager.h"
#include "config.h"
#include <fstream>
#include <sstream>
#include <torrent/object.h>
#include <torrent/dht_manager.h>
#include <torrent/object_stream.h>
#include <torrent/rate.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/runtime/runtime.h>
#include <torrent/tracker/dht_controller.h>
#include <torrent/utils/log.h>
#include "control.h"
#include "download.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__);
#include "globals.h"
#define LT_LOG_ERROR(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_ERROR, "dht_manager", log_fmt, __VA_ARGS__);
#include "control.h"
#include "dht_manager.h"
#include "download.h"
#include "download_store.h"
#include "manager.h"
namespace core {
const char* DhtManager::dht_settings[dht_settings_num] = { "disable", "off", "auto", "on" };
DhtManager::~DhtManager() {
torrent::this_thread::scheduler()->erase(&m_update_timeout);
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
priority_queue_erase(&taskScheduler, &m_updateTimeout);
priority_queue_erase(&taskScheduler, &m_stopTimeout);
}
void
DhtManager::load_dht_cache() {
if (m_start == dht_disable || !session_thread::manager()->is_used()) {
LT_LOG("ignoring cache file", 0);
if (m_start == dht_disable || !control->core()->download_store()->is_enabled())
return;
}
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();
std::fstream cache_file((control->core()->download_store()->path() + "rtorrent.dht_cache").c_str(), std::ios::in | std::ios::binary);
if (cache_stream.is_open()) {
cache_stream >> cache;
if (cache_file.is_open()) {
cache_file >> cache;
// If the cache file is corrupted we will just discard it with an
// error message.
if (cache_stream.fail()) {
LT_LOG_ERROR("cache file corrupted, discarding (path:%s)", cache_filename.c_str());
if (cache_file.fail()) {
lt_log_print(torrent::LOG_DHT_WARN, "DHT cache file corrupted, discarding.");
cache = torrent::Object::create_map();
} else {
LT_LOG("cache file read (path:%s)", cache_filename.c_str());
}
} else {
LT_LOG("could not open cache file (path:%s)", cache_filename.c_str());
}
torrent::runtime::network_manager()->dht_controller()->initialize(cache);
try {
torrent::dht_manager()->initialize(cache);
if (m_start == dht_on)
start_dht();
if (m_start == dht_on)
start_dht();
} catch (torrent::local_error& e) {
lt_log_print(torrent::LOG_DHT_WARN, "DHT failed: %s", e.what());
}
}
void
DhtManager::start_dht() {
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
priority_queue_erase(&taskScheduler, &m_stopTimeout);
if (!torrent::runtime::network_manager()->is_dht_valid()) {
LT_LOG("server start skipped, manager is uninitialized", 0);
if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active())
return;
}
if (torrent::runtime::network_manager()->is_dht_active()) {
LT_LOG("server start skipped, already active", 0);
torrent::ThrottlePair throttles = control->core()->get_throttle(m_throttleName);
torrent::dht_manager()->set_upload_throttle(throttles.first);
torrent::dht_manager()->set_download_throttle(throttles.second);
int port = rpc::call_command_value("dht.port");
if (port <= 0)
return;
}
if (!torrent::runtime::network_manager()->dht_controller()->start()) {
lt_log_print(torrent::LOG_DHT_INFO, "Starting DHT server on port %d.", port);
try {
torrent::dht_manager()->start(port);
torrent::dht_manager()->reset_statistics();
m_updateTimeout.slot() = std::tr1::bind(&DhtManager::update, this);
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds());
m_dhtPrevCycle = 0;
m_dhtPrevQueriesSent = 0;
m_dhtPrevRepliesReceived = 0;
m_dhtPrevQueriesReceived = 0;
m_dhtPrevBytesUp = 0;
m_dhtPrevBytesDown = 0;
} catch (torrent::local_error& e) {
lt_log_print(torrent::LOG_DHT_ERROR, "DHT start failed: %s", e.what());
m_start = dht_off;
return;
}
torrent::runtime::network_manager()->dht_controller()->reset_statistics();
m_update_timeout.slot() = std::bind(&DhtManager::update, this);
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_update_timeout, 60s);
m_dhtPrevCycle = 0;
m_dhtPrevQueriesSent = 0;
m_dhtPrevRepliesReceived = 0;
m_dhtPrevQueriesReceived = 0;
m_dhtPrevBytesUp = 0;
m_dhtPrevBytesDown = 0;
}
void
DhtManager::stop_dht() {
torrent::this_thread::scheduler()->erase(&m_update_timeout);
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
if (torrent::runtime::network_manager()->is_dht_active()) {
LT_LOG("stopping server", 0);
priority_queue_erase(&taskScheduler, &m_updateTimeout);
priority_queue_erase(&taskScheduler, &m_stopTimeout);
if (torrent::dht_manager()->is_active()) {
log_statistics(true);
torrent::runtime::network_manager()->dht_controller()->stop();
lt_log_print(torrent::LOG_DHT_INFO, "Stopping DHT server.");
torrent::dht_manager()->stop();
}
}
void
DhtManager::save_dht_cache() {
if (!session_thread::manager()->is_used())
if (!control->core()->download_store()->is_enabled() || !torrent::dht_manager()->is_valid())
return;
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);
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 (!cache_file.is_open())
return;
torrent::Object cache = torrent::Object::create_map();
cache_file << *torrent::runtime::network_manager()->dht_controller()->store_cache(&cache);
cache_file << *torrent::dht_manager()->store_cache(&cache);
if (!cache_file.good())
return;
@@ -141,32 +166,17 @@ DhtManager::save_dht_cache() {
}
void
DhtManager::set_mode_by_user(const std::string& arg) {
unsigned int mode = [arg]() {
for (int i = 0; i < dht_settings_num; i++) {
if (arg == dht_settings[i])
return i;
}
throw torrent::input_error("Invalid dht mode: " + arg);
}();
m_set_by_user = true;
if (!torrent::runtime::is_network_initialized()) {
m_start = mode;
return;
DhtManager::set_mode(const std::string& arg) {
int i;
for (i = 0; i < dht_settings_num; i++) {
if (arg == dht_settings[i]) {
m_start = i;
break;
}
}
set_mode_directly(mode);
}
void
DhtManager::set_mode_directly(unsigned int mode) {
if (mode >= dht_settings_num)
throw torrent::input_error("Invalid dht mode.");
m_start = mode;
if (i == dht_settings_num)
throw torrent::input_error("Invalid argument.");
if (m_start == dht_off)
stop_dht();
@@ -174,67 +184,50 @@ DhtManager::set_mode_directly(unsigned int mode) {
start_dht();
}
void
DhtManager::set_auto_if_untouched_and_has_session() {
if (m_set_by_user) {
set_mode_directly(m_start);
return;
}
if (rpc::call_command_string("session.path").empty()) {
LT_LOG("DHT auto-start disabled, session path not set.", 0);
return;
}
set_mode_directly(dht_auto);
LT_LOG("DHT auto-start enabled.", 0);
}
void
DhtManager::update() {
if (!torrent::runtime::network_manager()->is_dht_active())
if (!torrent::dht_manager()->is_active())
throw torrent::internal_error("DhtManager::update called with DHT inactive.");
if (m_start == dht_auto && !m_stop_timeout.is_scheduled()) {
if (m_start == dht_auto && !m_stopTimeout.is_queued()) {
DownloadList::const_iterator itr, end;
for (itr = control->core()->download_list()->begin(), end = control->core()->download_list()->end(); itr != end; ++itr)
if ((*itr)->download()->info()->is_active() && !(*itr)->download()->info()->is_private())
break;
if (itr == end) {
m_stop_timeout.slot() = std::bind(&DhtManager::stop_dht, this);
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_stop_timeout, 15min);
m_stopTimeout.slot() = std::tr1::bind(&DhtManager::stop_dht, this);
priority_queue_insert(&taskScheduler, &m_stopTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds());
}
}
// While bootstrapping (log_statistics returns true), check every minute if it completed, otherwise update every 15 minutes.
if (log_statistics(false))
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_update_timeout, 1min);
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds());
else
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_update_timeout, 15min);
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds());
}
bool
DhtManager::log_statistics(bool force) {
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
torrent::DhtManager::statistics_type stats = torrent::dht_manager()->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::runtime::network_manager()->is_dht_active_and_receiving_requests())
LT_LOG("listening port appears to be unreachable, no queries received", 0);
if (torrent::dht_manager()->can_receive_queries())
lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be unreachable, no queries received.");
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(false);
torrent::dht_manager()->set_can_receive(false);
}
if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) {
// No replies to over 20 queries plus two per node we have. Probably firewalled.
if (!m_warned)
LT_LOG("listening port appears to be firewalled, no replies received", 0);
lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be firewalled, no replies received.");
m_warned = true;
return false;
@@ -243,7 +236,7 @@ DhtManager::log_statistics(bool force) {
m_warned = false;
if (stats.queries_received > m_dhtPrevQueriesReceived)
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(true);
torrent::dht_manager()->set_can_receive(true);
// Nothing to log while bootstrapping, but check again every minute.
if (stats.cycle <= 1) {
@@ -264,12 +257,14 @@ DhtManager::log_statistics(bool force) {
// afterwards (i.e. every 2 hours), or when forced.
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, "
snprintf(buffer, sizeof(buffer),
"DHT statistics: %d queries in, %d queries out, %d replies received, %lld bytes read, %lld bytes sent, "
"%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,
@@ -282,6 +277,8 @@ 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;
@@ -292,11 +289,11 @@ DhtManager::dht_statistics() {
torrent::Object dhtStats = torrent::Object::create_map();
dhtStats.insert_key("dht", dht_settings[m_start]);
dhtStats.insert_key("active", torrent::runtime::network_manager()->is_dht_active());
dhtStats.insert_key("throttle", "");
dhtStats.insert_key("active", torrent::dht_manager()->is_active());
dhtStats.insert_key("throttle", m_throttleName);
if (torrent::runtime::network_manager()->is_dht_active()) {
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
if (torrent::dht_manager()->is_active()) {
torrent::DhtManager::statistics_type stats = torrent::dht_manager()->get_statistics();
dhtStats.insert_key("cycle", stats.cycle);
dhtStats.insert_key("queries_received", stats.queries_received);
@@ -304,8 +301,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", int64_t());
dhtStats.insert_key("bytes_written", int64_t());
dhtStats.insert_key("bytes_read", stats.down_rate.total());
dhtStats.insert_key("bytes_written", stats.up_rate.total());
dhtStats.insert_key("nodes", stats.num_nodes);
dhtStats.insert_key("buckets", stats.num_buckets);
dhtStats.insert_key("peers", stats.num_peers);
@@ -316,4 +313,12 @@ DhtManager::dht_statistics() {
return dhtStats;
}
void
DhtManager::set_throttle_name(const std::string& throttleName) {
if (torrent::dht_manager()->is_active())
throw torrent::input_error("Cannot set DHT throttle while active.");
m_throttleName = throttleName;
}
}
+54 -16
View File
@@ -1,18 +1,51 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_DHT_MANAGER_H
#define RTORRENT_CORE_DHT_MANAGER_H
#include <rak/priority_queue_default.h>
#include <torrent/object.h>
#include <torrent/system/scheduler.h>
namespace core {
class DhtManager {
public:
static constexpr int dht_disable = 0;
static constexpr int dht_off = 1;
static constexpr int dht_auto = 2;
static constexpr int dht_on = 3;
DhtManager() : m_warned(false), m_start(dht_off) { }
~DhtManager();
void load_dht_cache();
@@ -23,14 +56,19 @@ public:
void stop_dht();
void auto_start() { if (m_start == dht_auto) start_dht(); }
void set_mode_by_user(const std::string& arg);
void set_mode_directly(unsigned int mode);
void set_mode(const std::string& arg);
void set_auto_if_untouched_and_has_session();
void set_throttle_name(const std::string& throttleName);
const std::string& throttle_name() const { return m_throttleName; }
private:
static constexpr int dht_settings_num = 4;
static const char* dht_settings[dht_settings_num];
static const int dht_disable = 0;
static const int dht_off = 1;
static const int dht_auto = 2;
static const int dht_on = 3;
static const int dht_settings_num = 4;
static const char* dht_settings[dht_settings_num];
void update();
bool log_statistics(bool force);
@@ -42,12 +80,12 @@ private:
uint64_t m_dhtPrevBytesUp;
uint64_t m_dhtPrevBytesDown;
torrent::system::SchedulerEntry m_update_timeout;
torrent::system::SchedulerEntry m_stop_timeout;
rak::priority_item m_updateTimeout;
rak::priority_item m_stopTimeout;
bool m_warned;
bool m_warned{};
bool m_set_by_user{};
int m_start{dht_off};
int m_start;
std::string m_throttleName;
};
}
+71 -21
View File
@@ -1,28 +1,69 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include "core/download.h"
#include <list>
#include <rak/file_stat.h>
#include <rak/functional.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/tracker.h>
#include <torrent/tracker_list.h>
#include <torrent/data/file_list.h>
#include <torrent/utils/file_stat.h>
#include "rpc/parse_commands.h"
#include "control.h"
#include "core/manager.h"
#include "download.h"
#include "manager.h"
namespace core {
Download::Download(download_type d)
: m_download(d) {
Download::Download(download_type d) :
m_download(d),
m_hashFailed(false),
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));
m_resumeFlags(~uint32_t()),
m_group(0) {
m_download.info()->signal_tracker_success().push_back(tr1::bind(&Download::receive_tracker_msg, this, ""));
m_download.info()->signal_tracker_failed().push_back(tr1::bind(&Download::receive_tracker_msg, this, tr1::placeholders::_1));
}
Download::~Download() {
@@ -32,6 +73,17 @@ Download::~Download() {
m_download = download_type();
}
void
Download::enable_udp_trackers(bool state) {
for (torrent::TrackerList::iterator itr = m_download.tracker_list()->begin(), last = m_download.tracker_list()->end(); itr != last; ++itr)
if ((*itr)->type() == torrent::Tracker::TRACKER_UDP) {
if (state)
(*itr)->enable();
else
(*itr)->disable();
}
}
uint32_t
Download::priority() {
return bencode()->get_key("rtorrent").get_key_value("priority");
@@ -88,46 +140,44 @@ Download::distributed_copies() const {
}
void
Download::set_throttle_name(const std::string& name) {
Download::set_throttle_name(const std::string& throttleName) {
if (m_download.info()->is_active())
throw torrent::input_error("Cannot set throttle on active download.");
auto throttles = control->core()->get_throttle(name);
torrent::ThrottlePair throttles = control->core()->get_throttle(throttleName);
m_download.set_upload_throttle(throttles.first);
m_download.set_download_throttle(throttles.second);
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", name);
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", throttleName);
}
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.
torrent::utils::FileStat file_stat;
torrent::FileList* file_list = m_download.file_list();
rak::file_stat 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().str()))) {
!file_stat.update(file_list->front()->frozen_path()))) {
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 after the files have been moved.");
throw torrent::input_error("Cannot change the directory of an open download atter the files have been moved.");
}
control->core()->download_list()->close_directly(this);
file_list->set_root_dir(expand_path(path));
file_list->set_root_dir(rak::path_expand(path));
bencode()->get_key("rtorrent").insert_key("directory", path);
}
+58 -15
View File
@@ -1,16 +1,56 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_DOWNLOAD_H
#define RTORRENT_CORE_DOWNLOAD_H
#include <torrent/common.h>
#include <torrent/download.h>
#include <torrent/download_info.h>
#include <torrent/hash_string.h>
#include <torrent/tracker_list.h>
#include <torrent/data/file_list.h>
#include <torrent/peer/connection_list.h>
#include <torrent/tracker/wrappers.h>
#include "globals.h"
namespace torrent {
class PeerList;
class TrackerList;
}
namespace core {
class Download {
@@ -19,11 +59,10 @@ public:
typedef torrent::FileList file_list_type;
typedef torrent::PeerList peer_list_type;
typedef torrent::TrackerList tracker_list_type;
typedef torrent::TrackerController tracker_controller_type;
typedef torrent::ConnectionList connection_list_type;
typedef download_type::ConnectionType connection_type;
static constexpr uint32_t default_resume_flags = ~uint32_t{} & ~torrent::Download::open_enable_fallocate;
static const int variable_hashing_stopped = 0;
static const int variable_hashing_initial = 1;
static const int variable_hashing_last = 2;
@@ -32,10 +71,10 @@ public:
Download(download_type d);
~Download();
auto info() const { return m_download.info(); }
auto data() const { return m_download.data(); }
const torrent::DownloadInfo* info() const { return m_download.info(); }
const torrent::download_data* data() const { return m_download.data(); }
auto main() { return m_download.main(); }
torrent::DownloadMain* main() { return m_download.main(); }
bool is_open() const { return m_download.info()->is_open(); }
bool is_active() const { return m_download.info()->is_active(); }
@@ -63,15 +102,19 @@ public:
torrent::Object* bencode() { return m_download.bencode(); }
auto tracker_controller() { return m_download.tracker_controller(); }
uint32_t tracker_list_size() const { return m_download.c_tracker_controller().size(); }
tracker_list_type* tracker_list() { return m_download.tracker_list(); }
uint32_t tracker_list_size() const { return m_download.tracker_list()->size(); }
auto connection_list() { return m_download.connection_list(); }
uint32_t connection_list_size() const;
tracker_controller_type* tracker_controller() { return m_download.tracker_controller(); }
connection_list_type* connection_list() { return m_download.connection_list(); }
uint32_t connection_list_size() const;
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);
@@ -80,7 +123,7 @@ public:
void set_root_directory(const std::string& path);
void set_throttle_name(const std::string& name);
void set_throttle_name(const std::string& throttleName);
bool operator == (const std::string& str) const;
@@ -100,10 +143,10 @@ private:
// Store the FileList instance so we can use slots etc on it.
download_type m_download;
bool m_hashFailed{};
bool m_hashFailed;
std::string m_message;
uint32_t m_resumeFlags{default_resume_flags};
unsigned int m_group{};
uint32_t m_resumeFlags;
unsigned int m_group;
};
inline bool
+130 -107
View File
@@ -1,12 +1,47 @@
#include "config.h"
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "download_factory.h"
#include "config.h"
#include <cstdlib>
#include <fstream>
#include <functional>
#include <sstream>
#include <stdexcept>
#include <rak/path.h>
#include <tr1/functional>
#include <torrent/utils/log.h>
#include <torrent/utils/resume.h>
#include <torrent/object.h>
@@ -14,17 +49,19 @@
#include <torrent/exceptions.h>
#include <torrent/rate.h>
#include <torrent/data/file_utils.h>
#include <torrent/net/http_stack.h>
#include <torrent/runtime/client_config.h>
#include <torrent/utils/string_manip.h>
#include "control.h"
#include "globals.h"
#include "core/download.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
#include "curl_get.h"
#include "control.h"
#include "http_queue.h"
#include "globals.h"
#include "manager.h"
#include "download.h"
#include "download_factory.h"
#include "download_store.h"
namespace core {
bool
@@ -35,20 +72,21 @@ is_network_uri(const std::string& uri) {
std::strncmp(uri.c_str(), "ftp://", 6) == 0;
}
static std::unique_ptr<torrent::Object>
download_factory_load_stream(const char* filename) {
static bool
download_factory_add_stream(torrent::Object* root, const char* key, const char* filename) {
std::fstream stream(filename, std::ios::in | std::ios::binary);
if (!stream.is_open())
return std::unique_ptr<torrent::Object>();
return false;
auto obj = std::make_unique<torrent::Object>();
stream >> *obj;
torrent::Object obj;
stream >> obj;
if (!stream.good())
return std::unique_ptr<torrent::Object>();
return false;
return obj;
root->insert_key_move(key, obj);
return true;
}
bool
@@ -58,10 +96,19 @@ is_magnet_uri(const std::string& uri) {
}
DownloadFactory::DownloadFactory(Manager* m) :
m_manager(m) {
m_manager(m),
m_stream(NULL),
m_object(NULL),
m_commited(false),
m_loaded(false),
m_task_load.slot() = std::bind(&DownloadFactory::receive_load, this);
m_task_commit.slot() = std::bind(&DownloadFactory::receive_commit, this);
m_session(false),
m_start(false),
m_printLog(true),
m_isFile(false) {
m_taskLoad.slot() = std::tr1::bind(&DownloadFactory::receive_load, this);
m_taskCommit.slot() = std::tr1::bind(&DownloadFactory::receive_commit, this);
// m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech");
// m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed");
@@ -72,16 +119,18 @@ DownloadFactory::DownloadFactory(Manager* m) :
}
DownloadFactory::~DownloadFactory() {
torrent::this_thread::scheduler()->erase(&m_task_load);
torrent::this_thread::scheduler()->erase(&m_task_commit);
priority_queue_erase(&taskScheduler, &m_taskLoad);
priority_queue_erase(&taskScheduler, &m_taskCommit);
delete m_stream;
delete m_object;
m_stream = NULL;
}
void
DownloadFactory::load(const std::string& uri) {
m_uri = uri;
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
priority_queue_insert(&taskScheduler, &m_taskLoad, cachedTime);
}
// This function must be called before DownloadFactory::commit().
@@ -90,13 +139,13 @@ DownloadFactory::load_raw_data(const std::string& input) {
if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input));
m_stream = new std::stringstream(input);
m_loaded = true;
}
void
DownloadFactory::commit() {
torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms);
priority_queue_insert(&taskScheduler, &m_taskCommit, cachedTime);
}
void
@@ -105,42 +154,39 @@ DownloadFactory::receive_load() {
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
if (is_network_uri(m_uri)) {
m_stream.reset(new std::stringstream);
// Http handling here.
m_stream = new std::stringstream;
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
auto done_fn = [this]() { receive_loaded(); };
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
(*itr)->signal_done().push_front(std::tr1::bind(&DownloadFactory::receive_loaded, this));
(*itr)->signal_failed().push_front(std::tr1::bind(&DownloadFactory::receive_failed, this, std::tr1::placeholders::_1));
m_variables["tied_to_file"] = (int64_t)false;
return;
}
if (is_magnet_uri(m_uri)) {
} else if (is_magnet_uri(m_uri)) {
// DEBUG: Use m_object.
m_stream.reset(new std::stringstream());
m_stream = new std::stringstream();
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
m_variables["tied_to_file"] = (int64_t)false;
receive_loaded();
} else {
std::fstream stream(rak::path_expand(m_uri).c_str(), std::ios::in | std::ios::binary);
if (!stream.is_open())
return receive_failed("Could not open file");
m_object = new torrent::Object;
stream >> *m_object;
if (!stream.good())
return receive_failed("Reading torrent file failed");
m_isFile = true;
receive_loaded();
return;
}
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
if (!stream.is_open())
return receive_failed("Could not open file");
m_object = new torrent::Object;
stream >> *m_object;
if (!stream.good())
return receive_failed("Reading torrent file failed");
m_isFile = true;
receive_loaded();
}
void
@@ -161,19 +207,9 @@ DownloadFactory::receive_commit() {
void
DownloadFactory::receive_success() {
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;
if (rtorrent_object && rtorrent_object->has_key_value("key"))
tracker_key = rtorrent_object->get_key_value("key");
else
tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
Download* download = m_stream != nullptr ?
m_manager->download_list()->create(m_stream.get(), tracker_key, m_printLog) :
m_manager->download_list()->create(m_object, tracker_key, m_printLog);
Download* download = m_stream != NULL ?
m_manager->download_list()->create(m_stream, m_printLog) :
m_manager->download_list()->create(m_object, m_printLog);
m_object = NULL;
@@ -190,20 +226,17 @@ DownloadFactory::receive_success() {
torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map());
meta.insert_key("start", m_start);
meta.insert_key("print_log", m_printLog);
torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
for (auto& m_command : m_commands)
commands.push_back(m_command);
for (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr)
commands.push_back(*itr);
}
if (m_session) {
if (rtorrent_object)
root->insert_key_move("rtorrent", *rtorrent_object);
if (libtorrent_resume_object)
root->insert_key_move("libtorrent_resume", *libtorrent_resume_object);
download_factory_add_stream(root, "rtorrent", (rak::path_expand(m_uri) + ".rtorrent").c_str());
download_factory_add_stream(root, "libtorrent_resume", (rak::path_expand(m_uri) + ".libtorrent_resume").c_str());
} else {
// We only allow session torrents to keep their
// 'rtorrent/libtorrent' sections. The "fast_resume" section
@@ -214,8 +247,6 @@ DownloadFactory::receive_success() {
torrent::Object* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second;
torrent::Object& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second;
rtorrent->insert_key("key", download->tracker_controller().key());
initialize_rtorrent(download, rtorrent);
if (!rtorrent->has_key_string("custom1")) rtorrent->insert_key("custom1", std::string());
@@ -241,9 +272,8 @@ DownloadFactory::receive_success() {
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
}
// 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);
if (!rpc::call_command_value("trackers.use_udp"))
download->enable_udp_trackers(false);
// Check first if we already have these values set in the session
// torrent, so that it is safe to change the values.
@@ -254,25 +284,15 @@ 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_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 {
if (!rtorrent->has_key_string("directory"))
rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download));
}
else
rpc::call_command("d.directory_base.set", rtorrent->get_key("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));
rpc::call_command("d.peer_exchange.set", torrent::runtime::client_config()->is_pex_enabled(), rpc::make_target(download));
rpc::call_command("d.peer_exchange.set", rpc::call_command_value("protocol.pex"), rpc::make_target(download));
torrent::resume_load_addresses(*download->download(), resumeObject);
torrent::resume_load_file_priorities(*download->download(), resumeObject);
@@ -295,8 +315,8 @@ DownloadFactory::receive_success() {
if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid())
log_created(download, rtorrent);
for (const auto& command : m_commands)
rpc::parse_command_multiple_std(command, rpc::make_target(download));
std::for_each(m_commands.begin(), m_commands.end(),
rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_std), rpc::make_target(download)));
if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
throw torrent::input_error("The newly created download was removed.");
@@ -312,7 +332,7 @@ DownloadFactory::receive_success() {
if (m_printLog)
m_manager->push_log_std(msg);
if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) {
// Should stop it, mark it bad. Perhaps even delete it?
download->set_hash_failed(true);
@@ -328,7 +348,7 @@ void
DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
std::stringstream dump;
dump << "info_hash = " << torrent::utils::transform_to_hex_str(download->info()->hash()) << std::endl;
dump << "info_hash = " << torrent::hash_string_to_hex_str(download->info()->hash()) << std::endl;
dump << "session = " << (m_session ? "true" : "false") << std::endl;
if (download->download()->info()->is_meta_download())
@@ -341,8 +361,8 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
dump << "---COMMANDS---" << std::endl;
for (const auto& m_command : m_commands) {
dump << m_command << std::endl;
for (command_list_type::const_iterator itr = m_commands.begin(); itr != m_commands.end(); itr++) {
dump << *itr << std::endl;
}
std::string dump_str = dump.str();
@@ -361,17 +381,15 @@ DownloadFactory::receive_failed(const std::string& msg) {
void
DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) {
auto cached_seconds = torrent::this_thread::cached_seconds().count();
if (!rtorrent->has_key_value("state") || rtorrent->get_key_value("state") > 1) {
rtorrent->insert_key("state", (int64_t)m_start);
rtorrent->insert_key("state_changed", cached_seconds);
rtorrent->insert_key("state_changed", cachedTime.seconds());
rtorrent->insert_key("state_counter", int64_t());
} else if (!rtorrent->has_key_value("state_changed") ||
rtorrent->get_key_value("state_changed") > cached_seconds || rtorrent->get_key_value("state_changed") == 0 ||
rtorrent->get_key_value("state_changed") > cachedTime.seconds() || rtorrent->get_key_value("state_changed") == 0 ||
!rtorrent->has_key_value("state_counter") || (uint64_t)rtorrent->get_key_value("state_counter") > (1 << 20)) {
rtorrent->insert_key("state_changed", cached_seconds);
rtorrent->insert_key("state_changed", cachedTime.seconds());
rtorrent->insert_key("state_counter", int64_t());
}
@@ -389,12 +407,17 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
else
rpc::call_command("d.priority.set", (int64_t)2, rpc::make_target(download));
if (rtorrent->has_key_value("key")) {
download->tracker_list()->set_key(rtorrent->get_key_value("key"));
} else {
download->tracker_list()->set_key(random() % (std::numeric_limits<uint32_t>::max() - 1) + 1);
rtorrent->insert_key("key", download->tracker_list()->key());
}
if (rtorrent->has_key_value("total_uploaded"))
download->info()->mutable_up_rate()->set_total(rtorrent->get_key_value("total_uploaded"));
if (rtorrent->has_key_value("total_downloaded"))
download->info()->mutable_down_rate()->set_total(rtorrent->get_key_value("total_downloaded"));
if (rtorrent->has_key_value("chunks_done") && rtorrent->has_key_value("chunks_wanted"))
download->download()->set_chunks_done(rtorrent->get_key_value("chunks_done"), rtorrent->get_key_value("chunks_wanted"));
+51 -21
View File
@@ -1,3 +1,39 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// The DownloadFactory class assures that loading torrents can be done
// anywhere in the code by queueing the task. The user may change
// settings while, or even after, the torrent is loading.
@@ -5,22 +41,20 @@
#ifndef RTORRENT_CORE_DOWNLOAD_FACTORY_H
#define RTORRENT_CORE_DOWNLOAD_FACTORY_H
#include <functional>
#include <iosfwd>
#include <rak/priority_queue_default.h>
#include <torrent/object.h>
#include <torrent/system/scheduler.h>
#include <tr1/functional>
#include "http_queue.h"
namespace core {
class Download;
class Manager;
class DownloadFactory {
public:
typedef std::function<void ()> slot_void;
typedef std::tr1::function<void ()> slot_void;
typedef std::vector<std::string> command_list_type;
// Do not destroy this object while it is in a HttpQueue.
@@ -43,9 +77,6 @@ public:
bool get_start() const { return m_start; }
void set_start(bool v) { m_start = v; }
bool get_init_load() const { return m_initLoad; }
void set_init_load(bool v) { m_initLoad = v; }
bool print_log() const { return m_printLog; }
void set_print_log(bool v) { m_printLog = v; }
@@ -62,26 +93,25 @@ private:
void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
Manager* m_manager;
std::shared_ptr<std::iostream> m_stream;
torrent::Object* m_object{};
Manager* m_manager;
std::iostream* m_stream;
torrent::Object* m_object;
bool m_commited{};
bool m_loaded{};
bool m_commited;
bool m_loaded;
std::string m_uri;
bool m_session{};
bool m_start{};
bool m_printLog{true};
bool m_isFile{};
bool m_initLoad{};
bool m_session;
bool m_start;
bool m_printLog;
bool m_isFile;
command_list_type m_commands;
torrent::Object::map_type m_variables;
slot_void m_slot_finished;
torrent::system::SchedulerEntry m_task_load;
torrent::system::SchedulerEntry m_task_commit;
slot_void m_slot_finished;
rak::priority_item m_taskLoad;
rak::priority_item m_taskCommit;
};
bool is_network_uri(const std::string& uri);
+88 -86
View File
@@ -1,9 +1,46 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <rak/functional.h>
#include <rak/string_manip.h>
#include <torrent/data/file.h>
#include <torrent/utils/resume.h>
#include <torrent/exceptions.h>
@@ -13,7 +50,6 @@
#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"
@@ -23,11 +59,10 @@
#include "view.h"
#include "view_manager.h"
#include "core/dht_manager.h"
#include "core/download.h"
#include "core/download_list.h"
#include "session/session_manager.h"
#include "ui/root.h"
#include "dht_manager.h"
#include "download.h"
#include "download_list.h"
#include "download_store.h"
#define DL_TRIGGER_EVENT(download, event_name) \
rpc::commands.call_catch(event_name, rpc::make_target(download), torrent::Object(), "Event '" event_name "' failed: ");
@@ -35,7 +70,7 @@
namespace core {
inline void
DownloadList::check_contains([[maybe_unused]] Download* d) {
DownloadList::check_contains(Download* d) {
#ifdef USE_EXTRA_DEBUG
if (std::find(begin(), end(), d) == end())
throw torrent::internal_error("DownloadList::check_contains(...) failed.");
@@ -44,54 +79,35 @@ DownloadList::check_contains([[maybe_unused]] Download* d) {
void
DownloadList::clear() {
int error_count = 0;
std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadList::close), this));
std::for_each(begin(), end(), rak::call_delete<Download>());
while (!empty()) {
auto download = back();
try {
close(download);
base_type::pop_back();
torrent::download_remove(*download->download());
delete download;
} catch (torrent::internal_error& e) {
lt_log_print(torrent::LOG_ERROR, "DownloadList::clear() failed to close or remove download: %s", e.what());
error_count++;
continue;
}
}
if (error_count > 0)
throw torrent::internal_error("DownloadList::clear() failed to close or remove " + std::to_string(error_count) + " downloads.");
base_type::clear();
}
void
DownloadList::session_save() {
for (auto& download : *this)
session_thread::manager()->save_resume_download(download);
unsigned int c = std::count_if(begin(), end(), std::bind1st(std::mem_fun(&DownloadStore::save_resume), control->core()->download_store()));
if (c != size())
lt_log_print(torrent::LOG_ERROR, "Failed to save session torrents.");
control->dht_manager()->save_dht_cache();
control->ui()->save_input_history();
}
DownloadList::iterator
DownloadList::find(const torrent::HashString& hash) {
return std::find_if(begin(), end(), [hash](Download* d) { return hash == d->info()->hash(); });
return std::find_if(begin(), end(), rak::equal(hash, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
}
DownloadList::iterator
DownloadList::find_hex(const char* hash) {
if (strlen(hash) < 40)
return end();
torrent::HashString key;
if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end())
return end();
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));
return std::find_if(begin(), end(), [key](Download* d) { return key == d->info()->hash(); });
return std::find_if(begin(), end(), rak::equal(key, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
}
Download*
@@ -102,18 +118,18 @@ DownloadList::find_hex_ptr(const char* hash) {
}
Download*
DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog) {
DownloadList::create(torrent::Object* obj, bool printLog) {
torrent::Download download;
try {
download = torrent::download_add(obj, tracker_key);
download = torrent::download_add(obj);
} catch (torrent::local_error& e) {
delete obj;
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
delete obj;
return NULL;
}
@@ -123,13 +139,13 @@ DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog)
}
Download*
DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) {
DownloadList::create(std::istream* str, bool printLog) {
torrent::Object* object = new torrent::Object;
torrent::Download download;
try {
*str >> *object;
// Don't throw input_error from here as gcc-3.3.5 produces bad
// code.
if (str->fail()) {
@@ -141,7 +157,7 @@ DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) {
return NULL;
}
download = torrent::download_add(object, tracker_key);
download = torrent::download_add(object);
} catch (torrent::local_error& e) {
delete object;
@@ -164,15 +180,13 @@ DownloadList::insert(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download.");
try {
(*itr)->data()->slot_initial_hash() = std::bind(&DownloadList::hash_done, this, download);
(*itr)->data()->slot_download_done() = std::bind(&DownloadList::received_finished, this, download);
(*itr)->data()->slot_initial_hash() = tr1::bind(&DownloadList::hash_done, this, download);
(*itr)->data()->slot_download_done() = tr1::bind(&DownloadList::received_finished, this, download);
// This needs to be separated into two different calls to ensure
// the download remains in the view.
for (auto v : *control->view_manager())
v->insert(download);
for (auto v : *control->view_manager())
v->filter_download(download);
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::insert), download));
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::filter_download), download));
DL_TRIGGER_EVENT(*itr, "event.download.inserted");
@@ -201,12 +215,11 @@ DownloadList::erase(iterator itr) {
(*itr)->set_hash_failed(true);
close(*itr);
session_thread::manager()->remove_download(*itr);
control->core()->download_store()->remove(*itr);
DL_TRIGGER_EVENT(*itr, "event.download.erased");
for (auto v : *control->view_manager())
v->erase(*itr);
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr));
torrent::download_remove(*(*itr)->download());
delete *itr;
@@ -236,7 +249,7 @@ DownloadList::open_throw(Download* download) {
if (download->download()->info()->is_open())
return;
int openFlags = download->resume_flags();
if (rpc::call_command_value("system.file.allocate"))
@@ -275,7 +288,7 @@ void
DownloadList::close_quick(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download quickly.");
close(download);
// Make sure we cancel any tracker requests. This should rather be
// handled by some parameter to the close function, or some other
// way of giving the client more control of when STOPPED requests
@@ -331,7 +344,7 @@ DownloadList::resume(Download* download, int flags) {
// We need to make sure the flags aren't reset if someone decideds
// to call resume() while it is hashing, etc.
if (download->resume_flags() == Download::default_resume_flags)
if (download->resume_flags() == ~uint32_t())
download->set_resume_flags(flags);
// Manual or end-of-download rehashing clears the resume data so
@@ -355,9 +368,7 @@ DownloadList::resume(Download* download, int flags) {
// This will never actually do anything due to the above hash check.
// open_throw(download);
auto cached_seconds = torrent::this_thread::cached_seconds().count();
rpc::call_command("d.state_changed.set", cached_seconds, rpc::make_target(download));
rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download));
rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)) + 1, rpc::make_target(download));
if (download->is_done()) {
@@ -404,7 +415,7 @@ DownloadList::resume(Download* download, int flags) {
download->set_priority(download->priority());
download->download()->start(download->resume_flags());
download->set_resume_flags(Download::default_resume_flags);
download->set_resume_flags(~uint32_t());
DL_TRIGGER_EVENT(download, "event.download.resumed");
@@ -421,7 +432,7 @@ DownloadList::pause(Download* download, int flags) {
try {
download->set_resume_flags(Download::default_resume_flags);
download->set_resume_flags(~uint32_t());
rpc::parse_command_single(rpc::make_target(download), "view.set_not_visible=active");
@@ -439,15 +450,13 @@ DownloadList::pause(Download* download, int flags) {
download->download()->stop(flags);
torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
// TODO: This is actually for pause, not stop... And doesn't get
// called when the download isn't active, but was in the 'started'
// view.
DL_TRIGGER_EVENT(download, "event.download.paused");
auto cached_seconds = torrent::this_thread::cached_seconds().count();
rpc::call_command("d.state_changed.set", cached_seconds, rpc::make_target(download));
rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download));
rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)), rpc::make_target(download));
// If initial seeding is complete, don't try it again when restarting.
@@ -492,11 +501,7 @@ DownloadList::hash_done(Download* download) {
if (!download->is_hash_checked()) {
download->set_hash_failed(true);
auto& msg = download->download()->hash_error_message();
if (!msg.empty())
download->set_message(msg);
DL_TRIGGER_EVENT(download, "event.download.hash_failed");
return;
}
@@ -543,8 +548,8 @@ DownloadList::hash_done(Download* download) {
if (download->is_done()) {
confirm_finished(download);
} else {
download->set_message("Hash check on download completion found bad chunks.");
lt_log_print(torrent::LOG_TORRENT_ERROR, "Hash check on download completion found bad chunks.");
download->set_message("Hash check on download completion found bad chunks, consider using \"safe_sync\".");
lt_log_print(torrent::LOG_TORRENT_ERROR, "Hash check on download completion found bad chunks, consider using \"safe_sync\".");
DL_TRIGGER_EVENT(download, "event.download.hash_final_failed");
}
@@ -645,8 +650,10 @@ DownloadList::confirm_finished(Download* download) {
// the download.
//
// Obsolete.
if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0)
session_thread::manager()->save_resume_download(download);
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);
}
// Send the completed request before resuming so we don't reset the
// up/downloaded baseline.
@@ -659,9 +666,9 @@ DownloadList::confirm_finished(Download* download) {
if (find(infohash) == end())
return;
// if (download->resume_flags() != Download::default_resume_flags)
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != Download::default_resume_flags.");
// if (download->resume_flags() != ~uint32_t())
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
// See #1292.
//
@@ -671,7 +678,7 @@ DownloadList::confirm_finished(Download* download) {
//
// TODO: Add a check when setting the flags to see if the torrent is
// being hashed.
download->set_resume_flags(Download::default_resume_flags);
download->set_resume_flags(~uint32_t());
if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
resume(download,
@@ -687,10 +694,8 @@ 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().str();
std::string metafile = (*download->file_list()->begin())->frozen_path();
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;
@@ -698,13 +703,11 @@ 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.
@@ -715,7 +718,6 @@ 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);
}
+39 -4
View File
@@ -1,3 +1,39 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_DOWNLOAD_LIST_H
#define RTORRENT_CORE_DOWNLOAD_LIST_H
@@ -7,7 +43,6 @@
namespace torrent {
class HashString;
class Object;
}
namespace core {
@@ -39,7 +74,7 @@ public:
using base_type::empty;
using base_type::size;
DownloadList() = default;
DownloadList() { }
void clear();
@@ -51,8 +86,8 @@ public:
Download* find_hex_ptr(const char* hash);
// Might move this to DownloadFactory.
Download* create(std::istream* str, uint32_t tracker_key, bool printLog);
Download* create(torrent::Object* obj, uint32_t tracker_key, bool printLog);
Download* create(std::istream* str, bool printLog);
Download* create(torrent::Object* obj, bool printLog);
iterator insert(Download* d);
@@ -29,32 +29,38 @@
// 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>
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
#define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
#ifndef RTORRENT_RPC_PARSE_OPTIONS_H
#define RTORRENT_RPC_PARSE_OPTIONS_H
#include <cstring>
#include <functional>
#include <map>
#include <string>
#include <vector>
#include <tr1/functional>
namespace rpc {
#include "download.h"
// If a flag returned by the functor is negative it is treated as a
// negation of the flag.
namespace core {
typedef std::function<int (const std::string&)> parse_option_flag_type;
typedef std::function<const char* (unsigned int)> parse_option_rflag_type;
class DownloadSlotMap : public std::map<std::string, std::tr1::function<void (Download*)> > {
public:
typedef std::tr1::function<void (Download*)> slot_download;
typedef std::map<std::string, slot_download> Base;
void insert(const std::string& key, slot_download s) { Base::operator[](key) = s; }
void erase(const std::string& key) { Base::erase(key); }
int parse_option_flag(const std::string& option, parse_option_flag_type ftor);
int parse_option_flags(const std::string& option, parse_option_flag_type ftor, int flags = int());
void for_each(Download* d);
};
void parse_option_for_each(const std::string& option, parse_option_flag_type ftor);
std::string parse_option_print_vector(int flags, const std::vector<std::pair<const char*, int>>& flag_list);
std::string parse_option_print_flags(unsigned int flags, parse_option_rflag_type ftor);
inline void
DownloadSlotMap::for_each(Download* d) {
for (iterator itr = begin(), last = end(); itr != last; ++itr)
itr->second(d);
}
}
+221
View File
@@ -0,0 +1,221 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
// DownloadStore handles the saving and listing of session torrents.
#include "config.h"
#include <fstream>
#include <stdio.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"
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) {
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();
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());
// 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.d_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(), std::ptr_fun(&not_correct_format)), 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";
}
}

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