mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Compare commits
458 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 05563b4c9b | |||
| a544f8ad68 | |||
| ee18a1f3fc | |||
| b35413ea71 | |||
| f52f20f1b6 | |||
| f9f19fb041 | |||
| 41eef969ea | |||
| 1def5e8b36 | |||
| 8355870586 | |||
| ba2bc7e64d | |||
| 0c11deac50 | |||
| f6b3ad0efd | |||
| 5d350f0bcc | |||
| 86fa0d195f | |||
| 2354c9cdb5 | |||
| 1b25bc7f56 | |||
| c6bde213b4 | |||
| 959448acda | |||
| 3b6da6feac | |||
| ea2d22cb87 | |||
| fa351c017d | |||
| 1e1bdd551a | |||
| a07f57a703 | |||
| 0494ce70c8 | |||
| cfad36bf12 | |||
| 123c327a8f | |||
| 9884c9dd9b | |||
| d99cd5eb73 | |||
| 786f1234d2 | |||
| 23921cc97c | |||
| 6558f0ad42 | |||
| 9431dd5acc | |||
| 8598873627 | |||
| ce4cd27697 | |||
| 59fe93515e | |||
| 8249070ff1 | |||
| 517454b413 | |||
| a79aaad9ab | |||
| c6de871a77 | |||
| acb02379b8 | |||
| bf74686c29 | |||
| dbe7997131 | |||
| d595ebf7d8 | |||
| 08828045f5 | |||
| 662d67e861 | |||
| d08d7de20d | |||
| 83bdc271a4 | |||
| 29edda2f15 | |||
| fd69baa2c1 | |||
| 1603ba0573 | |||
| 19305ab662 | |||
| 5b2e202452 | |||
| c63db9cf97 | |||
| 72f2197add | |||
| e96f594afc | |||
| bc8d0da70f | |||
| 75377817b4 | |||
| 595617c408 | |||
| 578fe03ad6 | |||
| efe258a137 | |||
| 44d39713d5 | |||
| 49625ab5e5 | |||
| cc15e9308a | |||
| a5a96236df | |||
| f1cfe8ad72 | |||
| d0fc48cf7b | |||
| 5725eb3773 | |||
| ca706c21c0 | |||
| 14edd68653 | |||
| 50a609ade9 | |||
| 2cf8f2351b | |||
| add305f90c | |||
| 880510073a | |||
| 0989b2218d | |||
| 3d7e6cb077 | |||
| 64881317c6 | |||
| a5ecd89a54 | |||
| 84229a85be | |||
| e03ab27cf0 | |||
| e41b066555 | |||
| 8318133c79 | |||
| 088bf40bdf | |||
| 2f7a984992 | |||
| 840a57915e | |||
| 5e211c3a28 | |||
| 797a194abc | |||
| 501853cfbc | |||
| b0ef95592b | |||
| 26a7e9f545 | |||
| 0ed10984b3 | |||
| 5f09bb74de | |||
| c368b2de1e | |||
| 71ac256cb5 | |||
| b05b65bd65 | |||
| f05b48e228 | |||
| 1279bd9f7a | |||
| 981184574d | |||
| 2700b3141f | |||
| 4fec56a243 | |||
| dcf24711ef | |||
| 4e3ad1ab62 | |||
| b5a606649a | |||
| eb96876eb2 | |||
| a964b0a350 | |||
| 1adcf230d2 | |||
| 4235507292 | |||
| b7a21b1e9d | |||
| bd53959b40 | |||
| 5a4ba8bc32 | |||
| e64ec358fa | |||
| b78fd9aef5 | |||
| 21e399d099 | |||
| 08a907b547 | |||
| a0b8702895 | |||
| ad3c31862e | |||
| 2711e4c044 | |||
| 8d50aee96f | |||
| 71bb51c3fd | |||
| 63ea08bde6 | |||
| a82bdf22ac | |||
| 9f6731b4e2 | |||
| d935e0ffe9 | |||
| ba239bc8c5 | |||
| ea16276773 | |||
| f767053297 | |||
| 598914908f | |||
| 38fc815d52 | |||
| 674ae767aa | |||
| 0aaa470053 | |||
| 6f27159627 | |||
| de163293ab | |||
| fb4e775689 | |||
| 39f186e523 | |||
| 70e6964823 | |||
| 7ead88448b | |||
| 650f0299b5 | |||
| 5dfb2ae938 | |||
| f05a2ae520 | |||
| ecefdba734 | |||
| 87666199b3 | |||
| 9489793dcb | |||
| 2fa7568165 | |||
| f4b718f685 | |||
| b233e24465 | |||
| 289ab046bf | |||
| a8b6a47054 | |||
| 110591d5c1 | |||
| ae14baa357 | |||
| 0b0c824b4b | |||
| def6551488 | |||
| 787738e36a | |||
| 40c2d90c45 | |||
| 4a37fbde0b | |||
| 4bdeb58eb6 | |||
| 5dbb0020dc | |||
| 8f644e65dd | |||
| 16ff32b88c | |||
| 8806c06f9f | |||
| 60cfcd37c4 | |||
| a526ba58e9 | |||
| efd9507149 | |||
| 3d91dfdb33 | |||
| 30cec98799 | |||
| b825906034 | |||
| b05ecb5c5a | |||
| 900be334dc | |||
| 3a1da2fe34 | |||
| 70750a2bd3 | |||
| 1d2c424a70 | |||
| 8550facf43 | |||
| 184ead294a | |||
| 84bfc491ba | |||
| a2e0eca6e3 | |||
| 92eecdfd52 | |||
| 14219666c5 | |||
| a79a844dac | |||
| 59b6a013ce | |||
| b38f80e597 | |||
| 2d2a756a3c | |||
| 891a6ba69d | |||
| 2be730e4b3 | |||
| bf53700f97 | |||
| 946dc54f9b | |||
| ea2347734b | |||
| 5206e6cb88 | |||
| 48f82c17c2 | |||
| 675625255d | |||
| 658e9f7578 | |||
| e7a80c7b18 | |||
| 677f8f45c8 | |||
| ba1ba3096a | |||
| 65906a033a | |||
| dd5e0df05c | |||
| 00ef7d4be2 | |||
| e64f9fe324 | |||
| 9d3f6645be | |||
| 285827e611 | |||
| 7fa1166baa | |||
| 43ba43252e | |||
| 207375c0cc | |||
| 4a5bc86643 | |||
| 1039497a1a | |||
| 36a39e91c8 | |||
| d35a8d68e6 | |||
| bb1cdfc0e7 | |||
| b0c68aa398 | |||
| 1492d39a3a | |||
| 8dcf2bc609 | |||
| 7022722c64 | |||
| 2829a73d8b | |||
| 43c36db5fc | |||
| 9ed8fe8fd8 | |||
| 95cc070ecc | |||
| d43d08404a | |||
| c92becbb7c | |||
| 20887b1ccb | |||
| 3bd111e498 | |||
| f8ec1ca95e | |||
| d9976af767 | |||
| c649e49a42 | |||
| 9b0d74bd68 | |||
| 09dd1ce9c8 | |||
| eb45508ab9 | |||
| a1ff6f5710 | |||
| 756e3bd5ae | |||
| ce97bf583d | |||
| dd8281204f | |||
| 420f03b40b | |||
| 9ac43c2b40 | |||
| 25448320aa | |||
| 788442de6a | |||
| 4492715737 | |||
| f1a4c13c41 | |||
| e11ac9abe3 | |||
| 34aba86d67 | |||
| 5175414333 | |||
| 2b15c4a1fa | |||
| 84c0d516ef | |||
| 8b663dd169 | |||
| c48b7f5b93 | |||
| 4c06e7a923 | |||
| e3918f5d84 | |||
| 0948b5f86a | |||
| bb8d677f6e | |||
| dc6208ccc9 | |||
| 18d19e3dee | |||
| f0517e2748 | |||
| 47089bce70 | |||
| 64cb3d11a0 | |||
| 12347843a9 | |||
| 41589f06c2 | |||
| a51f367671 | |||
| ac4afeb4bc | |||
| 8d562d53fc | |||
| 1a79eec876 | |||
| c803970628 | |||
| 5f2f046165 | |||
| ad862f4b44 | |||
| 6c25e64c26 | |||
| 231606afc1 | |||
| a9196b43d4 | |||
| 8203949259 | |||
| 537c692f47 | |||
| 95b1a19ef1 | |||
| a4ab0112dc | |||
| 897a6face2 | |||
| 3ab38583b8 | |||
| 1003013f10 | |||
| 7bbd9a02a0 | |||
| f0809ec29d | |||
| e8c1f3ed2c | |||
| 3618b9dc4f | |||
| df8cb53ed2 | |||
| 2d565d1c80 | |||
| de6c48ca3f | |||
| 5fb61b2857 | |||
| 46e94259e8 | |||
| 9ff373fe58 | |||
| 6d888c008d | |||
| 9fe4d188e9 | |||
| 9d5b769d78 | |||
| 55615abe9e | |||
| 303edab9ec | |||
| 877c00d54e | |||
| 4c63cee7a2 | |||
| 58a74cee48 | |||
| 85e74b5542 | |||
| 6f8c1246dc | |||
| 97415c656b | |||
| 3d9c083032 | |||
| dd221ac66a | |||
| 25f729fab5 | |||
| 316b0b51d5 | |||
| a8622e5c80 | |||
| d1dd5ac080 | |||
| 9f2b81534a | |||
| 2ab7460cbc | |||
| 2a998df4f1 | |||
| d5b28c30a9 | |||
| a5a1e2fde5 | |||
| 34bc18940a | |||
| cde78f2353 | |||
| cc59125116 | |||
| 8ac31afd06 | |||
| 8d991b4ce5 | |||
| 3a227c190f | |||
| 9a2ce2b231 | |||
| f33fc331ce | |||
| 47af28aecd | |||
| c6ebdf876a | |||
| 5797ed9e7a | |||
| 9465c94b31 | |||
| 0adfc17335 | |||
| 37a5b7bccb | |||
| 80ef2e076d | |||
| 4ac7313ff1 | |||
| 6139217033 | |||
| 89b35af7a6 | |||
| 851ac469c3 | |||
| 1811248691 | |||
| bacf60af89 | |||
| 1f01b7e94d | |||
| d514e525ca | |||
| b2b723f248 | |||
| e3ab913f9a | |||
| 787e23a25d | |||
| 9f48226663 | |||
| 78915746ee | |||
| e7fc891f11 | |||
| 2e0a417367 | |||
| b5a6ee33a1 | |||
| 3378355b64 | |||
| 6f5d06907b | |||
| 712e7e5db0 | |||
| 2b73c92a3e | |||
| c5563d65c5 | |||
| d412caea66 | |||
| 9c92bfc7e2 | |||
| 4a074adc7b | |||
| 3bf494dbc6 | |||
| b193fedc65 | |||
| 6c5a6a3bb3 | |||
| 7534b02815 | |||
| 6d8c214d09 | |||
| 525b038dbb | |||
| 06741a7578 | |||
| 4cc79590be | |||
| 452397b8af | |||
| c9a8a1e35c | |||
| 8f77d87994 | |||
| 842edaa201 | |||
| 4876301cf4 | |||
| c2c6a4be26 | |||
| 350d03ca04 | |||
| 31602917b7 | |||
| a9898c6ef6 | |||
| 2bf81aa8f5 | |||
| a9c0b65b9d | |||
| 73fed24459 | |||
| f906e9a966 | |||
| 090b3889ce | |||
| 68fdb86c72 | |||
| 6b8a285e75 | |||
| 8f0331625a | |||
| 3c65afcf8c | |||
| cd9948a4a8 | |||
| 0d1b9e9d55 | |||
| 6561c00ae3 | |||
| b8cb828d96 | |||
| e3be3b2c12 | |||
| 0f93fa109c | |||
| 7e1193acab | |||
| 5792ed1ae2 | |||
| 8cfc71b936 | |||
| f2b065a798 | |||
| f33c2560a3 | |||
| db1e78fa9d | |||
| 48c40ee0c6 | |||
| 3aeb213dc4 | |||
| 5a200f5d8f | |||
| 713067ba94 | |||
| fea2cbfac6 | |||
| 6bf1731a1c | |||
| f2caa2651d | |||
| 511895a8b6 | |||
| 4e64fbc78b | |||
| 93b3a34f28 | |||
| ea1ca00f31 | |||
| 58b1fc4914 | |||
| 577818bde4 | |||
| 0ea7615d0a | |||
| 73c1233dc0 | |||
| 11ddc35d02 | |||
| 036916fd9f | |||
| b3fabd2a2b | |||
| 4b7c3ffafe | |||
| 730d43b6c7 | |||
| af2f30c183 | |||
| 36fd837d27 | |||
| 8dd8d691c5 | |||
| e367b162ab | |||
| 49cdfee65a | |||
| 5680db3598 | |||
| 4768eb8356 | |||
| fa2c7d961b | |||
| d6dcbc4a69 | |||
| cadfcb50d2 | |||
| 71a39cd8a0 | |||
| 0658486966 | |||
| 687fbbb83d | |||
| e355eb561f | |||
| 902de0b258 | |||
| 01e5df4167 | |||
| 8d85ce5857 | |||
| f9c9fa2e3b | |||
| 337897784d | |||
| 782b1e4ea8 | |||
| 3cfc213053 | |||
| b789d83b70 | |||
| 67babb65d6 | |||
| e0d5c95821 | |||
| 7f4c5df5ee | |||
| dd45684584 | |||
| fb8632e990 | |||
| b043b7b39e | |||
| 168093d256 | |||
| 0c2f0b7715 | |||
| 4a9d9952e1 | |||
| fd1d5dbdb2 | |||
| dd0c62c7f7 | |||
| 3a8e462bd3 | |||
| b360a734f1 | |||
| c18df7a366 | |||
| a269f808e1 | |||
| 4444df2e97 | |||
| 5a194ab037 | |||
| 1b43f8b591 | |||
| d6427203a4 | |||
| 87c6422052 | |||
| 6ab265ecd4 | |||
| 203c66a287 | |||
| c9fe2facfa | |||
| 5abcf52e55 | |||
| f2f84dd97a | |||
| 34de2b4ac9 | |||
| ef937863fd | |||
| 00fa4127e1 | |||
| 1b0cb722e6 | |||
| af23ca8032 | |||
| c85f9d6318 | |||
| ee120730cc | |||
| b284be6a66 | |||
| 6e976616a0 | |||
| 38b39bdafc | |||
| 48718bdac8 | |||
| 5ce84929e4 | |||
| c1d076f182 | |||
| f929594763 |
@@ -0,0 +1,33 @@
|
||||
---
|
||||
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
@@ -0,0 +1,16 @@
|
||||
---
|
||||
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
|
||||
@@ -0,0 +1,65 @@
|
||||
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!"
|
||||
@@ -0,0 +1,96 @@
|
||||
# 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 }}
|
||||
@@ -0,0 +1,84 @@
|
||||
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
|
||||
@@ -0,0 +1,107 @@
|
||||
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
|
||||
+4
-2
@@ -18,6 +18,8 @@
|
||||
.libs
|
||||
Makefile
|
||||
aclocal.m4
|
||||
actmp.*
|
||||
ar-lib
|
||||
autom4te.cache
|
||||
compile
|
||||
config.h
|
||||
@@ -67,6 +69,6 @@ TAGS
|
||||
# rTorrent specific files
|
||||
###########################
|
||||
src/rtorrent
|
||||
test/rtorrentTest
|
||||
test/rtorrent_Test*
|
||||
test/test-suite.log.tmp
|
||||
test-driver
|
||||
test/rtorrentTest.trs
|
||||
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j 12"
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++ SKIP_CHECK=true
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.6
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- clang-3.7
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages:
|
||||
- clang-3.8
|
||||
- libcppunit-dev
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.7 SKIP_CHECK=true
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.7
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.7
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.7
|
||||
- libcppunit-dev
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- libcppunit-dev
|
||||
|
||||
# TODO: Use the same branch name if libtorrent has it.
|
||||
before_install:
|
||||
- git clone https://github.com/rakshasa/libtorrent.git
|
||||
- |
|
||||
pushd libtorrent \
|
||||
&& (git checkout ${TRAVIS_BRANCH} || true) \
|
||||
&& ./autogen.sh \
|
||||
&& CXX="$COMPILER" ./configure --prefix=/usr \
|
||||
&& make \
|
||||
&& sudo make install \
|
||||
&& popd
|
||||
|
||||
script:
|
||||
- ./autogen.sh && CXX="$COMPILER" ./configure && make
|
||||
- if [ ! $SKIP_CHECK ]; then make check; fi
|
||||
+3
-17
@@ -3,24 +3,10 @@ SUBDIRS = \
|
||||
src \
|
||||
test
|
||||
|
||||
nobase_dist_pkgdata_DATA = \
|
||||
lua/rtorrent.lua
|
||||
|
||||
EXTRA_DIST= \
|
||||
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
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
BUILDING
|
||||
|
||||
Run "aclocal -I scripts && autoconf -i && autoheader && automake --add-missing"
|
||||
to generate the configure scripts if necessary. 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
|
||||
|
||||
Jari Sundell
|
||||
|
||||
Skomakerveien 33
|
||||
3185 Skoppum, NORWAY
|
||||
|
||||
Send bug reports, suggestions and patches to
|
||||
<sundell.software@gmail.com> or to the mailinglist.
|
||||
@@ -1,34 +1,88 @@
|
||||
[](https://paypal.me/jarisundelljp)
|
||||
|
||||
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).
|
||||
|
||||
Stable
|
||||
------
|
||||
|
||||
* [https://github.com/rakshasa/rtorrent-archive/raw/master/libtorrent-0.13.8.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/libtorrent-0.13.8.tar.gz)
|
||||
* [https://github.com/rakshasa/rtorrent-archive/raw/master/rtorrent-0.9.8.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/rtorrent-0.9.8.tar.gz)
|
||||
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.
|
||||
* [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
|
||||
* Etherium: 0x9AB1e3C3d8a875e870f161b3e9287Db0E6DAfF78
|
||||
* Litecoin: LdyaVR67LBnTf6mAT4QJnjSG2Zk67qxmfQ
|
||||
* Cardano: addr1qytaslmqmk6dspltw06sp0zf83dh09u79j49ceh5y26zdcccgq4ph7nmx6kgmzeldauj43254ey97f3x4xw49d86aguqwfhlte
|
||||
* [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 → Regular
+34
-31
@@ -1,18 +1,20 @@
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AC_INIT([rtorrent], [0.10.0], [sundell.software@gmail.com])
|
||||
AC_INIT([rtorrent],[0.16.18],[sundell.software@gmail.com])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIRS([scripts])
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
AM_PROG_AR
|
||||
|
||||
AC_DEFINE([API_VERSION], [10], [api version])
|
||||
LT_INIT
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_CXX
|
||||
AC_SYS_LARGEFILE
|
||||
AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
|
||||
|
||||
AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory])
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_DEFINE([API_VERSION], [23], [api version])
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
@@ -20,15 +22,6 @@ RAK_ENABLE_DEBUG
|
||||
RAK_ENABLE_EXTRA_DEBUG
|
||||
RAK_ENABLE_WERROR
|
||||
|
||||
TORRENT_DISABLE_IPV6
|
||||
|
||||
TORRENT_ENABLE_ARCH
|
||||
TORRENT_WITH_SYSROOT
|
||||
|
||||
TORRENT_WITHOUT_VARIABLE_FDSET
|
||||
TORRENT_WITHOUT_STATVFS
|
||||
TORRENT_WITHOUT_STATFS
|
||||
|
||||
AC_ARG_ENABLE(execinfo,
|
||||
AS_HELP_STRING([--disable-execinfo],
|
||||
[disable libexecinfo [[default=enable]]]),
|
||||
@@ -41,37 +34,46 @@ AC_ARG_ENABLE(execinfo,
|
||||
])
|
||||
|
||||
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
|
||||
AX_WITH_CURSES
|
||||
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
TORRENT_WITHOUT_NCURSES
|
||||
|
||||
if test "x$with_ncurses" != xno; then
|
||||
AX_WITH_CURSES
|
||||
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
fi
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl],, [LIBCURL_CHECK_CONFIG])
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.14.0])
|
||||
PKG_CHECK_MODULES([ZLIB], [zlib])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.18])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
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)
|
||||
dnl We don't have LuaJIT support, and the script breaks if not disabled.
|
||||
AM_CONDITIONAL([LUAJIT], [false])
|
||||
|
||||
AC_CHECK_FUNCS(posix_memalign)
|
||||
TORRENT_CHECK_CACHELINE()
|
||||
TORRENT_CHECK_POPCOUNT()
|
||||
TORRENT_WITH_LUA
|
||||
TORRENT_WITH_TINYXML2
|
||||
TORRENT_WITH_SYSTEMD
|
||||
|
||||
CC_ATTRIBUTE_UNUSED(
|
||||
AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
|
||||
AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
|
||||
)
|
||||
if test ${with_xmlrpc_c+y} && test ${with_xmlrpc_tinyxml2+y}; then
|
||||
AC_MSG_ERROR([--with-xmlrpc-c and --with-xmlrpc-tinyxml2 cannot be used together. Please choose only one])
|
||||
fi
|
||||
|
||||
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION)], 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 $CPPUNIT_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $ZLIB_LIBS $DEPENDENCIES_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
|
||||
|
||||
TORRENT_CHECK_CACHELINE
|
||||
TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
@@ -79,4 +81,5 @@ AC_CONFIG_FILES([
|
||||
src/Makefile
|
||||
test/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
+14
-4
@@ -4,20 +4,30 @@
|
||||
|
||||
# log.open_file = "log name", "file path"
|
||||
|
||||
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
|
||||
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
|
||||
|
||||
A newly opened log file is not connected to any logging events.
|
||||
|
||||
Some control over formatting will be provided at a later date.
|
||||
|
||||
## Appending to log files
|
||||
|
||||
log.append_file = "rtorrent.log", "/tmp/rtorrent.log"
|
||||
|
||||
The `log.open_file` clears any existing contents of the file. If you'd
|
||||
prefer to have a single log file that persists across application
|
||||
restarts, you can use the `log.append_file` in place of the
|
||||
`log.open_file` configuration key.
|
||||
|
||||
## Adding outputs to events
|
||||
|
||||
# log.add_output = "logging event", "log name"
|
||||
|
||||
log.add_output = "info", "rtorrent.log"
|
||||
|
||||
log.add_output = "dht_debug", "tracker.log"
|
||||
log.add_output = "tracker_debug", "tracker.log"
|
||||
log.add_output = "dht_all", "tracker.log"
|
||||
log.add_output = "tracker_events", "tracker.log"
|
||||
log.add_output = "tracker_requests", "tracker.log"
|
||||
|
||||
Each log handle can be added to multiple different logging events.
|
||||
|
||||
@@ -31,7 +41,7 @@ Each log handle can be added to multiple different logging events.
|
||||
"debug"
|
||||
|
||||
The above events receive logging events from all the sub-groups
|
||||
displayed below, and each event also reciving events from the event
|
||||
displayed below, and each event also receiving events from the event
|
||||
above in importance.
|
||||
|
||||
Thus some high-volume sub-group events such as “tracker\_debug” are not
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
\begin{verbatim}
|
||||
# log.open_file = "log name", "file path"
|
||||
|
||||
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
|
||||
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
|
||||
\end{verbatim}
|
||||
|
||||
A newly opened log file is not connected to any logging events.
|
||||
@@ -20,8 +20,9 @@ Some control over formatting will be provided at a later date.
|
||||
|
||||
log.add_output = "info", "rtorrent.log"
|
||||
|
||||
log.add_output = "dht_debug", "tracker.log"
|
||||
log.add_output = "tracker_debug", "tracker.log"
|
||||
log.add_output = "dht_all", "tracker.log"
|
||||
log.add_output = "tracker_events", "tracker.log"
|
||||
log.add_output = "tracker_requests", "tracker.log"
|
||||
\end{verbatim}
|
||||
|
||||
Each log handle can be added to multiple different logging events.
|
||||
|
||||
+1
-5
@@ -499,10 +499,6 @@ 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
|
||||
@@ -560,4 +556,4 @@ log messages, but may be useful to debug connection problems.
|
||||
.SH "AUTHORS"
|
||||
.PP
|
||||
|
||||
Jari "Rakshasa" Sundell <jaris@ifi.uio.no>
|
||||
Jari "Rakshasa" Sundell
|
||||
|
||||
+1
-11
@@ -978,16 +978,6 @@ 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>
|
||||
@@ -1122,7 +1112,7 @@ log messages, but may be useful to debug connection problems.
|
||||
<para>
|
||||
<simplelist type="vert">
|
||||
|
||||
<member>Jari "Rakshasa" Sundell <email>jaris@ifi.uio.no</email></member>
|
||||
<member>Jari "Rakshasa" Sundell <email>sundell.software@gmail.com</email></member>
|
||||
|
||||
</simplelist>
|
||||
</para>
|
||||
|
||||
+13
-1
@@ -46,8 +46,12 @@
|
||||
#session.path.set = ./session
|
||||
|
||||
# Watch a directory for new torrents, and stop those that have been
|
||||
# deleted.
|
||||
# deleted. Use directory.watch.ready for network shares or other watch
|
||||
# directories where files may be copied or written directly into place.
|
||||
# Do not mix directory.watch.ready and directory.watch.added on the same
|
||||
# watch directory.
|
||||
#
|
||||
#directory.watch.ready = ./watch, load.start
|
||||
#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent
|
||||
|
||||
# Close torrents when disk-space is low.
|
||||
@@ -73,6 +77,10 @@
|
||||
#
|
||||
#network.port_random.set = 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.
|
||||
#
|
||||
@@ -115,6 +123,10 @@
|
||||
#
|
||||
#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
|
||||
|
||||
@@ -76,6 +76,8 @@ schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M))
|
||||
##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)
|
||||
@@ -99,8 +101,11 @@ schedule2 = watch_load, 11, 10, ((load.verbose, (cat, (cfg.watch), "load/*.torre
|
||||
# Levels = critical error warn notice info debug
|
||||
# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
|
||||
print = (cat, "Logging to ", (cfg.logfile))
|
||||
|
||||
log.open_file = "log", (cfg.logfile)
|
||||
|
||||
log.add_output = "info", "log"
|
||||
##log.add_output = "tracker_debug", "log"
|
||||
#log.add_output = "tracker_events", "log"
|
||||
#log.add_output = "tracker_requests", "log"
|
||||
|
||||
### END of rtorrent.rc ###
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
--[[
|
||||
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 ]]--
|
||||
@@ -0,0 +1 @@
|
||||
valgrind --leak-check=full --track-origins=yes --show-reachable=yes --suppressions=/Users/rakshasa/projects/rtorrent/doc/valgrind.suppression --gen-suppressions=all --log-file=valgrind.log /usr/local/bin/rtorrent
|
||||
@@ -0,0 +1,343 @@
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:__76-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:__76-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:__80-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:__93-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:__93-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:__108-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:__108-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:__108-*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[CFPrefsPlistSource setDomainIdentifier:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource addNamedVolatileSourceForIdentifier:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource addSourceForIdentifier:user:byHost:container:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[_CFXPreferences copyAppValueForKey:identifier:container:configurationURL:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[_CFXPreferences withSearchListForIdentifier:container:cloudConfigurationURL:perform:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[_CFXPreferences withSearchLists:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:-[CFPrefsSource copyValueForKey:]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:-[OS_xpc_object dealloc]
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_CF*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:__CF*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_NS*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:getSuperclassMetadata
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_ZN5dyld*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_ZNK5dyld*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:___ZNK5dyld*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_dyld_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:*_dyld_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:___SC_getApplicationBundleID_block_invoke
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:xpc_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:xpc_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_xpc_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:_xpc_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_libxpc_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:si_module_with_name
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:_dispatch_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:_dispatch_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_dispatch_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:*_swift_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:libdispatch_init
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_os_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_od_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_objc_init
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_notify_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:bootstrap_*
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:$ss*
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:loadlocale
|
||||
fun:setlocale
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:initscr
|
||||
fun:_ZN7display6Canvas10initializeEv
|
||||
fun:_ZN7Control10initializeEv
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:assume_default_colors_sp
|
||||
fun:_ZN7display6Canvas10initializeEv
|
||||
fun:_ZN7Control10initializeEv
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:start_color_sp
|
||||
fun:_ZN7display6Canvas10initializeEv
|
||||
fun:_ZN7Control10initializeEv
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_ZN7display6Canvas10initializeEv
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
-- 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
|
||||
@@ -1,98 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
-198
@@ -1,198 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
return __builtin_popcountll(t);
|
||||
#else
|
||||
#error __builtin_popcount not found.
|
||||
unsigned int count = 0;
|
||||
|
||||
while (t) {
|
||||
count += t & 0x1;
|
||||
t >> 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the median of an unordered set of numbers of arbitrary
|
||||
// type by modifing the underlying dataset
|
||||
template <typename T = double, typename _InputIter>
|
||||
T median(_InputIter __first, _InputIter __last) {
|
||||
T __med;
|
||||
|
||||
unsigned int __size = __last - __first;
|
||||
unsigned int __middle = __size / 2;
|
||||
_InputIter __target1 = __first + __middle;
|
||||
std::nth_element(__first, __target1, __last);
|
||||
__med = *__target1;
|
||||
|
||||
if (__size % 2 == 0) {
|
||||
_InputIter __target2 = std::max_element(__first, __target1);
|
||||
__med = (__med + *__target2) / 2.0;
|
||||
}
|
||||
|
||||
return __med;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,110 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -1,88 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -1,77 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_FILE_STAT_H
|
||||
#define RAK_FILE_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <cinttypes>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class file_stat {
|
||||
public:
|
||||
// Consider storing rak::error_number.
|
||||
|
||||
bool update(int fd) { return fstat(fd, &m_stat) == 0; }
|
||||
bool update(const char* filename) { return stat(filename, &m_stat) == 0; }
|
||||
bool update(const std::string& filename) { return update(filename.c_str()); }
|
||||
|
||||
bool update_link(const char* filename) { return lstat(filename, &m_stat) == 0; }
|
||||
bool update_link(const std::string& filename) { return update_link(filename.c_str()); }
|
||||
|
||||
bool is_regular() const { return S_ISREG(m_stat.st_mode); }
|
||||
bool is_directory() const { return S_ISDIR(m_stat.st_mode); }
|
||||
bool is_character() const { return S_ISCHR(m_stat.st_mode); }
|
||||
bool is_block() const { return S_ISBLK(m_stat.st_mode); }
|
||||
bool is_fifo() const { return S_ISFIFO(m_stat.st_mode); }
|
||||
bool is_link() const { return S_ISLNK(m_stat.st_mode); }
|
||||
bool is_socket() const { return S_ISSOCK(m_stat.st_mode); }
|
||||
|
||||
off_t size() const { return m_stat.st_size; }
|
||||
|
||||
time_t access_time() const { return m_stat.st_atime; }
|
||||
time_t change_time() const { return m_stat.st_ctime; }
|
||||
time_t modified_time() const { return m_stat.st_mtime; }
|
||||
|
||||
private:
|
||||
struct stat m_stat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,84 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_FS_STAT_H
|
||||
#define RAK_FS_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <cinttypes>
|
||||
|
||||
#include <rak/error_number.h>
|
||||
|
||||
#if HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
namespace rak {
|
||||
|
||||
class fs_stat {
|
||||
public:
|
||||
|
||||
typedef FS_STAT_SIZE_TYPE blocksize_type;
|
||||
typedef FS_STAT_COUNT_TYPE blockcount_type;
|
||||
typedef FS_STAT_STRUCT fs_stat_type;
|
||||
|
||||
bool update(int fd) { return FS_STAT_FD; }
|
||||
bool update(const char* fn) { return FS_STAT_FN; }
|
||||
bool update(const std::string& filename) { return update(filename.c_str()); }
|
||||
|
||||
blocksize_type blocksize() { return FS_STAT_BLOCK_SIZE; }
|
||||
blockcount_type blocks_avail() { return m_stat.f_bavail; }
|
||||
int64_t bytes_avail() { return (int64_t) blocksize() * m_stat.f_bavail; }
|
||||
|
||||
private:
|
||||
fs_stat_type m_stat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,683 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -1,655 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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 <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::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () () { return (*m_base)(); }
|
||||
|
||||
private:
|
||||
std::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::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () (Arg1 arg1) { return (*m_base)(arg1); }
|
||||
|
||||
private:
|
||||
std::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::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::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::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::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::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::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
|
||||
@@ -1,198 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_PARTIAL_QUEUE_H
|
||||
#define RAK_PARTIAL_QUEUE_H
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace rak {
|
||||
|
||||
// First step, don't allow overflowing to the next layer. Only disable
|
||||
// the above layers for now.
|
||||
|
||||
// We also include 0 in a single layer as some chunk may be available
|
||||
// only through seeders.
|
||||
|
||||
class partial_queue {
|
||||
public:
|
||||
typedef uint8_t key_type;
|
||||
typedef uint32_t mapped_type;
|
||||
typedef uint16_t size_type;
|
||||
typedef std::pair<size_type, size_type> size_pair_type;
|
||||
|
||||
static const size_type num_layers = 8;
|
||||
|
||||
partial_queue() : m_data(NULL), m_maxLayerSize(0) {}
|
||||
~partial_queue() { disable(); }
|
||||
|
||||
bool is_full() const { return m_ceiling == 0; }
|
||||
bool is_layer_full(size_type l) const { return m_layers[l].second >= m_maxLayerSize; }
|
||||
|
||||
bool is_enabled() const { return m_data != NULL; }
|
||||
|
||||
// Add check to see if we can add more. Also make it possible to
|
||||
// check how full we are in the lower parts so the caller knows when
|
||||
// he can stop searching.
|
||||
//
|
||||
// Though propably not needed, as we must continue til the first
|
||||
// layer is full.
|
||||
|
||||
size_type max_size() const { return m_maxLayerSize * num_layers; }
|
||||
size_type max_layer_size() const { return m_maxLayerSize; }
|
||||
|
||||
// Must be less that or equal to (max size_type) / num_layers.
|
||||
void enable(size_type ls);
|
||||
void disable();
|
||||
|
||||
void clear();
|
||||
|
||||
// Safe to call while pop'ing and it will not reuse pop'ed indices
|
||||
// so it is guaranteed to reach max_size at some point. This will
|
||||
// ensure that the user needs to refill with new data at regular
|
||||
// intervals.
|
||||
bool insert(key_type key, mapped_type value);
|
||||
|
||||
// Only call this when pop'ing as it moves the index.
|
||||
bool prepare_pop();
|
||||
|
||||
mapped_type pop();
|
||||
|
||||
private:
|
||||
partial_queue(const partial_queue&);
|
||||
void operator = (const partial_queue&);
|
||||
|
||||
static size_type ceiling(size_type layer) { return (2 << layer) - 1; }
|
||||
|
||||
void find_non_empty();
|
||||
|
||||
mapped_type* m_data;
|
||||
size_type m_maxLayerSize;
|
||||
|
||||
size_type m_index;
|
||||
size_type m_ceiling;
|
||||
|
||||
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
@@ -1,107 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -1,145 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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;
|
||||
using base_type::clear;
|
||||
|
||||
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
|
||||
@@ -1,142 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
#define RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
|
||||
#include <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::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
@@ -1,111 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -1,559 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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 <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class socket_address_inet;
|
||||
class socket_address_inet6;
|
||||
|
||||
class socket_address {
|
||||
public:
|
||||
static const sa_family_t af_inet = AF_INET;
|
||||
static const int pf_inet = PF_INET;
|
||||
static const sa_family_t af_inet6 = AF_INET6;
|
||||
static const int pf_inet6 = PF_INET6;
|
||||
static const sa_family_t af_unspec = AF_UNSPEC;
|
||||
static const int pf_unspec = PF_UNSPEC;
|
||||
|
||||
#ifdef AF_LOCAL
|
||||
static const sa_family_t af_local = AF_LOCAL;
|
||||
static const int pf_local = PF_LOCAL;
|
||||
#else
|
||||
static const sa_family_t af_local = AF_UNIX;
|
||||
static const int pf_local = PF_UNIX;
|
||||
#endif
|
||||
|
||||
bool is_any() const;
|
||||
bool is_valid() const;
|
||||
bool is_bindable() const;
|
||||
bool is_address_any() const;
|
||||
|
||||
bool is_valid_inet_class() const { return family() == af_inet || family() == af_inet6; }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); }
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sa_family; }
|
||||
void set_family() { m_sockaddr.sa_family = af_unspec; }
|
||||
|
||||
uint16_t port() const;
|
||||
void set_port(uint16_t p);
|
||||
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
std::string pretty_address_str() const;
|
||||
|
||||
// Attemts to set it as an inet, then an inet6 address. It will
|
||||
// never set anything but net addresses, no local/unix.
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
uint32_t length() const;
|
||||
|
||||
socket_address_inet* sa_inet() { return reinterpret_cast<socket_address_inet*>(this); }
|
||||
const socket_address_inet* sa_inet() const { return reinterpret_cast<const socket_address_inet*>(this); }
|
||||
|
||||
sockaddr* c_sockaddr() { return &m_sockaddr; }
|
||||
sockaddr_in* c_sockaddr_inet() { return &m_sockaddrInet; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
|
||||
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
|
||||
|
||||
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
|
||||
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
|
||||
|
||||
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
|
||||
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
|
||||
|
||||
// Copy a socket address which has the length 'length. Zero out any
|
||||
// extranous bytes and ensure it does not go beyond the size of this
|
||||
// struct.
|
||||
void copy(const socket_address& src, size_t length);
|
||||
void copy_sockaddr(const sockaddr* src);
|
||||
|
||||
static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast<socket_address*>(sa); }
|
||||
static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast<const socket_address*>(sa); }
|
||||
|
||||
// The different families will be sorted according to the
|
||||
// sa_family_t's numeric value.
|
||||
bool operator == (const socket_address& rhs) const;
|
||||
bool operator < (const socket_address& rhs) const;
|
||||
|
||||
bool operator == (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
|
||||
bool operator == (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
|
||||
bool operator < (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
|
||||
bool operator < (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
|
||||
|
||||
private:
|
||||
union {
|
||||
sockaddr m_sockaddr;
|
||||
sockaddr_in m_sockaddrInet;
|
||||
sockaddr_in6 m_sockaddrInet6;
|
||||
};
|
||||
};
|
||||
|
||||
// Remember to set the AF_INET.
|
||||
|
||||
class socket_address_inet {
|
||||
public:
|
||||
bool is_any() const { return is_port_any() && is_address_any(); }
|
||||
bool is_valid() const { return !is_port_any() && !is_address_any(); }
|
||||
bool is_port_any() const { return port() == 0; }
|
||||
bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }
|
||||
|
||||
uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
|
||||
uint16_t port_n() const { return m_sockaddr.sin_port; }
|
||||
void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); }
|
||||
void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; }
|
||||
|
||||
// Should address() return the uint32_t?
|
||||
in_addr address() const { return m_sockaddr.sin_addr; }
|
||||
uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); }
|
||||
uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
|
||||
void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
|
||||
void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; }
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
void set_address_any() { set_port(0); set_address_h(INADDR_ANY); }
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sin_family; }
|
||||
void set_family() { m_sockaddr.sin_family = AF_INET; }
|
||||
|
||||
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
|
||||
sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
|
||||
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
|
||||
|
||||
socket_address_inet6 to_mapped_address() const;
|
||||
|
||||
bool operator == (const socket_address_inet& rhs) const;
|
||||
bool operator < (const socket_address_inet& rhs) const;
|
||||
|
||||
private:
|
||||
struct sockaddr_in m_sockaddr;
|
||||
};
|
||||
|
||||
class socket_address_inet6 {
|
||||
public:
|
||||
bool is_any() const { return is_port_any() && is_address_any(); }
|
||||
bool is_valid() const { return !is_port_any() && !is_address_any(); }
|
||||
bool is_port_any() const { return port() == 0; }
|
||||
bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
|
||||
|
||||
uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
|
||||
uint16_t port_n() const { return m_sockaddr.sin6_port; }
|
||||
void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
|
||||
void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
|
||||
|
||||
in6_addr address() const { return m_sockaddr.sin6_addr; }
|
||||
const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; }
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
void set_address_any() { set_port(0); set_address(in6addr_any); }
|
||||
|
||||
std::string pretty_address_str() const;
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sin6_family; }
|
||||
void set_family() { m_sockaddr.sin6_family = AF_INET6; }
|
||||
|
||||
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
|
||||
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
|
||||
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
|
||||
|
||||
socket_address normalize_address() const;
|
||||
|
||||
bool operator == (const socket_address_inet6& rhs) const;
|
||||
bool operator < (const socket_address_inet6& rhs) const;
|
||||
|
||||
private:
|
||||
struct sockaddr_in6 m_sockaddr;
|
||||
};
|
||||
|
||||
inline bool
|
||||
socket_address::is_any() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->is_any();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_any();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::is_valid() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->is_valid();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_valid();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::is_bindable() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return !sa_inet()->is_address_any();
|
||||
case af_inet6:
|
||||
return !sa_inet6()->is_address_any();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::is_address_any() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->is_address_any();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_address_any();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint16_t
|
||||
socket_address::port() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->port();
|
||||
case af_inet6:
|
||||
return sa_inet6()->port();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
socket_address::set_port(uint16_t p) {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->set_port(p);
|
||||
case af_inet6:
|
||||
return sa_inet6()->set_port(p);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address::address_str() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->address_str();
|
||||
case af_inet6:
|
||||
return sa_inet6()->address_str();
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::address_c_str(char* buf, socklen_t size) const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->address_c_str(buf, size);
|
||||
case af_inet6:
|
||||
return sa_inet6()->address_c_str(buf, size);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address::pretty_address_str() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->address_str();
|
||||
case af_inet6:
|
||||
return sa_inet6()->pretty_address_str();
|
||||
case af_unspec:
|
||||
return std::string("unspec");
|
||||
default:
|
||||
return std::string("invalid");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
socket_address::set_address_c_str(const char* a) {
|
||||
if (sa_inet()->set_address_c_str(a)) {
|
||||
sa_inet()->set_family();
|
||||
return true;
|
||||
|
||||
} else if (sa_inet6()->set_address_c_str(a)) {
|
||||
sa_inet6()->set_family();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the zero length really needed, should we require some length?
|
||||
inline uint32_t
|
||||
socket_address::length() const {
|
||||
switch(family()) {
|
||||
case af_inet:
|
||||
return sizeof(sockaddr_in);
|
||||
case af_inet6:
|
||||
return sizeof(sockaddr_in6);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
socket_address::copy(const socket_address& src, size_t length) {
|
||||
length = std::min(length, sizeof(socket_address));
|
||||
|
||||
std::memset(this, 0, sizeof(socket_address));
|
||||
std::memcpy(this, &src, length);
|
||||
}
|
||||
|
||||
inline void
|
||||
socket_address::copy_sockaddr(const sockaddr* src) {
|
||||
std::memset(this, 0, sizeof(socket_address));
|
||||
std::memcpy(this, src, socket_address::cast_from(src)->length());
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::operator == (const socket_address& rhs) const {
|
||||
if (family() != rhs.family())
|
||||
return false;
|
||||
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() == *rhs.sa_inet();
|
||||
case af_inet6:
|
||||
return *sa_inet6() == *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::operator < (const socket_address& rhs) const {
|
||||
if (family() != rhs.family())
|
||||
return family() < rhs.family();
|
||||
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() < *rhs.sa_inet();
|
||||
case af_inet6:
|
||||
return *sa_inet6() < *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address_inet::address_str() const {
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
if (!address_c_str(buf, INET_ADDRSTRLEN))
|
||||
return std::string();
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::address_c_str(char* buf, socklen_t size) const {
|
||||
return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::set_address_c_str(const char* a) {
|
||||
return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
|
||||
}
|
||||
|
||||
inline socket_address_inet6
|
||||
socket_address_inet::to_mapped_address() const {
|
||||
uint32_t addr32[4];
|
||||
addr32[0] = 0;
|
||||
addr32[1] = 0;
|
||||
addr32[2] = htonl(0xffff);
|
||||
addr32[3] = m_sockaddr.sin_addr.s_addr;
|
||||
|
||||
socket_address_inet6 sa;
|
||||
sa.clear();
|
||||
sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
|
||||
sa.set_port_n(m_sockaddr.sin_port);
|
||||
return sa;
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::operator == (const socket_address_inet& rhs) const {
|
||||
return
|
||||
m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
|
||||
m_sockaddr.sin_port == rhs.m_sockaddr.sin_port;
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::operator < (const socket_address_inet& rhs) const {
|
||||
return
|
||||
m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr ||
|
||||
(m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
|
||||
m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address_inet6::address_str() const {
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!address_c_str(buf, INET6_ADDRSTRLEN))
|
||||
return std::string();
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
|
||||
return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::set_address_c_str(const char* a) {
|
||||
return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address_inet6::pretty_address_str() const {
|
||||
char buf[INET6_ADDRSTRLEN + 2 + 6];
|
||||
|
||||
if (inet_ntop(family(), &m_sockaddr.sin6_addr, buf + 1, INET6_ADDRSTRLEN) == NULL)
|
||||
return std::string();
|
||||
|
||||
buf[0] = '[';
|
||||
|
||||
char* last_char = (char*)std::memchr(buf + 1, 0, INET6_ADDRSTRLEN);
|
||||
|
||||
// TODO: Throw exception here.
|
||||
|
||||
if (last_char == NULL || last_char >= buf + 1 + INET6_ADDRSTRLEN)
|
||||
throw std::logic_error("inet_ntop for inet6 returned bad buffer");
|
||||
|
||||
*(last_char++) = ']';
|
||||
|
||||
if (!is_port_any()) {
|
||||
if (snprintf(last_char, 7, ":%" PRIu16, port()) == -1)
|
||||
return std::string("error"); // TODO: Throw here.
|
||||
|
||||
} else {
|
||||
*last_char = '\0';
|
||||
}
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
inline socket_address
|
||||
socket_address_inet6::normalize_address() const {
|
||||
const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
|
||||
if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
|
||||
socket_address addr4;
|
||||
addr4.sa_inet()->set_family();
|
||||
addr4.sa_inet()->set_address_n(addr32[3]);
|
||||
addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
|
||||
return addr4;
|
||||
}
|
||||
return *reinterpret_cast<const socket_address*>(this);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
|
||||
return
|
||||
memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
|
||||
m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
|
||||
int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
|
||||
return
|
||||
addr_comp < 0 ||
|
||||
(addr_comp == 0 ||
|
||||
m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,427 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_STRING_MANIP_H
|
||||
#define RAK_STRING_MANIP_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <locale>
|
||||
#include <random>
|
||||
|
||||
|
||||
namespace rak {
|
||||
|
||||
// Use these trim functions until n1872 is widely supported.
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_begin(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*seq.begin()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = 0;
|
||||
|
||||
while (pos != seq.length() && std::isspace(seq[pos]))
|
||||
pos++;
|
||||
|
||||
return seq.substr(pos, seq.length() - pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_end(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*(--seq.end())))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = seq.size();
|
||||
|
||||
while (pos != 0 && std::isspace(seq[pos - 1]))
|
||||
pos--;
|
||||
|
||||
return seq.substr(0, pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim(const Sequence& seq) {
|
||||
return trim_begin(trim_end(seq));
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_begin_classic(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*seq.begin(), std::locale::classic()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = 0;
|
||||
|
||||
while (pos != seq.length() && std::isspace(seq[pos], std::locale::classic()))
|
||||
pos++;
|
||||
|
||||
return seq.substr(pos, seq.length() - pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_end_classic(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*(--seq.end()), std::locale::classic()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = seq.size();
|
||||
|
||||
while (pos != 0 && std::isspace(seq[pos - 1], std::locale::classic()))
|
||||
pos--;
|
||||
|
||||
return seq.substr(0, pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_classic(const Sequence& seq) {
|
||||
return trim_begin_classic(trim_end_classic(seq));
|
||||
}
|
||||
|
||||
// Consider rewritting such that m_seq is replaced by first/last.
|
||||
template <typename Sequence>
|
||||
class split_iterator_t {
|
||||
public:
|
||||
typedef typename Sequence::const_iterator const_iterator;
|
||||
typedef typename Sequence::value_type value_type;
|
||||
|
||||
split_iterator_t() {}
|
||||
|
||||
split_iterator_t(const Sequence& seq, value_type delim) :
|
||||
m_seq(&seq),
|
||||
m_delim(delim),
|
||||
m_pos(seq.begin()),
|
||||
m_next(std::find(seq.begin(), seq.end(), delim)) {
|
||||
}
|
||||
|
||||
Sequence operator * () { return Sequence(m_pos, m_next); }
|
||||
|
||||
split_iterator_t& operator ++ () {
|
||||
m_pos = m_next;
|
||||
|
||||
if (m_pos == m_seq->end())
|
||||
return *this;
|
||||
|
||||
m_pos++;
|
||||
m_next = std::find(m_pos, m_seq->end(), m_delim);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (__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) {
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
using bytes_randomizer = std::independent_bits_engine<std::mt19937, CHAR_BIT, uint8_t>;
|
||||
bytes_randomizer bytes(mt);
|
||||
Sequence s;
|
||||
s.reserve(length);
|
||||
std::generate_n(std::back_inserter(s), length, std::ref(bytes));
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_alpha(Iterator first, Iterator last) {
|
||||
while (first != last)
|
||||
if (!std::isalpha(*first++, std::locale::classic()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_alpha(const Sequence& src) {
|
||||
return is_all_alpha(src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_alnum(Iterator first, Iterator last) {
|
||||
while (first != last)
|
||||
if (!std::isalnum(*first++, std::locale::classic()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_alnum(const Sequence& src) {
|
||||
return is_all_alnum(src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_name(Iterator first, Iterator last) {
|
||||
while (first != last) {
|
||||
if (!std::isalnum(*first, std::locale::classic()) && *first != '_')
|
||||
return false;
|
||||
|
||||
first++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_name(const Sequence& src) {
|
||||
return is_all_name(src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
std::string
|
||||
sanitize(Iterator first, Iterator last) {
|
||||
std::string dest;
|
||||
for (; first != last; ++first) {
|
||||
if (std::isprint(*first) && *first != '\r' && *first != '\n' && *first != '\t')
|
||||
dest += *first;
|
||||
else
|
||||
dest += " ";
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
std::string
|
||||
sanitize(const Sequence& src) {
|
||||
return trim(sanitize(src.begin(), src.end()));
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
std::string striptags(Iterator first, Iterator last) {
|
||||
bool copychar = true;
|
||||
std::string dest;
|
||||
|
||||
for (; first != last; ++first) {
|
||||
if (std::isprint(*first) && *first == '<') {
|
||||
copychar = false;
|
||||
} else if (std::isprint(*first) && *first == '>') {
|
||||
copychar = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (copychar)
|
||||
dest += *first;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
std::string striptags(const Sequence& src) {
|
||||
return striptags(src.begin(), src.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
// 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 <cinttypes>
|
||||
#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
|
||||
@@ -1,109 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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
|
||||
@@ -107,25 +107,6 @@ 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],
|
||||
|
||||
Executable → Regular
Executable → Regular
+124
-16
@@ -10,8 +10,8 @@
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXX and
|
||||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||
# or '14' (for the C++14 standard).
|
||||
# CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or
|
||||
# '23' for the respective C++ standard version.
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
@@ -36,13 +36,15 @@
|
||||
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
|
||||
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
|
||||
# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
|
||||
# Copyright (c) 2021, 2024 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
|
||||
# Copyright (c) 2015, 2022, 2023, 2024 Olly Betts
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 12
|
||||
#serial 25
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
@@ -51,6 +53,8 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
|
||||
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
|
||||
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
|
||||
[$1], [20], [ax_cxx_compile_alternatives="20"],
|
||||
[$1], [23], [ax_cxx_compile_alternatives="23"],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
@@ -102,9 +106,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
dnl Cray's crayCC needs "-h std=c++11"
|
||||
dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
|
||||
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
|
||||
if test x"$switch" = xMSVC; then
|
||||
dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
|
||||
dnl with -std=c++17. We suffix the cache variable name with _MSVC to
|
||||
dnl avoid this.
|
||||
switch=-std:c++${alternative}
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
|
||||
else
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
fi
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
@@ -148,23 +161,44 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11]
|
||||
)
|
||||
|
||||
|
||||
dnl Test body for checking C++14 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++17 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++20 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++23 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23],
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_23]
|
||||
)
|
||||
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
@@ -176,7 +210,21 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
// MSVC always sets __cplusplus to 199711L in older versions; newer versions
|
||||
// only set it correctly if /Zc:__cplusplus is specified as well as a
|
||||
// /std:c++NN switch:
|
||||
//
|
||||
// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
|
||||
//
|
||||
// The value __cplusplus ought to have is available in _MSVC_LANG since
|
||||
// Visual Studio 2015 Update 3:
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
//
|
||||
// This was also the first MSVC version to support C++14 so we can't use the
|
||||
// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having
|
||||
// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later.
|
||||
#elif __cplusplus < 201103L && !defined _MSC_VER
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
@@ -467,7 +515,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201402L
|
||||
#elif __cplusplus < 201402L && !defined _MSC_VER
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
@@ -591,7 +639,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201703L
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
|
||||
|
||||
#error "This is not a C++17 compiler"
|
||||
|
||||
@@ -957,6 +1005,66 @@ namespace cxx17
|
||||
|
||||
} // namespace cxx17
|
||||
|
||||
#endif // __cplusplus < 201703L
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++20
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
|
||||
|
||||
#error "This is not a C++20 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#include <version>
|
||||
|
||||
namespace cxx20
|
||||
{
|
||||
|
||||
// As C++20 supports feature test macros in the standard, there is no
|
||||
// immediate need to actually test for feature availability on the
|
||||
// Autoconf side.
|
||||
|
||||
} // namespace cxx20
|
||||
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++23
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
|
||||
|
||||
#error "This is not a C++23 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#include <version>
|
||||
|
||||
namespace cxx23
|
||||
{
|
||||
|
||||
// As C++23 supports feature test macros in the standard, there is no
|
||||
// immediate need to actually test for feature availability on the
|
||||
// Autoconf side.
|
||||
|
||||
} // namespace cxx23
|
||||
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
|
||||
|
||||
]])
|
||||
|
||||
@@ -0,0 +1,710 @@
|
||||
# ===========================================================================
|
||||
# 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])
|
||||
])
|
||||
Executable → Regular
@@ -0,0 +1,37 @@
|
||||
# ===========================================================================
|
||||
# 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
|
||||
Executable → Regular
+144
-288
@@ -1,48 +1,3 @@
|
||||
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,
|
||||
AS_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,
|
||||
AS_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)
|
||||
|
||||
@@ -54,6 +9,8 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
}
|
||||
])],
|
||||
[
|
||||
use_epoll=yes
|
||||
|
||||
AC_DEFINE(USE_EPOLL, 1, Use epoll.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
@@ -86,51 +43,15 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
|
||||
}
|
||||
])],
|
||||
[
|
||||
use_kqueue=yes
|
||||
|
||||
AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
|
||||
AC_MSG_RESULT(yes)
|
||||
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
|
||||
AC_MSG_CHECKING(whether kqueue supports pipes and ptys)
|
||||
|
||||
AC_LINK_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,
|
||||
@@ -156,176 +77,9 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
|
||||
AC_ARG_WITH(variable-fdset,
|
||||
AS_HELP_STRING([--without-variable-fdset],[do not use non-portable variable sized fd_set's]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
|
||||
fi
|
||||
], [
|
||||
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for fallocate)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define _GNU_SOURCE
|
||||
#include <fcntl.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_LINK_IFELSE([AC_LANG_PROGRAM([[#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,
|
||||
AS_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_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#if HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
]], [[
|
||||
struct statvfs s; fsblkcnt_t c;
|
||||
statvfs("", &s);
|
||||
fstatvfs(0, &s);
|
||||
]])],[
|
||||
AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
|
||||
AC_MSG_RESULT(ok)
|
||||
have_stat_vfs=yes
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
have_stat_vfs=no
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_STATFS], [
|
||||
AC_CHECK_HEADERS(sys/statfs.h sys/param.h sys/mount.h)
|
||||
|
||||
AC_MSG_CHECKING(for statfs)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
]], [[
|
||||
struct statfs s;
|
||||
statfs("", &s);
|
||||
fstatfs(0, &s);
|
||||
]])],[
|
||||
AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
|
||||
AC_MSG_RESULT(ok)
|
||||
have_stat_vfs=yes
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
have_stat_vfs=no
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLED_STATFS], [
|
||||
AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size)
|
||||
AC_MSG_RESULT(No filesystem stats available)
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
|
||||
AC_ARG_WITH(statvfs,
|
||||
AS_HELP_STRING([--without-statvfs],[don't try to use statvfs to find free diskspace]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_STATVFS
|
||||
else
|
||||
have_stat_vfs=no
|
||||
fi
|
||||
],
|
||||
[
|
||||
TORRENT_CHECK_STATVFS
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATFS], [
|
||||
AC_ARG_WITH(statfs,
|
||||
AS_HELP_STRING([--without-statfs],[don't try to use statfs to find free diskspace]),
|
||||
[
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_STATFS
|
||||
else
|
||||
TORRENT_DISABLED_STATFS
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
TORRENT_CHECK_STATFS
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
TORRENT_DISABLED_STATFS
|
||||
fi
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_ARG_WITH(address-space,
|
||||
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
|
||||
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [default=1024mb-or-32768mb]]),
|
||||
[
|
||||
if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
|
||||
@@ -337,51 +91,48 @@ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_CHECK_SIZEOF(long)
|
||||
|
||||
if test $ac_cv_sizeof_long = 8; then
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 4096, Default address space size.)
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 32768, Default address space size.)
|
||||
else
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 1024, Default address space size.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
AC_ARG_WITH(fastcgi,
|
||||
AS_HELP_STRING([--with-fastcgi=PATH],[enable FastCGI RPC support (DO NOT USE)]),
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_ATOMIC], [
|
||||
AC_MSG_CHECKING([whether 64-bit atomic operations require -latomic])
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cstdint>
|
||||
#include <atomic>]],
|
||||
[[std::atomic<uint64_t> x(0);
|
||||
return x.load();]])],
|
||||
[
|
||||
AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
|
||||
AC_MSG_RESULT([no])
|
||||
ATOMIC_LIBS=""
|
||||
],
|
||||
[
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -latomic"
|
||||
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
elif test "$withval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
LIBS="$LIBS -lfcgi"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
|
||||
]], [[ FCGX_Init(); ]])],[
|
||||
AC_MSG_RESULT(ok)
|
||||
],[
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_ERROR(Could not compile FastCGI test.)
|
||||
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.])
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
|
||||
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -I$withval/include"
|
||||
LIBS="$LIBS -lfcgi -L$withval/lib"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #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
|
||||
LIBS="$save_LIBS"
|
||||
])
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
AC_SUBST([ATOMIC_LIBS])
|
||||
])
|
||||
|
||||
|
||||
@@ -400,7 +151,7 @@ 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`"
|
||||
@@ -427,17 +178,67 @@ 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 mcheck.h])
|
||||
AC_CHECK_HEADERS([sys/inotify.h])
|
||||
AC_MSG_CHECKING([whether sys/inotify.h actually works])
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/inotify.h>
|
||||
int main(int,const char**) { return (-1 == inotify_init()); }])
|
||||
],[
|
||||
AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
|
||||
AC_DEFINE(USE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
|
||||
AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(failed)]
|
||||
)
|
||||
@@ -445,12 +246,14 @@ 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
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
]], [[
|
||||
@@ -475,6 +278,7 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
AC_MSG_CHECKING([for pthread_setname_no])
|
||||
|
||||
@@ -492,3 +296,55 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP], [
|
||||
AC_MSG_CHECKING(for posix_spawn_file_actions_addclosefrom_np)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#define _GNU_SOURCE
|
||||
#include <spawn.h>
|
||||
]], [[
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawn_file_actions_addclosefrom_np(&actions, 3);
|
||||
]])],[
|
||||
AC_DEFINE(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP, 1, [Define if posix_spawn_file_actions_addclosefrom_np is available.])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
|
||||
AC_ARG_WITH(systemd,
|
||||
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
|
||||
[
|
||||
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])
|
||||
])
|
||||
|
||||
+176
-127
@@ -1,52 +1,3 @@
|
||||
AC_DEFUN([TORRENT_WITH_SYSROOT], [
|
||||
AC_ARG_WITH(sysroot,
|
||||
AS_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,
|
||||
AS_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_MINCORE_SIGNEDNESS], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(signedness of mincore parameter)
|
||||
@@ -75,7 +26,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.])
|
||||
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32 or OpenBSD.])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -104,7 +55,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)
|
||||
@@ -114,113 +65,211 @@ AC_DEFUN([TORRENT_CHECK_MADVISE], [
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
|
||||
AC_MSG_CHECKING(for __builtin_popcount)
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_FADVISE], [
|
||||
AC_MSG_CHECKING(for posix_fadvise)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int f() { return __builtin_popcount(0); }
|
||||
])],
|
||||
#include <fcntl.h>
|
||||
void f() { posix_fadvise(0, 0, 0, POSIX_FADV_RANDOM); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_BUILTIN_POPCOUNT, 1, Use __builtin_popcount.)
|
||||
AC_DEFINE(USE_POSIX_FADVISE, 1, Use posix_fadvise)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
|
||||
AC_MSG_CHECKING(for cacheline)
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_MSG_CHECKING([for target cacheline size])
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <stdlib.h>
|
||||
#include <linux/cache.h>
|
||||
void* vptr __cacheline_aligned;
|
||||
void f() { posix_memalign(&vptr, SMP_CACHE_BYTES, 42); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(found builtin)
|
||||
dnl 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.)
|
||||
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])
|
||||
|
||||
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_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_ALIGNED], [
|
||||
AC_ARG_ENABLE(aligned,
|
||||
AS_HELP_STRING([--enable-aligned],
|
||||
[enable alignment safe code [[default=check]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
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
|
||||
],[
|
||||
TORRENT_CHECK_ALIGNED
|
||||
])
|
||||
],[
|
||||
# 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_DISABLE_INSTRUMENTATION], [
|
||||
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; }
|
||||
])],
|
||||
[has_native_be64=yes; endian_header_file='<sys/endian.h>'],
|
||||
[has_native_be64=no]
|
||||
)
|
||||
AC_MSG_RESULT([$has_native_be64])
|
||||
fi
|
||||
|
||||
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
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_INSTRUMENTATION], [
|
||||
AC_MSG_CHECKING([if instrumentation should be included])
|
||||
|
||||
AC_ARG_ENABLE(instrumentation,
|
||||
AS_HELP_STRING([--disable-instrumentation],
|
||||
[disable instrumentation [[default=enabled]]]),
|
||||
AS_HELP_STRING([--enable-instrumentation],
|
||||
[enable instrumentation [[default=disabled]]]),
|
||||
[
|
||||
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_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [
|
||||
AC_ARG_ENABLE(interrupt-socket,
|
||||
AS_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_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_DISABLE_IPV6], [
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AS_HELP_STRING([--enable-ipv6],
|
||||
|
||||
+38
-19
@@ -5,12 +5,6 @@ rtorrent_LDADD = libsub_root.a @PTHREAD_LIBS@
|
||||
rtorrent_SOURCES = main.cc
|
||||
|
||||
libsub_root_a_SOURCES = \
|
||||
core/curl_get.cc \
|
||||
core/curl_get.h \
|
||||
core/curl_socket.cc \
|
||||
core/curl_socket.h \
|
||||
core/curl_stack.cc \
|
||||
core/curl_stack.h \
|
||||
core/dht_manager.cc \
|
||||
core/dht_manager.h \
|
||||
core/download.cc \
|
||||
@@ -19,15 +13,10 @@ libsub_root_a_SOURCES = \
|
||||
core/download_factory.h \
|
||||
core/download_list.cc \
|
||||
core/download_list.h \
|
||||
core/download_slot_map.h \
|
||||
core/download_store.cc \
|
||||
core/download_store.h \
|
||||
core/http_queue.cc \
|
||||
core/http_queue.h \
|
||||
core/manager.cc \
|
||||
core/manager.h \
|
||||
core/poll_manager.cc \
|
||||
core/poll_manager.h \
|
||||
core/range_map.h \
|
||||
core/view.cc \
|
||||
core/view.h \
|
||||
@@ -37,6 +26,7 @@ libsub_root_a_SOURCES = \
|
||||
display/attributes.h \
|
||||
display/canvas.cc \
|
||||
display/canvas.h \
|
||||
display/color_map.h \
|
||||
display/frame.cc \
|
||||
display/frame.h \
|
||||
display/manager.cc \
|
||||
@@ -107,6 +97,12 @@ libsub_root_a_SOURCES = \
|
||||
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 \
|
||||
@@ -121,6 +117,21 @@ libsub_root_a_SOURCES = \
|
||||
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 \
|
||||
@@ -151,15 +162,20 @@ libsub_root_a_SOURCES = \
|
||||
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/socket_fd.cc \
|
||||
utils/socket_fd.h \
|
||||
utils/watch_ready_queue.cc \
|
||||
utils/watch_ready_queue.h \
|
||||
\
|
||||
command_download.cc \
|
||||
command_dynamic.cc \
|
||||
@@ -183,11 +199,14 @@ libsub_root_a_SOURCES = \
|
||||
globals.h \
|
||||
option_parser.cc \
|
||||
option_parser.h \
|
||||
setup.cc \
|
||||
setup.h \
|
||||
signal_handler.cc \
|
||||
signal_handler.h \
|
||||
thread_base.cc \
|
||||
thread_base.h \
|
||||
thread_worker.cc \
|
||||
thread_worker.h
|
||||
signal_handler.h
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
|
||||
|
||||
if NO_NCURSES
|
||||
libsub_root_a_SOURCES += display/curses_stub.cc display/curses_stub.h
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
|
||||
|
||||
+299
-199
@@ -1,97 +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 <functional>
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/socket_address.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <rak/regex.h>
|
||||
#include <functional>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/tracker.h>
|
||||
#include <torrent/tracker_controller.h>
|
||||
#include <torrent/tracker_list.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#include <torrent/data/download_data.h>
|
||||
#include <torrent/data/file.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/net/resolver.h>
|
||||
#include <torrent/net/types.h>
|
||||
#include <torrent/peer/connection_list.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/utils/file_stat.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/download_store.h"
|
||||
#include "core/manager.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "session/session_manager.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
std::string
|
||||
torrent::string_utf8
|
||||
retrieve_d_base_path(core::Download* download) {
|
||||
if (download->file_list()->is_multi_file())
|
||||
return download->file_list()->frozen_root_dir();
|
||||
else
|
||||
return download->file_list()->empty() ? std::string() : download->file_list()->at(0)->frozen_path();
|
||||
|
||||
if (download->file_list()->empty())
|
||||
return {};
|
||||
|
||||
return download->file_list()->at(0)->frozen_path();
|
||||
}
|
||||
|
||||
std::string
|
||||
torrent::string_utf8
|
||||
retrieve_d_base_filename(core::Download* download) {
|
||||
const std::string* base;
|
||||
torrent::string_utf8 base_path;
|
||||
|
||||
if (download->file_list()->is_multi_file())
|
||||
base = &download->file_list()->frozen_root_dir();
|
||||
base_path = download->file_list()->frozen_root_dir();
|
||||
else if (!download->file_list()->empty())
|
||||
base_path = download->file_list()->at(0)->frozen_path();
|
||||
else
|
||||
base = &download->file_list()->at(0)->frozen_path();
|
||||
return {};
|
||||
|
||||
std::string::size_type split = base->rfind('/');
|
||||
auto split = base_path.str().rfind('/');
|
||||
|
||||
if (split == std::string::npos)
|
||||
return *base;
|
||||
else
|
||||
return base->substr(split + 1);
|
||||
return base_path;
|
||||
|
||||
return torrent::string_utf8::from_string(base_path.str().substr(split + 1));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -104,7 +72,7 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
|
||||
const std::string& type = (itr++)->as_string();
|
||||
const std::string& prefix = (itr++)->as_string();
|
||||
const std::string& postfix = (itr++)->as_string();
|
||||
|
||||
|
||||
if (type.empty())
|
||||
throw torrent::input_error("Invalid arguments.");
|
||||
|
||||
@@ -113,23 +81,23 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
|
||||
|
||||
if (type == "base_path") {
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
link = expand_path(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
|
||||
} else if (type == "base_filename") {
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
link = rak::path_expand(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix);
|
||||
link = expand_path(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix);
|
||||
|
||||
// } else if (type == "directory_path") {
|
||||
// target = rpc::call_command_string("d.directory", rpc::make_target(download));
|
||||
// link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
// link = path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
|
||||
} else if (type == "tied") {
|
||||
link = rak::path_expand(rpc::call_command_string("d.tied_to_file", rpc::make_target(download)));
|
||||
link = expand_path(rpc::call_command_string("d.tied_to_file", rpc::make_target(download)));
|
||||
|
||||
if (link.empty())
|
||||
return torrent::Object();
|
||||
|
||||
link = rak::path_expand(prefix + link + postfix);
|
||||
link = expand_path(prefix + link + postfix);
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
|
||||
} else {
|
||||
@@ -138,22 +106,19 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
|
||||
|
||||
switch (changeType) {
|
||||
case 0:
|
||||
if (symlink(target.c_str(), link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
if (symlink(target.c_str(), link.c_str()) == -1)
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s", std::strerror(errno));
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
rak::file_stat fileStat;
|
||||
rak::error_number::clear_global();
|
||||
torrent::utils::FileStat fileStat;
|
||||
errno = 0;
|
||||
|
||||
if (!fileStat.update_link(link) || !fileStat.is_link() || unlink(link.c_str()) == -1)
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s", std::strerror(errno));
|
||||
|
||||
if (!fileStat.update_link(link) || !fileStat.is_link() ||
|
||||
unlink(link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -170,8 +135,8 @@ apply_d_delete_tied(core::Download* download) {
|
||||
if (tie.empty())
|
||||
return torrent::Object();
|
||||
|
||||
if (::unlink(rak::path_expand(tie).c_str()) == -1)
|
||||
control->core()->push_log_std("Could not unlink tied file: " + std::string(rak::error_number::current().c_str()));
|
||||
if (::unlink(expand_path(tie).c_str()) == -1)
|
||||
control->core()->push_log_std("Could not unlink tied file: " + std::string(std::strerror(errno)));
|
||||
|
||||
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(download));
|
||||
return torrent::Object();
|
||||
@@ -182,9 +147,9 @@ apply_d_directory(core::Download* download, const std::string& name) {
|
||||
if (!download->file_list()->is_multi_file())
|
||||
download->set_root_directory(name);
|
||||
else if (name.empty() || *name.rbegin() == '/')
|
||||
download->set_root_directory(name + download->info()->name());
|
||||
download->set_root_directory(name + download->info()->name().str());
|
||||
else
|
||||
download->set_root_directory(name + "/" + download->info()->name());
|
||||
download->set_root_directory(name + "/" + download->info()->name().str());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -198,8 +163,8 @@ apply_d_connection_type(core::Download* download, const std::string& name) {
|
||||
|
||||
torrent::Object
|
||||
apply_d_choke_heuristics(core::Download* download, const std::string& name, bool is_down) {
|
||||
torrent::Download::HeuristicType t =
|
||||
(torrent::Download::HeuristicType)torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str());
|
||||
torrent::heuristics_enum t =
|
||||
static_cast<torrent::heuristics_enum>(torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str()));
|
||||
|
||||
if (is_down)
|
||||
download->download()->set_download_choke_heuristic(t);
|
||||
@@ -299,41 +264,16 @@ retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::O
|
||||
throw torrent::bencode_error("d.custom.keys/items takes no arguments.");
|
||||
|
||||
torrent::Object result = keys_only ? torrent::Object::create_list() : torrent::Object::create_map();
|
||||
torrent::Object::map_type& entries = download->bencode()->get_key("rtorrent").get_key("custom").as_map();
|
||||
|
||||
for (torrent::Object::map_type::const_iterator itr = entries.begin(), last = entries.end(); itr != last; itr++) {
|
||||
if (keys_only) result.as_list().push_back(itr->first);
|
||||
else result.as_map()[itr->first] = itr->second;
|
||||
}
|
||||
for (const auto& entry : download->bencode()->get_key("rtorrent").get_key("custom").as_map())
|
||||
if (keys_only)
|
||||
result.as_list().push_back(entry.first);
|
||||
else
|
||||
result.as_map()[entry.first] = entry.second;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_bitfield(core::Download* download) {
|
||||
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
|
||||
|
||||
if (bitField->empty())
|
||||
return torrent::Object("");
|
||||
|
||||
return torrent::Object(rak::transform_hex(bitField->begin(), bitField->end()));
|
||||
}
|
||||
|
||||
struct call_add_d_peer_t {
|
||||
call_add_d_peer_t(core::Download* d, int port) : m_download(d), m_port(port) { }
|
||||
|
||||
void operator() (const sockaddr* sa, int err) {
|
||||
if (sa == NULL) {
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "could not resolve hostname for added peer");
|
||||
} else {
|
||||
m_download->download()->add_peer(sa, m_port);
|
||||
}
|
||||
}
|
||||
|
||||
core::Download* m_download;
|
||||
int m_port;
|
||||
};
|
||||
|
||||
void
|
||||
apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
int port, ret;
|
||||
@@ -356,7 +296,19 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
if (port < 1 || port > 65535)
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port));
|
||||
assert(std::this_thread::get_id() == torrent::main_thread::thread_id());
|
||||
|
||||
auto callback_id = torrent::system::make_callback_id();
|
||||
|
||||
// Currently discarding SOCK_STREAM.
|
||||
torrent::this_thread::resolver()->resolve_preferred(callback_id, host, AF_UNSPEC, AF_INET, [download, port](torrent::c_sa_shared_ptr sa, int err) {
|
||||
if (sa == nullptr) {
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "could not resolve hostname for added peer: %s", gai_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
download->download()->add_peer(sa.get(), port);
|
||||
});
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -371,7 +323,8 @@ d_chunks_seen(core::Download* download) {
|
||||
std::string result;
|
||||
result.resize(size * 2);
|
||||
|
||||
rak::transform_hex((const char*)seen, (const char*)seen + size, result.begin());
|
||||
torrent::utils::transform_to_hex(seen, seen + size, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -387,30 +340,28 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
std::vector<rak::regex> regex_list;
|
||||
std::vector<std::string> regex_list;
|
||||
|
||||
bool use_regex = true;
|
||||
|
||||
if (args.front().is_list())
|
||||
std::transform(args.front().as_list().begin(), args.front().as_list().end(),
|
||||
std::back_inserter(regex_list),
|
||||
std::bind(&torrent::Object::as_string_c, std::placeholders::_1));
|
||||
for (const auto& o : args.front().as_list())
|
||||
regex_list.push_back(o.as_string_c());
|
||||
else if (args.front().is_string() && !args.front().as_string().empty())
|
||||
regex_list.push_back(args.front().as_string());
|
||||
else
|
||||
use_regex = false;
|
||||
|
||||
for (torrent::FileList::const_iterator itr = download->file_list()->begin(), last = download->file_list()->end(); itr != last; itr++) {
|
||||
for (const auto& file : *download->file_list()) {
|
||||
if (use_regex &&
|
||||
std::find_if(regex_list.begin(), regex_list.end(),
|
||||
std::bind(&rak::regex::operator(), std::placeholders::_1, (*itr)->path()->as_string())) == regex_list.end())
|
||||
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& pattern) { return fnmatch(pattern.c_str(), file->path()->as_string().c_str(), 0) == 0; }))
|
||||
continue;
|
||||
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
row.push_back(rpc::parse_command(rpc::make_target(file.get()), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,21 +378,25 @@ t_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (int itr = 0, last = download->tracker_list()->size(); itr != last; itr++) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto result_raw = torrent::Object::create_list();
|
||||
auto& result = result_raw.as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
torrent::Tracker* t = download->tracker_list()->at(itr);
|
||||
for (uint32_t idx = 0, last = download->tracker_list_size(); idx < last; idx++) {
|
||||
auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto tracker = download->tracker_controller().at(idx);
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(t), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
if (!tracker.is_valid())
|
||||
continue;
|
||||
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
auto& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(&tracker), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
return result_raw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -454,17 +409,16 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end();
|
||||
itr != last; itr++) {
|
||||
for (const auto& connection : *download->connection_list()) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
row.push_back(rpc::parse_command(rpc::make_target(connection), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,9 +443,11 @@ p_call_target(const torrent::Object::list_type& args) {
|
||||
|
||||
torrent::HashString hash;
|
||||
|
||||
if (peer_id.size() != 40 ||
|
||||
torrent::hash_string_from_hex_c_str(peer_id.c_str(), hash) == peer_id.c_str())
|
||||
throw torrent::input_error("Not a hash string.");
|
||||
if (peer_id.size() != 40)
|
||||
throw torrent::input_error("invalid argument: peer id target is not 40 bytes long");
|
||||
|
||||
if (torrent::utils::transform_from_hex(peer_id.c_str(), peer_id.c_str() + 40, hash) != hash.end())
|
||||
throw torrent::input_error("invalid argument: peer id target is not a hex string");
|
||||
|
||||
torrent::ConnectionList::iterator peerItr = download->connection_list()->find(hash.c_str());
|
||||
|
||||
@@ -512,17 +468,20 @@ download_tracker_insert(core::Download* download, const torrent::Object::list_ty
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
int64_t group;
|
||||
int64_t group = 0;
|
||||
|
||||
if (args.front().is_string())
|
||||
rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group);
|
||||
else
|
||||
if (args.front().is_string()) {
|
||||
if (!rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group))
|
||||
throw torrent::input_error("Invalid tracker group number.");
|
||||
} else {
|
||||
group = args.front().as_value();
|
||||
}
|
||||
|
||||
if (group < 0 || group > 32)
|
||||
throw torrent::input_error("Tracker group number invalid.");
|
||||
|
||||
download->download()->tracker_list()->insert_url(group, args.back().as_string(), true);
|
||||
download->tracker_controller().add_extra_tracker(group, args.back().as_string());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
@@ -538,6 +497,19 @@ download_get_variable(core::Download* download, const char* first_key, const cha
|
||||
return download->bencode()->get_key(first_key).get_key(second_key);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_get_value_or_zero(core::Download* download, const char* first_key, const char* second_key = NULL) {
|
||||
auto object = download_get_variable(download, first_key, second_key);
|
||||
|
||||
if (object.is_empty())
|
||||
return int64_t(0);
|
||||
|
||||
if (!object.is_value())
|
||||
throw torrent::bencode_error("Download variable is not a value.");
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_set_variable(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key = NULL) {
|
||||
if (second_key == NULL)
|
||||
@@ -582,20 +554,17 @@ download_set_variable_string(core::Download* download, const torrent::Object::st
|
||||
//
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
download_get_variable(download, first_key, second_key).as_list().push_back(rawArgs);
|
||||
|
||||
d_list_push_back_string(core::Download* download, const std::string& arg, const char* first_key, const char* second_key) {
|
||||
download_get_variable(download, first_key, second_key).as_list().push_back(arg);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back_unique(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
d_list_push_back_unique_string(core::Download* download, const std::string& arg, const char* first_key, const char* second_key) {
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
if (std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) == list.end())
|
||||
list.push_back(rawArgs);
|
||||
if (std::none_of(list.begin(), list.end(), [arg](const torrent::Object& obj) { return torrent::object_equal(obj, arg); }))
|
||||
list.push_back(arg);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -605,8 +574,7 @@ d_list_has(core::Download* download, const torrent::Object& rawArgs, const char*
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
return (int64_t)(std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) != list.end());
|
||||
return (int64_t)(std::any_of(list.begin(), list.end(), [args](const auto& obj) { return torrent::object_equal(obj, args); }));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -614,7 +582,7 @@ d_list_remove(core::Download* download, const torrent::Object& rawArgs, const ch
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
list.erase(std::remove_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)), list.end());
|
||||
list.erase(std::remove_if(list.begin(), list.end(), [args](const torrent::Object& obj) { return torrent::object_equal(obj, args); }), list.end());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -628,7 +596,6 @@ d_list_remove(core::Download* download, const torrent::Object& rawArgs, const ch
|
||||
#define CMD2_BIND_CL std::bind(&core::Download::connection_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_FL std::bind(&core::Download::file_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_PL std::bind(&core::Download::c_peer_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_TL std::bind(&core::Download::tracker_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_TC std::bind(&core::Download::tracker_controller, std::placeholders::_1)
|
||||
|
||||
#define CMD2_BIND_INFO std::bind(&core::Download::info, std::placeholders::_1)
|
||||
@@ -648,12 +615,16 @@ d_list_remove(core::Download* download, const torrent::Object& rawArgs, const ch
|
||||
|
||||
#define CMD2_DL_TIMESTAMP(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set_if_z", std::bind(&download_set_variable_value_ifz, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key)); \
|
||||
CMD2_DL(key ".or_zero", [](core::Download* download, auto) { \
|
||||
return download_get_value_or_zero(download, first_key, second_key); }); \
|
||||
CMD2_DL_VALUE(key ".elapsed", [](core::Download* download, auto value) { \
|
||||
return download_get_value_or_zero(download, first_key, second_key).as_value() > value; });
|
||||
|
||||
#define CMD2_DL_VAR_STRING(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
@@ -673,30 +644,48 @@ void cg_d_group_set(core::Download* download, const torrent::Objec
|
||||
|
||||
void
|
||||
initialize_command_download() {
|
||||
CMD2_DL("d.hash", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(hash)));
|
||||
CMD2_DL("d.local_id", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
|
||||
CMD2_DL("d.local_id_html", std::bind(&rak::copy_escape_html_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
|
||||
CMD2_DL("d.bitfield", std::bind(&retrieve_d_bitfield, std::placeholders::_1));
|
||||
CMD2_DL("d.base_path", std::bind(&retrieve_d_base_path, std::placeholders::_1));
|
||||
CMD2_DL("d.base_filename", std::bind(&retrieve_d_base_filename, std::placeholders::_1));
|
||||
CMD2_DL("d.hash", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->hash()); });
|
||||
CMD2_DL("d.local_id", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.local_id_html", [](auto* download, auto) { return torrent::utils::copy_escape_html_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.bitfield", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(*download->download()->file_list()->bitfield()); });
|
||||
CMD2_DL("d.base_path", [](auto* download, auto) { return retrieve_d_base_path(download).str(); });
|
||||
CMD2_DL("d.base_path.hex", [](auto* download, auto) { return retrieve_d_base_path(download).object_hex(); });
|
||||
CMD2_DL("d.base_path.base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64(); });
|
||||
CMD2_DL("d.base_path.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64_as_binary(); });
|
||||
CMD2_DL("d.base_path.as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_as_binary(); });
|
||||
CMD2_DL("d.base_path.or_base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_base64(); });
|
||||
CMD2_DL("d.base_path.or_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_as_binary(); });
|
||||
CMD2_DL("d.base_filename", [](auto* download, auto) { return retrieve_d_base_filename(download).str(); });
|
||||
CMD2_DL("d.base_filename.hex", [](auto* download, auto) { return retrieve_d_base_filename(download).object_hex(); });
|
||||
CMD2_DL("d.base_filename.base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64(); });
|
||||
CMD2_DL("d.base_filename.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64_as_binary(); });
|
||||
CMD2_DL("d.base_filename.as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_as_binary(); });
|
||||
CMD2_DL("d.base_filename.or_base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_base64(); });
|
||||
CMD2_DL("d.base_filename.or_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_as_binary(); });
|
||||
|
||||
CMD2_DL("d.name", CMD2_ON_INFO(name));
|
||||
CMD2_DL("d.creation_date", CMD2_ON_INFO(creation_date));
|
||||
CMD2_DL("d.load_date", CMD2_ON_INFO(load_date));
|
||||
CMD2_DL("d.name", [](auto* download, auto) { return download->info()->name().str(); });
|
||||
CMD2_DL("d.name.hex", [](auto* download, auto) { return download->info()->name().object_hex(); });
|
||||
CMD2_DL("d.name.base64", [](auto* download, auto) { return download->info()->name().object_base64(); });
|
||||
CMD2_DL("d.name.base64_as_binary", [](auto* download, auto) { return download->info()->name().object_base64_as_binary(); });
|
||||
CMD2_DL("d.name.as_binary", [](auto* download, auto) { return download->info()->name().object_as_binary(); });
|
||||
CMD2_DL("d.name.or_base64", [](auto* download, auto) { return download->info()->name().object_utf8_or_base64(); });
|
||||
CMD2_DL("d.name.or_as_binary", [](auto* download, auto) { return download->info()->name().object_utf8_or_as_binary(); });
|
||||
CMD2_DL("d.creation_date", [](auto* download, auto) { return download->info()->creation_date(); });
|
||||
CMD2_DL("d.load_date", [](auto* download, auto) { return download->info()->load_date(); });
|
||||
|
||||
//
|
||||
// Network related:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.up.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.up.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.down.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.down.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.skip.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(skip_rate)));
|
||||
CMD2_DL ("d.skip.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(skip_rate)));
|
||||
CMD2_DL ("d.up.rate", [](auto* download, auto) { return download->info()->up_rate()->rate(); });
|
||||
CMD2_DL ("d.up.total", [](auto* download, auto) { return download->info()->up_rate()->total(); });
|
||||
CMD2_DL ("d.down.rate", [](auto* download, auto) { return download->info()->down_rate()->rate(); });
|
||||
CMD2_DL ("d.down.total", [](auto* download, auto) { return download->info()->down_rate()->total(); });
|
||||
CMD2_DL ("d.skip.rate", [](auto* download, auto) { return download->info()->skip_rate()->rate(); });
|
||||
CMD2_DL ("d.skip.total", [](auto* download, auto) { return download->info()->skip_rate()->total(); });
|
||||
|
||||
CMD2_DL ("d.peer_exchange", CMD2_ON_INFO(is_pex_enabled));
|
||||
CMD2_DL_VALUE_V ("d.peer_exchange.set", std::bind(&torrent::Download::set_pex_enabled, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.peer_exchange", [](auto* download, auto) { return download->info()->is_pex_enabled(); });
|
||||
CMD2_DL_VALUE_V ("d.peer_exchange.set", [](auto* download, auto value) { download->download()->set_pex_enabled(value); });
|
||||
|
||||
CMD2_DL_LIST ("d.create_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_DL_LIST ("d.delete_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 1));
|
||||
@@ -712,16 +701,16 @@ initialize_command_download() {
|
||||
// Control functinos:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.is_open", CMD2_ON_INFO(is_open));
|
||||
CMD2_DL ("d.is_active", CMD2_ON_INFO(is_active));
|
||||
CMD2_DL ("d.is_open", [](auto* download, auto) { return download->info()->is_open(); });
|
||||
CMD2_DL ("d.is_active", [](auto* download, auto) { return download->info()->is_active(); });
|
||||
CMD2_DL ("d.is_hash_checked", std::bind(&torrent::Download::is_hash_checked, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_hash_checking", std::bind(&torrent::Download::is_hash_checking, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_multi_file", std::bind(&torrent::FileList::is_multi_file, CMD2_BIND_FL));
|
||||
CMD2_DL ("d.is_private", CMD2_ON_INFO(is_private));
|
||||
CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active));
|
||||
CMD2_DL ("d.is_private", [](auto* download, auto) { return download->info()->is_private(); });
|
||||
CMD2_DL ("d.is_pex_active", [](auto* download, auto) { return download->info()->is_pex_active(); });
|
||||
CMD2_DL ("d.is_partially_done", CMD2_ON_DATA(is_partially_done));
|
||||
CMD2_DL ("d.is_not_partially_done", CMD2_ON_DATA(is_not_partially_done));
|
||||
CMD2_DL ("d.is_meta", CMD2_ON_INFO(is_meta_download));
|
||||
CMD2_DL ("d.is_meta", [](auto* download, auto) { return download->info()->is_meta_download(); });
|
||||
|
||||
CMD2_DL_V ("d.resume", std::bind(&core::DownloadList::resume_default, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1));
|
||||
@@ -731,8 +720,8 @@ initialize_command_download() {
|
||||
CMD2_DL_V ("d.erase", std::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.check_hash", std::bind(&core::DownloadList::check_hash, control->core()->download_list(), std::placeholders::_1));
|
||||
|
||||
CMD2_DL ("d.save_resume", std::bind(&core::DownloadStore::save_resume, control->core()->download_store(), std::placeholders::_1));
|
||||
CMD2_DL ("d.save_full_session", std::bind(&core::DownloadStore::save_full, control->core()->download_store(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.save_resume", [](core::Download* download, auto) { session_thread::manager()->save_resume_download(download); });
|
||||
CMD2_DL_V ("d.save_full_session", [](core::Download* download, auto) { session_thread::manager()->save_full_download(download); });
|
||||
|
||||
CMD2_DL_V ("d.update_priorities", CMD2_ON_DL(update_priorities));
|
||||
|
||||
@@ -792,15 +781,15 @@ initialize_command_download() {
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.started", "rtorrent", "timestamp.started");
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.finished", "rtorrent", "timestamp.finished");
|
||||
|
||||
CMD2_DL ("d.connection_current", std::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type)));
|
||||
CMD2_DL_STRING("d.connection_current.set", std::bind(&apply_d_connection_type, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL ("d.connection_current", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CONNECTION_TYPE, d->download()->connection_type()); });
|
||||
CMD2_DL_STRING_V("d.connection_current.set", [](auto* d, auto arg) { apply_d_connection_type(d, arg); });
|
||||
|
||||
CMD2_DL_VAR_STRING("d.connection_leech", "rtorrent", "connection_leech");
|
||||
CMD2_DL_VAR_STRING("d.connection_seed", "rtorrent", "connection_seed");
|
||||
|
||||
CMD2_DL ("d.up.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(upload_choke_heuristic)));
|
||||
CMD2_DL ("d.up.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->upload_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.up.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, false));
|
||||
CMD2_DL ("d.down.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(download_choke_heuristic)));
|
||||
CMD2_DL ("d.down.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->download_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.down.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, true));
|
||||
|
||||
CMD2_DL_VAR_STRING("d.up.choke_heuristics.leech", "rtorrent", "choke_heuristics.up.leech");
|
||||
@@ -814,8 +803,8 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.views", std::bind(&download_get_variable, std::placeholders::_1, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.has", std::bind(&d_list_has, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.remove", std::bind(&d_list_remove, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.push_back", std::bind(&d_list_push_back, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.push_back_unique", std::bind(&d_list_push_back_unique, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL_STRING ("d.views.push_back", std::bind(&d_list_push_back_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL_STRING ("d.views.push_back_unique", std::bind(&d_list_push_back_unique_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
|
||||
// This command really needs to be improved, so we have proper
|
||||
// logging support.
|
||||
@@ -855,7 +844,7 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.bytes_done", CMD2_ON_DL(bytes_done));
|
||||
CMD2_DL ("d.ratio", std::bind(&retrieve_d_ratio, std::placeholders::_1));
|
||||
CMD2_DL ("d.chunks_hashed", CMD2_ON_DL(chunks_hashed));
|
||||
CMD2_DL ("d.free_diskspace", CMD2_ON_FL(free_diskspace));
|
||||
CMD2_DL ("d.free_diskspace", [](auto* download, auto) { return download->file_list()->free_diskspace_no_cache(); });
|
||||
|
||||
CMD2_DL ("d.size_files", CMD2_ON_FL(size_files));
|
||||
CMD2_DL ("d.size_bytes", CMD2_ON_FL(size_bytes));
|
||||
@@ -873,17 +862,20 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.wanted_chunks", CMD2_ON_DATA(wanted_chunks));
|
||||
|
||||
// Do not exposre d.tracker_announce.force to regular users.
|
||||
CMD2_DL_V ("d.tracker_announce", std::bind(&torrent::Download::manual_request, CMD2_BIND_DL, false));
|
||||
CMD2_DL_V ("d.tracker_announce.force", std::bind(&torrent::Download::manual_request, CMD2_BIND_DL, true));
|
||||
CMD2_DL_V ("d.tracker_announce", std::bind(&torrent::Download::manual_request, CMD2_BIND_DL, false));
|
||||
CMD2_DL_V ("d.tracker_announce.force", std::bind(&torrent::Download::manual_request, CMD2_BIND_DL, true));
|
||||
|
||||
CMD2_DL ("d.tracker_numwant", std::bind(&torrent::TrackerList::numwant, CMD2_BIND_TL));
|
||||
CMD2_DL_VALUE_V ("d.tracker_numwant.set", std::bind(&torrent::TrackerList::set_numwant, CMD2_BIND_TL, std::placeholders::_2));
|
||||
CMD2_DL ("d.tracker_numwant", std::bind(&torrent::tracker::TrackerControllerWrapper::numwant, CMD2_BIND_TC));
|
||||
CMD2_DL_VALUE_V ("d.tracker_numwant.set", std::bind(&torrent::tracker::TrackerControllerWrapper::set_numwant, CMD2_BIND_TC, std::placeholders::_2));
|
||||
// TODO: Deprecate 'd.tracker_focus'.
|
||||
CMD2_DL ("d.tracker_focus", std::bind(&core::Download::tracker_list_size, std::placeholders::_1));
|
||||
CMD2_DL ("d.tracker_size", std::bind(&core::Download::tracker_list_size, std::placeholders::_1));
|
||||
|
||||
CMD2_DL_LIST ("d.tracker.insert", std::bind(&download_tracker_insert, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_VALUE_V ("d.tracker.send_scrape", std::bind(&torrent::TrackerController::scrape_request, CMD2_BIND_TC, std::placeholders::_2));
|
||||
CMD2_DL ("d.tracker.has_active", std::bind(&torrent::tracker::TrackerControllerWrapper::has_active_trackers, CMD2_BIND_TC));
|
||||
CMD2_DL ("d.tracker.has_active_not_scrape", std::bind(&torrent::tracker::TrackerControllerWrapper::has_active_trackers_not_scrape, CMD2_BIND_TC));
|
||||
CMD2_DL ("d.tracker.has_usable", std::bind(&torrent::tracker::TrackerControllerWrapper::has_usable_trackers, CMD2_BIND_TC));
|
||||
CMD2_DL_LIST ("d.tracker.insert", std::bind(&download_tracker_insert, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_VALUE_V ("d.tracker.send_scrape", [](auto download, uint64_t arg) { download->tracker_controller().scrape_request(arg); });
|
||||
|
||||
CMD2_DL ("d.directory", CMD2_ON_FL(root_dir));
|
||||
CMD2_DL_STRING_V("d.directory.set", std::bind(&apply_d_directory, std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -905,7 +897,7 @@ initialize_command_download() {
|
||||
// CG_GROUP_INDEX()));
|
||||
|
||||
CMD2_DL ("d.group", std::bind(&cg_d_group, std::placeholders::_1));
|
||||
CMD2_DL ("d.group.name", std::bind(&cg_d_group, std::placeholders::_1));
|
||||
CMD2_DL ("d.group.name", std::bind(&cg_d_group_name, std::placeholders::_1));
|
||||
CMD2_DL_V ("d.group.set", std::bind(&cg_d_group_set, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_LIST ("f.multicall", std::bind(&f_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -913,4 +905,112 @@ initialize_command_download() {
|
||||
CMD2_DL_LIST ("t.multicall", std::bind(&t_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("p.call_target", std::bind(&p_call_target, std::placeholders::_2));
|
||||
|
||||
rpc::rpc.mark_safe("add_peer");
|
||||
rpc::rpc.mark_safe("d.hash");
|
||||
rpc::rpc.mark_safe("d.local_id");
|
||||
rpc::rpc.mark_safe("d.local_id_html");
|
||||
rpc::rpc.mark_safe("d.bitfield");
|
||||
rpc::rpc.mark_safe("d.base_path");
|
||||
rpc::rpc.mark_safe("d.base_path.hex");
|
||||
rpc::rpc.mark_safe("d.base_path.base64");
|
||||
rpc::rpc.mark_safe("d.base_path.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_path.as_binary");
|
||||
rpc::rpc.mark_safe("d.base_path.or_base64");
|
||||
rpc::rpc.mark_safe("d.base_path.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename");
|
||||
rpc::rpc.mark_safe("d.base_filename.hex");
|
||||
rpc::rpc.mark_safe("d.base_filename.base64");
|
||||
rpc::rpc.mark_safe("d.base_filename.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename.as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename.or_base64");
|
||||
rpc::rpc.mark_safe("d.base_filename.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.name");
|
||||
rpc::rpc.mark_safe("d.name.hex");
|
||||
rpc::rpc.mark_safe("d.name.base64");
|
||||
rpc::rpc.mark_safe("d.name.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.name.as_binary");
|
||||
rpc::rpc.mark_safe("d.name.or_base64");
|
||||
rpc::rpc.mark_safe("d.name.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.directory");
|
||||
rpc::rpc.mark_safe("d.directory_base");
|
||||
rpc::rpc.mark_safe("d.creation_date");
|
||||
rpc::rpc.mark_safe("d.load_date");
|
||||
rpc::rpc.mark_safe("d.up.rate");
|
||||
rpc::rpc.mark_safe("d.up.total");
|
||||
rpc::rpc.mark_safe("d.down.rate");
|
||||
rpc::rpc.mark_safe("d.down.total");
|
||||
rpc::rpc.mark_safe("d.skip.rate");
|
||||
rpc::rpc.mark_safe("d.skip.total");
|
||||
rpc::rpc.mark_safe("d.is_open");
|
||||
rpc::rpc.mark_safe("d.is_active");
|
||||
rpc::rpc.mark_safe("d.is_hash_checked");
|
||||
rpc::rpc.mark_safe("d.is_hash_checking");
|
||||
rpc::rpc.mark_safe("d.is_multi_file");
|
||||
rpc::rpc.mark_safe("d.is_private");
|
||||
rpc::rpc.mark_safe("d.is_pex_active");
|
||||
rpc::rpc.mark_safe("d.is_partially_done");
|
||||
rpc::rpc.mark_safe("d.is_not_partially_done");
|
||||
rpc::rpc.mark_safe("d.is_meta");
|
||||
rpc::rpc.mark_safe("d.peer_exchange");
|
||||
rpc::rpc.mark_safe("d.resume");
|
||||
rpc::rpc.mark_safe("d.pause");
|
||||
rpc::rpc.mark_safe("d.open");
|
||||
rpc::rpc.mark_safe("d.close");
|
||||
rpc::rpc.mark_safe("d.close.directly");
|
||||
rpc::rpc.mark_safe("d.erase");
|
||||
rpc::rpc.mark_safe("d.check_hash");
|
||||
rpc::rpc.mark_safe("d.save_resume");
|
||||
rpc::rpc.mark_safe("d.save_full_session");
|
||||
rpc::rpc.mark_safe("d.update_priorities");
|
||||
rpc::rpc.mark_safe("d.custom");
|
||||
rpc::rpc.mark_safe("d.custom1");
|
||||
rpc::rpc.mark_safe("d.custom2");
|
||||
rpc::rpc.mark_safe("d.custom3");
|
||||
rpc::rpc.mark_safe("d.custom4");
|
||||
rpc::rpc.mark_safe("d.custom5");
|
||||
rpc::rpc.mark_safe("d.size_bytes");
|
||||
rpc::rpc.mark_safe("d.size_chunks");
|
||||
rpc::rpc.mark_safe("d.size_pex");
|
||||
rpc::rpc.mark_safe("d.completed_bytes");
|
||||
rpc::rpc.mark_safe("d.complete");
|
||||
rpc::rpc.mark_safe("d.timestamp.started");
|
||||
rpc::rpc.mark_safe("d.timestamp.finished");
|
||||
rpc::rpc.mark_safe("d.bytes_done");
|
||||
rpc::rpc.mark_safe("d.peers_accounted");
|
||||
rpc::rpc.mark_safe("d.chunks_hashed");
|
||||
rpc::rpc.mark_safe("d.tracker_size");
|
||||
rpc::rpc.mark_safe("d.completed_chunks");
|
||||
rpc::rpc.mark_safe("d.left_bytes");
|
||||
rpc::rpc.mark_safe("d.chunk_size");
|
||||
rpc::rpc.mark_safe("d.priority");
|
||||
rpc::rpc.mark_safe("d.priority_str");
|
||||
rpc::rpc.mark_safe("d.state");
|
||||
rpc::rpc.mark_safe("d.state_changed");
|
||||
rpc::rpc.mark_safe("d.state_counter");
|
||||
rpc::rpc.mark_safe("d.connection_current");
|
||||
rpc::rpc.mark_safe("d.connection_leech");
|
||||
rpc::rpc.mark_safe("d.connection_seed");
|
||||
rpc::rpc.mark_safe("d.throttle_name");
|
||||
rpc::rpc.mark_safe("d.uploads_max");
|
||||
rpc::rpc.mark_safe("d.downloads_max");
|
||||
rpc::rpc.mark_safe("d.peers_min");
|
||||
rpc::rpc.mark_safe("d.peers_max");
|
||||
rpc::rpc.mark_safe("d.peers_connected");
|
||||
rpc::rpc.mark_safe("d.peers_not_connected");
|
||||
rpc::rpc.mark_safe("d.peers_complete");
|
||||
rpc::rpc.mark_safe("d.tracker_numwant");
|
||||
rpc::rpc.mark_safe("d.tracker_focus");
|
||||
rpc::rpc.mark_safe("d.message");
|
||||
rpc::rpc.mark_safe("d.hashing");
|
||||
rpc::rpc.mark_safe("d.hashing_failed");
|
||||
rpc::rpc.mark_safe("d.free_diskspace");
|
||||
rpc::rpc.mark_safe("d.views");
|
||||
rpc::rpc.mark_safe("d.views.remove");
|
||||
rpc::rpc.mark_safe("d.views.push_back_unique");
|
||||
rpc::rpc.mark_safe("d.ratio");
|
||||
rpc::rpc.mark_safe("f.multicall");
|
||||
rpc::rpc.mark_safe("p.multicall");
|
||||
rpc::rpc.mark_safe("p.call_target");
|
||||
rpc::rpc.mark_safe("t.multicall");
|
||||
}
|
||||
|
||||
+149
-137
@@ -1,70 +1,33 @@
|
||||
// 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 "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "control.h"
|
||||
#include "globals.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 },
|
||||
{"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", 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 f : object_storage_flags)
|
||||
if (f.first == flag)
|
||||
return f.second;
|
||||
for (auto [n, f] : object_storage_flags)
|
||||
if (n == flag)
|
||||
return f;
|
||||
|
||||
throw torrent::input_error("unknown flag");
|
||||
}
|
||||
@@ -109,7 +72,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;
|
||||
@@ -122,9 +85,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);
|
||||
@@ -134,20 +97,32 @@ 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& rawKey = (itrArgs++)->as_string();
|
||||
const std::string& raw_key = (itrArgs++)->as_string();
|
||||
|
||||
if (rawKey.empty() ||
|
||||
control->object_storage()->find_raw_string(torrent::raw_string::from_string(rawKey)) != control->object_storage()->end() ||
|
||||
rpc::commands.has(rawKey) || rpc::commands.has(rawKey + ".set"))
|
||||
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"))
|
||||
throw torrent::input_error("Invalid key.");
|
||||
|
||||
torrent::Object value;
|
||||
@@ -171,90 +146,101 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
throw torrent::input_error("Invalid type.");
|
||||
}
|
||||
|
||||
// We must initialize this varriable to prevent a critical memory leak
|
||||
int cmd_flags = rpc::CommandMap::flag_delete_key;
|
||||
int cmd_flags = 0;
|
||||
|
||||
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_xmlrpc;
|
||||
cmd_flags |= rpc::CommandMap::flag_public_rpc;
|
||||
|
||||
if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_list_type) {
|
||||
torrent::Object valueList = torrent::Object::create_list();
|
||||
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(rawKey, valueList, flags);
|
||||
control->object_storage()->insert_str(raw_key, valueList, flags);
|
||||
} else {
|
||||
control->object_storage()->insert_str(rawKey, value, flags);
|
||||
control->object_storage()->insert_str(raw_key, 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>
|
||||
(create_new_key(rawKey),
|
||||
std::bind(&rpc::object_storage::call_function_str, control->object_storage(),
|
||||
rawKey, 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>(
|
||||
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);
|
||||
|
||||
} else {
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type> >::type>
|
||||
(create_new_key(rawKey),
|
||||
std::bind(&rpc::object_storage::get_str, control->object_storage(), rawKey),
|
||||
&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>(
|
||||
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);
|
||||
}
|
||||
|
||||
// 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>(rawKey, ".rlookup"),
|
||||
// std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), rawKey),
|
||||
// (create_new_key<9>(raw_key, ".rlookup"),
|
||||
// std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), raw_key),
|
||||
// &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>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_bool, control->object_storage(), rawKey, 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>(
|
||||
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);
|
||||
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>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_value, control->object_storage(), rawKey, 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>(
|
||||
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);
|
||||
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>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_string, control->object_storage(), rawKey, std::placeholders::_2),
|
||||
&rpc::command_base_call_string<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>(
|
||||
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>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_list, control->object_storage(), rawKey, 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_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);
|
||||
break;
|
||||
case rpc::object_storage::flag_function_type:
|
||||
case rpc::object_storage::flag_multi_type:
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,22 +268,15 @@ 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& rawKey = (itrArgs++)->as_string();
|
||||
const std::string& raw_key = (itrArgs++)->as_string();
|
||||
|
||||
if (rawKey.empty() || rpc::commands.has(rawKey))
|
||||
if (raw_key.empty() || rpc::commands.has(raw_key))
|
||||
throw torrent::input_error("Invalid key.");
|
||||
|
||||
int flags = rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc;
|
||||
int new_flags = rpc::parse_option_flags(itrArgs->as_string(), std::bind(&object_storage_parse_flag, std::placeholders::_1));
|
||||
|
||||
if ((new_flags & rpc::object_storage::flag_private))
|
||||
flags &= ~rpc::CommandMap::flag_public_xmlrpc;
|
||||
|
||||
if ((new_flags & rpc::object_storage::flag_constant))
|
||||
flags &= ~rpc::CommandMap::flag_modifiable;
|
||||
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
new_args.push_back(raw_key);
|
||||
|
||||
if ((new_flags & rpc::object_storage::flag_function_type) ||
|
||||
(new_flags & rpc::object_storage::flag_multi_type)) {
|
||||
@@ -345,8 +324,7 @@ 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(create_new_key(new_key), create_new_key(dest_key),
|
||||
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable);
|
||||
rpc::commands.create_redirect(new_key, dest_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_modifiable);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -372,9 +350,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);
|
||||
}
|
||||
|
||||
@@ -384,9 +362,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();
|
||||
@@ -402,13 +380,11 @@ system_method_set_key(const torrent::Object::list_type& args) {
|
||||
|
||||
torrent::Object
|
||||
system_method_list_keys(const torrent::Object::string_type& args) {
|
||||
const torrent::Object::map_type& multi_cmd = control->object_storage()->get_str(args).as_map();
|
||||
|
||||
torrent::Object rawResult = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = rawResult.as_list();
|
||||
torrent::Object rawResult = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = rawResult.as_list();
|
||||
|
||||
for (torrent::Object::map_const_iterator itr = multi_cmd.begin(), last = multi_cmd.end(); itr != last; itr++)
|
||||
result.push_back(itr->first);
|
||||
for (const auto& itr : control->object_storage()->get_str(args).as_map())
|
||||
result.push_back(itr.first);
|
||||
|
||||
return rawResult;
|
||||
}
|
||||
@@ -428,8 +404,14 @@ cmd_catch(rpc::target_type target, const torrent::Object& args) {
|
||||
|
||||
void
|
||||
initialize_command_dynamic() {
|
||||
CMD2_VAR_BOOL ("method.use_deprecated", true);
|
||||
CMD2_VAR_VALUE ("method.use_intermediate", 1);
|
||||
// clang-format off
|
||||
#ifdef HAVE_XMLRPC_TINYXML2
|
||||
CMD2_ANY ("system.listMethods", std::bind(&system_listMethods)); // only used by tinyxml2
|
||||
#endif
|
||||
|
||||
// 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));
|
||||
@@ -462,14 +444,44 @@ initialize_command_dynamic() {
|
||||
|
||||
CMD2_ANY ("catch", std::bind(&cmd_catch, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("strings.choke_heuristics", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS));
|
||||
CMD2_ANY ("strings.choke_heuristics.upload", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_UPLOAD));
|
||||
CMD2_ANY ("strings.choke_heuristics.download", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD));
|
||||
CMD2_ANY ("strings.connection_type", std::bind(&torrent::option_list_strings, torrent::OPTION_CONNECTION_TYPE));
|
||||
CMD2_ANY ("strings.encryption", std::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION));
|
||||
CMD2_ANY ("strings.ip_filter", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_FILTER));
|
||||
CMD2_ANY ("strings.ip_tos", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_TOS));
|
||||
CMD2_ANY ("strings.log_group", std::bind(&torrent::option_list_strings, torrent::OPTION_LOG_GROUP));
|
||||
CMD2_ANY ("strings.tracker_event", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_EVENT));
|
||||
CMD2_ANY ("strings.tracker_mode", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
|
||||
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");
|
||||
}
|
||||
|
||||
+149
-170
@@ -1,52 +1,19 @@
|
||||
// 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 <rak/error_number.h>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/hash_string.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/directory_events.h>
|
||||
#include <torrent/utils/file_stat.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/manager.h"
|
||||
@@ -54,76 +21,58 @@
|
||||
#include "rpc/command_scheduler.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
#include "thread_worker.h"
|
||||
#include "utils/watch_ready_queue.h"
|
||||
|
||||
torrent::Object
|
||||
apply_on_ratio(const torrent::Object& rawArgs) {
|
||||
const std::string& groupName = rawArgs.as_string();
|
||||
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());
|
||||
|
||||
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())
|
||||
if (view_itr == 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]
|
||||
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();
|
||||
int64_t min_ratio = rpc::commands.call("group." + group_name + ".ratio.min", rpc::make_target()).as_value();
|
||||
int64_t max_ratio = rpc::commands.call("group." + group_name + ".ratio.max", rpc::make_target()).as_value();
|
||||
int64_t min_upload = rpc::commands.call("group." + group_name + ".ratio.upload", rpc::make_target()).as_value();
|
||||
|
||||
std::vector<core::Download*> downloads;
|
||||
|
||||
for (core::View::iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
|
||||
for (auto itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) {
|
||||
if (!(*itr)->is_seeding() || rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) != 0)
|
||||
continue;
|
||||
|
||||
// rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
|
||||
int64_t total_done = (*itr)->download()->bytes_done();
|
||||
int64_t total_upload = (*itr)->info()->up_rate()->total();
|
||||
|
||||
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))
|
||||
if (!(total_upload >= min_upload && total_upload * 100 >= total_done * min_ratio) &&
|
||||
!(max_ratio > 0 && total_upload * 100 > total_done * max_ratio))
|
||||
continue;
|
||||
|
||||
downloads.push_back(*itr);
|
||||
}
|
||||
|
||||
sprintf(buffer, "group.%s.ratio.command", groupName.c_str());
|
||||
auto ratio_command = "group." + group_name + ".ratio.command";
|
||||
|
||||
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: ");
|
||||
}
|
||||
for (const auto& download : downloads)
|
||||
rpc::commands.call_catch(ratio_command, rpc::make_target(download), torrent::Object(), "Ratio reached, but command failed: ");
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_start_tied() {
|
||||
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)
|
||||
for (const auto& download : *control->core()->download_list()) {
|
||||
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
|
||||
continue;
|
||||
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
torrent::utils::FileStat fs;
|
||||
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
|
||||
|
||||
if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile)))
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "d.try_start=");
|
||||
if (!tied_to_file.empty() && fs.update(expand_path(tied_to_file)))
|
||||
rpc::parse_command_single(rpc::make_target(download), "d.try_start=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
@@ -131,15 +80,15 @@ apply_start_tied() {
|
||||
|
||||
torrent::Object
|
||||
apply_stop_untied() {
|
||||
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)
|
||||
for (const auto& download : *control->core()->download_list()) {
|
||||
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 0)
|
||||
continue;
|
||||
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
torrent::utils::FileStat fs;
|
||||
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
|
||||
|
||||
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)))
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop=");
|
||||
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file)))
|
||||
rpc::parse_command_single(rpc::make_target(download), "d.try_stop=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
@@ -147,12 +96,12 @@ apply_stop_untied() {
|
||||
|
||||
torrent::Object
|
||||
apply_close_untied() {
|
||||
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));
|
||||
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));
|
||||
|
||||
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=");
|
||||
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=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
@@ -160,11 +109,11 @@ apply_close_untied() {
|
||||
|
||||
torrent::Object
|
||||
apply_remove_untied() {
|
||||
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));
|
||||
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));
|
||||
|
||||
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) {
|
||||
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file))) {
|
||||
// Need to clear tied_to_file so it doesn't try to delete it.
|
||||
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(*itr));
|
||||
|
||||
@@ -185,9 +134,9 @@ apply_schedule(const torrent::Object::list_type& args) {
|
||||
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
|
||||
const std::string& arg1 = (itr++)->as_string();
|
||||
const std::string& arg2 = (itr++)->as_string();
|
||||
const std::string& arg3 = (itr++)->as_string();
|
||||
auto& arg1 = (itr++)->as_string();
|
||||
auto& arg2 = (itr++)->as_string();
|
||||
auto& arg3 = (itr++)->as_string();
|
||||
|
||||
control->command_scheduler()->parse(arg1, arg2, arg3, *itr);
|
||||
|
||||
@@ -201,7 +150,7 @@ apply_load(const torrent::Object::list_type& args, int flags) {
|
||||
if (argsItr == args.end())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
const std::string& filename = argsItr->as_string();
|
||||
auto& filename = argsItr->as_string();
|
||||
core::Manager::command_list_type commands;
|
||||
|
||||
while (++argsItr != args.end())
|
||||
@@ -216,28 +165,29 @@ 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) {
|
||||
core::DownloadList* downloadList = control->core()->download_list();
|
||||
|
||||
apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
|
||||
bool closed = false;
|
||||
core::Manager::DListItr itr = downloadList->begin();
|
||||
|
||||
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);
|
||||
torrent::FileList::cache_list cache;
|
||||
|
||||
(*itr)->set_hash_failed(true);
|
||||
(*itr)->set_message(std::string("Low diskspace."));
|
||||
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;
|
||||
|
||||
closed = true;
|
||||
}
|
||||
control->core()->download_list()->close(download);
|
||||
|
||||
++itr;
|
||||
download->set_hash_failed(true);
|
||||
download->set_message(std::string("Low diskspace."));
|
||||
|
||||
closed = true;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -247,23 +197,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 viewItr;
|
||||
core::ViewManager::iterator view_itr;
|
||||
|
||||
if (argsItr != args.end() && !argsItr->as_string().empty())
|
||||
viewItr = viewManager->find((argsItr++)->as_string());
|
||||
view_itr = viewManager->find((argsItr++)->as_string());
|
||||
else
|
||||
viewItr = viewManager->find("default");
|
||||
view_itr = viewManager->find("default");
|
||||
|
||||
if (viewItr == viewManager->end())
|
||||
if (view_itr == 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 = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
|
||||
for (core::View::const_iterator itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) {
|
||||
const torrent::HashString* hashString = &(*itr)->info()->hash();
|
||||
|
||||
resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end()));
|
||||
resultList.push_back(torrent::utils::transform_to_hex_str(*hashString));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -275,32 +225,29 @@ d_multicall(const torrent::Object::list_type& args) {
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator viewItr;
|
||||
core::ViewManager::iterator view_itr;
|
||||
|
||||
if (!args.front().as_string().empty())
|
||||
viewItr = viewManager->find(args.front().as_string());
|
||||
view_itr = viewManager->find(args.front().as_string());
|
||||
else
|
||||
viewItr = viewManager->find("default");
|
||||
view_itr = viewManager->find("default");
|
||||
|
||||
if (viewItr == viewManager->end())
|
||||
if (view_itr == 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.
|
||||
unsigned int dlist_size = (*viewItr)->size_visible();
|
||||
core::Download* dlist[dlist_size];
|
||||
|
||||
std::copy((*viewItr)->begin_visible(), (*viewItr)->end_visible(), dlist);
|
||||
std::vector<core::Download*> dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
|
||||
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) {
|
||||
for (auto download : dlist) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*vItr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
auto& cmd = cItr->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,32 +258,34 @@ torrent::Object
|
||||
d_multicall_filtered(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("d.multicall.filtered requires at least 2 arguments.");
|
||||
torrent::Object::list_const_iterator arg = args.begin();
|
||||
|
||||
auto arg = args.begin();
|
||||
|
||||
// Find the given view
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator viewItr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
auto* viewManager = control->view_manager();
|
||||
auto view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
|
||||
if (viewItr == viewManager->end())
|
||||
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;
|
||||
(*viewItr)->filter_by(*++arg, dlist);
|
||||
(*view_itr)->filter_by(*++arg, dlist);
|
||||
|
||||
// Generate result by iterating over all items
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
++arg; // skip to first command
|
||||
|
||||
for (core::View::iterator item = dlist.begin(); item != dlist.end(); ++item) {
|
||||
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++) {
|
||||
const std::string& cmdstr = command->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
|
||||
auto& cmdstr = command->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,53 +298,83 @@ call_watch_command(const std::string& command, const std::string& path) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_added(const torrent::Object::list_type& args) {
|
||||
directory_watch(const torrent::Object::list_type& args, int flags) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
const std::string& path = args.front().as_string();
|
||||
const std::string& command = args.back().as_string();
|
||||
auto& path = args.front().as_string();
|
||||
auto& command = args.back().as_string();
|
||||
std::string expanded_path = expand_path(path);
|
||||
|
||||
if (!control->directory_events()->open())
|
||||
throw torrent::input_error("Could not open inotify:" + std::string(rak::error_number::current().c_str()));
|
||||
throw torrent::input_error("Could not open inotify:" + std::string(std::strerror(errno)));
|
||||
|
||||
control->directory_events()->notify_on(path.c_str(),
|
||||
torrent::directory_events::flag_on_added | torrent::directory_events::flag_on_updated,
|
||||
std::bind(&call_watch_command, command, std::placeholders::_1));
|
||||
torrent::watch_descriptor::slot_string slot =
|
||||
flags == torrent::directory_events::flag_on_ready ?
|
||||
torrent::watch_descriptor::slot_string([command](const auto& arg) { control->watch_ready_queue()->push(command, arg); }) :
|
||||
torrent::watch_descriptor::slot_string(std::bind(&call_watch_command, command, std::placeholders::_1));
|
||||
|
||||
control->directory_events()->notify_on(expanded_path.c_str(), flags, slot);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_added(const torrent::Object::list_type& args) {
|
||||
return directory_watch(args,
|
||||
torrent::directory_events::flag_on_added |
|
||||
torrent::directory_events::flag_on_updated);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_ready(const torrent::Object::list_type& args) {
|
||||
return directory_watch(args,
|
||||
torrent::directory_events::flag_on_ready);
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_events() {
|
||||
CMD2_ANY_STRING ("on_ratio", std::bind(&apply_on_ratio, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("on_ratio", [](auto, auto& args) { return apply_on_ratio(args); });
|
||||
|
||||
CMD2_ANY ("start_tied", std::bind(&apply_start_tied));
|
||||
CMD2_ANY ("stop_untied", std::bind(&apply_stop_untied));
|
||||
CMD2_ANY ("close_untied", std::bind(&apply_close_untied));
|
||||
CMD2_ANY ("remove_untied", std::bind(&apply_remove_untied));
|
||||
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_LIST ("schedule2", std::bind(&apply_schedule, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("schedule_remove2", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2));
|
||||
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_STRING_V("import", std::bind(&apply_import, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("try_import", std::bind(&apply_try_import, std::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_LIST ("load.normal", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.raw", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_start | core::Manager::create_raw_data));
|
||||
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_VALUE ("close_low_diskspace", std::bind(&apply_close_low_diskspace, std::placeholders::_2));
|
||||
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_LIST ("download_list", std::bind(&apply_download_list, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("d.multicall2", std::bind(&d_multicall, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("d.multicall.filtered", std::bind(&d_multicall_filtered, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("download_list", [](auto, auto& args) { return apply_download_list(args); });
|
||||
|
||||
CMD2_ANY_LIST ("directory.watch.added", std::bind(&directory_watch_added, std::placeholders::_2));
|
||||
// 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");
|
||||
}
|
||||
|
||||
+79
-62
@@ -1,43 +1,5 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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>
|
||||
@@ -53,7 +15,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((torrent::priority_t)value);
|
||||
file->set_priority(static_cast<torrent::priority_enum>(value));
|
||||
}
|
||||
|
||||
// TODO: Redundant.
|
||||
@@ -62,24 +24,34 @@ apply_f_path(torrent::File* file) {
|
||||
if (file->path()->empty())
|
||||
return std::string();
|
||||
|
||||
torrent::Object resultRaw(*file->path()->begin());
|
||||
torrent::Object::string_type& result = resultRaw.as_string();
|
||||
torrent::Object result_raw(file->path()->begin()->str());
|
||||
auto& result = result_raw.as_string();
|
||||
|
||||
for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++)
|
||||
result += '/' + *itr;
|
||||
result += '/' + itr->str();
|
||||
|
||||
return resultRaw;
|
||||
return result_raw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_f_path_components(torrent::File* file) {
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
apply_f_path_components(torrent::File* file, int output_type) {
|
||||
auto result_raw = torrent::Object::create_list();
|
||||
auto& result = result_raw.as_list();
|
||||
|
||||
for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++)
|
||||
result.push_back(*itr);
|
||||
for (const auto& itr : *file->path()) {
|
||||
switch (output_type) {
|
||||
case 0: result.push_back(itr.str()); break;
|
||||
case 1: result.push_back(itr.object_hex()); break;
|
||||
case 2: result.push_back(itr.object_base64()); break;
|
||||
case 3: result.push_back(itr.object_base64_as_binary()); break;
|
||||
case 4: result.push_back(itr.object_as_binary()); break;
|
||||
case 5: result.push_back(itr.object_utf8_or_base64()); break;
|
||||
case 6: result.push_back(itr.object_utf8_or_as_binary()); break;
|
||||
default: throw torrent::input_error("apply_f_path_components(): invalid output type");
|
||||
};
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
return result_raw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -95,7 +67,7 @@ apply_fi_filename_last(torrent::FileListIterator* itr) {
|
||||
if (itr->depth() >= itr->file()->path()->size())
|
||||
return "ERROR";
|
||||
|
||||
return itr->file()->path()->at(itr->depth());
|
||||
return itr->file()->path()->at(itr->depth()).str();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -118,21 +90,32 @@ initialize_command_file() {
|
||||
CMD2_FILE_V("f.prioritize_last.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
CMD2_FILE_V("f.prioritize_last.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
|
||||
CMD2_FILE("f.size_bytes", std::bind(&torrent::File::size_bytes, std::placeholders::_1));
|
||||
CMD2_FILE("f.size_chunks", std::bind(&torrent::File::size_chunks, std::placeholders::_1));
|
||||
CMD2_FILE("f.completed_chunks", std::bind(&torrent::File::completed_chunks, std::placeholders::_1));
|
||||
CMD2_FILE("f.size_bytes", [](auto* file, auto) { return file->size_bytes(); });
|
||||
CMD2_FILE("f.size_chunks", [](auto* file, auto) { return file->size_chunks(); });
|
||||
CMD2_FILE("f.completed_chunks", [](auto* file, auto) { return file->completed_chunks(); });
|
||||
|
||||
CMD2_FILE("f.offset", std::bind(&torrent::File::offset, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_first", std::bind(&torrent::File::range_first, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_second", std::bind(&torrent::File::range_second, std::placeholders::_1));
|
||||
CMD2_FILE("f.offset", [](auto* file, auto) { return file->offset(); });
|
||||
CMD2_FILE("f.range_first", [](auto* file, auto) { return file->range_first(); });
|
||||
CMD2_FILE("f.range_second", [](auto* file, auto) { return file->range_second(); });
|
||||
|
||||
CMD2_FILE("f.priority", std::bind(&torrent::File::priority, std::placeholders::_1));
|
||||
CMD2_FILE_VALUE_V("f.priority.set", std::bind(&apply_f_set_priority, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_FILE("f.priority", [](auto* file, auto) { return file->priority(); });
|
||||
CMD2_FILE_VALUE_V("f.priority.set", [](auto* file, auto v) { apply_f_set_priority(file, v); });
|
||||
|
||||
CMD2_FILE("f.path", std::bind(&apply_f_path, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_components", std::bind(&apply_f_path_components, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_depth", std::bind(&apply_f_path_depth, std::placeholders::_1));
|
||||
CMD2_FILE("f.frozen_path", std::bind(&torrent::File::frozen_path, std::placeholders::_1));
|
||||
CMD2_FILE("f.path", [](auto* file, auto) { return apply_f_path(file); });
|
||||
CMD2_FILE("f.path_components", [](auto* file, auto) { return apply_f_path_components(file, 0); });
|
||||
CMD2_FILE("f.path_components.hex", [](auto* file, auto) { return apply_f_path_components(file, 1); });
|
||||
CMD2_FILE("f.path_components.base64", [](auto* file, auto) { return apply_f_path_components(file, 2); });
|
||||
CMD2_FILE("f.path_components.base64_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 3); });
|
||||
CMD2_FILE("f.path_components.as_binary", [](auto* file, auto) { return apply_f_path_components(file, 4); });
|
||||
CMD2_FILE("f.path_components.or_base64", [](auto* file, auto) { return apply_f_path_components(file, 5); });
|
||||
CMD2_FILE("f.path_components.or_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 6); });
|
||||
CMD2_FILE("f.path_depth", [](auto* file, auto) { return apply_f_path_depth(file); });
|
||||
CMD2_FILE("f.frozen_path", [](auto* file, auto) { return file->frozen_path().str(); });
|
||||
CMD2_FILE("f.frozen_path.hex", [](auto* file, auto) { return file->frozen_path().object_hex(); });
|
||||
CMD2_FILE("f.frozen_path.base64", [](auto* file, auto) { return file->frozen_path().object_base64(); });
|
||||
CMD2_FILE("f.frozen_path.as_binary", [](auto* file, auto) { return file->frozen_path().object_as_binary(); });
|
||||
CMD2_FILE("f.frozen_path.or_base64", [](auto* file, auto) { return file->frozen_path().object_utf8_or_base64(); });
|
||||
CMD2_FILE("f.frozen_path.or_as_binary", [](auto* file, auto) { return file->frozen_path().object_utf8_or_as_binary(); });
|
||||
|
||||
CMD2_FILE("f.match_depth_prev", std::bind(&torrent::File::match_depth_prev, std::placeholders::_1));
|
||||
CMD2_FILE("f.match_depth_next", std::bind(&torrent::File::match_depth_next, std::placeholders::_1));
|
||||
@@ -141,4 +124,38 @@ initialize_command_file() {
|
||||
|
||||
CMD2_FILEITR("fi.filename_last", std::bind(&apply_fi_filename_last, std::placeholders::_1));
|
||||
CMD2_FILEITR("fi.is_file", std::bind(&torrent::FileListIterator::is_file, std::placeholders::_1));
|
||||
|
||||
rpc::rpc.mark_safe("f.path");
|
||||
rpc::rpc.mark_safe("f.path_components");
|
||||
rpc::rpc.mark_safe("f.path_depth");
|
||||
rpc::rpc.mark_safe("f.frozen_path");
|
||||
rpc::rpc.mark_safe("f.frozen_path.hex");
|
||||
rpc::rpc.mark_safe("f.frozen_path.base64");
|
||||
rpc::rpc.mark_safe("f.frozen_path.base64_as_binary");
|
||||
rpc::rpc.mark_safe("f.frozen_path.as_binary");
|
||||
rpc::rpc.mark_safe("f.frozen_path.or_base64");
|
||||
rpc::rpc.mark_safe("f.frozen_path.or_as_binary");
|
||||
rpc::rpc.mark_safe("f.offset");
|
||||
rpc::rpc.mark_safe("f.size_bytes");
|
||||
rpc::rpc.mark_safe("f.size_chunks");
|
||||
rpc::rpc.mark_safe("f.completed_chunks");
|
||||
rpc::rpc.mark_safe("f.range_first");
|
||||
rpc::rpc.mark_safe("f.range_second");
|
||||
rpc::rpc.mark_safe("f.priority");
|
||||
rpc::rpc.mark_safe("f.priority.set");
|
||||
rpc::rpc.mark_safe("f.is_created");
|
||||
rpc::rpc.mark_safe("f.is_open");
|
||||
rpc::rpc.mark_safe("f.is_create_queued");
|
||||
rpc::rpc.mark_safe("f.is_resize_queued");
|
||||
rpc::rpc.mark_safe("f.prioritize_first");
|
||||
rpc::rpc.mark_safe("f.prioritize_first.enable");
|
||||
rpc::rpc.mark_safe("f.prioritize_first.disable");
|
||||
rpc::rpc.mark_safe("f.prioritize_last");
|
||||
rpc::rpc.mark_safe("f.prioritize_last.enable");
|
||||
rpc::rpc.mark_safe("f.prioritize_last.disable");
|
||||
rpc::rpc.mark_safe("f.last_touched");
|
||||
rpc::rpc.mark_safe("f.match_depth_prev");
|
||||
rpc::rpc.mark_safe("f.match_depth_next");
|
||||
rpc::rpc.mark_safe("fi.filename_last");
|
||||
rpc::rpc.mark_safe("fi.is_file");
|
||||
}
|
||||
|
||||
+62
-46
@@ -69,7 +69,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++)
|
||||
@@ -121,8 +121,7 @@ cg_get_index(const torrent::Object& raw_args) {
|
||||
|
||||
if (arg.is_string()) {
|
||||
if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) {
|
||||
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)));
|
||||
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg.as_string() == cg->name(); });
|
||||
|
||||
if (itr == cg_list_hack.end())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
@@ -154,14 +153,17 @@ 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 (std::vector<torrent::choke_group*>::iterator itr = cg_list_hack.begin(), last = cg_list_hack.end(); itr != last; itr++)
|
||||
result.push_back((*itr)->name());
|
||||
|
||||
for (auto itr : cg_list_hack)
|
||||
result.push_back(itr->name());
|
||||
|
||||
return torrent::Object::from_list(result);
|
||||
}
|
||||
@@ -178,24 +180,21 @@ 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::find_if(cg_list_hack.begin(), cg_list_hack.end(),
|
||||
rak::equal(arg, std::mem_fun(&torrent::choke_group::name))) != cg_list_hack.end())
|
||||
if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](auto cg) { return arg == cg->name(); }))
|
||||
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::choke_queue::HEURISTICS_UPLOAD_LEECH);
|
||||
cg_list_hack.back()->down_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_DOWNLOAD_LEECH);
|
||||
cg_list_hack.back()->up_queue()->set_heuristics(torrent::HEURISTICS_UPLOAD_LEECH);
|
||||
cg_list_hack.back()->down_queue()->set_heuristics(torrent::HEURISTICS_DOWNLOAD_LEECH);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_index_of(const std::string& arg) {
|
||||
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)));
|
||||
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg == cg->name(); });
|
||||
|
||||
if (itr == cg_list_hack.end())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
@@ -338,52 +337,69 @@ options.
|
||||
|
||||
void
|
||||
initialize_command_groups() {
|
||||
CMD2_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD2_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
|
||||
CMD_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
|
||||
#if USE_CHOKE_GROUP
|
||||
CMD2_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
#else
|
||||
apply_cg_insert("default");
|
||||
|
||||
CMD2_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
#endif
|
||||
|
||||
// Commands specific for a group. Supports as the first argument the
|
||||
// name, the index or a negative index.
|
||||
CMD2_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.tracker.mode", std::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE,
|
||||
std::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT())));
|
||||
CMD2_ANY_LIST ("choke_group.tracker.mode.set", std::bind(&apply_cg_tracker_mode_set, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.tracker.mode", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_TRACKER_MODE, cg_get_group(arg)->tracker_mode()); });
|
||||
CMD_ANY_LIST ("choke_group.tracker.mode.set", [](auto, auto arg) { return apply_cg_tracker_mode_set(arg); });
|
||||
|
||||
CMD2_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD2_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
CMD_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
|
||||
CMD2_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD2_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
|
||||
CMD2_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.up.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->up_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.up.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, true); });
|
||||
|
||||
CMD2_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
|
||||
CMD2_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->down_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.down.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, false); });
|
||||
|
||||
rpc::rpc.mark_safe("choke_group.list");
|
||||
rpc::rpc.mark_safe("choke_group.size");
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
+35
-76
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
#define RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
|
||||
@@ -43,13 +7,32 @@
|
||||
|
||||
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_xmlrpc, NULL, NULL);
|
||||
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_rpc, 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, \
|
||||
@@ -92,9 +75,9 @@ 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*>, 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_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_VAR_BOOL(key, value) \
|
||||
control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_bool_type); \
|
||||
@@ -136,24 +119,20 @@ void initialize_commands();
|
||||
CMD2_ANY(key, std::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
#define CMD2_REDIRECT(from_key, to_key) \
|
||||
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(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_FILE(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
|
||||
#define CMD2_REDIRECT_TRACKER(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_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);
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
|
||||
|
||||
//
|
||||
// Conversion of return types:
|
||||
@@ -188,24 +167,4 @@ 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
|
||||
|
||||
+19
-52
@@ -1,56 +1,18 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
|
||||
|
||||
@@ -67,7 +29,7 @@ torrent::Object
|
||||
apply_ip_tables_size_data(const std::string& args) {
|
||||
rpc::ip_table_list::const_iterator itr = ip_tables.find(args);
|
||||
|
||||
if (itr != ip_tables.end())
|
||||
if (itr == ip_tables.end())
|
||||
throw torrent::input_error("IP table does not exist.");
|
||||
|
||||
uint32_t size = itr->table.sizeof_data();
|
||||
@@ -91,7 +53,7 @@ apply_ip_tables_get(const torrent::Object::list_type& args) {
|
||||
if (table_itr == ip_tables.end())
|
||||
throw torrent::input_error("Could not find ip table.");
|
||||
|
||||
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
if(!table_itr->table.defined(address_start, address_end))
|
||||
@@ -241,9 +203,14 @@ ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address
|
||||
uint32_t mask=0;
|
||||
uint32_t end_mask=0;
|
||||
|
||||
mask = (~mask) << (32-mask_bits);
|
||||
if (mask_bits == 0) {
|
||||
mask = 0;
|
||||
end_mask = ~(uint32_t)0;
|
||||
} else {
|
||||
mask = (~mask) << (32-mask_bits);
|
||||
end_mask = (~end_mask) >> mask_bits;
|
||||
}
|
||||
*address_start = ip & mask;
|
||||
end_mask = (~end_mask) >> mask_bits;
|
||||
*address_end = (ip & mask) | end_mask;
|
||||
|
||||
valid=true;
|
||||
@@ -300,7 +267,7 @@ apply_ipv4_filter_get(const std::string& args) {
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
|
||||
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
|
||||
@@ -328,8 +295,8 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
std::string value_name = args.back().as_string();
|
||||
int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, value_name.c_str());
|
||||
|
||||
std::fstream file(rak::path_expand(filename).c_str(), std::ios::in);
|
||||
|
||||
std::fstream file(expand_path(filename).c_str(), std::ios::in);
|
||||
|
||||
if (!file.is_open())
|
||||
throw torrent::input_error("Could not open ip filter file: " + filename);
|
||||
|
||||
@@ -386,7 +353,7 @@ apply_ipv4_filter_dump() {
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value));
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_to_c_str_or_throw(torrent::OPTION_IP_FILTER, value));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
|
||||
|
||||
+190
-162
@@ -1,65 +1,31 @@
|
||||
// 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"
|
||||
|
||||
@@ -69,11 +35,10 @@ 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 (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++)
|
||||
if ((*itr)->is_active())
|
||||
size += (*itr)->file_list()->size_bytes();
|
||||
for (const auto& d : *control->core()->download_list())
|
||||
if (d->is_active())
|
||||
size += d->file_list()->size_bytes();
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -131,8 +96,12 @@ post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object:
|
||||
|
||||
inline const std::string&
|
||||
check_name(const std::string& str) {
|
||||
if (!rak::is_all_name(str))
|
||||
throw torrent::input_error("Non-alphanumeric characters found.");
|
||||
auto itr = std::find_if(str.begin(), str.end(), [](char c) {
|
||||
return !std::isalnum(c, std::locale::classic()) && c != '_';
|
||||
});
|
||||
|
||||
if (itr != str.end())
|
||||
throw torrent::input_error("Invalid characters found in name.");
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -146,40 +115,24 @@ 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",
|
||||
"schedule2=group." + name + ".ratio,5,60,on_ratio=" + name));
|
||||
"schedule=group." + name + ".ratio,5,60,on_ratio=" + name));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple",
|
||||
"schedule_remove2=group." + name + ".ratio"));
|
||||
"schedule.remove=group." + name + ".ratio"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
|
||||
"d.try_close= ;d.ignore_commands.set=1"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".view", "string", view));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.min", "value", (int64_t)200));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.max", "value", (int64_t)300));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.upload", "value", (int64_t)20 << 20));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".view", "string", view));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.min", "value", (int64_t)200));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.max", "value", (int64_t)300));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.upload", "value", (int64_t)20 << 20));
|
||||
|
||||
if (rpc::call_command_value("method.use_intermediate") == 1) {
|
||||
// Deprecated in 0.7.0:
|
||||
|
||||
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");
|
||||
}
|
||||
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");
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -218,12 +171,16 @@ cmd_file_append(const torrent::Object::list_type& args) {
|
||||
|
||||
FILE* output = fopen(args.front().as_string().c_str(), "a");
|
||||
|
||||
if (output == NULL)
|
||||
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + rak::error_number::current().c_str());
|
||||
if (output == nullptr)
|
||||
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + std::strerror(errno));
|
||||
|
||||
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
|
||||
|
||||
fprintf(output, "\n");
|
||||
try {
|
||||
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
|
||||
fprintf(output, "\n");
|
||||
} catch (...) {
|
||||
fclose(output);
|
||||
throw;
|
||||
}
|
||||
fclose(output);
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -231,116 +188,187 @@ cmd_file_append(const torrent::Object::list_type& args) {
|
||||
void
|
||||
initialize_command_local() {
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
core::DownloadStore* dStore = control->core()->download_store();
|
||||
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
|
||||
CMD2_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD2_ANY ("system.pid", std::bind(&getpid));
|
||||
CMD_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD_ANY ("system.pid", std::bind(&getpid));
|
||||
|
||||
CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
|
||||
CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
|
||||
CMD2_VAR_C_STRING("system.library_version", torrent::version());
|
||||
CMD2_VAR_VALUE ("system.file.allocate", 0);
|
||||
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
|
||||
CMD2_VAR_VALUE ("system.file.split_size", -1);
|
||||
CMD2_VAR_STRING ("system.file.split_suffix", ".part");
|
||||
CMD_VAR_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_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
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,
|
||||
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
|
||||
CMD2_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
CMD_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
|
||||
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.last");
|
||||
CMD_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD_VAR_LIST ("file.prioritize_toc.last");
|
||||
|
||||
CMD2_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
|
||||
CMD2_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
|
||||
CMD2_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
|
||||
CMD_ANY ("system.files.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_STRING ("system.env", std::bind(&system_env, std::placeholders::_2));
|
||||
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", std::bind(&rak::timer::seconds, &cachedTime));
|
||||
CMD2_ANY ("system.time_seconds", std::bind(&rak::timer::current_seconds));
|
||||
CMD2_ANY ("system.time_usec", std::bind(&rak::timer::current_usec));
|
||||
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
|
||||
|
||||
CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::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_VAR_BOOL ("system.daemon", false);
|
||||
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
|
||||
|
||||
CMD2_ANY_V ("system.shutdown.normal", std::bind(&Control::receive_normal_shutdown, control));
|
||||
CMD2_ANY_V ("system.shutdown.quick", std::bind(&Control::receive_quick_shutdown, control));
|
||||
CMD2_REDIRECT_GENERIC_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
CMD_VAR_BOOL ("system.daemon", false);
|
||||
|
||||
CMD2_ANY ("system.cwd", std::bind(&system_get_cwd));
|
||||
CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::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.sync.always_safe", std::bind(&CM_t::safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", std::bind(&CM_t::set_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.safe_free_diskspace", std::bind(&CM_t::safe_free_diskspace, chunkManager));
|
||||
CMD2_ANY ("pieces.sync.timeout", std::bind(&CM_t::timeout_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", std::bind(&CM_t::set_timeout_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.timeout_safe", std::bind(&CM_t::timeout_safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", std::bind(&CM_t::set_timeout_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.queue_size", std::bind(&CM_t::sync_queue_size, chunkManager));
|
||||
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
|
||||
CMD2_ANY ("pieces.preload.type", std::bind(&CM_t::preload_type, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.type.set", std::bind(&CM_t::set_preload_type, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_size", std::bind(&CM_t::preload_min_size, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", std::bind(&CM_t::set_preload_min_size, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_rate", std::bind(&CM_t::preload_required_rate, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", std::bind(&CM_t::set_preload_required_rate, chunkManager, std::placeholders::_2));
|
||||
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
|
||||
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
|
||||
|
||||
CMD2_ANY ("pieces.memory.current", std::bind(&CM_t::memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.sync_queue", std::bind(&CM_t::sync_queue_memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.block_count", std::bind(&CM_t::memory_block_count, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.max", std::bind(&CM_t::max_memory_usage, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.memory.max.set", std::bind(&CM_t::set_max_memory_usage, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.stats_preloaded", std::bind(&CM_t::stats_preloaded, chunkManager));
|
||||
CMD2_ANY ("pieces.stats_not_preloaded", std::bind(&CM_t::stats_not_preloaded, chunkManager));
|
||||
CMD_ANY ("system.sockets.size", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
|
||||
CMD_ANY ("system.sockets.max_size", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
|
||||
CMD_ANY_VALUE_V ("system.sockets.max_size.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
|
||||
CMD_ANY_V ("system.sockets.adjust_alloc", [](auto, auto) { torrent::runtime::socket_manager()->adjust_allocation(); });
|
||||
|
||||
CMD2_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
|
||||
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
|
||||
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
|
||||
|
||||
CMD2_ANY ("pieces.hash.queue_size", std::bind(&torrent::hash_queue_size));
|
||||
CMD2_VAR_BOOL ("pieces.hash.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); });
|
||||
CMD_ANY (category_name + ".min_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_min_allocation(category); });
|
||||
CMD_ANY (category_name + ".max_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_allocation(category); });
|
||||
|
||||
CMD2_VAR_STRING ("directory.default", "./");
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
CMD2_VAR_STRING ("session.name", "");
|
||||
CMD2_VAR_BOOL ("session.use_lock", true);
|
||||
CMD2_VAR_BOOL ("session.on_completion", true);
|
||||
CMD_ANY_VALUE_V(category_name + ".min_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_min_allocation(category, value); });
|
||||
CMD_ANY_VALUE_V(category_name + ".max_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_max_allocation(category, value); });
|
||||
}
|
||||
|
||||
CMD2_ANY ("session.path", std::bind(&core::DownloadStore::path, dStore));
|
||||
CMD2_ANY_STRING_V("session.path.set", std::bind(&core::DownloadStore::set_path, dStore, std::placeholders::_2));
|
||||
CMD_ANY ("pieces.sync.always_safe", [](auto, auto) { return torrent::runtime::memory_manager()->safe_sync(); });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.always_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_safe_sync(value); });
|
||||
CMD_ANY ("pieces.sync.safe_free_diskspace", [](auto, auto) { return torrent::runtime::memory_manager()->sync_safe_free_diskspace(); });
|
||||
CMD_ANY ("pieces.sync.timeout", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_sync().count(); });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.timeout.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_sync(value); });
|
||||
// CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_safe_sync(); });
|
||||
// CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_safe_sync(value); });
|
||||
CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return 0; });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto) { });
|
||||
CMD_ANY ("pieces.sync.queue_size", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_block_count(); });
|
||||
|
||||
CMD2_ANY_V ("session.save", std::bind(&core::DownloadList::session_save, dList));
|
||||
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); });
|
||||
|
||||
#define CMD2_EXECUTE(key, flags) \
|
||||
CMD2_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
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));
|
||||
|
||||
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.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); });
|
||||
|
||||
CMD2_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
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);
|
||||
|
||||
// TODO: Convert to new command types:
|
||||
*rpc::command_base::argument(0) = "placeholder.0";
|
||||
*rpc::command_base::argument(1) = "placeholder.1";
|
||||
*rpc::command_base::argument(2) = "placeholder.2";
|
||||
*rpc::command_base::argument(3) = "placeholder.3";
|
||||
CMD2_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD2_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD2_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD2_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
CMD_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
|
||||
CMD2_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
CMD_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
|
||||
rpc::rpc.mark_safe("system.api_version");
|
||||
rpc::rpc.mark_safe("system.client_version");
|
||||
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");
|
||||
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");
|
||||
}
|
||||
|
||||
+64
-60
@@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iterator>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
@@ -8,53 +9,24 @@
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "globals.h"
|
||||
#include "setup.h"
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/manager.h"
|
||||
#include "rak/path.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
static const int log_flag_use_gz = 0x1;
|
||||
static const int log_flag_append_pid = 0x2;
|
||||
static const int log_flag_append_file = 0x4;
|
||||
|
||||
void
|
||||
log_add_group_output_str(const char* group_name, const char* output_id) {
|
||||
int log_group = torrent::option_find_string(torrent::OPTION_LOG_GROUP, group_name);
|
||||
torrent::log_add_group_output(log_group, output_id);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log_open(int output_flags, const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
apply_log_open(int output_flags, const torrent::Object::list_type& raw_args) {
|
||||
std::vector<std::string> args;
|
||||
|
||||
std::string output_id = (itr++)->as_string();
|
||||
std::string file_name = rak::path_expand((itr++)->as_string());
|
||||
|
||||
if ((output_flags & log_flag_append_pid)) {
|
||||
char buffer[32];
|
||||
snprintf(buffer, 32, ".%li", (long)getpid());
|
||||
|
||||
file_name += buffer;
|
||||
}
|
||||
|
||||
bool append = (output_flags & log_flag_append_file);
|
||||
|
||||
if ((output_flags & log_flag_use_gz))
|
||||
torrent::log_open_gz_file_output(output_id.c_str(), file_name.c_str(), append);
|
||||
else
|
||||
torrent::log_open_file_output(output_id.c_str(), file_name.c_str(), append);
|
||||
|
||||
while (itr != args.end())
|
||||
log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str());
|
||||
for (const auto& arg : raw_args)
|
||||
args.push_back(arg.as_string());
|
||||
|
||||
apply_log_open_str(output_flags, args);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
@@ -62,10 +34,35 @@ 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();
|
||||
}
|
||||
|
||||
@@ -86,7 +83,7 @@ apply_log(const torrent::Object::string_type& arg, int logType) {
|
||||
}
|
||||
|
||||
if (!arg.empty()) {
|
||||
int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||
int logFd = open(expand_path(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||
|
||||
if (logFd < 0)
|
||||
throw torrent::input_error("Could not open execute log file.");
|
||||
@@ -108,19 +105,21 @@ 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 (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());
|
||||
for (const auto& d : *control->core()->download_list()) {
|
||||
std::vector<torrent::vm_mapping> tmp_mappings = torrent::chunk_list_mapping(d->download());
|
||||
|
||||
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
|
||||
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
|
||||
}
|
||||
|
||||
FILE* log_file = fopen(str.c_str(), "w");
|
||||
|
||||
for (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));
|
||||
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));
|
||||
}
|
||||
|
||||
fclose(log_file);
|
||||
@@ -129,18 +128,23 @@ log_vmmap_dump(const std::string& str) {
|
||||
|
||||
void
|
||||
initialize_command_logging() {
|
||||
CMD2_ANY_LIST ("log.open_file", std::bind(&apply_log_open, 0, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_gz_file", std::bind(&apply_log_open, log_flag_use_gz, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_file_pid", std::bind(&apply_log_open, log_flag_append_pid, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_gz_file_pid", std::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_file", std::bind(&apply_log_open, 0, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_file.flush", std::bind(&apply_log_open, log_flag_flush, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_gz_file", std::bind(&apply_log_open, log_flag_use_gz, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_file_pid", std::bind(&apply_log_open, log_flag_append_pid, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.open_gz_file_pid", std::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.append_file.flush", std::bind(&apply_log_open, log_flag_append_file | log_flag_flush, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
|
||||
CMD2_ANY_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.xmlrpc", std::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, 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
|
||||
}
|
||||
|
||||
+322
-181
@@ -1,56 +1,27 @@
|
||||
// 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"
|
||||
@@ -58,26 +29,121 @@
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#ifdef HAVE_SYSTEMD
|
||||
#include <sys/socket.h>
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
torrent::Object
|
||||
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 {};
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_encryption(const torrent::Object::list_type& args) {
|
||||
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
|
||||
if (args.empty())
|
||||
throw torrent::input_error("No encryption options specified.");
|
||||
|
||||
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());
|
||||
torrent::encryption_mode encryption_mode, handshake_mode, stream_mode;
|
||||
|
||||
if (opt == torrent::ConnectionManager::encryption_none)
|
||||
options_mask = torrent::ConnectionManager::encryption_none;
|
||||
else
|
||||
options_mask |= opt;
|
||||
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 {};
|
||||
}
|
||||
|
||||
torrent::connection_manager()->set_encryption_options(options_mask);
|
||||
if (args.size() != 2)
|
||||
return apply_obsolete_encryption(args);
|
||||
|
||||
return torrent::Object();
|
||||
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 {};
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -87,94 +153,60 @@ apply_tos(const torrent::Object::string_type& arg) {
|
||||
if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1))
|
||||
value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str());
|
||||
|
||||
torrent::connection_manager()->set_priority(value);
|
||||
torrent::runtime::network_config()->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_xmlrpc() {
|
||||
rpc::xmlrpc.initialize();
|
||||
rpc::xmlrpc.slot_find_download() = std::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), std::placeholders::_1);
|
||||
rpc::xmlrpc.slot_find_file() = std::bind(&xmlrpc_find_file, std::placeholders::_1, std::placeholders::_2);
|
||||
rpc::xmlrpc.slot_find_tracker() = std::bind(&xmlrpc_find_tracker, std::placeholders::_1, std::placeholders::_2);
|
||||
rpc::xmlrpc.slot_find_peer() = std::bind(&xmlrpc_find_peer, std::placeholders::_1, std::placeholders::_2);
|
||||
initialize_rpc_handlers() {
|
||||
rpc::rpc.initialize_handlers();
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
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))
|
||||
for (const auto& [name, cmd] : rpc::commands) {
|
||||
if (!(cmd.m_flags & rpc::CommandMap::flag_public_rpc))
|
||||
continue;
|
||||
|
||||
rpc::xmlrpc.insert_command(itr->first, itr->second.m_parm, itr->second.m_doc);
|
||||
rpc::rpc.insert_command(name.c_str(), cmd.m_parm, cmd.m_doc);
|
||||
++count;
|
||||
}
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "XMLRPC initialized with %u functions.", count);
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "RPC manager initialized with %u functions.", count);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_scgi(const std::string& arg, int type) {
|
||||
if (worker_thread->scgi() != NULL)
|
||||
if (scgi_thread::scgi() != nullptr)
|
||||
throw torrent::input_error("SCGI already enabled.");
|
||||
|
||||
if (!rpc::xmlrpc.is_valid())
|
||||
initialize_xmlrpc();
|
||||
initialize_rpc_handlers();
|
||||
|
||||
rpc::SCgi* scgi = new rpc::SCgi;
|
||||
torrent::sa_unique_ptr sa;
|
||||
|
||||
rak::address_info* ai = NULL;
|
||||
rak::socket_address sa;
|
||||
rak::socket_address* saPtr;
|
||||
auto scgi = std::make_unique<rpc::SCgi>();
|
||||
|
||||
try {
|
||||
int port, err;
|
||||
char dummy;
|
||||
int port{};
|
||||
char dummy{};
|
||||
char address[1024];
|
||||
std::string path;
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) {
|
||||
sa.sa_inet()->clear();
|
||||
saPtr = &sa;
|
||||
sa = torrent::sa_make_inet();
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is open to any address and is a security risk");
|
||||
|
||||
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
|
||||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
|
||||
if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0)
|
||||
throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");
|
||||
|
||||
saPtr = ai->address();
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(address, AF_UNSPEC).get());
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not bind address: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
|
||||
|
||||
@@ -185,33 +217,82 @@ apply_scgi(const std::string& arg, int type) {
|
||||
if (port <= 0 || port >= (1 << 16))
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
saPtr->set_port(port);
|
||||
scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route"));
|
||||
torrent::sap_set_port(sa, port);
|
||||
scgi->open_port(sa.get(), torrent::sap_length(sa), rpc::call_command_value("network.scgi.dont_route"));
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
default:
|
||||
path = rak::path_expand(arg);
|
||||
path = expand_path(arg);
|
||||
|
||||
unlink(path.c_str());
|
||||
scgi->open_named(path);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ai != NULL) rak::address_info::free_address_info(ai);
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
if (ai != NULL) rak::address_info::free_address_info(ai);
|
||||
|
||||
delete scgi;
|
||||
throw torrent::input_error(e.what());
|
||||
}
|
||||
|
||||
worker_thread->set_scgi(scgi);
|
||||
scgi_thread::set_scgi(scgi.release());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_scgi_systemd() {
|
||||
#ifdef HAVE_SYSTEMD
|
||||
if (scgi_thread::scgi() != nullptr)
|
||||
throw torrent::input_error("SCGI already enabled.");
|
||||
|
||||
int n = sd_listen_fds(0);
|
||||
if (n < 1)
|
||||
throw torrent::input_error("No systemd socket(s) provided (sd_listen_fds returned " +
|
||||
std::to_string(n) + ").");
|
||||
|
||||
// Iterate over all provided fds. Use the first listening stream socket;
|
||||
// close the rest. The systemd docs say unused fds should be closed.
|
||||
int selected_fd = -1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int fd = SD_LISTEN_FDS_START + i;
|
||||
|
||||
if (selected_fd != -1) {
|
||||
::close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto err = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1);
|
||||
|
||||
if (err < 0) {
|
||||
// Safe to ignore errors here - we just skip it and move on.
|
||||
::close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
// Not the socket we're looking for.
|
||||
::close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
selected_fd = fd;
|
||||
}
|
||||
|
||||
if (selected_fd == -1)
|
||||
throw torrent::input_error("No listening stream socket found among systemd-provided fds.");
|
||||
|
||||
initialize_rpc_handlers();
|
||||
|
||||
rpc::SCgi* scgi = new rpc::SCgi;
|
||||
scgi->open_fd(selected_fd);
|
||||
|
||||
scgi_thread::set_scgi(scgi);
|
||||
return torrent::Object();
|
||||
#else
|
||||
throw torrent::input_error("Systemd SCGI endpoint is not supported.");
|
||||
#endif
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_xmlrpc_dialect(const std::string& arg) {
|
||||
int value;
|
||||
@@ -225,88 +306,148 @@ apply_xmlrpc_dialect(const std::string& arg) {
|
||||
else
|
||||
value = -1;
|
||||
|
||||
rpc::xmlrpc.set_dialect(value);
|
||||
rpc::rpc.set_dialect(value);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_network() {
|
||||
torrent::ConnectionManager* cm = torrent::connection_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
core::CurlStack* httpStack = control->core()->http_stack();
|
||||
auto file_manager = torrent::file_manager();
|
||||
auto http_stack = torrent::net_thread::http_stack();
|
||||
auto nw_config = torrent::runtime::network_config();
|
||||
|
||||
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
|
||||
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); });
|
||||
|
||||
// Isn't port_open used?
|
||||
CMD2_VAR_BOOL ("network.port_open", true);
|
||||
CMD2_VAR_BOOL ("network.port_random", true);
|
||||
CMD2_VAR_STRING ("network.port_range", "6881-6999");
|
||||
CMD_ANY ("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 ("network.listen.port", std::bind(&torrent::ConnectionManager::listen_port, cm));
|
||||
CMD2_ANY ("network.listen.backlog", std::bind(&torrent::ConnectionManager::listen_backlog, cm));
|
||||
CMD2_ANY_VALUE_V ("network.listen.backlog.set", std::bind(&torrent::ConnectionManager::set_listen_backlog, cm, std::placeholders::_2));
|
||||
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(); });
|
||||
|
||||
CMD2_VAR_BOOL ("protocol.pex", true);
|
||||
CMD2_ANY_LIST ("protocol.encryption.set", std::bind(&apply_encryption, std::placeholders::_2));
|
||||
CMD_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
|
||||
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
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_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.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
|
||||
CMD_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
|
||||
CMD_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
|
||||
CMD_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
|
||||
CMD_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
|
||||
CMD_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
|
||||
CMD_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
|
||||
CMD_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
|
||||
CMD_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||
CMD_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||
|
||||
CMD2_ANY ("network.http.cacert", std::bind(&core::CurlStack::http_cacert, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.cacert.set", std::bind(&core::CurlStack::set_http_cacert, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.capath", std::bind(&core::CurlStack::http_capath, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack));
|
||||
CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", std::bind(&core::CurlStack::set_http_proxy, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_host", std::bind(&core::CurlStack::ssl_verify_host, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", std::bind(&core::CurlStack::set_ssl_verify_host, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2));
|
||||
CMD_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
|
||||
CMD_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
|
||||
|
||||
CMD2_ANY ("network.send_buffer.size", std::bind(&torrent::ConnectionManager::send_buffer_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", std::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY ("network.receive_buffer.size", std::bind(&torrent::ConnectionManager::receive_buffer_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", std::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("network.tos.set", std::bind(&apply_tos, std::placeholders::_2));
|
||||
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.bind_address", std::bind(&core::Manager::bind_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.bind_address.set", std::bind(&core::Manager::set_bind_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.local_address", std::bind(&core::Manager::local_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.local_address.set", std::bind(&core::Manager::set_local_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.proxy_address", std::bind(&core::Manager::proxy_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.proxy_address.set", std::bind(&core::Manager::set_proxy_address, control->core(), std::placeholders::_2));
|
||||
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.open_files", std::bind(&torrent::FileManager::open_files, fileManager));
|
||||
CMD2_ANY ("network.max_open_files", std::bind(&torrent::FileManager::max_open_files, fileManager));
|
||||
CMD2_ANY_VALUE_V ("network.max_open_files.set", std::bind(&torrent::FileManager::set_max_open_files, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("network.total_handshakes", std::bind(&torrent::total_handshakes));
|
||||
CMD2_ANY ("network.open_sockets", std::bind(&torrent::ConnectionManager::size, cm));
|
||||
CMD2_ANY ("network.max_open_sockets", std::bind(&torrent::ConnectionManager::max_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", std::bind(&torrent::ConnectionManager::set_max_size, cm, std::placeholders::_2));
|
||||
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_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
|
||||
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); });
|
||||
CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); });
|
||||
CMD_ANY ("network.proxy.http", [](auto, auto) { return torrent::runtime::proxy_manager()->http_proxy_url(); });
|
||||
CMD_ANY_STRING_V("network.proxy.http.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_http_proxy_url(str); });
|
||||
|
||||
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", std::bind(&apply_xmlrpc_dialect, std::placeholders::_2));
|
||||
CMD2_ANY ("network.xmlrpc.size_limit", std::bind(&rpc::XmlRpc::size_limit));
|
||||
CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", std::bind(&rpc::XmlRpc::set_size_limit, std::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 ("network.block.ipv4", std::bind(&torrent::ConnectionManager::is_block_ipv4, cm));
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4.set", std::bind(&torrent::ConnectionManager::set_block_ipv4, cm, std::placeholders::_2));
|
||||
CMD2_ANY ("network.block.ipv6", std::bind(&torrent::ConnectionManager::is_block_ipv6, cm));
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv6.set", std::bind(&torrent::ConnectionManager::set_block_ipv6, cm, std::placeholders::_2));
|
||||
CMD_ANY_STRING ("network.scgi.open_port", [](auto, auto& arg) { return apply_scgi(arg, 1); });
|
||||
CMD_ANY_STRING ("network.scgi.open_local", [](auto, auto& arg) { return apply_scgi(arg, 2); });
|
||||
CMD_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
|
||||
|
||||
CMD2_ANY ("network.prefer.ipv6", std::bind(&torrent::ConnectionManager::is_prefer_ipv6, cm));
|
||||
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", std::bind(&torrent::ConnectionManager::set_prefer_ipv6, cm, std::placeholders::_2));
|
||||
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");
|
||||
}
|
||||
|
||||
+42
-71
@@ -1,85 +1,28 @@
|
||||
// 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) {
|
||||
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
|
||||
auto sa = peer->peer_info()->socket_address();
|
||||
auto addr_str = torrent::sa_addr_str(sa);
|
||||
|
||||
if (addr->family() == rak::socket_address::af_inet6)
|
||||
return "[" + addr->address_str() + "]";
|
||||
else
|
||||
return addr->address_str();
|
||||
}
|
||||
if (sa->sa_family == AF_INET6)
|
||||
return "[" + addr_str + "]";
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_port(torrent::Peer* peer) {
|
||||
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port();
|
||||
return addr_str;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -92,18 +35,20 @@ retrieve_p_client_version(torrent::Peer* peer) {
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_options_str(torrent::Peer* peer) {
|
||||
return rak::transform_hex(peer->peer_info()->options(), peer->peer_info()->options() + 8);
|
||||
return torrent::utils::transform_to_hex_str(peer->peer_info()->options(), peer->peer_info()->options() + 8);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_completed_percent(torrent::Peer* peer) {
|
||||
if (peer->bitfield()->size_bits() == 0)
|
||||
return int64_t(0);
|
||||
return (100 * peer->bitfield()->size_set()) / peer->bitfield()->size_bits();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_peer() {
|
||||
CMD2_PEER("p.id", std::bind(&retrieve_p_id, std::placeholders::_1));
|
||||
CMD2_PEER("p.id_html", std::bind(&retrieve_p_id_html, std::placeholders::_1));
|
||||
CMD2_PEER("p.id", [](auto* peer, auto) { return torrent::utils::transform_to_hex_str(peer->id()); });
|
||||
CMD2_PEER("p.id_html", [](auto* peer, auto) { return torrent::utils::copy_escape_html_str(peer->id()); });
|
||||
CMD2_PEER("p.client_version", std::bind(&retrieve_p_client_version, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.options_str", std::bind(&retrieve_p_options_str, std::placeholders::_1));
|
||||
@@ -117,7 +62,7 @@ initialize_command_peer() {
|
||||
CMD2_PEER("p.is_preferred", std::bind(&torrent::PeerInfo::is_preferred, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
|
||||
|
||||
CMD2_PEER("p.address", std::bind(&retrieve_p_address, std::placeholders::_1));
|
||||
CMD2_PEER("p.port", std::bind(&retrieve_p_port, std::placeholders::_1));
|
||||
CMD2_PEER("p.port", [](auto* peer, auto) { return torrent::sa_port(peer->peer_info()->socket_address()); });
|
||||
|
||||
CMD2_PEER("p.completed_percent", std::bind(&retrieve_p_completed_percent, std::placeholders::_1));
|
||||
|
||||
@@ -135,4 +80,30 @@ initialize_command_peer() {
|
||||
|
||||
CMD2_PEER_V("p.disconnect", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, 0));
|
||||
CMD2_PEER_V("p.disconnect_delayed", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, torrent::ConnectionList::disconnect_delayed));
|
||||
|
||||
rpc::rpc.mark_safe("p.address");
|
||||
rpc::rpc.mark_safe("p.port");
|
||||
rpc::rpc.mark_safe("p.client_version");
|
||||
rpc::rpc.mark_safe("p.options_str");
|
||||
rpc::rpc.mark_safe("p.id");
|
||||
rpc::rpc.mark_safe("p.id_html");
|
||||
rpc::rpc.mark_safe("p.up_rate");
|
||||
rpc::rpc.mark_safe("p.up_total");
|
||||
rpc::rpc.mark_safe("p.down_rate");
|
||||
rpc::rpc.mark_safe("p.down_total");
|
||||
rpc::rpc.mark_safe("p.peer_rate");
|
||||
rpc::rpc.mark_safe("p.peer_total");
|
||||
rpc::rpc.mark_safe("p.is_encrypted");
|
||||
rpc::rpc.mark_safe("p.is_incoming");
|
||||
rpc::rpc.mark_safe("p.is_obfuscated");
|
||||
rpc::rpc.mark_safe("p.is_snubbed");
|
||||
rpc::rpc.mark_safe("p.is_unwanted");
|
||||
rpc::rpc.mark_safe("p.is_preferred");
|
||||
rpc::rpc.mark_safe("p.snubbed");
|
||||
rpc::rpc.mark_safe("p.snubbed.set");
|
||||
rpc::rpc.mark_safe("p.banned");
|
||||
rpc::rpc.mark_safe("p.banned.set");
|
||||
rpc::rpc.mark_safe("p.completed_percent");
|
||||
rpc::rpc.mark_safe("p.disconnect");
|
||||
rpc::rpc.mark_safe("p.disconnect_delayed");
|
||||
}
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -52,7 +16,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);
|
||||
|
||||
@@ -83,7 +47,7 @@ cmd_scheduler_simple_removed(core::Download* download) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_scheduler_simple_update(core::Download* download) {
|
||||
cmd_scheduler_simple_update([[maybe_unused]] core::Download* download) {
|
||||
core::View* viewActive = *control->view_manager()->find("active");
|
||||
core::View* viewStarted = *control->view_manager()->find("started");
|
||||
|
||||
@@ -91,7 +55,6 @@ cmd_scheduler_simple_update(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;
|
||||
@@ -102,8 +65,7 @@ cmd_scheduler_simple_update(core::Download* download) {
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (viewActive->size_visible() > maxActive) {
|
||||
|
||||
} else {
|
||||
while (viewActive->size_visible() > maxActive)
|
||||
control->core()->download_list()->pause(*viewActive->begin_visible());
|
||||
}
|
||||
|
||||
+104
-85
@@ -1,46 +1,10 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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"
|
||||
@@ -56,35 +20,47 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
|
||||
unsigned int prefixWidth, ret;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
rak::address_info* ai;
|
||||
torrent::sa_unique_ptr sa;
|
||||
|
||||
ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy);
|
||||
if (ret < 1 || rak::address_info::get_address_info(host, PF_INET, SOCK_STREAM, &ai) != 0)
|
||||
throw torrent::input_error("Could not resolve host.");
|
||||
|
||||
if (ret < 1)
|
||||
throw torrent::input_error("Invalid address/prefix.");
|
||||
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(host, AF_INET).get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
uint32_t begin, end;
|
||||
rak::socket_address sa;
|
||||
sa.copy(*ai->address(), ai->length());
|
||||
begin = end = sa.sa_inet()->address_h();
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
auto sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
|
||||
|
||||
begin = end = sa_addr;
|
||||
|
||||
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.sa_inet()->address_h() & ~netmask)
|
||||
|
||||
if (prefixWidth >= 32 || sa_addr & ~netmask)
|
||||
throw torrent::input_error("Invalid address/prefix.");
|
||||
|
||||
end = sa.sa_inet()->address_h() | ~netmask;
|
||||
end = sa_addr | ~netmask;
|
||||
|
||||
} else if (++itr != args.end()) {
|
||||
if (rak::address_info::get_address_info(itr->as_string().c_str(), PF_INET, SOCK_STREAM, &ai) != 0)
|
||||
throw torrent::input_error("Could not resolve host.");
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(itr->as_string(), AF_INET).get());
|
||||
|
||||
sa.copy(*ai->address(), ai->length());
|
||||
rak::address_info::free_address_info(ai);
|
||||
end = sa.sa_inet()->address_h();
|
||||
} 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;
|
||||
}
|
||||
|
||||
// convert to [begin, end) making sure the end doesn't overflow
|
||||
@@ -94,33 +70,35 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
|
||||
|
||||
torrent::Object
|
||||
apply_throttle(const torrent::Object::list_type& args, bool up) {
|
||||
torrent::Object::list_const_iterator argItr = args.begin();
|
||||
auto arg_itr = args.begin();
|
||||
|
||||
if (argItr == args.end())
|
||||
if (arg_itr == args.end())
|
||||
throw torrent::input_error("Missing throttle name.");
|
||||
|
||||
const std::string& name = argItr->as_string();
|
||||
const std::string& name = arg_itr->as_string();
|
||||
if (name.empty() || name == "NULL")
|
||||
throw torrent::input_error("Invalid throttle name '" + name + "'.");
|
||||
|
||||
if (++argItr == args.end() || argItr->as_string().empty())
|
||||
if (++arg_itr == args.end() || arg_itr->as_string().empty())
|
||||
throw torrent::input_error("Missing throttle rate for '" + name + "'.");
|
||||
|
||||
int64_t rate;
|
||||
rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate);
|
||||
rpc::parse_whole_value_nothrow(arg_itr->as_string().c_str(), &rate);
|
||||
|
||||
if (rate < 0)
|
||||
throw torrent::input_error("Throttle rate must be non-negative.");
|
||||
|
||||
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
|
||||
if (itr == control->core()->throttles().end())
|
||||
itr = control->core()->throttles().insert(std::make_pair(name, torrent::ThrottlePair(NULL, NULL))).first;
|
||||
auto itr = control->core()->throttles().find(name);
|
||||
|
||||
torrent::Throttle*& throttle = up ? itr->second.first : itr->second.second;
|
||||
if (rate != 0 && throttle == NULL)
|
||||
if (itr == control->core()->throttles().end())
|
||||
itr = control->core()->throttles().insert(std::make_pair(name, core::ThrottlePair(nullptr, nullptr))).first;
|
||||
|
||||
auto*& throttle = up ? itr->second.first : itr->second.second;
|
||||
|
||||
if (rate != 0 && throttle == nullptr)
|
||||
throttle = (up ? torrent::up_throttle_global() : torrent::down_throttle_global())->create_slave();
|
||||
|
||||
if (throttle != NULL)
|
||||
if (throttle != nullptr)
|
||||
throttle->set_max_rate(rate * 1024);
|
||||
|
||||
return torrent::Object();
|
||||
@@ -133,10 +111,10 @@ static const int throttle_info_rate = (1 << 3);
|
||||
|
||||
torrent::Object
|
||||
retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
|
||||
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();
|
||||
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();
|
||||
|
||||
if (throttle == NULL && name.empty())
|
||||
throttle = global;
|
||||
@@ -151,20 +129,6 @@ 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);
|
||||
@@ -196,10 +160,10 @@ initialize_command_throttle() {
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads.div._val", 1);
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads.global._val", 0);
|
||||
|
||||
CMD2_REDIRECT_GENERIC("throttle.max_uploads.div", "throttle.max_uploads.div._val");
|
||||
CMD2_REDIRECT_GENERIC("throttle.max_uploads.global", "throttle.max_uploads.global._val");
|
||||
CMD2_REDIRECT_GENERIC("throttle.max_downloads.div", "throttle.max_downloads.div._val");
|
||||
CMD2_REDIRECT_GENERIC("throttle.max_downloads.global", "throttle.max_downloads.global._val");
|
||||
CMD2_REDIRECT ("throttle.max_uploads.div", "throttle.max_uploads.div._val");
|
||||
CMD2_REDIRECT ("throttle.max_uploads.global", "throttle.max_uploads.global._val");
|
||||
CMD2_REDIRECT ("throttle.max_downloads.div", "throttle.max_downloads.div._val");
|
||||
CMD2_REDIRECT ("throttle.max_downloads.global", "throttle.max_downloads.global._val");
|
||||
|
||||
CMD2_ANY_VALUE ("throttle.max_uploads.div.set", std::bind(&throttle_update, "throttle.max_uploads.div._val.set", std::placeholders::_2));
|
||||
CMD2_ANY_VALUE ("throttle.max_uploads.global.set", std::bind(&throttle_update, "throttle.max_uploads.global._val.set", std::placeholders::_2));
|
||||
@@ -222,10 +186,65 @@ initialize_command_throttle() {
|
||||
// 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.ip", std::bind(&apply_address_throttle, std::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");
|
||||
}
|
||||
|
||||
+119
-109
@@ -1,46 +1,14 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <rak/address_info.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <torrent/dht_manager.h>
|
||||
#include <torrent/tracker.h>
|
||||
#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 <torrent/utils/log.h>
|
||||
|
||||
#include "core/download.h"
|
||||
@@ -52,37 +20,20 @@
|
||||
#include "core/dht_manager.h"
|
||||
|
||||
void
|
||||
tracker_set_enabled(torrent::Tracker* tracker, bool state) {
|
||||
tracker_set_enabled(torrent::tracker::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) {
|
||||
if (!torrent::dht_manager()->is_valid())
|
||||
throw torrent::input_error("DHT not enabled.");
|
||||
|
||||
int port, ret;
|
||||
int port;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
|
||||
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
|
||||
int ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
|
||||
|
||||
if (ret == 1)
|
||||
port = 6881;
|
||||
@@ -92,79 +43,138 @@ apply_dht_add_node(const std::string& arg) {
|
||||
if (port < 1 || port > 65535)
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port));
|
||||
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);
|
||||
});
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_enable_trackers(int64_t arg) {
|
||||
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));
|
||||
if (arg == 0) {
|
||||
for (auto download : *control->core()->download_list())
|
||||
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
|
||||
|
||||
if (arg && !rpc::call_command_value("trackers.use_udp"))
|
||||
(*itr)->enable_udp_trackers(false);
|
||||
}
|
||||
} else {
|
||||
for (auto download : *control->core()->download_list())
|
||||
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_tracker() {
|
||||
CMD2_TRACKER ("t.is_open", std::bind(&torrent::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_enabled", std::bind(&torrent::Tracker::is_enabled, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_usable", std::bind(&torrent::Tracker::is_usable, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_busy", std::bind(&torrent::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_extra_tracker", std::bind(&torrent::Tracker::is_extra_tracker, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.can_scrape", std::bind(&torrent::Tracker::can_scrape, std::placeholders::_1));
|
||||
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_V ("t.enable", std::bind(&torrent::Tracker::enable, std::placeholders::_1));
|
||||
CMD2_TRACKER_V ("t.disable", std::bind(&torrent::Tracker::disable, std::placeholders::_1));
|
||||
// TODO: Deprecate.
|
||||
CMD2_TRACKER ("t.can_scrape", [](auto* tracker, auto) { return tracker->is_scrapable(); });
|
||||
|
||||
CMD2_TRACKER_VALUE_V("t.is_enabled.set", std::bind(&tracker_set_enabled, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_TRACKER_V ("t.enable", [](auto* tracker, auto) { tracker->enable(); });
|
||||
CMD2_TRACKER_V ("t.disable", [](auto* tracker, auto) { tracker->disable(); });
|
||||
|
||||
CMD2_TRACKER ("t.url", std::bind(&torrent::Tracker::url, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.group", std::bind(&torrent::Tracker::group, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.type", std::bind(&torrent::Tracker::type, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.id", std::bind(&torrent::Tracker::tracker_id, std::placeholders::_1));
|
||||
CMD2_TRACKER_VALUE_V("t.is_enabled.set", [](auto* tracker, auto& value) { return tracker_set_enabled(tracker, value); });
|
||||
|
||||
CMD2_TRACKER ("t.latest_event", std::bind(&torrent::Tracker::latest_event, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.latest_new_peers", std::bind(&torrent::Tracker::latest_new_peers, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.latest_sum_peers", std::bind(&torrent::Tracker::latest_sum_peers, std::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(); });
|
||||
|
||||
// Time since last connection, connection attempt.
|
||||
CMD2_TRACKER ("t.latest_event", [](auto* tracker, auto) { return tracker->state().latest_event(); });
|
||||
CMD2_TRACKER ("t.latest_new_peers", [](auto* tracker, auto) { return tracker->state().latest_new_peers(); });
|
||||
CMD2_TRACKER ("t.latest_sum_peers", [](auto* tracker, auto) { return tracker->state().latest_sum_peers(); });
|
||||
|
||||
CMD2_TRACKER ("t.normal_interval", std::bind(&torrent::Tracker::normal_interval, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.min_interval", std::bind(&torrent::Tracker::min_interval, std::placeholders::_1));
|
||||
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.activity_time_next", std::bind(&torrent::Tracker::activity_time_next, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.activity_time_last", std::bind(&torrent::Tracker::activity_time_last, std::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.success_time_next", std::bind(&torrent::Tracker::success_time_next, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.success_time_last", std::bind(&torrent::Tracker::success_time_last, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.success_counter", std::bind(&torrent::Tracker::success_counter, std::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.failed_time_next", std::bind(&torrent::Tracker::failed_time_next, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.failed_time_last", std::bind(&torrent::Tracker::failed_time_last, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.failed_counter", std::bind(&torrent::Tracker::failed_counter, std::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.scrape_time_last", std::bind(&torrent::Tracker::scrape_time_last, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_counter", std::bind(&torrent::Tracker::scrape_counter, std::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_complete", std::bind(&torrent::Tracker::scrape_complete, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_incomplete", std::bind(&torrent::Tracker::scrape_incomplete, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_downloaded", std::bind(&torrent::Tracker::scrape_downloaded, std::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_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1)));
|
||||
CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0)));
|
||||
CMD2_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_VAR_BOOL ("trackers.use_udp", true);
|
||||
CMD2_VAR_VALUE ("trackers.numwant", -1);
|
||||
|
||||
CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2));
|
||||
CMD2_VAR_VALUE ("dht.port", int64_t(6881));
|
||||
CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2));
|
||||
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, control->dht_manager()));
|
||||
CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, control->dht_manager()));
|
||||
CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), std::placeholders::_2));
|
||||
CMD2_ANY ("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");
|
||||
}
|
||||
|
||||
+195
-152
@@ -1,55 +1,17 @@
|
||||
// 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 <rak/algorithm.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
#include <torrent/utils/log.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"
|
||||
@@ -64,7 +26,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.");
|
||||
|
||||
@@ -112,8 +74,8 @@ apply_view_list() {
|
||||
torrent::Object rawResult = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = rawResult.as_list();
|
||||
|
||||
for (core::ViewManager::const_iterator itr = control->view_manager()->begin(), last = control->view_manager()->end(); itr != last; itr++)
|
||||
result.push_back((*itr)->name());
|
||||
for (auto itr : *control->view_manager())
|
||||
result.push_back(itr->name());
|
||||
|
||||
return rawResult;
|
||||
}
|
||||
@@ -131,11 +93,12 @@ 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(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
apply_print([[maybe_unused]] rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
char buffer[1024];
|
||||
rpc::print_object(buffer, buffer + 1024, &rawArgs, 0);
|
||||
|
||||
@@ -144,7 +107,7 @@ apply_print(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
apply_cat([[maybe_unused]] rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
std::string result;
|
||||
|
||||
rpc::print_object_std(&result, &rawArgs, 0);
|
||||
@@ -152,7 +115,7 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_value(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
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)
|
||||
@@ -220,7 +183,7 @@ apply_not(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_false(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
apply_false([[maybe_unused]] rpc::target_type target, [[maybe_unused]] const torrent::Object& rawArgs) {
|
||||
return (int64_t)0;
|
||||
}
|
||||
|
||||
@@ -229,18 +192,18 @@ apply_and(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST)
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
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)))
|
||||
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)))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -252,17 +215,17 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST)
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
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)))
|
||||
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)))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -298,7 +261,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());
|
||||
@@ -427,7 +390,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();
|
||||
|
||||
@@ -443,7 +406,9 @@ apply_to_time(const torrent::Object& rawArgs, int flags) {
|
||||
|
||||
torrent::Object
|
||||
apply_to_elapsed_time(const torrent::Object& rawArgs) {
|
||||
uint64_t arg = cachedTime.seconds() - rawArgs.as_value();
|
||||
auto cached_seconds = torrent::this_thread::cached_seconds().count();
|
||||
|
||||
uint64_t arg = cached_seconds - rawArgs.as_value();
|
||||
|
||||
char buffer[48];
|
||||
snprintf(buffer, 48, "%2d:%02d:%02d", (int)(arg / 3600), (int)((arg / 60) % 60), (int)(arg % 60));
|
||||
@@ -470,7 +435,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));
|
||||
@@ -486,7 +451,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)
|
||||
@@ -507,11 +472,14 @@ apply_to_throttle(const torrent::Object& rawArgs) {
|
||||
// if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 }
|
||||
// <cond1>,<branch1>,<cond2>,<branch2>,<branch3>
|
||||
torrent::Object
|
||||
apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
const torrent::Object::list_type& args = rawArgs.as_list();
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
apply_if(rpc::target_type target, const torrent::Object& raw_args, int flags) {
|
||||
auto& args = raw_args.as_list();
|
||||
auto itr = args.begin();
|
||||
|
||||
while (itr != args.end() && itr != --args.end()) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Empty argument list to " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
|
||||
{
|
||||
torrent::Object tmp;
|
||||
const torrent::Object* conditional;
|
||||
|
||||
@@ -535,40 +503,44 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
result = false;
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Type not supported by 'if'.");
|
||||
throw torrent::input_error("Type not supported by " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
};
|
||||
|
||||
itr++;
|
||||
|
||||
if (result)
|
||||
break;
|
||||
|
||||
itr++;
|
||||
if (!result && itr != args.end())
|
||||
itr++;
|
||||
}
|
||||
|
||||
if (itr == args.end())
|
||||
return torrent::Object();
|
||||
|
||||
if (flags & 0x1 && itr->is_string()) {
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
if (flags & 0x1) {
|
||||
if (itr->is_string())
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
|
||||
} else if (flags & 0x1 && itr->is_dict_key()) {
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
if (itr->is_dict_key())
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
|
||||
} else if (flags & 0x1 && itr->is_list()) {
|
||||
// Move this into a special function or something. Also, might be
|
||||
// nice to have a parse_command function that takes list
|
||||
// iterator...
|
||||
if (itr->is_list()) {
|
||||
for (const auto& cmd_itr : itr->as_list()) {
|
||||
if (cmd_itr.is_string())
|
||||
rpc::parse_command(target, cmd_itr.as_string().c_str(), cmd_itr.as_string().c_str() + cmd_itr.as_string().size());
|
||||
|
||||
for (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 if (cmd_itr.is_dict_key())
|
||||
rpc::commands.call_command(cmd_itr.as_dict_key().c_str(), cmd_itr.as_dict_obj(), target);
|
||||
|
||||
return torrent::Object();
|
||||
else
|
||||
throw torrent::input_error("Invalid command type in branch list.");
|
||||
}
|
||||
|
||||
} else {
|
||||
return *itr;
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
throw torrent::input_error("Invalid command type in branch.");
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -584,7 +556,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.");
|
||||
|
||||
@@ -641,8 +613,9 @@ 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 && rak::timer::current_seconds() - start_time < rpc::convert_to_value(args.back()));
|
||||
return (int64_t)(start_time != 0 && cached_seconds - start_time < rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -651,8 +624,9 @@ 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 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back()));
|
||||
return (int64_t)(start_time != 0 && cached_seconds - start_time > rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
inline std::vector<int64_t>
|
||||
@@ -662,26 +636,26 @@ as_vector(const torrent::Object::list_type& args) {
|
||||
|
||||
std::vector<int64_t> result;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
for (const auto& arg : args) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
result.push_back(itr->as_value());
|
||||
} else if (itr->is_string()) {
|
||||
result.push_back(rpc::convert_to_value(itr->as_string()));
|
||||
} else if (itr->is_list()) {
|
||||
std::vector<int64_t> subResult = as_vector(itr->as_list());
|
||||
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, const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
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");
|
||||
|
||||
@@ -710,8 +684,9 @@ apply_math_basic(const char* name, const std::function<int64_t(int64_t,int64_t)>
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename Comp>
|
||||
int64_t
|
||||
apply_arith_basic(const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
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.");
|
||||
|
||||
@@ -743,25 +718,44 @@ apply_arith_count(const torrent::Object::list_type& args) {
|
||||
|
||||
int64_t val = 0;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
for (const auto& arg : args) {
|
||||
|
||||
switch (itr->type()) {
|
||||
switch (arg.type()) {
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
case torrent::Object::TYPE_STRING:
|
||||
val++;
|
||||
break;
|
||||
case torrent::Object::TYPE_LIST:
|
||||
val += apply_arith_count(itr->as_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)
|
||||
@@ -771,7 +765,8 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) {
|
||||
return (int64_t)(apply_math_basic(op, std::plus<int64_t>(), args) / apply_arith_count(args));
|
||||
} else if (strcmp(op, "median") == 0) {
|
||||
std::vector<int64_t> result = as_vector(args);
|
||||
return (int64_t)rak::median(result.begin(), result.end());
|
||||
|
||||
return (int64_t)median(result.begin(), result.end());
|
||||
} else {
|
||||
throw torrent::input_error("Wrong operation supplied to apply_arith_other.");
|
||||
}
|
||||
@@ -784,9 +779,9 @@ cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
|
||||
|
||||
std::vector<std::string> throttle_name_list;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
if (itr->is_string())
|
||||
throttle_name_list.push_back(itr->as_string());
|
||||
for (const auto& arg : args) {
|
||||
if (arg.is_string())
|
||||
throttle_name_list.push_back(arg.as_string());
|
||||
}
|
||||
|
||||
if (up)
|
||||
@@ -797,58 +792,69 @@ cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
|
||||
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();
|
||||
}
|
||||
|
||||
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(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::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", std::bind(&apply_view_list));
|
||||
CMD2_ANY_LIST ("view.set", std::bind(&apply_view_set, std::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", 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.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", 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.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", 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));
|
||||
|
||||
// Cleanup and add . to view.
|
||||
|
||||
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));
|
||||
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));
|
||||
|
||||
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_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_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));
|
||||
|
||||
// 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_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_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.throttle.global.step.small", 5);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
|
||||
|
||||
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_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_VAR_STRING ("ui.torrent_list.layout", "full");
|
||||
|
||||
// Move.
|
||||
CMD2_ANY("print", &apply_print);
|
||||
@@ -881,17 +887,54 @@ initialize_command_ui() {
|
||||
CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, "math.add", std::plus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, "math.sub", std::minus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, "math.mul", std::multiplies<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, "math.div", std::divides<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, "math.mod", std::modulus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.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");
|
||||
}
|
||||
|
||||
+88
-113
@@ -1,140 +1,101 @@
|
||||
// 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 "control.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/directory_events.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"
|
||||
|
||||
#include "control.h"
|
||||
Control::Control()
|
||||
: m_ui(new ui::Root()),
|
||||
m_display(new display::Manager()),
|
||||
m_input(new input::Manager()),
|
||||
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
|
||||
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()) {
|
||||
|
||||
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_core = std::make_unique<core::Manager>();
|
||||
m_view_manager = std::make_unique<core::ViewManager>();
|
||||
m_dht_manager = std::make_unique<core::DhtManager>();
|
||||
|
||||
m_commandScheduler(new rpc::CommandScheduler()),
|
||||
m_objectStorage(new rpc::object_storage()),
|
||||
m_directory_events(new torrent::directory_events()),
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
|
||||
|
||||
m_tick(0),
|
||||
m_shutdownReceived(false),
|
||||
m_shutdownQuick(false) {
|
||||
m_task_shutdown.slot() = [this] { handle_shutdown(); };
|
||||
m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); };
|
||||
|
||||
m_core = new core::Manager();
|
||||
m_viewManager = new core::ViewManager();
|
||||
m_dhtManager = new core::DhtManager();
|
||||
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input, std::placeholders::_1));
|
||||
|
||||
m_taskShutdown.slot() = std::bind(&Control::handle_shutdown, this);
|
||||
|
||||
m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log_std));
|
||||
m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); });
|
||||
}
|
||||
|
||||
Control::~Control() {
|
||||
delete m_inputStdin;
|
||||
delete m_input;
|
||||
m_view_manager.reset();
|
||||
|
||||
delete m_viewManager;
|
||||
|
||||
delete m_ui;
|
||||
delete m_display;
|
||||
delete m_core;
|
||||
delete m_dhtManager;
|
||||
|
||||
delete m_directory_events;
|
||||
delete m_commandScheduler;
|
||||
delete m_objectStorage;
|
||||
m_ui.reset();
|
||||
m_display.reset();
|
||||
}
|
||||
|
||||
void
|
||||
Control::initialize() {
|
||||
session_thread::thread()->start_thread();
|
||||
scgi_thread::thread()->start_thread();
|
||||
|
||||
display::Canvas::initialize();
|
||||
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));
|
||||
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(); });
|
||||
|
||||
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_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
|
||||
|
||||
m_ui->init(this);
|
||||
|
||||
if(!display::Canvas::daemon()) {
|
||||
m_inputStdin->insert(torrent::main_thread()->poll());
|
||||
}
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->insert();
|
||||
}
|
||||
|
||||
void
|
||||
Control::cleanup() {
|
||||
// delete m_scgi; m_scgi = NULL;
|
||||
rpc::xmlrpc.cleanup();
|
||||
rpc::rpc.cleanup();
|
||||
|
||||
priority_queue_erase(&taskScheduler, &m_taskShutdown);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests);
|
||||
|
||||
if(!display::Canvas::daemon()) {
|
||||
m_inputStdin->remove(torrent::main_thread()->poll());
|
||||
}
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->remove();
|
||||
|
||||
m_core->download_store()->disable();
|
||||
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_ui->cleanup();
|
||||
m_core->cleanup();
|
||||
@@ -147,50 +108,64 @@ Control::cleanup() {
|
||||
|
||||
void
|
||||
Control::cleanup_exception() {
|
||||
// delete m_scgi; m_scgi = NULL;
|
||||
|
||||
display::Canvas::cleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
Control::is_shutdown_completed() {
|
||||
if (!m_shutdownQuick || worker_thread->is_active())
|
||||
if (!m_shutdown_quick)
|
||||
return false;
|
||||
|
||||
// Tracker requests can be disowned, so wait for these to
|
||||
// finish. The edge case of torrent http downloads may delay
|
||||
// shutdown.
|
||||
if (!core()->http_stack()->empty() || !core()->http_queue()->empty())
|
||||
|
||||
// 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())
|
||||
return false;
|
||||
|
||||
return torrent::is_inactive();
|
||||
return core()->is_download_shutdown_completed();
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_shutdown() {
|
||||
m_watch_ready_queue->shutdown();
|
||||
|
||||
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
|
||||
|
||||
if (!m_shutdownQuick) {
|
||||
// Temporary hack:
|
||||
if (worker_thread->is_active())
|
||||
worker_thread->queue_item(&ThreadBase::stop_thread);
|
||||
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();
|
||||
|
||||
torrent::connection_manager()->listen_close();
|
||||
m_directory_events->close();
|
||||
m_core->shutdown(false);
|
||||
|
||||
if (!m_taskShutdown.is_queued())
|
||||
priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + rak::timer::from_seconds(5));
|
||||
if (!m_task_shutdown.is_scheduled())
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
|
||||
|
||||
} else {
|
||||
// Temporary hack:
|
||||
if (worker_thread->is_active())
|
||||
worker_thread->queue_item(&ThreadBase::stop_thread);
|
||||
|
||||
torrent::runtime::quick_shutdown();
|
||||
m_core->shutdown(true);
|
||||
}
|
||||
|
||||
m_shutdownQuick = true;
|
||||
m_shutdownReceived = false;
|
||||
if (!m_task_shutdown_clear_requests.is_scheduled())
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s);
|
||||
|
||||
m_shutdown_quick = true;
|
||||
m_shutdown_received = false;
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_shutdown_clear_requests() {
|
||||
torrent::net_thread::http_stack()->clear_requests();
|
||||
|
||||
// Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests.
|
||||
if (m_clear_requests_count++ == 0)
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s);
|
||||
else
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s);
|
||||
}
|
||||
|
||||
+48
-68
@@ -1,47 +1,12 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CONTROL_H
|
||||
#define RTORRENT_CONTROL_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <sys/types.h>
|
||||
#include <rak/timer.h>
|
||||
#include <rak/priority_queue_default.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
|
||||
namespace ui {
|
||||
class Root;
|
||||
@@ -60,49 +25,57 @@ 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_shutdownReceived; }
|
||||
bool is_shutdown_started() { return m_shutdownQuick; }
|
||||
bool is_shutdown_received() { return m_shutdown_received; }
|
||||
bool is_shutdown_started() { return m_shutdown_quick; }
|
||||
|
||||
void initialize();
|
||||
void cleanup();
|
||||
void cleanup_exception();
|
||||
|
||||
void handle_shutdown();
|
||||
void handle_shutdown_clear_requests();
|
||||
|
||||
void receive_normal_shutdown() { m_shutdownReceived = true; __sync_synchronize(); }
|
||||
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; __sync_synchronize(); }
|
||||
void receive_normal_shutdown() { m_shutdown_received = true; }
|
||||
void receive_quick_shutdown() { m_shutdown_received = true; m_shutdown_quick = true; }
|
||||
|
||||
core::Manager* core() { return m_core; }
|
||||
core::ViewManager* view_manager() { return m_viewManager; }
|
||||
core::DhtManager* dht_manager() { return m_dhtManager; }
|
||||
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(); }
|
||||
|
||||
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; }
|
||||
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(); }
|
||||
|
||||
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; }
|
||||
rpc::object_storage* object_storage() { return m_objectStorage; }
|
||||
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; }
|
||||
torrent::directory_events* directory_events() { return m_directory_events.get(); }
|
||||
utils::WatchReadyQueue* watch_ready_queue() { return m_watch_ready_queue.get(); }
|
||||
|
||||
uint64_t tick() const { return m_tick; }
|
||||
void inc_tick() { m_tick++; }
|
||||
@@ -114,28 +87,35 @@ private:
|
||||
Control(const Control&);
|
||||
void operator = (const Control&);
|
||||
|
||||
core::Manager* m_core;
|
||||
core::ViewManager* m_viewManager;
|
||||
core::DhtManager* m_dhtManager;
|
||||
std::unique_ptr<core::Manager> m_core;
|
||||
std::unique_ptr<core::ViewManager> m_view_manager;
|
||||
std::unique_ptr<core::DhtManager> m_dht_manager;
|
||||
|
||||
ui::Root* m_ui;
|
||||
display::Manager* m_display;
|
||||
input::Manager* m_input;
|
||||
input::InputEvent* m_inputStdin;
|
||||
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;
|
||||
|
||||
rpc::CommandScheduler* m_commandScheduler;
|
||||
rpc::object_storage* m_objectStorage;
|
||||
torrent::directory_events* m_directory_events;
|
||||
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;
|
||||
|
||||
uint64_t m_tick;
|
||||
uint64_t m_tick{};
|
||||
|
||||
mode_t m_umask;
|
||||
std::string m_workingDirectory;
|
||||
|
||||
rak::priority_item m_taskShutdown;
|
||||
torrent::utils::SchedulerEntry m_task_shutdown;
|
||||
torrent::utils::SchedulerEntry m_task_shutdown_clear_requests;
|
||||
|
||||
bool m_shutdownReceived lt_cacheline_aligned;
|
||||
bool m_shutdownQuick lt_cacheline_aligned;
|
||||
int m_clear_requests_count{};
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_shutdown_received{};
|
||||
std::atomic<bool> m_shutdown_quick{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// 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::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_WHATEVER);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
|
||||
|
||||
m_ipv6 = false;
|
||||
|
||||
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::retry_ipv6() {
|
||||
CURL* nhandle = curl_easy_duphandle(m_handle);
|
||||
|
||||
curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
|
||||
curl_easy_cleanup(m_handle);
|
||||
|
||||
m_handle = nhandle;
|
||||
m_ipv6 = true;
|
||||
}
|
||||
|
||||
void
|
||||
CurlGet::receive_timeout() {
|
||||
return m_stack->transfer_done(m_handle, "Timed out");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// 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_using_ipv6() { return m_ipv6; }
|
||||
void retry_ipv6();
|
||||
|
||||
bool is_busy() const { return m_handle; }
|
||||
bool is_active() const { return m_active; }
|
||||
|
||||
void set_active(bool a) { m_active = a; }
|
||||
|
||||
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;
|
||||
bool m_ipv6;
|
||||
|
||||
rak::priority_item m_taskTimeout;
|
||||
|
||||
CURL* m_handle;
|
||||
CurlStack* m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,134 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// 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
|
||||
@@ -1,271 +0,0 @@
|
||||
// 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_host(true),
|
||||
m_ssl_verify_peer(true),
|
||||
m_dns_timeout(60) {
|
||||
|
||||
m_taskTimeout.slot() = std::bind(&CurlStack::receive_timeout, this);
|
||||
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071000)
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
|
||||
#endif
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
|
||||
}
|
||||
|
||||
CurlStack::~CurlStack() {
|
||||
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.");
|
||||
|
||||
if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
|
||||
iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
|
||||
|
||||
if (itr == end())
|
||||
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
|
||||
|
||||
if (!(*itr)->is_using_ipv6()) {
|
||||
(*itr)->retry_ipv6();
|
||||
|
||||
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_add_handle.");
|
||||
}
|
||||
|
||||
} else {
|
||||
transfer_done(msg->easy_handle,
|
||||
msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
|
||||
}
|
||||
|
||||
return remaining_msgs != 0;
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::transfer_done(void* handle, const char* msg) {
|
||||
iterator itr = std::find_if(begin(), end(), 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_VERIFYHOST, (long)(m_ssl_verify_host ? 2 : 0));
|
||||
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)(m_ssl_verify_peer ? 1 : 0));
|
||||
curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout);
|
||||
|
||||
base_type::push_back(get);
|
||||
|
||||
if (m_active >= m_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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
// 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_host() const { return m_ssl_verify_host; }
|
||||
bool ssl_verify_peer() const { return m_ssl_verify_peer; }
|
||||
void set_ssl_verify_host(bool s) { m_ssl_verify_host = s; }
|
||||
void set_ssl_verify_peer(bool s) { m_ssl_verify_peer = s; }
|
||||
|
||||
long dns_timeout() const { return m_dns_timeout; }
|
||||
void set_dns_timeout(long timeout) { m_dns_timeout = timeout; }
|
||||
|
||||
static void global_init();
|
||||
static void global_cleanup();
|
||||
|
||||
void receive_action(CurlSocket* socket, int type);
|
||||
|
||||
static int set_timeout(void* 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_host;
|
||||
bool m_ssl_verify_peer;
|
||||
long m_dns_timeout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+108
-125
@@ -1,80 +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 "dht_manager.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 "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
#include "control.h"
|
||||
#include "dht_manager.h"
|
||||
#include "download.h"
|
||||
#include "download_store.h"
|
||||
#include "globals.h"
|
||||
#include "manager.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "session/session_manager.h"
|
||||
|
||||
#define LT_LOG_THIS(log_fmt, ...) \
|
||||
lt_log_print_subsystem(torrent::LOG_DHT_MANAGER, "dht_manager", log_fmt, __VA_ARGS__);
|
||||
#define LT_LOG(log_fmt, ...) \
|
||||
lt_log_print_subsystem(torrent::LOG_DHT_CONTROLLER, "dht_manager", log_fmt, __VA_ARGS__);
|
||||
|
||||
#define LT_LOG_ERROR(log_fmt, ...) \
|
||||
lt_log_print_subsystem(torrent::LOG_DHT_ERROR, "dht_manager", log_fmt, __VA_ARGS__);
|
||||
|
||||
namespace core {
|
||||
|
||||
const char* DhtManager::dht_settings[dht_settings_num] = { "disable", "off", "auto", "on" };
|
||||
|
||||
DhtManager::~DhtManager() {
|
||||
priority_queue_erase(&taskScheduler, &m_updateTimeout);
|
||||
priority_queue_erase(&taskScheduler, &m_stopTimeout);
|
||||
torrent::this_thread::scheduler()->erase(&m_update_timeout);
|
||||
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::load_dht_cache() {
|
||||
if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) {
|
||||
LT_LOG_THIS("ignoring cache file", 0);
|
||||
if (m_start == dht_disable || !session_thread::manager()->is_used()) {
|
||||
LT_LOG("ignoring cache file", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cache_filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
|
||||
std::fstream cache_stream(cache_filename.c_str(), std::ios::in | std::ios::binary);
|
||||
auto cache_filename = session_thread::manager()->path() + "rtorrent.dht_cache";
|
||||
auto cache_stream = std::fstream(cache_filename.c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
torrent::Object cache = torrent::Object::create_map();
|
||||
|
||||
@@ -84,17 +52,17 @@ DhtManager::load_dht_cache() {
|
||||
// If the cache file is corrupted we will just discard it with an
|
||||
// error message.
|
||||
if (cache_stream.fail()) {
|
||||
LT_LOG_THIS("cache file corrupted, discarding (path:%s)", cache_filename.c_str());
|
||||
LT_LOG_ERROR("cache file corrupted, discarding (path:%s)", cache_filename.c_str());
|
||||
cache = torrent::Object::create_map();
|
||||
} else {
|
||||
LT_LOG_THIS("cache file read (path:%s)", cache_filename.c_str());
|
||||
LT_LOG("cache file read (path:%s)", cache_filename.c_str());
|
||||
}
|
||||
|
||||
} else {
|
||||
LT_LOG_THIS("could not open cache file (path:%s)", cache_filename.c_str());
|
||||
LT_LOG("could not open cache file (path:%s)", cache_filename.c_str());
|
||||
}
|
||||
|
||||
torrent::dht_manager()->initialize(cache);
|
||||
torrent::runtime::network_manager()->dht_controller()->initialize(cache);
|
||||
|
||||
if (m_start == dht_on)
|
||||
start_dht();
|
||||
@@ -102,36 +70,28 @@ DhtManager::load_dht_cache() {
|
||||
|
||||
void
|
||||
DhtManager::start_dht() {
|
||||
priority_queue_erase(&taskScheduler, &m_stopTimeout);
|
||||
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
|
||||
|
||||
if (!torrent::dht_manager()->is_valid()) {
|
||||
LT_LOG_THIS("server start skipped, manager is uninitialized", 0);
|
||||
if (!torrent::runtime::network_manager()->is_dht_valid()) {
|
||||
LT_LOG("server start skipped, manager is uninitialized", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (torrent::dht_manager()->is_active()) {
|
||||
LT_LOG_THIS("server start skipped, already active", 0);
|
||||
if (torrent::runtime::network_manager()->is_dht_active()) {
|
||||
LT_LOG("server start skipped, already active", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
torrent::ThrottlePair throttles = control->core()->get_throttle(m_throttleName);
|
||||
torrent::dht_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::dht_manager()->start(port)) {
|
||||
if (!torrent::runtime::network_manager()->dht_controller()->start()) {
|
||||
m_start = dht_off;
|
||||
return;
|
||||
}
|
||||
|
||||
torrent::dht_manager()->reset_statistics();
|
||||
torrent::runtime::network_manager()->dht_controller()->reset_statistics();
|
||||
|
||||
m_updateTimeout.slot() = std::bind(&DhtManager::update, this);
|
||||
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds());
|
||||
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;
|
||||
@@ -143,31 +103,34 @@ DhtManager::start_dht() {
|
||||
|
||||
void
|
||||
DhtManager::stop_dht() {
|
||||
priority_queue_erase(&taskScheduler, &m_updateTimeout);
|
||||
priority_queue_erase(&taskScheduler, &m_stopTimeout);
|
||||
torrent::this_thread::scheduler()->erase(&m_update_timeout);
|
||||
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
|
||||
|
||||
if (torrent::dht_manager()->is_active()) {
|
||||
LT_LOG_THIS("stopping server", 0);
|
||||
if (torrent::runtime::network_manager()->is_dht_active()) {
|
||||
LT_LOG("stopping server", 0);
|
||||
|
||||
log_statistics(true);
|
||||
torrent::dht_manager()->stop();
|
||||
torrent::runtime::network_manager()->dht_controller()->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::save_dht_cache() {
|
||||
if (!control->core()->download_store()->is_enabled() || !torrent::dht_manager()->is_valid())
|
||||
if (!session_thread::manager()->is_used())
|
||||
return;
|
||||
|
||||
std::string filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
|
||||
std::string filename_tmp = filename + ".new";
|
||||
std::fstream cache_file(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
|
||||
if (!torrent::runtime::network_manager()->is_dht_valid())
|
||||
return;
|
||||
|
||||
auto filename = session_thread::manager()->path() + "rtorrent.dht_cache";
|
||||
auto filename_tmp = filename + ".new";
|
||||
auto cache_file = std::fstream(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
|
||||
|
||||
if (!cache_file.is_open())
|
||||
return;
|
||||
|
||||
torrent::Object cache = torrent::Object::create_map();
|
||||
cache_file << *torrent::dht_manager()->store_cache(&cache);
|
||||
cache_file << *torrent::runtime::network_manager()->dht_controller()->store_cache(&cache);
|
||||
|
||||
if (!cache_file.good())
|
||||
return;
|
||||
@@ -178,17 +141,32 @@ DhtManager::save_dht_cache() {
|
||||
}
|
||||
|
||||
void
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (i == dht_settings_num)
|
||||
throw torrent::input_error("Invalid argument.");
|
||||
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 (m_start == dht_off)
|
||||
stop_dht();
|
||||
@@ -196,50 +174,67 @@ DhtManager::set_mode(const std::string& arg) {
|
||||
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::dht_manager()->is_active())
|
||||
if (!torrent::runtime::network_manager()->is_dht_active())
|
||||
throw torrent::internal_error("DhtManager::update called with DHT inactive.");
|
||||
|
||||
if (m_start == dht_auto && !m_stopTimeout.is_queued()) {
|
||||
if (m_start == dht_auto && !m_stop_timeout.is_scheduled()) {
|
||||
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_stopTimeout.slot() = std::bind(&DhtManager::stop_dht, this);
|
||||
priority_queue_insert(&taskScheduler, &m_stopTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds());
|
||||
m_stop_timeout.slot() = std::bind(&DhtManager::stop_dht, this);
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_stop_timeout, 15min);
|
||||
}
|
||||
}
|
||||
|
||||
// While bootstrapping (log_statistics returns true), check every minute if it completed, otherwise update every 15 minutes.
|
||||
if (log_statistics(false))
|
||||
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds());
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_update_timeout, 1min);
|
||||
else
|
||||
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds());
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_update_timeout, 15min);
|
||||
}
|
||||
|
||||
bool
|
||||
DhtManager::log_statistics(bool force) {
|
||||
torrent::DhtManager::statistics_type stats = torrent::dht_manager()->get_statistics();
|
||||
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
|
||||
|
||||
// Check for firewall problems.
|
||||
|
||||
if (stats.cycle > 2 && stats.queries_sent - m_dhtPrevQueriesSent > 100 && stats.queries_received == m_dhtPrevQueriesReceived) {
|
||||
// We should have had clients ping us at least but have received
|
||||
// nothing, that means the UDP port is probably unreachable.
|
||||
if (torrent::dht_manager()->can_receive_queries())
|
||||
LT_LOG_THIS("listening port appears to be unreachable, no queries received", 0);
|
||||
if (torrent::runtime::network_manager()->is_dht_active_and_receiving_requests())
|
||||
LT_LOG("listening port appears to be unreachable, no queries received", 0);
|
||||
|
||||
torrent::dht_manager()->set_can_receive(false);
|
||||
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(false);
|
||||
}
|
||||
|
||||
if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) {
|
||||
// No replies to over 20 queries plus two per node we have. Probably firewalled.
|
||||
if (!m_warned)
|
||||
LT_LOG_THIS("listening port appears to be firewalled, no replies received", 0);
|
||||
LT_LOG("listening port appears to be firewalled, no replies received", 0);
|
||||
|
||||
m_warned = true;
|
||||
return false;
|
||||
@@ -248,7 +243,7 @@ DhtManager::log_statistics(bool force) {
|
||||
m_warned = false;
|
||||
|
||||
if (stats.queries_received > m_dhtPrevQueriesReceived)
|
||||
torrent::dht_manager()->set_can_receive(true);
|
||||
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(true);
|
||||
|
||||
// Nothing to log while bootstrapping, but check again every minute.
|
||||
if (stats.cycle <= 1) {
|
||||
@@ -269,14 +264,12 @@ 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, %lld bytes read, %lld bytes sent, "
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"DHT statistics: %d queries in, %d queries out, %d replies received, "
|
||||
"%d known nodes in %d buckets, %d peers (highest: %d) tracked in %d torrents.",
|
||||
stats.queries_received - m_dhtPrevQueriesReceived,
|
||||
stats.queries_sent - m_dhtPrevQueriesSent,
|
||||
stats.replies_received - m_dhtPrevRepliesReceived,
|
||||
(long long unsigned int)(stats.down_rate.total() - m_dhtPrevBytesDown),
|
||||
(long long unsigned int)(stats.up_rate.total() - m_dhtPrevBytesUp),
|
||||
stats.num_nodes,
|
||||
stats.num_buckets,
|
||||
stats.num_peers,
|
||||
@@ -289,8 +282,6 @@ DhtManager::log_statistics(bool force) {
|
||||
m_dhtPrevQueriesSent = stats.queries_sent;
|
||||
m_dhtPrevRepliesReceived = stats.replies_received;
|
||||
m_dhtPrevQueriesReceived = stats.queries_received;
|
||||
m_dhtPrevBytesUp = stats.up_rate.total();
|
||||
m_dhtPrevBytesDown = stats.down_rate.total();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -301,11 +292,11 @@ DhtManager::dht_statistics() {
|
||||
torrent::Object dhtStats = torrent::Object::create_map();
|
||||
|
||||
dhtStats.insert_key("dht", dht_settings[m_start]);
|
||||
dhtStats.insert_key("active", torrent::dht_manager()->is_active());
|
||||
dhtStats.insert_key("throttle", m_throttleName);
|
||||
dhtStats.insert_key("active", torrent::runtime::network_manager()->is_dht_active());
|
||||
dhtStats.insert_key("throttle", "");
|
||||
|
||||
if (torrent::dht_manager()->is_active()) {
|
||||
torrent::DhtManager::statistics_type stats = torrent::dht_manager()->get_statistics();
|
||||
if (torrent::runtime::network_manager()->is_dht_active()) {
|
||||
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
|
||||
|
||||
dhtStats.insert_key("cycle", stats.cycle);
|
||||
dhtStats.insert_key("queries_received", stats.queries_received);
|
||||
@@ -313,8 +304,8 @@ DhtManager::dht_statistics() {
|
||||
dhtStats.insert_key("replies_received", stats.replies_received);
|
||||
dhtStats.insert_key("errors_received", stats.errors_received);
|
||||
dhtStats.insert_key("errors_caught", stats.errors_caught);
|
||||
dhtStats.insert_key("bytes_read", stats.down_rate.total());
|
||||
dhtStats.insert_key("bytes_written", stats.up_rate.total());
|
||||
dhtStats.insert_key("bytes_read", int64_t());
|
||||
dhtStats.insert_key("bytes_written", int64_t());
|
||||
dhtStats.insert_key("nodes", stats.num_nodes);
|
||||
dhtStats.insert_key("buckets", stats.num_buckets);
|
||||
dhtStats.insert_key("peers", stats.num_peers);
|
||||
@@ -325,12 +316,4 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-54
@@ -1,51 +1,18 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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/utils/scheduler.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
class DhtManager {
|
||||
public:
|
||||
DhtManager() : m_warned(false), m_start(dht_off) { }
|
||||
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();
|
||||
|
||||
void load_dht_cache();
|
||||
@@ -56,19 +23,14 @@ public:
|
||||
void stop_dht();
|
||||
void auto_start() { if (m_start == dht_auto) start_dht(); }
|
||||
|
||||
void set_mode(const std::string& arg);
|
||||
void set_mode_by_user(const std::string& arg);
|
||||
void set_mode_directly(unsigned int mode);
|
||||
|
||||
void set_throttle_name(const std::string& throttleName);
|
||||
const std::string& throttle_name() const { return m_throttleName; }
|
||||
void set_auto_if_untouched_and_has_session();
|
||||
|
||||
private:
|
||||
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];
|
||||
static constexpr int dht_settings_num = 4;
|
||||
static const char* dht_settings[dht_settings_num];
|
||||
|
||||
void update();
|
||||
bool log_statistics(bool force);
|
||||
@@ -80,12 +42,12 @@ private:
|
||||
uint64_t m_dhtPrevBytesUp;
|
||||
uint64_t m_dhtPrevBytesDown;
|
||||
|
||||
rak::priority_item m_updateTimeout;
|
||||
rak::priority_item m_stopTimeout;
|
||||
bool m_warned;
|
||||
torrent::utils::SchedulerEntry m_update_timeout;
|
||||
torrent::utils::SchedulerEntry m_stop_timeout;
|
||||
|
||||
int m_start;
|
||||
std::string m_throttleName;
|
||||
bool m_warned{};
|
||||
bool m_set_by_user{};
|
||||
int m_start{dht_off};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+19
-69
@@ -1,66 +1,25 @@
|
||||
// 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.h>
|
||||
#include <torrent/tracker_list.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#include <torrent/data/file.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
#include <torrent/utils/file_stat.h>
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "control.h"
|
||||
#include "download.h"
|
||||
#include "manager.h"
|
||||
#include "core/manager.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
Download::Download(download_type d) :
|
||||
m_download(d),
|
||||
m_hashFailed(false),
|
||||
|
||||
m_resumeFlags(~uint32_t()),
|
||||
m_group(0) {
|
||||
Download::Download(download_type d)
|
||||
: m_download(d) {
|
||||
|
||||
m_download.info()->signal_tracker_success().push_back(std::bind(&Download::receive_tracker_msg, this, ""));
|
||||
m_download.info()->signal_tracker_failed().push_back(std::bind(&Download::receive_tracker_msg, this, std::placeholders::_1));
|
||||
@@ -73,17 +32,6 @@ 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");
|
||||
@@ -140,44 +88,46 @@ Download::distributed_copies() const {
|
||||
}
|
||||
|
||||
void
|
||||
Download::set_throttle_name(const std::string& throttleName) {
|
||||
Download::set_throttle_name(const std::string& name) {
|
||||
if (m_download.info()->is_active())
|
||||
throw torrent::input_error("Cannot set throttle on active download.");
|
||||
|
||||
torrent::ThrottlePair throttles = control->core()->get_throttle(throttleName);
|
||||
auto throttles = control->core()->get_throttle(name);
|
||||
|
||||
m_download.set_upload_throttle(throttles.first);
|
||||
m_download.set_download_throttle(throttles.second);
|
||||
|
||||
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", throttleName);
|
||||
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", name);
|
||||
}
|
||||
|
||||
void
|
||||
Download::set_root_directory(const std::string& path) {
|
||||
// If the download is open, hashed and has completed chunks make
|
||||
// sure to verify that the download files are still present.
|
||||
//
|
||||
//
|
||||
// This should ensure that no one tries to set the destination
|
||||
// directory 'after' moving files. In cases where the user wants to
|
||||
// override this behavior the download must first be closed or
|
||||
// 'd.directory_base.set' may be used.
|
||||
rak::file_stat file_stat;
|
||||
torrent::FileList* file_list = m_download.file_list();
|
||||
|
||||
torrent::utils::FileStat file_stat;
|
||||
torrent::FileList* file_list = m_download.file_list();
|
||||
|
||||
if (is_hash_checked() && file_list->completed_chunks() != 0 &&
|
||||
|
||||
(file_list->is_multi_file() ?
|
||||
!file_list->is_root_dir_created() :
|
||||
!file_stat.update(file_list->front()->frozen_path()))) {
|
||||
!file_stat.update(file_list->front()->frozen_path().str()))) {
|
||||
|
||||
set_message("Cannot change the directory of an open download after the files have been moved.");
|
||||
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(this));
|
||||
control->core()->download_list()->close_directly(this);
|
||||
|
||||
throw torrent::input_error("Cannot change the directory of an open download atter the files have been moved.");
|
||||
throw torrent::input_error("Cannot change the directory of an open download after the files have been moved.");
|
||||
}
|
||||
|
||||
control->core()->download_list()->close_directly(this);
|
||||
file_list->set_root_dir(rak::path_expand(path));
|
||||
file_list->set_root_dir(expand_path(path));
|
||||
|
||||
bencode()->get_key("rtorrent").insert_key("directory", path);
|
||||
}
|
||||
|
||||
+15
-58
@@ -1,56 +1,16 @@
|
||||
// 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 {
|
||||
@@ -59,10 +19,11 @@ 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;
|
||||
@@ -71,10 +32,10 @@ public:
|
||||
Download(download_type d);
|
||||
~Download();
|
||||
|
||||
const torrent::DownloadInfo* info() const { return m_download.info(); }
|
||||
const torrent::download_data* data() const { return m_download.data(); }
|
||||
auto info() const { return m_download.info(); }
|
||||
auto data() const { return m_download.data(); }
|
||||
|
||||
torrent::DownloadMain* main() { return m_download.main(); }
|
||||
auto 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(); }
|
||||
@@ -102,19 +63,15 @@ public:
|
||||
|
||||
torrent::Object* bencode() { return m_download.bencode(); }
|
||||
|
||||
tracker_list_type* tracker_list() { return m_download.tracker_list(); }
|
||||
uint32_t tracker_list_size() const { return m_download.tracker_list()->size(); }
|
||||
auto tracker_controller() { return m_download.tracker_controller(); }
|
||||
uint32_t tracker_list_size() const { return m_download.c_tracker_controller().size(); }
|
||||
|
||||
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;
|
||||
auto 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);
|
||||
|
||||
@@ -123,7 +80,7 @@ public:
|
||||
|
||||
void set_root_directory(const std::string& path);
|
||||
|
||||
void set_throttle_name(const std::string& throttleName);
|
||||
void set_throttle_name(const std::string& name);
|
||||
|
||||
bool operator == (const std::string& str) const;
|
||||
|
||||
@@ -143,10 +100,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;
|
||||
unsigned int m_group;
|
||||
uint32_t m_resumeFlags{default_resume_flags};
|
||||
unsigned int m_group{};
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
||||
+100
-132
@@ -1,48 +1,12 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "download_factory.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <rak/path.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
@@ -50,18 +14,16 @@
|
||||
#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 "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"
|
||||
#include "core/download.h"
|
||||
#include "core/http_queue.h"
|
||||
#include "core/manager.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
@@ -73,21 +35,20 @@ is_network_uri(const std::string& uri) {
|
||||
std::strncmp(uri.c_str(), "ftp://", 6) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
download_factory_add_stream(torrent::Object* root, const char* key, const char* filename) {
|
||||
static std::unique_ptr<torrent::Object>
|
||||
download_factory_load_stream(const char* filename) {
|
||||
std::fstream stream(filename, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!stream.is_open())
|
||||
return false;
|
||||
|
||||
torrent::Object obj;
|
||||
stream >> obj;
|
||||
if (!stream.is_open())
|
||||
return std::unique_ptr<torrent::Object>();
|
||||
|
||||
auto obj = std::make_unique<torrent::Object>();
|
||||
stream >> *obj;
|
||||
|
||||
if (!stream.good())
|
||||
return false;
|
||||
return std::unique_ptr<torrent::Object>();
|
||||
|
||||
root->insert_key_move(key, obj);
|
||||
return true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -97,20 +58,10 @@ is_magnet_uri(const std::string& uri) {
|
||||
}
|
||||
|
||||
DownloadFactory::DownloadFactory(Manager* m) :
|
||||
m_manager(m),
|
||||
m_stream(NULL),
|
||||
m_object(NULL),
|
||||
m_commited(false),
|
||||
m_loaded(false),
|
||||
m_manager(m) {
|
||||
|
||||
m_session(false),
|
||||
m_start(false),
|
||||
m_printLog(true),
|
||||
m_isFile(false),
|
||||
m_initLoad(false) {
|
||||
|
||||
m_taskLoad.slot() = std::bind(&DownloadFactory::receive_load, this);
|
||||
m_taskCommit.slot() = std::bind(&DownloadFactory::receive_commit, this);
|
||||
m_task_load.slot() = std::bind(&DownloadFactory::receive_load, this);
|
||||
m_task_commit.slot() = std::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");
|
||||
@@ -121,18 +72,16 @@ DownloadFactory::DownloadFactory(Manager* m) :
|
||||
}
|
||||
|
||||
DownloadFactory::~DownloadFactory() {
|
||||
priority_queue_erase(&taskScheduler, &m_taskLoad);
|
||||
priority_queue_erase(&taskScheduler, &m_taskCommit);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_load);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_commit);
|
||||
|
||||
delete m_stream;
|
||||
delete m_object;
|
||||
m_stream = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
DownloadFactory::load(const std::string& uri) {
|
||||
m_uri = uri;
|
||||
priority_queue_insert(&taskScheduler, &m_taskLoad, cachedTime);
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
|
||||
}
|
||||
|
||||
// This function must be called before DownloadFactory::commit().
|
||||
@@ -141,13 +90,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 = new std::stringstream(input);
|
||||
m_stream.reset(new std::stringstream(input));
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
void
|
||||
DownloadFactory::commit() {
|
||||
priority_queue_insert(&taskScheduler, &m_taskCommit, cachedTime);
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -156,39 +105,42 @@ DownloadFactory::receive_load() {
|
||||
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
|
||||
|
||||
if (is_network_uri(m_uri)) {
|
||||
// Http handling here.
|
||||
m_stream = new std::stringstream;
|
||||
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
|
||||
m_stream.reset(new std::stringstream);
|
||||
|
||||
(*itr)->signal_done().push_front(std::bind(&DownloadFactory::receive_loaded, this));
|
||||
(*itr)->signal_failed().push_front(std::bind(&DownloadFactory::receive_failed, this, std::placeholders::_1));
|
||||
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);
|
||||
|
||||
m_variables["tied_to_file"] = (int64_t)false;
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (is_magnet_uri(m_uri)) {
|
||||
if (is_magnet_uri(m_uri)) {
|
||||
// DEBUG: Use m_object.
|
||||
m_stream = new std::stringstream();
|
||||
m_stream.reset(new std::stringstream());
|
||||
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
|
||||
|
||||
m_variables["tied_to_file"] = (int64_t)false;
|
||||
receive_loaded();
|
||||
|
||||
} else {
|
||||
std::fstream stream(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
|
||||
@@ -209,9 +161,19 @@ DownloadFactory::receive_commit() {
|
||||
|
||||
void
|
||||
DownloadFactory::receive_success() {
|
||||
Download* download = m_stream != NULL ?
|
||||
m_manager->download_list()->create(m_stream, m_printLog) :
|
||||
m_manager->download_list()->create(m_object, m_printLog);
|
||||
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);
|
||||
|
||||
m_object = NULL;
|
||||
|
||||
@@ -228,17 +190,20 @@ 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 (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr)
|
||||
commands.push_back(*itr);
|
||||
for (auto& m_command : m_commands)
|
||||
commands.push_back(m_command);
|
||||
}
|
||||
|
||||
if (m_session) {
|
||||
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());
|
||||
|
||||
if (rtorrent_object)
|
||||
root->insert_key_move("rtorrent", *rtorrent_object);
|
||||
|
||||
if (libtorrent_resume_object)
|
||||
root->insert_key_move("libtorrent_resume", *libtorrent_resume_object);
|
||||
|
||||
} else {
|
||||
// We only allow session torrents to keep their
|
||||
// 'rtorrent/libtorrent' sections. The "fast_resume" section
|
||||
@@ -249,6 +214,8 @@ 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());
|
||||
@@ -274,9 +241,6 @@ DownloadFactory::receive_success() {
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
|
||||
}
|
||||
|
||||
if (!rpc::call_command_value("trackers.use_udp"))
|
||||
download->enable_udp_trackers(false);
|
||||
|
||||
// Skip forcing trackers to scrape when rtorrent starts
|
||||
if (m_initLoad && rpc::call_command_value("trackers.delay_scrape"))
|
||||
download->set_resume_flags(torrent::Download::start_skip_tracker);
|
||||
@@ -290,15 +254,25 @@ DownloadFactory::receive_success() {
|
||||
rpc::call_command_value("system.file.split_size"),
|
||||
rpc::call_command_string("system.file.split_suffix"));
|
||||
|
||||
if (!rtorrent->has_key_string("directory"))
|
||||
rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download));
|
||||
else
|
||||
if (rtorrent->has_key_string("directory")) {
|
||||
rpc::call_command("d.directory_base.set", rtorrent->get_key("directory"), rpc::make_target(download));
|
||||
|
||||
} else if (download->download()->info()->is_meta_download()) {
|
||||
auto& metadata_path = control->core()->magnet_path();
|
||||
|
||||
if (!metadata_path.empty())
|
||||
rpc::call_command("d.directory.set", metadata_path, rpc::make_target(download));
|
||||
else
|
||||
rpc::call_command("d.directory.set", session_thread::session_path(), rpc::make_target(download));
|
||||
|
||||
} else {
|
||||
rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download));
|
||||
}
|
||||
|
||||
if (!m_session && m_variables["tied_to_file"].as_value())
|
||||
rpc::call_command("d.tied_to_file.set", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download));
|
||||
|
||||
rpc::call_command("d.peer_exchange.set", rpc::call_command_value("protocol.pex"), rpc::make_target(download));
|
||||
rpc::call_command("d.peer_exchange.set", torrent::runtime::client_config()->is_pex_enabled(), rpc::make_target(download));
|
||||
|
||||
torrent::resume_load_addresses(*download->download(), resumeObject);
|
||||
torrent::resume_load_file_priorities(*download->download(), resumeObject);
|
||||
@@ -321,8 +295,8 @@ DownloadFactory::receive_success() {
|
||||
if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid())
|
||||
log_created(download, rtorrent);
|
||||
|
||||
std::for_each(m_commands.begin(), m_commands.end(),
|
||||
rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_std), rpc::make_target(download)));
|
||||
for (const auto& command : m_commands)
|
||||
rpc::parse_command_multiple_std(command, 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.");
|
||||
@@ -338,7 +312,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);
|
||||
@@ -354,7 +328,7 @@ void
|
||||
DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
|
||||
std::stringstream dump;
|
||||
|
||||
dump << "info_hash = " << torrent::hash_string_to_hex_str(download->info()->hash()) << std::endl;
|
||||
dump << "info_hash = " << torrent::utils::transform_to_hex_str(download->info()->hash()) << std::endl;
|
||||
dump << "session = " << (m_session ? "true" : "false") << std::endl;
|
||||
|
||||
if (download->download()->info()->is_meta_download())
|
||||
@@ -367,8 +341,8 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
|
||||
|
||||
dump << "---COMMANDS---" << std::endl;
|
||||
|
||||
for (command_list_type::const_iterator itr = m_commands.begin(); itr != m_commands.end(); itr++) {
|
||||
dump << *itr << std::endl;
|
||||
for (const auto& m_command : m_commands) {
|
||||
dump << m_command << std::endl;
|
||||
}
|
||||
|
||||
std::string dump_str = dump.str();
|
||||
@@ -387,15 +361,17 @@ 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", cachedTime.seconds());
|
||||
rtorrent->insert_key("state_changed", cached_seconds);
|
||||
rtorrent->insert_key("state_counter", int64_t());
|
||||
|
||||
} else if (!rtorrent->has_key_value("state_changed") ||
|
||||
rtorrent->get_key_value("state_changed") > cachedTime.seconds() || rtorrent->get_key_value("state_changed") == 0 ||
|
||||
rtorrent->get_key_value("state_changed") > cached_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", cachedTime.seconds());
|
||||
rtorrent->insert_key("state_changed", cached_seconds);
|
||||
rtorrent->insert_key("state_counter", int64_t());
|
||||
}
|
||||
|
||||
@@ -413,14 +389,6 @@ 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"));
|
||||
|
||||
|
||||
+15
-50
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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.
|
||||
@@ -44,13 +8,14 @@
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <rak/priority_queue_default.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
|
||||
#include "http_queue.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class Download;
|
||||
class Manager;
|
||||
|
||||
class DownloadFactory {
|
||||
@@ -97,26 +62,26 @@ private:
|
||||
|
||||
void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
|
||||
|
||||
Manager* m_manager;
|
||||
std::iostream* m_stream;
|
||||
torrent::Object* m_object;
|
||||
Manager* m_manager;
|
||||
std::shared_ptr<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;
|
||||
bool m_isFile;
|
||||
bool m_initLoad;
|
||||
bool m_session{};
|
||||
bool m_start{};
|
||||
bool m_printLog{true};
|
||||
bool m_isFile{};
|
||||
bool m_initLoad{};
|
||||
|
||||
command_list_type m_commands;
|
||||
torrent::Object::map_type m_variables;
|
||||
|
||||
slot_void m_slot_finished;
|
||||
rak::priority_item m_taskLoad;
|
||||
rak::priority_item m_taskCommit;
|
||||
slot_void m_slot_finished;
|
||||
torrent::utils::SchedulerEntry m_task_load;
|
||||
torrent::utils::SchedulerEntry m_task_commit;
|
||||
};
|
||||
|
||||
bool is_network_uri(const std::string& uri);
|
||||
|
||||
+82
-86
@@ -1,46 +1,9 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <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>
|
||||
@@ -50,6 +13,7 @@
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
@@ -59,10 +23,10 @@
|
||||
#include "view.h"
|
||||
#include "view_manager.h"
|
||||
|
||||
#include "dht_manager.h"
|
||||
#include "download.h"
|
||||
#include "download_list.h"
|
||||
#include "download_store.h"
|
||||
#include "core/dht_manager.h"
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "session/session_manager.h"
|
||||
#include "ui/root.h"
|
||||
|
||||
#define DL_TRIGGER_EVENT(download, event_name) \
|
||||
@@ -71,7 +35,7 @@
|
||||
namespace core {
|
||||
|
||||
inline void
|
||||
DownloadList::check_contains(Download* d) {
|
||||
DownloadList::check_contains([[maybe_unused]] Download* d) {
|
||||
#ifdef USE_EXTRA_DEBUG
|
||||
if (std::find(begin(), end(), d) == end())
|
||||
throw torrent::internal_error("DownloadList::check_contains(...) failed.");
|
||||
@@ -80,18 +44,33 @@ DownloadList::check_contains(Download* d) {
|
||||
|
||||
void
|
||||
DownloadList::clear() {
|
||||
std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadList::close), this));
|
||||
std::for_each(begin(), end(), rak::call_delete<Download>());
|
||||
int error_count = 0;
|
||||
|
||||
base_type::clear();
|
||||
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.");
|
||||
}
|
||||
|
||||
void
|
||||
DownloadList::session_save() {
|
||||
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.");
|
||||
for (auto& download : *this)
|
||||
session_thread::manager()->save_resume_download(download);
|
||||
|
||||
control->dht_manager()->save_dht_cache();
|
||||
control->ui()->save_input_history();
|
||||
@@ -99,17 +78,20 @@ DownloadList::session_save() {
|
||||
|
||||
DownloadList::iterator
|
||||
DownloadList::find(const torrent::HashString& hash) {
|
||||
return std::find_if(begin(), end(), rak::equal(hash, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
|
||||
return std::find_if(begin(), end(), [hash](Download* d) { return hash == d->info()->hash(); });
|
||||
}
|
||||
|
||||
DownloadList::iterator
|
||||
DownloadList::find_hex(const char* hash) {
|
||||
if (strlen(hash) < 40)
|
||||
return end();
|
||||
|
||||
torrent::HashString key;
|
||||
|
||||
for (torrent::HashString::iterator itr = key.begin(), last = key.end(); itr != last; itr++, hash += 2)
|
||||
*itr = (rak::hexchar_to_value(*hash) << 4) + rak::hexchar_to_value(*(hash + 1));
|
||||
if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end())
|
||||
return end();
|
||||
|
||||
return std::find_if(begin(), end(), rak::equal(key, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash))));
|
||||
return std::find_if(begin(), end(), [key](Download* d) { return key == d->info()->hash(); });
|
||||
}
|
||||
|
||||
Download*
|
||||
@@ -120,18 +102,18 @@ DownloadList::find_hex_ptr(const char* hash) {
|
||||
}
|
||||
|
||||
Download*
|
||||
DownloadList::create(torrent::Object* obj, bool printLog) {
|
||||
DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog) {
|
||||
torrent::Download download;
|
||||
|
||||
try {
|
||||
download = torrent::download_add(obj);
|
||||
download = torrent::download_add(obj, tracker_key);
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -141,13 +123,13 @@ DownloadList::create(torrent::Object* obj, bool printLog) {
|
||||
}
|
||||
|
||||
Download*
|
||||
DownloadList::create(std::istream* str, bool printLog) {
|
||||
DownloadList::create(std::istream* str, uint32_t tracker_key, 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()) {
|
||||
@@ -159,7 +141,7 @@ DownloadList::create(std::istream* str, bool printLog) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
download = torrent::download_add(object);
|
||||
download = torrent::download_add(object, tracker_key);
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
delete object;
|
||||
@@ -187,8 +169,10 @@ DownloadList::insert(Download* download) {
|
||||
|
||||
// This needs to be separated into two different calls to ensure
|
||||
// the download remains in the view.
|
||||
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));
|
||||
for (auto v : *control->view_manager())
|
||||
v->insert(download);
|
||||
for (auto v : *control->view_manager())
|
||||
v->filter_download(download);
|
||||
|
||||
DL_TRIGGER_EVENT(*itr, "event.download.inserted");
|
||||
|
||||
@@ -217,11 +201,12 @@ DownloadList::erase(iterator itr) {
|
||||
(*itr)->set_hash_failed(true);
|
||||
|
||||
close(*itr);
|
||||
|
||||
control->core()->download_store()->remove(*itr);
|
||||
session_thread::manager()->remove_download(*itr);
|
||||
|
||||
DL_TRIGGER_EVENT(*itr, "event.download.erased");
|
||||
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr));
|
||||
|
||||
for (auto v : *control->view_manager())
|
||||
v->erase(*itr);
|
||||
|
||||
torrent::download_remove(*(*itr)->download());
|
||||
delete *itr;
|
||||
@@ -251,7 +236,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"))
|
||||
@@ -290,7 +275,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
|
||||
@@ -346,7 +331,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() == ~uint32_t())
|
||||
if (download->resume_flags() == Download::default_resume_flags)
|
||||
download->set_resume_flags(flags);
|
||||
|
||||
// Manual or end-of-download rehashing clears the resume data so
|
||||
@@ -370,7 +355,9 @@ DownloadList::resume(Download* download, int flags) {
|
||||
// This will never actually do anything due to the above hash check.
|
||||
// open_throw(download);
|
||||
|
||||
rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(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_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)) + 1, rpc::make_target(download));
|
||||
|
||||
if (download->is_done()) {
|
||||
@@ -417,7 +404,7 @@ DownloadList::resume(Download* download, int flags) {
|
||||
download->set_priority(download->priority());
|
||||
download->download()->start(download->resume_flags());
|
||||
|
||||
download->set_resume_flags(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
DL_TRIGGER_EVENT(download, "event.download.resumed");
|
||||
|
||||
@@ -434,7 +421,7 @@ DownloadList::pause(Download* download, int flags) {
|
||||
|
||||
try {
|
||||
|
||||
download->set_resume_flags(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
rpc::parse_command_single(rpc::make_target(download), "view.set_not_visible=active");
|
||||
|
||||
@@ -452,13 +439,15 @@ 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");
|
||||
|
||||
rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(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_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.
|
||||
@@ -503,7 +492,11 @@ 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;
|
||||
}
|
||||
@@ -550,8 +543,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, consider using \"safe_sync\".");
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Hash check on download completion found bad chunks, consider using \"safe_sync\".");
|
||||
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.");
|
||||
DL_TRIGGER_EVENT(download, "event.download.hash_final_failed");
|
||||
}
|
||||
|
||||
@@ -652,10 +645,8 @@ DownloadList::confirm_finished(Download* download) {
|
||||
// the download.
|
||||
//
|
||||
// Obsolete.
|
||||
if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0) {
|
||||
// torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
|
||||
control->core()->download_store()->save_resume(download);
|
||||
}
|
||||
if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0)
|
||||
session_thread::manager()->save_resume_download(download);
|
||||
|
||||
// Send the completed request before resuming so we don't reset the
|
||||
// up/downloaded baseline.
|
||||
@@ -668,9 +659,9 @@ DownloadList::confirm_finished(Download* download) {
|
||||
|
||||
if (find(infohash) == end())
|
||||
return;
|
||||
|
||||
// if (download->resume_flags() != ~uint32_t())
|
||||
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
|
||||
|
||||
// if (download->resume_flags() != Download::default_resume_flags)
|
||||
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != Download::default_resume_flags.");
|
||||
|
||||
// See #1292.
|
||||
//
|
||||
@@ -680,7 +671,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(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
|
||||
resume(download,
|
||||
@@ -696,8 +687,10 @@ DownloadList::process_meta_download(Download* download) {
|
||||
rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
|
||||
rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
std::string metafile = (*download->file_list()->begin())->frozen_path();
|
||||
std::string metafile = (*download->file_list()->begin())->frozen_path().str();
|
||||
|
||||
std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!file.is_open()) {
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not read download metadata.");
|
||||
return;
|
||||
@@ -705,11 +698,13 @@ DownloadList::process_meta_download(Download* download) {
|
||||
|
||||
torrent::Object* bencode = new torrent::Object(torrent::Object::create_map());
|
||||
file >> bencode->insert_key("info", torrent::Object());
|
||||
|
||||
if (file.fail()) {
|
||||
delete bencode;
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
|
||||
return;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Steal the keys we still need. The old download has no use for them.
|
||||
@@ -720,6 +715,7 @@ DownloadList::process_meta_download(Download* download) {
|
||||
bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list"));
|
||||
|
||||
erase_ptr(download);
|
||||
|
||||
control->core()->try_create_download_from_meta_download(bencode, metafile);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_LIST_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_LIST_H
|
||||
|
||||
@@ -43,6 +7,7 @@
|
||||
|
||||
namespace torrent {
|
||||
class HashString;
|
||||
class Object;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
@@ -74,7 +39,7 @@ public:
|
||||
using base_type::empty;
|
||||
using base_type::size;
|
||||
|
||||
DownloadList() { }
|
||||
DownloadList() = default;
|
||||
|
||||
void clear();
|
||||
|
||||
@@ -86,8 +51,8 @@ public:
|
||||
Download* find_hex_ptr(const char* hash);
|
||||
|
||||
// Might move this to DownloadFactory.
|
||||
Download* create(std::istream* str, bool printLog);
|
||||
Download* create(torrent::Object* obj, bool printLog);
|
||||
Download* create(std::istream* str, uint32_t tracker_key, bool printLog);
|
||||
Download* create(torrent::Object* obj, uint32_t tracker_key, bool printLog);
|
||||
|
||||
iterator insert(Download* d);
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "download.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class DownloadSlotMap : public std::map<std::string, std::function<void (Download*)> > {
|
||||
public:
|
||||
typedef std::function<void (Download*)> slot_download;
|
||||
typedef std::map<std::string, slot_download> Base;
|
||||
|
||||
void insert(const std::string& key, slot_download s) { Base::operator[](key) = s; }
|
||||
void erase(const std::string& key) { Base::erase(key); }
|
||||
|
||||
void for_each(Download* d);
|
||||
};
|
||||
|
||||
inline void
|
||||
DownloadSlotMap::for_each(Download* d) {
|
||||
for (iterator itr = begin(), last = end(); itr != last; ++itr)
|
||||
itr->second(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,233 +0,0 @@
|
||||
// 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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/object_stream.h>
|
||||
|
||||
#include "utils/directory.h"
|
||||
|
||||
#include "download.h"
|
||||
#include "download_store.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void
|
||||
DownloadStore::enable(bool lock) {
|
||||
if (is_enabled())
|
||||
throw torrent::input_error("Session directory already enabled.");
|
||||
|
||||
if (m_path.empty())
|
||||
return;
|
||||
|
||||
if (lock)
|
||||
m_lockfile.set_path(m_path + "rtorrent.lock");
|
||||
else
|
||||
m_lockfile.set_path(std::string());
|
||||
|
||||
if (!m_lockfile.try_lock()) {
|
||||
if (rak::error_number::current().is_bad_path())
|
||||
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", " + rak::error_number::current().c_str());
|
||||
else
|
||||
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by_as_string() + "\".");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DownloadStore::disable() {
|
||||
if (!is_enabled())
|
||||
return;
|
||||
|
||||
m_lockfile.unlock();
|
||||
}
|
||||
|
||||
void
|
||||
DownloadStore::set_path(const std::string& path) {
|
||||
if (is_enabled())
|
||||
throw torrent::input_error("Tried to change session directory while it is enabled.");
|
||||
|
||||
if (!path.empty() && *path.rbegin() != '/')
|
||||
m_path = rak::path_expand(path + '/');
|
||||
else
|
||||
m_path = rak::path_expand(path);
|
||||
}
|
||||
|
||||
bool
|
||||
DownloadStore::write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask) {
|
||||
int fd;
|
||||
torrent::Object tmp;
|
||||
std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc);
|
||||
|
||||
if (!output.is_open())
|
||||
goto download_store_save_error;
|
||||
|
||||
torrent::object_write_bencode(&output, &obj, skip_mask);
|
||||
|
||||
if (!output.good())
|
||||
goto download_store_save_error;
|
||||
|
||||
output.close();
|
||||
|
||||
// Test the new file, to ensure it is a valid bencode string.
|
||||
output.open(filename.c_str(), std::ios::in);
|
||||
output >> tmp;
|
||||
|
||||
if (!output.good())
|
||||
goto download_store_save_error;
|
||||
|
||||
output.close();
|
||||
|
||||
// Ensure that the new file is actually written to the disk
|
||||
fd = ::open(filename.c_str(), O_WRONLY);
|
||||
if (fd < 0)
|
||||
goto download_store_save_error;
|
||||
|
||||
fdatasync(fd);
|
||||
::close(fd);
|
||||
|
||||
return true;
|
||||
|
||||
download_store_save_error:
|
||||
output.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DownloadStore::save(Download* d, int flags) {
|
||||
if (!is_enabled())
|
||||
return true;
|
||||
|
||||
torrent::Object* resume_base = &d->download()->bencode()->get_key("libtorrent_resume");
|
||||
torrent::Object* rtorrent_base = &d->download()->bencode()->get_key("rtorrent");
|
||||
|
||||
// Move this somewhere else?
|
||||
rtorrent_base->insert_key("chunks_done", d->download()->file_list()->completed_chunks());
|
||||
rtorrent_base->insert_key("chunks_wanted", d->download()->data()->wanted_chunks());
|
||||
rtorrent_base->insert_key("total_uploaded", d->info()->up_rate()->total());
|
||||
rtorrent_base->insert_key("total_downloaded", d->info()->down_rate()->total());
|
||||
|
||||
// Don't save for completed torrents when we've cleared the uncertain_pieces.
|
||||
torrent::resume_save_progress(*d->download(), *resume_base);
|
||||
torrent::resume_save_uncertain_pieces(*d->download(), *resume_base);
|
||||
|
||||
torrent::resume_save_addresses(*d->download(), *resume_base);
|
||||
torrent::resume_save_file_priorities(*d->download(), *resume_base);
|
||||
torrent::resume_save_tracker_settings(*d->download(), *resume_base);
|
||||
|
||||
// Temp fixing of all flags, move to a better place:
|
||||
resume_base->set_flags(torrent::Object::flag_session_data);
|
||||
rtorrent_base->set_flags(torrent::Object::flag_session_data);
|
||||
|
||||
std::string base_filename = create_filename(d);
|
||||
|
||||
if (!write_bencode(base_filename + ".libtorrent_resume.new", *resume_base, 0) ||
|
||||
!write_bencode(base_filename + ".rtorrent.new", *rtorrent_base, 0))
|
||||
return false;
|
||||
|
||||
::rename((base_filename + ".libtorrent_resume.new").c_str(), (base_filename + ".libtorrent_resume").c_str());
|
||||
::rename((base_filename + ".rtorrent.new").c_str(), (base_filename + ".rtorrent").c_str());
|
||||
|
||||
if (!(flags & flag_skip_static) &&
|
||||
write_bencode(base_filename + ".new", *d->bencode(), torrent::Object::flag_session_data))
|
||||
::rename((base_filename + ".new").c_str(), base_filename.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DownloadStore::remove(Download* d) {
|
||||
if (!is_enabled())
|
||||
return;
|
||||
|
||||
::unlink((create_filename(d) + ".libtorrent_resume").c_str());
|
||||
::unlink((create_filename(d) + ".rtorrent").c_str());
|
||||
::unlink(create_filename(d).c_str());
|
||||
}
|
||||
|
||||
// This also needs to check that it isn't a directory.
|
||||
bool
|
||||
not_correct_format(const utils::directory_entry& entry) {
|
||||
return !DownloadStore::is_correct_format(entry.s_name);
|
||||
}
|
||||
|
||||
utils::Directory
|
||||
DownloadStore::get_formated_entries() {
|
||||
if (!is_enabled())
|
||||
return utils::Directory();
|
||||
|
||||
utils::Directory d(m_path);
|
||||
|
||||
if (!d.update(utils::Directory::update_hide_dot))
|
||||
throw torrent::storage_error("core::DownloadStore::update() could not open directory \"" + m_path + "\"");
|
||||
|
||||
d.erase(std::remove_if(d.begin(), d.end(), std::ptr_fun(¬_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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// 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_STORE_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_STORE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "utils/lockfile.h"
|
||||
|
||||
namespace utils {
|
||||
class Directory;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
class Download;
|
||||
|
||||
class DownloadStore {
|
||||
public:
|
||||
static const int flag_skip_static = 0x1;
|
||||
|
||||
bool is_enabled() { return m_lockfile.is_locked(); }
|
||||
|
||||
void enable(bool lock);
|
||||
void disable();
|
||||
|
||||
const std::string& path() const { return m_path; }
|
||||
void set_path(const std::string& path);
|
||||
|
||||
bool save(Download* d, int flags);
|
||||
bool save_full(Download* d) { return save(d, 0); }
|
||||
bool save_resume(Download* d) { return save(d, flag_skip_static); }
|
||||
void remove(Download* d);
|
||||
|
||||
// Currently shows all entries in the correct format.
|
||||
utils::Directory get_formated_entries();
|
||||
|
||||
static bool is_correct_format(const std::string& f);
|
||||
|
||||
private:
|
||||
std::string create_filename(Download* d);
|
||||
|
||||
bool write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask);
|
||||
|
||||
std::string m_path;
|
||||
utils::Lockfile m_lockfile;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+20
-61
@@ -1,80 +1,41 @@
|
||||
// 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 <memory>
|
||||
#include <sstream>
|
||||
#include <torrent/http.h>
|
||||
|
||||
#include "rak/functional.h"
|
||||
#include "http_queue.h"
|
||||
#include "curl_get.h"
|
||||
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/net/http_get.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
HttpQueue::iterator
|
||||
HttpQueue::insert(const std::string& url, std::iostream* s) {
|
||||
std::auto_ptr<CurlGet> h(m_slot_factory());
|
||||
|
||||
h->set_url(url);
|
||||
h->set_stream(s);
|
||||
h->set_timeout(5 * 60);
|
||||
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn) {
|
||||
auto itr = base_type::insert(end(), torrent::net::HttpGet(url, stream));
|
||||
|
||||
iterator signal_itr = base_type::insert(end(), h.get());
|
||||
itr->set_max_file_size(15 << 20);
|
||||
itr->set_redirect_only_http_https();
|
||||
|
||||
h->signal_done().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
|
||||
h->signal_failed().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
|
||||
for (auto& slot : m_signal_insert)
|
||||
slot(*itr);
|
||||
|
||||
(*signal_itr)->start();
|
||||
itr->add_done_slot(torrent::this_thread::thread(), std::move(done_fn));
|
||||
itr->add_done_slot(torrent::this_thread::thread(), [this, itr]() { erase(itr); });
|
||||
|
||||
h.release();
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), std::move(failed_fn));
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), [this, itr](auto) { erase(itr); });
|
||||
|
||||
for (signal_curl_get::iterator itr = m_signal_insert.begin(), last = m_signal_insert.end(); itr != last; itr++)
|
||||
(*itr)(*signal_itr);
|
||||
torrent::net_thread::http_stack()->start_get(*itr);
|
||||
|
||||
return signal_itr;
|
||||
return itr;
|
||||
}
|
||||
|
||||
void
|
||||
HttpQueue::erase(iterator signal_itr) {
|
||||
for (signal_curl_get::iterator itr = m_signal_erase.begin(), last = m_signal_erase.end(); itr != last; itr++)
|
||||
(*itr)(*signal_itr);
|
||||
for (const auto& slot : m_signal_erase)
|
||||
slot(*signal_itr);
|
||||
|
||||
delete *signal_itr;
|
||||
signal_itr->close_and_keep_callbacks();
|
||||
base_type::erase(signal_itr);
|
||||
}
|
||||
|
||||
@@ -82,8 +43,6 @@ void
|
||||
HttpQueue::clear() {
|
||||
while (!empty())
|
||||
erase(begin());
|
||||
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-47
@@ -1,56 +1,22 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CORE_HTTP_QUEUE_H
|
||||
#define RTORRENT_CORE_HTTP_QUEUE_H
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <torrent/net/http_get.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
class CurlGet;
|
||||
// TODO: Remove this.
|
||||
|
||||
class HttpQueue : private std::list<CurlGet*> {
|
||||
class HttpQueue : private std::list<torrent::net::HttpGet> {
|
||||
public:
|
||||
typedef std::list<CurlGet*> base_type;
|
||||
typedef std::function<CurlGet* ()> slot_factory;
|
||||
typedef std::function<void (CurlGet*)> slot_curl_get;
|
||||
typedef std::list<slot_curl_get> signal_curl_get;
|
||||
using base_type = std::list<torrent::net::HttpGet>;
|
||||
using slot_curl_get = std::function<void (torrent::net::HttpGet)>;
|
||||
using signal_curl_get = std::list<slot_curl_get>;
|
||||
|
||||
using base_type::iterator;
|
||||
using base_type::const_iterator;
|
||||
@@ -65,7 +31,7 @@ public:
|
||||
using base_type::empty;
|
||||
using base_type::size;
|
||||
|
||||
HttpQueue() {}
|
||||
HttpQueue() = default;
|
||||
~HttpQueue() { clear(); }
|
||||
|
||||
// Note that any slots connected to the CurlGet signals must be
|
||||
@@ -73,18 +39,16 @@ public:
|
||||
//
|
||||
// Consider adding a flag to indicate whetever HttpQueue should
|
||||
// delete the stream.
|
||||
iterator insert(const std::string& url, std::iostream* s);
|
||||
iterator insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn);
|
||||
void erase(iterator itr);
|
||||
|
||||
void clear();
|
||||
|
||||
void set_slot_factory(slot_factory s) { m_slot_factory = s; }
|
||||
|
||||
signal_curl_get& signal_insert() { return m_signal_insert; }
|
||||
signal_curl_get& signal_erase() { return m_signal_erase; }
|
||||
|
||||
private:
|
||||
slot_factory m_slot_factory;
|
||||
signal_curl_get m_signal_insert;
|
||||
signal_curl_get m_signal_erase;
|
||||
};
|
||||
|
||||
+162
-261
@@ -1,76 +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 "core/manager.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <rak/address_info.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/regex.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/error.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/tracker_list.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "utils/directory.h"
|
||||
#include "utils/base64.h"
|
||||
#include "utils/file_status_cache.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "curl_get.h"
|
||||
#include "control.h"
|
||||
#include "download.h"
|
||||
#include "download_factory.h"
|
||||
#include "download_store.h"
|
||||
#include "http_queue.h"
|
||||
#include "manager.h"
|
||||
#include "poll_manager.h"
|
||||
#include "view.h"
|
||||
#include "core/download.h"
|
||||
#include "core/download_factory.h"
|
||||
#include "core/http_queue.h"
|
||||
#include "core/view.h"
|
||||
|
||||
#include <torrent/runtime/client_config.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
@@ -85,16 +48,13 @@ Manager::push_log(const char* msg) {
|
||||
m_log_complete->lock_and_push_log(msg, strlen(msg), 0);
|
||||
}
|
||||
|
||||
Manager::Manager() :
|
||||
m_hashingView(NULL),
|
||||
m_log_important(torrent::log_open_log_buffer("important")),
|
||||
m_log_complete(torrent::log_open_log_buffer("complete"))
|
||||
{
|
||||
m_downloadStore = new DownloadStore();
|
||||
m_downloadList = new DownloadList();
|
||||
m_fileStatusCache = new FileStatusCache();
|
||||
m_httpQueue = new HttpQueue();
|
||||
m_httpStack = new CurlStack();
|
||||
Manager::Manager()
|
||||
: m_log_important(torrent::log_open_log_buffer("important")),
|
||||
m_log_complete(torrent::log_open_log_buffer("complete")) {
|
||||
|
||||
m_download_list = std::make_unique<DownloadList>();
|
||||
m_file_status_cache = std::make_unique<FileStatusCache>();
|
||||
m_http_queue = std::make_unique<HttpQueue>();
|
||||
|
||||
torrent::Throttle* unthrottled = torrent::Throttle::create_throttle();
|
||||
unthrottled->set_max_rate(0);
|
||||
@@ -103,49 +63,45 @@ Manager::Manager() :
|
||||
|
||||
Manager::~Manager() {
|
||||
torrent::Throttle::destroy_throttle(m_throttles["NULL"].first);
|
||||
delete m_downloadList;
|
||||
}
|
||||
|
||||
// TODO: Clean up logs objects.
|
||||
bool
|
||||
Manager::is_download_shutdown_completed() {
|
||||
for (const auto& download : *download_list()) {
|
||||
// TODO: Why is this being checked?
|
||||
// if (download->tracker_controller().is_active())
|
||||
// return false;
|
||||
|
||||
delete m_downloadStore;
|
||||
delete m_httpQueue;
|
||||
delete m_fileStatusCache;
|
||||
if (download->tracker_controller().has_active_trackers_not_dht_scrape_disownable())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_hashing_view(View* v) {
|
||||
if (v == NULL || m_hashingView != NULL)
|
||||
throw torrent::internal_error("Manager::set_hashing_view(...) received NULL or is already set.");
|
||||
if (v == nullptr || m_hashingView != nullptr)
|
||||
throw torrent::internal_error("Manager::set_hashing_view(...) received nullptr or is already set.");
|
||||
|
||||
m_hashingView = v;
|
||||
m_hashingView->signal_changed().push_back(std::bind(&Manager::receive_hashing_changed, this));
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
ThrottlePair
|
||||
Manager::get_throttle(const std::string& name) {
|
||||
ThrottleMap::const_iterator itr = m_throttles.find(name);
|
||||
torrent::ThrottlePair throttles = (itr == m_throttles.end() ? torrent::ThrottlePair(NULL, NULL) : itr->second);
|
||||
auto itr = m_throttles.find(name);
|
||||
auto throttles = (itr == m_throttles.end() ? ThrottlePair(nullptr, nullptr) : itr->second);
|
||||
|
||||
if (throttles.first == NULL)
|
||||
if (throttles.first == nullptr)
|
||||
throttles.first = torrent::up_throttle_global();
|
||||
|
||||
if (throttles.second == NULL)
|
||||
if (throttles.second == nullptr)
|
||||
throttles.second = torrent::down_throttle_global();
|
||||
|
||||
return throttles;
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles) {
|
||||
m_addressThrottles.set_merge(begin, end, throttles);
|
||||
torrent::connection_manager()->address_throttle() = std::bind(&core::Manager::get_address_throttle, control->core(), std::placeholders::_1);
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
Manager::get_address_throttle(const sockaddr* addr) {
|
||||
return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(NULL, NULL));
|
||||
}
|
||||
|
||||
int64_t
|
||||
Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool rate, bool up) {
|
||||
ThrottleMap::iterator itr = throttles().find(name);
|
||||
@@ -156,7 +112,7 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
|
||||
torrent::Throttle* throttle = up ? itr->second.first : itr->second.second;
|
||||
|
||||
// check whether the actual up/down throttle exist (one of the pair can be missing)
|
||||
if (throttle == NULL)
|
||||
if (throttle == nullptr)
|
||||
return (int64_t)-1;
|
||||
|
||||
int64_t throttle_max = (int64_t)throttle->max_rate();
|
||||
@@ -175,13 +131,14 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
|
||||
}
|
||||
}
|
||||
|
||||
// Most of this should be possible to move out.
|
||||
void
|
||||
Manager::initialize_second() {
|
||||
torrent::Http::slot_factory() = std::bind(&CurlStack::new_object, m_httpStack);
|
||||
m_httpQueue->set_slot_factory(std::bind(&CurlStack::new_object, m_httpStack));
|
||||
|
||||
CurlStack::global_init();
|
||||
Manager::set_magnet_path(const std::string& path) {
|
||||
if (path.empty())
|
||||
m_magnet_path.clear();
|
||||
else if (path.back() == '/')
|
||||
m_magnet_path = path;
|
||||
else
|
||||
m_magnet_path = path + '/';
|
||||
}
|
||||
|
||||
void
|
||||
@@ -189,157 +146,19 @@ Manager::cleanup() {
|
||||
// Need to disconnect log signals? Not really since we won't receive
|
||||
// any more.
|
||||
|
||||
m_downloadList->clear();
|
||||
|
||||
// When we implement asynchronous DNS lookups, we need to cancel them
|
||||
// here before the torrent::* objects are deleted.
|
||||
m_download_list->clear();
|
||||
|
||||
torrent::cleanup();
|
||||
|
||||
delete m_httpStack;
|
||||
CurlStack::global_cleanup();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Manager::shutdown(bool force) {
|
||||
if (!force)
|
||||
std::for_each(m_downloadList->begin(), m_downloadList->end(), std::bind1st(std::mem_fun(&DownloadList::pause_default), m_downloadList));
|
||||
else
|
||||
std::for_each(m_downloadList->begin(), m_downloadList->end(), std::bind1st(std::mem_fun(&DownloadList::close_quick), m_downloadList));
|
||||
}
|
||||
|
||||
void
|
||||
Manager::listen_open() {
|
||||
// This stuff really should be moved outside of manager, make it
|
||||
// part of the init script.
|
||||
if (!rpc::call_command_value("network.port_open"))
|
||||
return;
|
||||
|
||||
int portFirst, portLast;
|
||||
torrent::Object portRange = rpc::call_command("network.port_range");
|
||||
|
||||
if (portRange.is_string()) {
|
||||
if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2)
|
||||
throw torrent::input_error("Invalid port_range argument.");
|
||||
|
||||
// } else if (portRange.is_list()) {
|
||||
|
||||
if (!force) {
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->pause_default(d);
|
||||
} else {
|
||||
throw torrent::input_error("Invalid port_range argument.");
|
||||
}
|
||||
|
||||
if (portFirst > portLast || portLast >= (1 << 16))
|
||||
throw torrent::input_error("Invalid port range.");
|
||||
|
||||
if (rpc::call_command_value("network.port_random")) {
|
||||
int boundary = portFirst + random() % (portLast - portFirst + 1);
|
||||
|
||||
if (torrent::connection_manager()->listen_open(boundary, portLast) ||
|
||||
torrent::connection_manager()->listen_open(portFirst, boundary))
|
||||
return;
|
||||
|
||||
} else {
|
||||
if (torrent::connection_manager()->listen_open(portFirst, portLast))
|
||||
return;
|
||||
}
|
||||
|
||||
throw torrent::input_error("Could not open/bind port for listening: " + std::string(rak::error_number::current().c_str()));
|
||||
}
|
||||
|
||||
std::string
|
||||
Manager::bind_address() const {
|
||||
return rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->address_str();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_bind_address(const std::string& addr) {
|
||||
int err;
|
||||
rak::address_info* ai;
|
||||
|
||||
if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
|
||||
(err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
|
||||
throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + ".");
|
||||
|
||||
try {
|
||||
|
||||
if (torrent::connection_manager()->listen_port() != 0) {
|
||||
torrent::connection_manager()->listen_close();
|
||||
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
|
||||
listen_open();
|
||||
|
||||
} else {
|
||||
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
|
||||
}
|
||||
|
||||
m_httpStack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string());
|
||||
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
rak::address_info::free_address_info(ai);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Manager::local_address() const {
|
||||
return rak::socket_address::cast_from(torrent::connection_manager()->local_address())->address_str();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_local_address(const std::string& addr) {
|
||||
int err;
|
||||
rak::address_info* ai;
|
||||
|
||||
if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
|
||||
(err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
|
||||
throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + ".");
|
||||
|
||||
try {
|
||||
|
||||
torrent::connection_manager()->set_local_address(ai->address()->c_sockaddr());
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
rak::address_info::free_address_info(ai);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Manager::proxy_address() const {
|
||||
return rak::socket_address::cast_from(torrent::connection_manager()->proxy_address())->address_str();
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_proxy_address(const std::string& addr) {
|
||||
int port;
|
||||
rak::address_info* ai;
|
||||
|
||||
char buf[addr.length() + 1];
|
||||
|
||||
int err = std::sscanf(addr.c_str(), "%[^:]:%i", buf, &port);
|
||||
|
||||
if (err <= 0)
|
||||
throw torrent::input_error("Could not parse proxy address.");
|
||||
|
||||
if (err == 1)
|
||||
port = 80;
|
||||
|
||||
if ((err = rak::address_info::get_address_info(buf, PF_INET, SOCK_STREAM, &ai)) != 0)
|
||||
throw torrent::input_error("Could not set proxy address: " + std::string(rak::address_info::strerror(err)) + ".");
|
||||
|
||||
try {
|
||||
|
||||
ai->address()->set_port(port);
|
||||
torrent::connection_manager()->set_proxy_address(ai->address()->c_sockaddr());
|
||||
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
rak::address_info::free_address_info(ai);
|
||||
throw e;
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->close_quick(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +167,22 @@ Manager::receive_http_failed(std::string msg) {
|
||||
push_log_std("Http download error: \"" + msg + "\"");
|
||||
}
|
||||
|
||||
bool
|
||||
is_data_uri(const std::string& uri) {
|
||||
return std::strncmp(uri.c_str(), "data:", 5) == 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
decode_data_uri(const std::string& uri) {
|
||||
const auto pos = uri.find("base64,", 5);
|
||||
if (pos == std::string::npos)
|
||||
throw torrent::input_error("Invalid data uri: not base64 encoded.");
|
||||
const auto start = pos + 7;
|
||||
if (start >= uri.size())
|
||||
throw torrent::input_error("Empty base64.");
|
||||
return utils::decode_base64(uri.substr(start));
|
||||
}
|
||||
|
||||
void
|
||||
Manager::try_create_download(const std::string& uri, int flags, const command_list_type& commands) {
|
||||
// If the path was attempted loaded before, skip it.
|
||||
@@ -355,7 +190,8 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
|
||||
!(flags & create_raw_data) &&
|
||||
!is_network_uri(uri) &&
|
||||
!is_magnet_uri(uri) &&
|
||||
!file_status_cache()->insert(uri, 0))
|
||||
!is_data_uri(uri) &&
|
||||
!file_status_cache()->insert(uri))
|
||||
return;
|
||||
|
||||
// Adding download.
|
||||
@@ -366,12 +202,18 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
|
||||
|
||||
f->set_start(flags & create_start);
|
||||
f->set_print_log(!(flags & create_quiet));
|
||||
f->slot_finished(std::bind(&rak::call_delete_func<core::DownloadFactory>, f));
|
||||
f->slot_finished([f]() { delete f; });
|
||||
|
||||
if (flags & create_raw_data)
|
||||
if (is_data_uri(uri)) {
|
||||
// Allow the use of data URIs, primarily for JSON-RPC which
|
||||
// doesn't have a defined mechanism for binary data
|
||||
f->load_raw_data(decode_data_uri(uri));
|
||||
f->variables()["tied_to_file"] = (int64_t)false;
|
||||
} else if (flags & create_raw_data) {
|
||||
f->load_raw_data(uri);
|
||||
else
|
||||
} else {
|
||||
f->load(uri);
|
||||
}
|
||||
|
||||
f->commit();
|
||||
}
|
||||
@@ -385,12 +227,12 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
|
||||
|
||||
torrent::Object& meta = bencode->get_key("rtorrent_meta_download");
|
||||
torrent::Object::list_type& commands = meta.get_key_list("commands");
|
||||
for (torrent::Object::list_type::const_iterator itr = commands.begin(); itr != commands.end(); ++itr)
|
||||
f->commands().insert(f->commands().end(), itr->as_string());
|
||||
for (const auto& command : commands)
|
||||
f->commands().insert(f->commands().end(), command.as_string());
|
||||
|
||||
f->set_start(meta.get_key_value("start"));
|
||||
f->set_print_log(meta.get_key_value("print_log"));
|
||||
f->slot_finished(std::bind(&rak::call_delete_func<core::DownloadFactory>, f));
|
||||
f->slot_finished([f]() { delete f; });
|
||||
|
||||
// Bit of a waste to create the bencode repesentation here
|
||||
// only to have the DownloadFactory decode it.
|
||||
@@ -406,15 +248,71 @@ path_expand_transform(std::string path, const utils::directory_entry& entry) {
|
||||
return path + entry.s_name;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Consider rewritting such that m_seq is replaced by first/last.
|
||||
template <typename Sequence>
|
||||
class split_iterator_t {
|
||||
public:
|
||||
typedef typename Sequence::const_iterator const_iterator;
|
||||
typedef typename Sequence::value_type value_type;
|
||||
|
||||
split_iterator_t() {}
|
||||
|
||||
split_iterator_t(const Sequence& seq, value_type delim) :
|
||||
m_seq(&seq),
|
||||
m_delim(delim),
|
||||
m_pos(seq.begin()),
|
||||
m_next(std::find(seq.begin(), seq.end(), delim)) {
|
||||
}
|
||||
|
||||
Sequence operator * () { return Sequence(m_pos, m_next); }
|
||||
|
||||
split_iterator_t& operator ++ () {
|
||||
m_pos = m_next;
|
||||
|
||||
if (m_pos == m_seq->end())
|
||||
return *this;
|
||||
|
||||
m_pos++;
|
||||
m_next = std::find(m_pos, m_seq->end(), m_delim);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (const split_iterator_t&) const { return m_pos == m_seq->end(); }
|
||||
bool operator != (const split_iterator_t&) const { return m_pos != m_seq->end(); }
|
||||
|
||||
private:
|
||||
const Sequence* m_seq;
|
||||
value_type m_delim;
|
||||
const_iterator m_pos;
|
||||
const_iterator m_next;
|
||||
};
|
||||
|
||||
template <typename Sequence>
|
||||
inline split_iterator_t<Sequence>
|
||||
split_iterator(const Sequence& seq, typename Sequence::value_type delim) {
|
||||
return split_iterator_t<Sequence>(seq, delim);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline split_iterator_t<Sequence>
|
||||
split_iterator(const Sequence&) {
|
||||
return split_iterator_t<Sequence>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Move this somewhere better.
|
||||
void
|
||||
path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
std::vector<utils::Directory> currentCache;
|
||||
std::vector<utils::Directory> nextCache;
|
||||
|
||||
rak::split_iterator_t<std::string> first = rak::split_iterator(pattern, '/');
|
||||
rak::split_iterator_t<std::string> last = rak::split_iterator(pattern);
|
||||
|
||||
auto first = split_iterator(pattern, '/');
|
||||
auto last = split_iterator(pattern);
|
||||
|
||||
if (first == last)
|
||||
return;
|
||||
|
||||
@@ -422,7 +320,7 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
if ((*first).empty()) {
|
||||
currentCache.push_back(utils::Directory("/"));
|
||||
++first;
|
||||
} else if (rak::trim(*first) == "~") {
|
||||
} else if (torrent::utils::trim_spaces_str(*first) == "~") {
|
||||
currentCache.push_back(utils::Directory("~"));
|
||||
++first;
|
||||
} else {
|
||||
@@ -432,27 +330,29 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
// Might be an idea to use depth-first search instead.
|
||||
|
||||
for (; first != last; ++first) {
|
||||
rak::regex r(*first);
|
||||
const std::string& pattern = *first;
|
||||
|
||||
if (r.pattern().empty())
|
||||
if (pattern.empty())
|
||||
continue;
|
||||
|
||||
// Special case for ".."?
|
||||
|
||||
for (std::vector<utils::Directory>::iterator itr = currentCache.begin(); itr != currentCache.end(); ++itr) {
|
||||
for (auto& itr : currentCache) {
|
||||
// Only include filenames starting with '.' if the pattern
|
||||
// starts with the same.
|
||||
itr->update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr->erase(std::remove_if(itr->begin(), itr->end(), rak::on(rak::mem_ref(&utils::directory_entry::s_name), std::not1(r))), itr->end());
|
||||
itr.update((pattern[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr.erase(std::remove_if(itr.begin(), itr.end(), [&pattern](const utils::directory_entry& entry) { return fnmatch(pattern.c_str(), entry.s_name.c_str(), 0) != 0; }), itr.end());
|
||||
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + (itr->path() == "/" ? "" : "/")));
|
||||
for (const auto& cache : itr)
|
||||
nextCache.push_back(path_expand_transform(itr.path() + (itr.path() == "/" ? "" : "/"), cache));
|
||||
}
|
||||
|
||||
currentCache.clear();
|
||||
currentCache.swap(nextCache);
|
||||
}
|
||||
|
||||
std::transform(currentCache.begin(), currentCache.end(), std::back_inserter(*paths), std::mem_fun_ref(&utils::Directory::path));
|
||||
for (const auto& cache : currentCache)
|
||||
paths->push_back(cache.path());
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -473,8 +373,8 @@ Manager::try_create_download_expand(const std::string& uri, int flags, command_l
|
||||
path_expand(&paths, uri);
|
||||
|
||||
if (!paths.empty())
|
||||
for (std::vector<std::string>::iterator itr = paths.begin(); itr != paths.end(); ++itr)
|
||||
try_create_download(*itr, flags, commands);
|
||||
for (auto& path : paths)
|
||||
try_create_download(path, flags, commands);
|
||||
|
||||
else
|
||||
try_create_download(uri, flags, commands);
|
||||
@@ -485,15 +385,15 @@ Manager::try_create_download_expand(const std::string& uri, int flags, command_l
|
||||
// hashing view and starts hashing if nessesary.
|
||||
void
|
||||
Manager::receive_hashing_changed() {
|
||||
bool foundHashing = std::find_if(m_hashingView->begin_visible(), m_hashingView->end_visible(),
|
||||
std::mem_fun(&Download::is_hash_checking)) != m_hashingView->end_visible();
|
||||
|
||||
bool foundHashing = std::any_of(m_hashingView->begin_visible(), m_hashingView->end_visible(),
|
||||
std::mem_fn(&Download::is_hash_checking));
|
||||
|
||||
// Try quick hashing all those with hashing == initial, set them to
|
||||
// something else when failed.
|
||||
for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) {
|
||||
if ((*itr)->is_hash_checked())
|
||||
throw torrent::internal_error("core::Manager::receive_hashing_changed() (*itr)->is_hash_checked().");
|
||||
|
||||
|
||||
if ((*itr)->is_hash_checking() || (*itr)->is_hash_failed())
|
||||
continue;
|
||||
|
||||
@@ -505,7 +405,7 @@ Manager::receive_hashing_changed() {
|
||||
continue;
|
||||
|
||||
try {
|
||||
m_downloadList->open_throw(*itr);
|
||||
m_download_list->open_throw(*itr);
|
||||
|
||||
// Since the bitfield is allocated on loading of resume load or
|
||||
// hash start, and unallocated on close, we know that if it it
|
||||
@@ -536,6 +436,7 @@ Manager::receive_hashing_changed() {
|
||||
|
||||
} else {
|
||||
(*itr)->set_hash_failed(true);
|
||||
(*itr)->set_message("Hashing failed: " + std::string(e.what()));
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Hashing failed: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
+22
-43
@@ -4,13 +4,10 @@
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <torrent/utils/log_buffer.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "download_list.h"
|
||||
#include "poll_manager.h"
|
||||
#include "range_map.h"
|
||||
|
||||
namespace torrent {
|
||||
@@ -23,10 +20,10 @@ class FileStatusCache;
|
||||
|
||||
namespace core {
|
||||
|
||||
class DownloadStore;
|
||||
class HttpQueue;
|
||||
|
||||
typedef std::map<std::string, torrent::ThrottlePair> ThrottleMap;
|
||||
using ThrottlePair = std::pair<torrent::Throttle*, torrent::Throttle*>;
|
||||
using ThrottleMap = std::map<std::string, ThrottlePair>;
|
||||
|
||||
class View;
|
||||
|
||||
@@ -35,48 +32,31 @@ public:
|
||||
typedef DownloadList::iterator DListItr;
|
||||
typedef utils::FileStatusCache FileStatusCache;
|
||||
|
||||
// typedef std::function<void (DownloadList::iterator)> slot_ready;
|
||||
// typedef std::function<void ()> slot_void;
|
||||
|
||||
Manager();
|
||||
~Manager();
|
||||
|
||||
DownloadList* download_list() { return m_downloadList; }
|
||||
DownloadStore* download_store() { return m_downloadStore; }
|
||||
FileStatusCache* file_status_cache() { return m_fileStatusCache; }
|
||||
bool is_download_shutdown_completed();
|
||||
|
||||
HttpQueue* http_queue() { return m_httpQueue; }
|
||||
CurlStack* http_stack() { return m_httpStack; }
|
||||
DownloadList* download_list() { return m_download_list.get(); }
|
||||
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
|
||||
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
HttpQueue* http_queue() { return m_http_queue.get(); }
|
||||
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
void set_hashing_view(View* v);
|
||||
|
||||
torrent::log_buffer* log_important() { return m_log_important.get(); }
|
||||
torrent::log_buffer* log_complete() { return m_log_complete.get(); }
|
||||
auto* log_important() { return m_log_important.get(); }
|
||||
auto* log_complete() { return m_log_complete.get(); }
|
||||
|
||||
ThrottleMap& throttles() { return m_throttles; }
|
||||
torrent::ThrottlePair get_throttle(const std::string& name);
|
||||
ThrottleMap& throttles() { return m_throttles; }
|
||||
ThrottlePair get_throttle(const std::string& name);
|
||||
|
||||
int64_t retrieve_throttle_value(const torrent::Object::string_type& name, bool rate, bool up);
|
||||
|
||||
// Use custom throttle for the given range of IP addresses.
|
||||
void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles);
|
||||
torrent::ThrottlePair get_address_throttle(const sockaddr* addr);
|
||||
|
||||
// Really should find a more descriptive name.
|
||||
void initialize_second();
|
||||
void cleanup();
|
||||
|
||||
void listen_open();
|
||||
|
||||
std::string bind_address() const;
|
||||
void set_bind_address(const std::string& addr);
|
||||
|
||||
std::string local_address() const;
|
||||
void set_local_address(const std::string& addr);
|
||||
|
||||
std::string proxy_address() const;
|
||||
void set_proxy_address(const std::string& addr);
|
||||
const std::string& magnet_path();
|
||||
void set_magnet_path(const std::string& path);
|
||||
|
||||
void shutdown(bool force);
|
||||
|
||||
@@ -99,8 +79,6 @@ public:
|
||||
void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile);
|
||||
|
||||
private:
|
||||
typedef RangeMap<uint32_t, torrent::ThrottlePair> AddressThrottleMap;
|
||||
|
||||
void create_http(const std::string& uri);
|
||||
void create_final(std::istream* s);
|
||||
|
||||
@@ -109,24 +87,25 @@ private:
|
||||
void receive_http_failed(std::string msg);
|
||||
void receive_hashing_changed();
|
||||
|
||||
DownloadList* m_downloadList;
|
||||
DownloadStore* m_downloadStore;
|
||||
FileStatusCache* m_fileStatusCache;
|
||||
HttpQueue* m_httpQueue;
|
||||
CurlStack* m_httpStack;
|
||||
std::unique_ptr<DownloadList> m_download_list;
|
||||
std::unique_ptr<FileStatusCache> m_file_status_cache;
|
||||
std::unique_ptr<HttpQueue> m_http_queue;
|
||||
|
||||
View* m_hashingView;
|
||||
View* m_hashingView{};
|
||||
|
||||
ThrottleMap m_throttles;
|
||||
AddressThrottleMap m_addressThrottles;
|
||||
|
||||
torrent::log_buffer_ptr m_log_important;
|
||||
torrent::log_buffer_ptr m_log_complete;
|
||||
|
||||
std::string m_magnet_path;
|
||||
};
|
||||
|
||||
// Meh, cleanup.
|
||||
extern void receive_tracker_dump(const std::string& url, const char* data, size_t size);
|
||||
|
||||
inline const std::string& Manager::magnet_path() { return m_magnet_path; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// 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 <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/poll_epoll.h>
|
||||
#include <torrent/poll_kqueue.h>
|
||||
#include <torrent/poll_select.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "manager.h"
|
||||
#include "poll_manager.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
torrent::Poll*
|
||||
create_poll() {
|
||||
const char* poll_name = getenv("RTORRENT_POLL");
|
||||
|
||||
int maxOpen = sysconf(_SC_OPEN_MAX);
|
||||
|
||||
torrent::Poll* poll = NULL;
|
||||
|
||||
if (poll_name != NULL) {
|
||||
if (!strcmp(poll_name, "epoll"))
|
||||
poll = torrent::PollEPoll::create(maxOpen);
|
||||
else if (!strcmp(poll_name, "kqueue"))
|
||||
poll = torrent::PollKQueue::create(maxOpen);
|
||||
else if (!strcmp(poll_name, "select"))
|
||||
poll = torrent::PollSelect::create(maxOpen);
|
||||
|
||||
if (poll == NULL)
|
||||
control->core()->push_log_std(std::string("Cannot enable '") + poll_name + "' based polling.");
|
||||
}
|
||||
|
||||
if (poll != NULL)
|
||||
control->core()->push_log_std(std::string("Using '") + poll_name + "' based polling.");
|
||||
|
||||
else if ((poll = torrent::PollEPoll::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'epoll' based polling.");
|
||||
|
||||
else if ((poll = torrent::PollKQueue::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'kqueue' based polling.");
|
||||
|
||||
else if ((poll = torrent::PollSelect::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'select' based polling.");
|
||||
|
||||
else
|
||||
throw torrent::internal_error("Could not create any Poll object.");
|
||||
|
||||
return poll;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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_POLL_MANAGER_H
|
||||
#define RTORRENT_CORE_POLL_MANAGER_H
|
||||
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace torrent {
|
||||
class Poll;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
torrent::Poll* create_poll();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -29,10 +29,8 @@
|
||||
// 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
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_CORE_RANGE_MAP_H
|
||||
#define RTORRENT_CORE_RANGE_MAP_H
|
||||
@@ -49,13 +47,15 @@ namespace core {
|
||||
template<typename Key, typename T, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, T> > >
|
||||
class RangeMap : private std::map<Key, std::pair<Key, T>, Compare,
|
||||
typename Alloc::template rebind<std::pair<const Key, std::pair<Key, T> > >::other> {
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> {
|
||||
|
||||
typedef std::map<Key, std::pair<Key, T>, Compare,
|
||||
typename Alloc::template rebind<std::pair<const Key, std::pair<Key, T> > >::other> base_type;
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> base_type;
|
||||
|
||||
//std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>
|
||||
|
||||
public:
|
||||
RangeMap() {}
|
||||
RangeMap() = default;
|
||||
RangeMap(const Compare& c) : base_type(c) {}
|
||||
|
||||
typedef typename base_type::iterator iterator;
|
||||
|
||||
+68
-80
@@ -1,63 +1,26 @@
|
||||
// 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 <functional>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
#include <torrent/download.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/object_storage.h"
|
||||
#include "control.h"
|
||||
#include "download.h"
|
||||
#include "download_list.h"
|
||||
#include "manager.h"
|
||||
#include "rpc/object_storage.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "view.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
// Also add focus thingie here?
|
||||
struct view_downloads_compare : std::binary_function<Download*, Download*, bool> {
|
||||
view_downloads_compare(const torrent::Object& cmd) : m_command(cmd) {}
|
||||
struct view_downloads_compare {
|
||||
view_downloads_compare(const torrent::Object& cmd) :
|
||||
m_command(cmd) {}
|
||||
|
||||
bool operator () (Download* d1, Download* d2) const {
|
||||
bool operator()(Download* d1, Download* d2) const {
|
||||
try {
|
||||
if (m_command.is_empty())
|
||||
return false;
|
||||
@@ -75,8 +38,7 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
|
||||
// return rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(),
|
||||
// rpc::make_target_pair(d1, d2)).as_value();
|
||||
|
||||
return rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(),
|
||||
rpc::make_target_pair(d1, d2)).as_value();
|
||||
return rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target_pair(d1, d2)).as_value();
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
control->core()->push_log(e.what());
|
||||
@@ -88,10 +50,11 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
|
||||
const torrent::Object& m_command;
|
||||
};
|
||||
|
||||
struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) : m_command(cmd), m_command2(cmd2) {}
|
||||
struct view_downloads_filter {
|
||||
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) :
|
||||
m_command(cmd), m_command2(cmd2) {}
|
||||
|
||||
bool operator () (Download* d1) const {
|
||||
bool operator()(Download* d1) const {
|
||||
return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1);
|
||||
}
|
||||
|
||||
@@ -121,11 +84,16 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
|
||||
switch (result.type()) {
|
||||
// case torrent::Object::TYPE_RAW_BENCODE: return !result.as_raw_bencode().empty();
|
||||
case torrent::Object::TYPE_VALUE: return result.as_value();
|
||||
case torrent::Object::TYPE_STRING: return !result.as_string().empty();
|
||||
case torrent::Object::TYPE_LIST: return !result.as_list().empty();
|
||||
case torrent::Object::TYPE_MAP: return !result.as_map().empty();
|
||||
default: return false;
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
return result.as_value();
|
||||
case torrent::Object::TYPE_STRING:
|
||||
return !result.as_string().empty();
|
||||
case torrent::Object::TYPE_LIST:
|
||||
return !result.as_list().empty();
|
||||
case torrent::Object::TYPE_MAP:
|
||||
return !result.as_map().empty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// The default filter action is to return true, to not filter
|
||||
@@ -139,20 +107,19 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
}
|
||||
}
|
||||
|
||||
const torrent::Object& m_command;
|
||||
const torrent::Object& m_command2;
|
||||
const torrent::Object& m_command;
|
||||
const torrent::Object& m_command2;
|
||||
};
|
||||
|
||||
void
|
||||
View::emit_changed() {
|
||||
priority_queue_erase(&taskScheduler, &m_delayChanged);
|
||||
priority_queue_insert(&taskScheduler, &m_delayChanged, cachedTime);
|
||||
torrent::this_thread::scheduler()->update_wait_for(&m_delay_changed, 0ms);
|
||||
}
|
||||
|
||||
void
|
||||
View::emit_changed_now() {
|
||||
for (signal_void::iterator itr = m_signal_changed.begin(), last = m_signal_changed.end(); itr != last; itr++)
|
||||
(*itr)();
|
||||
for (auto& itr : m_signal_changed)
|
||||
itr();
|
||||
}
|
||||
|
||||
View::~View() {
|
||||
@@ -160,7 +127,7 @@ View::~View() {
|
||||
return;
|
||||
|
||||
clear_filter_on();
|
||||
priority_queue_erase(&taskScheduler, &m_delayChanged);
|
||||
torrent::this_thread::scheduler()->erase(&m_delay_changed);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -171,18 +138,16 @@ View::initialize(const std::string& name) {
|
||||
if (name.empty())
|
||||
throw torrent::internal_error("View::initialize(...) called with an empty name.");
|
||||
|
||||
core::DownloadList* dlist = control->core()->download_list();
|
||||
|
||||
m_name = name;
|
||||
|
||||
// Urgh, wrong. No filtering being done.
|
||||
std::for_each(dlist->begin(), dlist->end(), rak::bind1st(std::mem_fun(&View::push_back), this));
|
||||
for (const auto& d : *control->core()->download_list())
|
||||
push_back(d);
|
||||
|
||||
m_size = base_type::size();
|
||||
m_size = base_type::size();
|
||||
m_focus = 0;
|
||||
|
||||
set_last_changed(rak::timer());
|
||||
m_delayChanged.slot() = std::bind(&View::emit_changed_now, this);
|
||||
m_delay_changed.slot() = [this]() { emit_changed_now(); };
|
||||
}
|
||||
|
||||
void
|
||||
@@ -232,20 +197,45 @@ View::set_not_visible(Download* download) {
|
||||
}
|
||||
|
||||
void
|
||||
View::next_focus() {
|
||||
View::next_focus(unsigned int i) {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
m_focus = (m_focus + 1) % (size() + 1);
|
||||
// If at the boundary, roll over
|
||||
if (m_focus == size() - 1) {
|
||||
m_focus = size();
|
||||
emit_changed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Move forward, stop at the boundary
|
||||
if (m_focus == size()) // Needs special handling to ensure it's not off by one
|
||||
m_focus = i - 1;
|
||||
else
|
||||
m_focus += i;
|
||||
if (m_focus > size() - 1)
|
||||
m_focus = size() - 1;
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void
|
||||
View::prev_focus() {
|
||||
View::prev_focus(unsigned int i) {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
m_focus = (m_focus - 1 + size() + 1) % (size() + 1);
|
||||
// If at the boundary, roll over
|
||||
if (m_focus == size()) {
|
||||
m_focus = size() - 1;
|
||||
emit_changed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Move backward, stop at the boundary
|
||||
m_focus -= i;
|
||||
if (m_focus < 0 || m_focus > size())
|
||||
m_focus = size();
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
@@ -267,12 +257,12 @@ View::filter() {
|
||||
return;
|
||||
|
||||
// Parition the list in two steps so we know which elements changed.
|
||||
iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter, m_temp_filter));
|
||||
iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter, m_temp_filter));
|
||||
iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter, m_temp_filter));
|
||||
iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter, m_temp_filter));
|
||||
|
||||
base_type changed(splitVisible, splitFiltered);
|
||||
iterator splitChanged = changed.begin() + std::distance(splitVisible, end_visible());
|
||||
|
||||
iterator splitChanged = changed.begin() + std::distance(splitVisible, end_visible());
|
||||
|
||||
m_size = std::distance(begin(), std::copy(splitChanged, changed.end(), splitVisible));
|
||||
std::copy(changed.begin(), splitChanged, begin_filtered());
|
||||
|
||||
@@ -290,12 +280,10 @@ View::filter() {
|
||||
// set the elements to NULL as we trigger commands on them. Or
|
||||
// perhaps always clear them, thus not throwing anything.
|
||||
if (!m_event_removed.is_empty())
|
||||
std::for_each(changed.begin(), splitChanged,
|
||||
std::bind(&rpc::call_object_d_nothrow, m_event_removed, std::placeholders::_1));
|
||||
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_removed, std::placeholders::_1));
|
||||
|
||||
if (!m_event_added.is_empty())
|
||||
std::for_each(changed.begin(), splitChanged,
|
||||
std::bind(&rpc::call_object_d_nothrow, m_event_added, std::placeholders::_1));
|
||||
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_added, std::placeholders::_1));
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
@@ -358,7 +346,7 @@ View::clear_filter_on() {
|
||||
|
||||
inline void
|
||||
View::insert_visible(Download* d) {
|
||||
iterator itr = std::find_if(begin_visible(), end_visible(), std::bind1st(view_downloads_compare(m_sortNew), d));
|
||||
auto itr = std::find_if(begin_visible(), end_visible(), [this, d](auto d2) { return view_downloads_compare(m_sortNew)(d, d2); });
|
||||
|
||||
m_size++;
|
||||
m_focus += (m_focus >= position(itr));
|
||||
@@ -377,4 +365,4 @@ View::erase_internal(iterator itr) {
|
||||
base_type::erase(itr);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace core
|
||||
|
||||
+74
-104
@@ -1,39 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// Provides a filtered and sorted list of downloads that can be
|
||||
// updated auto-magically.
|
||||
//
|
||||
@@ -50,11 +14,11 @@
|
||||
#define RTORRENT_CORE_VIEW_DOWNLOADS_H
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <rak/timer.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
@@ -64,77 +28,83 @@ class Download;
|
||||
|
||||
class View : private std::vector<Download*> {
|
||||
public:
|
||||
typedef std::vector<Download*> base_type;
|
||||
typedef std::function<void ()> slot_void;
|
||||
typedef std::list<slot_void> signal_void;
|
||||
typedef std::vector<Download*> base_type;
|
||||
typedef std::function<void()> slot_void;
|
||||
typedef std::list<slot_void> signal_void;
|
||||
|
||||
using base_type::iterator;
|
||||
using base_type::const_iterator;
|
||||
using base_type::reverse_iterator;
|
||||
using base_type::const_reverse_iterator;
|
||||
|
||||
using base_type::iterator;
|
||||
using base_type::reverse_iterator;
|
||||
|
||||
using base_type::size_type;
|
||||
|
||||
View() {}
|
||||
View() = default;
|
||||
~View();
|
||||
|
||||
void initialize(const std::string& name);
|
||||
void initialize(const std::string& name);
|
||||
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
bool empty_visible() const { return m_size == 0; }
|
||||
bool empty_visible() const { return m_size == 0; }
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
size_type size_visible() const { return m_size; }
|
||||
size_type size_not_visible() const { return base_type::size() - m_size; }
|
||||
size_type size() const { return m_size; }
|
||||
size_type size_visible() const { return m_size; }
|
||||
size_type size_not_visible() const { return base_type::size() - m_size; }
|
||||
|
||||
// Perhaps this should be renamed?
|
||||
iterator begin_visible() { return begin(); }
|
||||
const_iterator begin_visible() const { return begin(); }
|
||||
iterator begin_visible() { return begin(); }
|
||||
const_iterator begin_visible() const { return begin(); }
|
||||
|
||||
iterator end_visible() { return begin() + m_size; }
|
||||
const_iterator end_visible() const { return begin() + m_size; }
|
||||
iterator end_visible() { return begin() + m_size; }
|
||||
const_iterator end_visible() const { return begin() + m_size; }
|
||||
|
||||
iterator begin_filtered() { return begin() + m_size; }
|
||||
const_iterator begin_filtered() const { return begin() + m_size; }
|
||||
iterator begin_filtered() { return begin() + m_size; }
|
||||
const_iterator begin_filtered() const { return begin() + m_size; }
|
||||
|
||||
iterator end_filtered() { return base_type::end(); }
|
||||
const_iterator end_filtered() const { return base_type::end(); }
|
||||
iterator end_filtered() { return base_type::end(); }
|
||||
const_iterator end_filtered() const { return base_type::end(); }
|
||||
|
||||
iterator focus() { return begin() + m_focus; }
|
||||
const_iterator focus() const { return begin() + m_focus; }
|
||||
void set_focus(iterator itr) { m_focus = position(itr); emit_changed(); }
|
||||
iterator focus() { return begin() + m_focus; }
|
||||
const_iterator focus() const { return begin() + m_focus; }
|
||||
void set_focus(iterator itr) {
|
||||
m_focus = position(itr);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void insert(Download* download) { base_type::push_back(download); }
|
||||
void erase(Download* download);
|
||||
void insert(Download* download) { base_type::push_back(download); }
|
||||
void erase(Download* download);
|
||||
|
||||
void set_visible(Download* download);
|
||||
void set_not_visible(Download* download);
|
||||
void set_visible(Download* download);
|
||||
void set_not_visible(Download* download);
|
||||
|
||||
void next_focus();
|
||||
void prev_focus();
|
||||
void next_focus(unsigned int i);
|
||||
void prev_focus(unsigned int i);
|
||||
|
||||
void sort();
|
||||
void next_focus() { next_focus(1); }
|
||||
void prev_focus() { prev_focus(1); }
|
||||
|
||||
void set_sort_new(const torrent::Object& s) { m_sortNew = s; }
|
||||
void set_sort_current(const torrent::Object& s) { m_sortCurrent = s; }
|
||||
void sort();
|
||||
|
||||
void set_sort_new(const torrent::Object& s) { m_sortNew = s; }
|
||||
void set_sort_current(const torrent::Object& s) { m_sortCurrent = s; }
|
||||
|
||||
// Need to explicity trigger filtering.
|
||||
void filter();
|
||||
void filter_by(const torrent::Object& condition, base_type& result);
|
||||
void filter_download(core::Download* download);
|
||||
void filter();
|
||||
void filter_by(const torrent::Object& condition, base_type& result);
|
||||
void filter_download(core::Download* download);
|
||||
|
||||
const torrent::Object& get_filter() const { return m_filter; }
|
||||
void set_filter(const torrent::Object& s) { m_filter = s; }
|
||||
void set_filter(const torrent::Object& s) { m_filter = s; }
|
||||
const torrent::Object& get_filter_temp() const { return m_temp_filter; }
|
||||
void set_filter_temp(const torrent::Object& s) { m_temp_filter = s; }
|
||||
void set_filter_on_event(const std::string& event);
|
||||
void set_filter_temp(const torrent::Object& s) { m_temp_filter = s; }
|
||||
void set_filter_on_event(const std::string& event);
|
||||
|
||||
void clear_filter_on();
|
||||
void clear_filter_on();
|
||||
|
||||
const torrent::Object& event_added() const { return m_event_added; }
|
||||
const torrent::Object& event_removed() const { return m_event_removed; }
|
||||
void set_event_added(const torrent::Object& cmd) { m_event_added = cmd; }
|
||||
const torrent::Object& event_added() const { return m_event_added; }
|
||||
const torrent::Object& event_removed() const { return m_event_removed; }
|
||||
void set_event_added(const torrent::Object& cmd) { m_event_added = cmd; }
|
||||
void set_event_removed(const torrent::Object& cmd) { m_event_removed = cmd; }
|
||||
|
||||
// The time of the last change to the view, semantics of this is
|
||||
@@ -143,50 +113,50 @@ public:
|
||||
//
|
||||
// Currently initialized to rak::timer(), though perhaps we should
|
||||
// use cachedTimer.
|
||||
rak::timer last_changed() const { return m_lastChanged; }
|
||||
void set_last_changed(const rak::timer& t = ::cachedTime) { m_lastChanged = t; }
|
||||
auto last_changed() const { return m_last_changed; }
|
||||
void set_last_changed(std::chrono::microseconds t = torrent::this_thread::cached_time()) { m_last_changed = t; }
|
||||
|
||||
// Don't connect any slots until after initialize else it get's
|
||||
// triggered when adding the Download's in DownloadList.
|
||||
signal_void& signal_changed() { return m_signal_changed; }
|
||||
signal_void& signal_changed() { return m_signal_changed; }
|
||||
|
||||
private:
|
||||
View(const View&);
|
||||
void operator = (const View&);
|
||||
void operator=(const View&);
|
||||
|
||||
void push_back(Download* d) { base_type::push_back(d); }
|
||||
void push_back(Download* d) { base_type::push_back(d); }
|
||||
|
||||
inline void insert_visible(Download* d);
|
||||
inline void erase_internal(iterator itr);
|
||||
inline void insert_visible(Download* d);
|
||||
inline void erase_internal(iterator itr);
|
||||
|
||||
void emit_changed();
|
||||
void emit_changed_now();
|
||||
void emit_changed();
|
||||
void emit_changed_now();
|
||||
|
||||
size_type position(const_iterator itr) const { return itr - begin(); }
|
||||
size_type position(const_iterator itr) const { return itr - begin(); }
|
||||
|
||||
// An received thing for changed status so we can sort and filter.
|
||||
|
||||
std::string m_name;
|
||||
std::string m_name;
|
||||
|
||||
size_type m_size;
|
||||
size_type m_focus;
|
||||
size_type m_size;
|
||||
size_type m_focus;
|
||||
|
||||
// These should be replaced by a faster non-string command type.
|
||||
torrent::Object m_sortNew;
|
||||
torrent::Object m_sortCurrent;
|
||||
torrent::Object m_sortNew;
|
||||
torrent::Object m_sortCurrent;
|
||||
|
||||
torrent::Object m_filter;
|
||||
torrent::Object m_temp_filter; // Temporary view filter (eg: name based filter)
|
||||
torrent::Object m_filter;
|
||||
torrent::Object m_temp_filter; // Temporary view filter (eg: name based filter)
|
||||
|
||||
torrent::Object m_event_added;
|
||||
torrent::Object m_event_removed;
|
||||
torrent::Object m_event_added;
|
||||
torrent::Object m_event_removed;
|
||||
|
||||
rak::timer m_lastChanged;
|
||||
std::chrono::microseconds m_last_changed{};
|
||||
|
||||
signal_void m_signal_changed;
|
||||
rak::priority_item m_delayChanged;
|
||||
signal_void m_signal_changed;
|
||||
torrent::utils::SchedulerEntry m_delay_changed;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace core
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,43 +1,6 @@
|
||||
// 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 <rak/functional.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/object.h>
|
||||
|
||||
@@ -55,7 +18,8 @@ namespace core {
|
||||
|
||||
void
|
||||
ViewManager::clear() {
|
||||
std::for_each(begin(), end(), rak::call_delete<View>());
|
||||
for (auto v : *this)
|
||||
delete v;
|
||||
|
||||
base_type::clear();
|
||||
}
|
||||
@@ -71,17 +35,18 @@ ViewManager::insert(const std::string& name) {
|
||||
View* view = new View();
|
||||
view->initialize(name);
|
||||
|
||||
return base_type::insert(end(), view);
|
||||
base_type::push_back(view);
|
||||
return --end();
|
||||
}
|
||||
|
||||
ViewManager::iterator
|
||||
ViewManager::find(const std::string& name) {
|
||||
return std::find_if(begin(), end(), rak::equal(name, std::mem_fun(&View::name)));
|
||||
return std::find_if(begin(), end(), [name](View* v){ return name == v->name(); });
|
||||
}
|
||||
|
||||
ViewManager::iterator
|
||||
ViewManager::find_throw(const std::string& name) {
|
||||
iterator itr = std::find_if(begin(), end(), rak::equal(name, std::mem_fun(&View::name)));
|
||||
iterator itr = std::find_if(begin(), end(), [name](View* v){ return name == v->name(); });
|
||||
|
||||
if (itr == end())
|
||||
throw torrent::input_error("Could not find view: " + name);
|
||||
@@ -93,7 +58,7 @@ void
|
||||
ViewManager::sort(const std::string& name, uint32_t timeout) {
|
||||
iterator viewItr = find_throw(name);
|
||||
|
||||
if ((*viewItr)->last_changed() + rak::timer::from_seconds(timeout) > cachedTime)
|
||||
if ((*viewItr)->last_changed() + std::chrono::seconds(timeout) > torrent::this_thread::cached_time())
|
||||
return;
|
||||
|
||||
// Should we rename sort, or add a seperate function?
|
||||
@@ -125,8 +90,8 @@ ViewManager::set_filter_on(const std::string& name, const filter_args& args) {
|
||||
|
||||
// TODO: Ensure the filter keys are rlookup.
|
||||
|
||||
for (filter_args::const_iterator itr = args.begin(); itr != args.end(); ++itr)
|
||||
(*viewItr)->set_filter_on_event(*itr);
|
||||
for (const auto& arg : args)
|
||||
(*viewItr)->set_filter_on_event(arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-43
@@ -1,59 +1,23 @@
|
||||
// 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_VIEW_MANAGER_H
|
||||
#define RTORRENT_CORE_VIEW_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <rak/unordered_vector.h>
|
||||
#include <torrent/utils/unordered_vector.h>
|
||||
|
||||
#include "view.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ViewManager : public rak::unordered_vector<View*> {
|
||||
class ViewManager : public torrent::utils::unordered_vector<View*> {
|
||||
public:
|
||||
typedef rak::unordered_vector<View*> base_type;
|
||||
typedef std::list<std::string> filter_args;
|
||||
|
||||
typedef torrent::utils::unordered_vector<View*> base_type;
|
||||
typedef std::list<std::string> filter_args;
|
||||
|
||||
using base_type::iterator;
|
||||
using base_type::const_iterator;
|
||||
using base_type::reverse_iterator;
|
||||
using base_type::const_reverse_iterator;
|
||||
|
||||
|
||||
using base_type::size_type;
|
||||
|
||||
using base_type::begin;
|
||||
@@ -64,7 +28,7 @@ public:
|
||||
using base_type::empty;
|
||||
using base_type::size;
|
||||
|
||||
ViewManager() {}
|
||||
ViewManager() = default;
|
||||
~ViewManager() { clear(); }
|
||||
|
||||
// Ffff... Just throwing together an interface, need to think some
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(HAVE_NCURSESW_CURSES_H)
|
||||
#if defined(HAVE_NO_NCURSES)
|
||||
#include "curses_stub.h"
|
||||
#elif defined(HAVE_NCURSESW_CURSES_H)
|
||||
#include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSESW_H)
|
||||
#include <ncursesw.h>
|
||||
@@ -35,7 +37,7 @@ public:
|
||||
static const int color_invalid = ~int();
|
||||
static const int color_default = 0;
|
||||
|
||||
Attributes() {}
|
||||
Attributes() = default;
|
||||
Attributes(const char* pos, int attr, int col) :
|
||||
m_position(pos), m_attributes(attr), m_colors(col) {}
|
||||
Attributes(const char* pos, const Attributes& old) :
|
||||
|
||||
+142
-57
@@ -1,45 +1,9 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
@@ -47,21 +11,31 @@
|
||||
|
||||
namespace display {
|
||||
|
||||
bool Canvas::m_isInitialized = false;
|
||||
bool Canvas::m_isDaemon = false;
|
||||
bool Canvas::m_initialized{};
|
||||
bool Canvas::m_daemon{};
|
||||
|
||||
// Maps ncurses color IDs to a ncurses attribute int
|
||||
std::unordered_map<int, int> Canvas::m_attr_map = {};
|
||||
|
||||
Canvas::Canvas(int x, int y, int width, int height) {
|
||||
if (!m_isDaemon) {
|
||||
m_window = newwin(height, width, y, x);
|
||||
if (!m_daemon) {
|
||||
m_window = newwin(height, width, y, x);
|
||||
|
||||
if (m_window == NULL)
|
||||
throw torrent::internal_error("Could not allocate ncurses canvas.");
|
||||
if (m_window == nullptr)
|
||||
throw torrent::internal_error("Could not allocate ncurses canvas.");
|
||||
}
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
if (!m_daemon && m_window != nullptr) {
|
||||
delwin(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::resize(int x, int y, int w, int h) {
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
wresize(m_window, h, w);
|
||||
mvwin(m_window, y, x);
|
||||
}
|
||||
@@ -69,11 +43,11 @@ Canvas::resize(int x, int y, int w, int h) {
|
||||
|
||||
void
|
||||
Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes) {
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
move(x, y);
|
||||
|
||||
attr_t org_attr;
|
||||
short org_pair;
|
||||
short org_pair;
|
||||
wattr_get(m_window, &org_attr, &org_pair, NULL);
|
||||
|
||||
attributes_list::const_iterator attrItr = attributes->begin();
|
||||
@@ -102,15 +76,17 @@ Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, cons
|
||||
|
||||
void
|
||||
Canvas::initialize() {
|
||||
if (m_isInitialized)
|
||||
return;
|
||||
if (m_initialized)
|
||||
throw torrent::internal_error("Canvas::initialize() called more than once.");
|
||||
|
||||
m_isDaemon = rpc::call_command_value("system.daemon");
|
||||
m_daemon = rpc::call_command_value("system.daemon");
|
||||
m_initialized = true;
|
||||
|
||||
m_isInitialized = true;
|
||||
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
initscr();
|
||||
start_color();
|
||||
use_default_colors();
|
||||
Canvas::build_colors();
|
||||
raw();
|
||||
noecho();
|
||||
nodelay(stdscr, TRUE);
|
||||
@@ -121,26 +97,135 @@ Canvas::initialize() {
|
||||
|
||||
void
|
||||
Canvas::cleanup() {
|
||||
if (!m_isInitialized)
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
m_isInitialized = false;
|
||||
m_initialized = false;
|
||||
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
noraw();
|
||||
endwin();
|
||||
}
|
||||
}
|
||||
|
||||
// Function wrapper for what possibly is a macro
|
||||
int
|
||||
get_colors() {
|
||||
return COLORS;
|
||||
}
|
||||
|
||||
// Turns the string color definitions from the "ui.color.*" RPC
|
||||
// commands into valid ncurses color pairs
|
||||
void
|
||||
Canvas::build_colors() {
|
||||
|
||||
// This may get called early in the start process by the config
|
||||
// file, so we need to delay building until initscr() has a chance
|
||||
// to run
|
||||
if (!m_initialized || m_daemon)
|
||||
return;
|
||||
|
||||
// basic color names, index maps to ncurses COLOR_*
|
||||
static constexpr std::array color_names{
|
||||
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};
|
||||
|
||||
// Those hold the background colors of "odd" and "even"
|
||||
int bg_odd = -1;
|
||||
int bg_even = -1;
|
||||
|
||||
for (int k = 1; k < RCOLOR_MAX; k++) {
|
||||
init_pair(k, -1, -1);
|
||||
|
||||
std::string color_def = rpc::call_command_string(color_vars[k]);
|
||||
|
||||
if (color_def.empty())
|
||||
continue; // Use terminal default if definition is empty
|
||||
|
||||
short color[2] = {-1, -1}; // fg, bg
|
||||
short color_idx = 0; // 0 = fg; 1 = bg
|
||||
short bright = 0;
|
||||
unsigned long attr = A_NORMAL;
|
||||
|
||||
// Process string as space-separated words
|
||||
size_t start = 0, end = 0;
|
||||
|
||||
while (true) {
|
||||
end = color_def.find(' ', start);
|
||||
std::string word = color_def.substr(start, end - start);
|
||||
|
||||
if (word == "bold")
|
||||
attr |= A_BOLD;
|
||||
else if (word == "standout")
|
||||
attr |= A_STANDOUT;
|
||||
else if (word == "underline")
|
||||
attr |= A_UNDERLINE;
|
||||
else if (word == "reverse")
|
||||
attr |= A_REVERSE;
|
||||
else if (word == "blink")
|
||||
attr |= A_BLINK;
|
||||
else if (word == "dim")
|
||||
attr |= A_DIM;
|
||||
else if (word == "on") {
|
||||
color_idx = 1;
|
||||
bright = 0;
|
||||
} // Switch to background color
|
||||
else if (word == "gray" || word == "grey")
|
||||
color[color_idx] = bright ? 7 : 8; // Bright gray is white
|
||||
else if (word == "bright")
|
||||
bright = 8;
|
||||
else if (word.find_first_not_of("0123456789") == std::string::npos) {
|
||||
// Handle numeric index
|
||||
short c = -1;
|
||||
sscanf(word.c_str(), "%hd", &c);
|
||||
color[color_idx] = c;
|
||||
} else
|
||||
for (short c = 0; c < 8; c++) { // Check for basic color names
|
||||
if (word == color_names[c]) {
|
||||
color[color_idx] = bright + c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end == std::string::npos)
|
||||
break;
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
// Check that fg & bg color index is valid
|
||||
if ((color[0] != -1 && color[0] >= get_colors()) || (color[1] != -1 && color[1] >= get_colors())) {
|
||||
Canvas::cleanup();
|
||||
throw torrent::input_error(color_def + ": your terminal only supports " + std::to_string(get_colors()) + " colors.");
|
||||
}
|
||||
|
||||
m_attr_map[k] = attr; // overwrite or insert the value
|
||||
init_pair(k, color[0], color[1]);
|
||||
if (k == RCOLOR_EVEN)
|
||||
bg_even = color[1];
|
||||
if (k == RCOLOR_ODD)
|
||||
bg_odd = color[1];
|
||||
}
|
||||
|
||||
// Now make copies of the basic colors with the "odd" and "even" definitions mixed in
|
||||
for (int k = 1; k < RCOLOR_MAX; k++) {
|
||||
short fg, bg;
|
||||
pair_content(k, &fg, &bg);
|
||||
|
||||
// Replace the background color, and mix in the attributes
|
||||
m_attr_map[k + 1 * RCOLOR_MAX] = m_attr_map[k] | m_attr_map[RCOLOR_EVEN];
|
||||
m_attr_map[k + 2 * RCOLOR_MAX] = m_attr_map[k] | m_attr_map[RCOLOR_ODD];
|
||||
init_pair(k + 1 * RCOLOR_MAX, fg, bg == -1 ? bg_even : bg);
|
||||
init_pair(k + 2 * RCOLOR_MAX, fg, bg == -1 ? bg_odd : bg);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, int>
|
||||
Canvas::term_size() {
|
||||
struct winsize ws;
|
||||
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0)
|
||||
return std::pair<int, int>(ws.ws_col, ws.ws_row);
|
||||
}
|
||||
return std::pair<int, int>(80, 24);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace display
|
||||
|
||||
+225
-86
@@ -1,130 +1,205 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_DISPLAY_CANVAS_H
|
||||
#define RTORRENT_DISPLAY_CANVAS_H
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "attributes.h"
|
||||
#include "color_map.h"
|
||||
|
||||
namespace display {
|
||||
|
||||
class Canvas {
|
||||
public:
|
||||
typedef std::vector<Attributes> attributes_list;
|
||||
typedef std::vector<Attributes> attributes_list;
|
||||
typedef std::unordered_map<int, int> attributes_map;
|
||||
|
||||
Canvas(int x = 0, int y = 0, int width = 0, int height = 0);
|
||||
~Canvas() { if (!m_isDaemon) { delwin(m_window); } }
|
||||
~Canvas();
|
||||
|
||||
void refresh() { if (!m_isDaemon) { wnoutrefresh(m_window); } }
|
||||
static void refresh_std() { if (!m_isDaemon) { wnoutrefresh(stdscr); } }
|
||||
void redraw() { if (!m_isDaemon) { redrawwin(m_window); } }
|
||||
static void redraw_std() { if (!m_isDaemon) { redrawwin(stdscr); } }
|
||||
void refresh();
|
||||
void redraw();
|
||||
void resize(int w, int h);
|
||||
void resize(int x, int y, int w, int h);
|
||||
|
||||
void resize(int w, int h) { if (!m_isDaemon) { wresize(m_window, h, w); } }
|
||||
void resize(int x, int y, int w, int h);
|
||||
static void refresh_std();
|
||||
static void redraw_std();
|
||||
static void resize_term(int x, int y);
|
||||
static void resize_term(std::pair<int, int> dim);
|
||||
|
||||
static void resize_term(int x, int y) { if (!m_isDaemon) { resizeterm(y, x); } }
|
||||
static void resize_term(std::pair<int, int> dim) { if (!m_isDaemon) { resizeterm(dim.second, dim.first); } }
|
||||
unsigned int get_x();
|
||||
unsigned int get_y();
|
||||
unsigned int width();
|
||||
unsigned int height();
|
||||
|
||||
unsigned int get_x() { int x, __UNUSED y; if (!m_isDaemon) { getyx(m_window, y, x); } else { x=1; } return x; }
|
||||
unsigned int get_y() { int x, y; if (!m_isDaemon) { getyx(m_window, y, x); } else { y=1; } return y; }
|
||||
|
||||
unsigned int width() { int x, __UNUSED y; if (!m_isDaemon) { getmaxyx(m_window, y, x); } else { x=80; } return x; }
|
||||
unsigned int height() { int x, y; if (!m_isDaemon) { getmaxyx(m_window, y, x); } else { y=24; } return y; }
|
||||
|
||||
void move(unsigned int x, unsigned int y) { if (!m_isDaemon) { wmove(m_window, y, x); } }
|
||||
|
||||
chtype get_background() { chtype bg=0; if (!m_isDaemon) { bg=getbkgd(m_window); } return bg; }
|
||||
void set_background(chtype c) { if (!m_isDaemon) { return wbkgdset(m_window, c); } }
|
||||
|
||||
void erase() { if (!m_isDaemon) { werase(m_window); } }
|
||||
static void erase_std() { if (!m_isDaemon) { werase(stdscr); } }
|
||||
|
||||
void print_border(chtype ls, chtype rs,
|
||||
chtype ts, chtype bs,
|
||||
chtype tl, chtype tr,
|
||||
chtype bl, chtype br) { if (!m_isDaemon) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); } }
|
||||
void move(unsigned int x, unsigned int y);
|
||||
void erase();
|
||||
static void erase_std();
|
||||
|
||||
// The format string is non-const, but that will not be a problem
|
||||
// since the string shall always be a C string choosen at
|
||||
// compiletime. Might cause extra copying of the string?
|
||||
|
||||
void print(const char* str, ...);
|
||||
void print(unsigned int x, unsigned int y, const char* str, ...);
|
||||
void print(const char* str, ...);
|
||||
void print(unsigned int x, unsigned int y, const char* str, ...);
|
||||
void print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes);
|
||||
void print_char(const chtype ch);
|
||||
void print_char(unsigned int x, unsigned int y, const chtype ch);
|
||||
|
||||
void print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes);
|
||||
|
||||
void print_char(const chtype ch) { if (!m_isDaemon) { waddch(m_window, ch); } }
|
||||
void print_char(unsigned int x, unsigned int y, const chtype ch) { if (!m_isDaemon) { mvwaddch(m_window, y, x, ch); } }
|
||||
|
||||
void set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) { if (!m_isDaemon) { mvwchgat(m_window, y, x, n, attr, color, NULL); } }
|
||||
|
||||
void set_default_attributes(int attr) { if (!m_isDaemon) { (void)wattrset(m_window, attr); } }
|
||||
void set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color);
|
||||
void set_attr(unsigned int x, unsigned int y, unsigned int n, ColorKind k);
|
||||
void set_default_attributes(int attr);
|
||||
|
||||
// Initialize stdscr.
|
||||
static void initialize();
|
||||
static void cleanup();
|
||||
static void initialize();
|
||||
static void cleanup();
|
||||
|
||||
static int get_screen_width() { int x, __UNUSED y; if (!m_isDaemon) { getmaxyx(stdscr, y, x); } else { x=80; } return x; }
|
||||
static int get_screen_height() { int x, y; if (!m_isDaemon) { getmaxyx(stdscr, y, x); } else { y=24;} return y; }
|
||||
static void build_colors();
|
||||
|
||||
static int get_screen_width();
|
||||
static int get_screen_height();
|
||||
|
||||
static std::pair<int, int> term_size();
|
||||
|
||||
static void do_update() { if (!m_isDaemon) { doupdate(); } }
|
||||
static void do_update();
|
||||
|
||||
static bool daemon() { return m_isDaemon; }
|
||||
static bool daemon() { return m_daemon; }
|
||||
static const attributes_map& attr_map() { return m_attr_map; }
|
||||
|
||||
private:
|
||||
Canvas(const Canvas&);
|
||||
void operator = (const Canvas&);
|
||||
void operator=(const Canvas&);
|
||||
|
||||
static bool m_isInitialized;
|
||||
static bool m_isDaemon;
|
||||
static bool m_initialized;
|
||||
static bool m_daemon;
|
||||
|
||||
WINDOW* m_window;
|
||||
// Maps ncurses color IDs to a ncurses attribute int
|
||||
static std::unordered_map<int, int> m_attr_map;
|
||||
|
||||
WINDOW* m_window;
|
||||
};
|
||||
|
||||
inline void
|
||||
Canvas::refresh() {
|
||||
if (!m_daemon) {
|
||||
wnoutrefresh(m_window);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::refresh_std() {
|
||||
if (!m_daemon) {
|
||||
wnoutrefresh(stdscr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::redraw() {
|
||||
if (!m_daemon) {
|
||||
redrawwin(m_window);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::redraw_std() {
|
||||
if (!m_daemon) {
|
||||
redrawwin(stdscr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::resize(int w, int h) {
|
||||
if (!m_daemon) {
|
||||
wresize(m_window, h, w);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::resize_term(int x, int y) {
|
||||
if (!m_daemon) {
|
||||
resizeterm(y, x);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::resize_term(std::pair<int, int> dim) {
|
||||
if (!m_daemon) {
|
||||
resizeterm(dim.second, dim.first);
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
Canvas::get_x() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getyx(m_window, y, x);
|
||||
} else {
|
||||
x = 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
Canvas::get_y() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getyx(m_window, y, x);
|
||||
} else {
|
||||
y = 1;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
Canvas::width() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(m_window, y, x);
|
||||
} else {
|
||||
x = 80;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
Canvas::height() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(m_window, y, x);
|
||||
} else {
|
||||
y = 24;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::move(unsigned int x, unsigned int y) {
|
||||
if (!m_daemon) {
|
||||
wmove(m_window, y, x);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::erase() {
|
||||
if (!m_daemon) {
|
||||
werase(m_window);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::erase_std() {
|
||||
if (!m_daemon) {
|
||||
werase(stdscr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::print(const char* str, ...) {
|
||||
va_list arglist;
|
||||
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
va_start(arglist, str);
|
||||
vw_printw(m_window, const_cast<char*>(str), arglist);
|
||||
va_end(arglist);
|
||||
@@ -135,7 +210,7 @@ inline void
|
||||
Canvas::print(unsigned int x, unsigned int y, const char* str, ...) {
|
||||
va_list arglist;
|
||||
|
||||
if (!m_isDaemon) {
|
||||
if (!m_daemon) {
|
||||
va_start(arglist, str);
|
||||
wmove(m_window, y, x);
|
||||
vw_printw(m_window, const_cast<char*>(str), arglist);
|
||||
@@ -143,6 +218,70 @@ Canvas::print(unsigned int x, unsigned int y, const char* str, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::print_char(const chtype ch) {
|
||||
if (!m_daemon) {
|
||||
waddch(m_window, ch);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::print_char(unsigned int x, unsigned int y, const chtype ch) {
|
||||
if (!m_daemon) {
|
||||
mvwaddch(m_window, y, x, ch);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) {
|
||||
if (!m_daemon) {
|
||||
mvwchgat(m_window, y, x, n, attr, color, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::set_attr(unsigned int x, unsigned int y, unsigned int n, ColorKind k) {
|
||||
if (!m_daemon) {
|
||||
mvwchgat(m_window, y, x, n, m_attr_map[k], k, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::set_default_attributes(int attr) {
|
||||
if (!m_daemon) {
|
||||
(void)wattrset(m_window, attr);
|
||||
}
|
||||
}
|
||||
|
||||
inline int
|
||||
Canvas::get_screen_width() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(stdscr, y, x);
|
||||
} else {
|
||||
x = 80;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline int
|
||||
Canvas::get_screen_height() {
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(stdscr, y, x);
|
||||
} else {
|
||||
y = 24;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
inline void
|
||||
Canvas::do_update() {
|
||||
if (!m_daemon) {
|
||||
doupdate();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace display
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user