mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-06 18:22:32 +00:00
Compare commits
487 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a88cab6d2e | |||
| 9a93281ded | |||
| 133ce36570 | |||
| a142301d02 | |||
| f04e512887 | |||
| d32d59315d | |||
| 86e85ae485 | |||
| 6e9902c23b | |||
| d4427931a2 | |||
| ea3828a17e | |||
| 4e246a401f | |||
| eacf9798e2 | |||
| 892e595015 | |||
| 1da0e3476d | |||
| c0a5a55444 | |||
| 551712f842 | |||
| c7c290a86b | |||
| 2e1a499942 | |||
| c86f0d0333 | |||
| 92bec88d09 | |||
| d067bd802e | |||
| 50924eeda0 | |||
| 1e40014482 | |||
| 8cafb55881 | |||
| a6bc99bb82 | |||
| 52ceb39ca3 | |||
| 926893ee62 | |||
| cf13789f8c | |||
| d15d93be88 | |||
| 582e4e4025 | |||
| 952777d75e | |||
| 19dbaa7442 | |||
| 3f72e27603 | |||
| e267e8bc07 | |||
| 79765768ff | |||
| 8cc1d8f2c5 | |||
| 3798de01a0 | |||
| 8ac98c6d3a | |||
| 81500adc53 | |||
| 14d7121185 | |||
| 7659cd0ec0 | |||
| f43f9e430d | |||
| f22475d1bf | |||
| b697a4608b | |||
| 765665fc28 | |||
| 5f70986099 | |||
| 6154d16987 | |||
| a5e8631cba | |||
| 07dcd04357 | |||
| 863de44c18 | |||
| 24135ed48e | |||
| 83709d28c9 | |||
| 859d5a9578 | |||
| adc9b1dec5 | |||
| 285972a20d | |||
| 3ec2f52db5 | |||
| ac64fc3f63 | |||
| b26dc42f3a | |||
| 6572088aec | |||
| 31a0ea1a2d | |||
| 2d72a0d2c0 | |||
| a3a384b049 | |||
| f37dd0d5c2 | |||
| 78c25011cd | |||
| 35d98c91e0 | |||
| 27811db659 | |||
| 4e73ce6bfd | |||
| 8c8e73bb72 | |||
| 0d5b344d2a | |||
| 703cac9a42 | |||
| e6c008b2b7 | |||
| 81de60e0ae | |||
| c361d6010e | |||
| 724dc088ca | |||
| c62fa6a756 | |||
| 656d735de7 | |||
| 408013478c | |||
| fa61b8c11c | |||
| 1339a3ace9 | |||
| 4ba128163f | |||
| 908a99751f | |||
| c115640934 | |||
| 9043c46815 | |||
| 1f418366d4 | |||
| 30c78c7034 | |||
| 74435f6c40 | |||
| a4b281afa4 | |||
| f84670dd63 | |||
| f0207ce654 | |||
| 9cce5a0bd1 | |||
| 95cff549c6 | |||
| 92898a9831 | |||
| fcfbf0e79f | |||
| 680b47c197 | |||
| 7804ed3009 | |||
| d9b39f5ac6 | |||
| 08aa287cfc | |||
| 851d1902a0 | |||
| b600ff0c0e | |||
| a639461c4a | |||
| c1057d5ac7 | |||
| 2ac65ad7e1 | |||
| a4939cb9fd | |||
| 3d88ac2cc8 | |||
| f37fefcc54 | |||
| 885836f68b | |||
| ca4c3bee8d | |||
| 6c278668e4 | |||
| 1665437588 | |||
| 327164f9d8 | |||
| 5d22fdd4b6 | |||
| 7455f2eb86 | |||
| 53767cee92 | |||
| aa9e729ca7 | |||
| e43853b782 | |||
| 81932c0b12 | |||
| 61264c4f17 | |||
| 244a84dcf5 | |||
| c9a5736d5d | |||
| 9322acb33d | |||
| a5e722b48f | |||
| ba4828d226 | |||
| dfced79186 | |||
| dd2a4cc151 | |||
| fd372b5e48 | |||
| 6dc87e499a | |||
| 6c11a1dbb0 | |||
| 3ea47d7acb | |||
| b82f3614c3 | |||
| 2987ba8081 | |||
| 33f8fe804b | |||
| 1a4f6dab1a | |||
| 943b576e1f | |||
| 29d57e858a | |||
| 7ec9b6685b | |||
| d5de8a91d1 | |||
| 4d6f6fe335 | |||
| 2ec90c6892 | |||
| 63dfe341a6 | |||
| 13676f06e5 | |||
| 6cb176ada3 | |||
| 8b6a1ad079 | |||
| 3002c95b2c | |||
| 9590949fa7 | |||
| 321147cdb8 | |||
| 6ee61ee6b5 | |||
| 2097c9ca3e | |||
| 10ce6864b8 | |||
| e15270271d | |||
| 226e670dec | |||
| 74bd0be5d8 | |||
| e3a5ed9c75 | |||
| c7c5a00f66 | |||
| 71a52bfac2 | |||
| 16e1961636 | |||
| 2aa130eda9 | |||
| 008561ef47 | |||
| e02c6b29fa | |||
| e2c769f459 | |||
| c3f6db0384 | |||
| 40a5b63223 | |||
| e6439a173e | |||
| 84913766d5 | |||
| 89b02f275e | |||
| ce00085107 | |||
| d7529d3b84 | |||
| 23cf6b260c | |||
| 06f1c032b0 | |||
| bdb0d99c5c | |||
| 7c5e42f4b9 | |||
| e1afe25413 | |||
| 0cba9cbf9b | |||
| 017cb1bd59 | |||
| dfdbf5e69c | |||
| 15e64bdade | |||
| 5838b8e68c | |||
| 13162f98cb | |||
| b5e4dc0342 | |||
| 41a059c999 | |||
| 55c61e9099 | |||
| e1fa392ecb | |||
| 9d7398d1da | |||
| a194da08b0 | |||
| 51c5190eb1 | |||
| 66619840d8 | |||
| 63c2b7aef5 | |||
| 2c60226bd2 | |||
| d111594d20 | |||
| a0f97e4b06 | |||
| a7079c594e | |||
| ed48d586d8 | |||
| 8be4e5bbf7 | |||
| 8140c3fe07 | |||
| 8385957b06 | |||
| 1363e50a7b | |||
| f24154e772 | |||
| 3f698b3b39 | |||
| a8c67b4aab | |||
| aac0ea48f7 | |||
| 1db32f2f63 | |||
| efc9097d62 | |||
| 5a56fbd5d1 | |||
| 7ea5729676 | |||
| c01709fa27 | |||
| 0797d636fb | |||
| b68d4c2db9 | |||
| 9abcea84c7 | |||
| cc1f7fb2cb | |||
| 944d304193 | |||
| 629e421d67 | |||
| 3e7f9d8b4f | |||
| a8cb524345 | |||
| 0510e4db9d | |||
| a975804797 | |||
| adf4a32097 | |||
| 3edeb364bc | |||
| 73a344711d | |||
| 4ba24af463 | |||
| 44f0ac3447 | |||
| a92da121d7 | |||
| 4fb036f87d | |||
| 6a8d332b4c | |||
| 911596d65e | |||
| b19cf8b4ff | |||
| 83d7dc8964 | |||
| b89fa31f37 | |||
| 30d8379391 | |||
| 605819ea6c | |||
| 1f5e4d37d5 | |||
| 33601ddc0c | |||
| e1cc736f11 | |||
| 9647749b01 | |||
| 06db5776ae | |||
| 62cb5a4605 | |||
| d4905d512a | |||
| 9ba4d1d92e | |||
| 1c47bf6162 | |||
| 50d6437792 | |||
| eb5443bbad | |||
| 1a728fc683 | |||
| 0d1dc8a331 | |||
| b5f2cfe393 | |||
| 7343e33a6a | |||
| e3cc2c601d | |||
| 3cf9cffe68 | |||
| 0ba4d7d943 | |||
| cc10161c90 | |||
| d1e807acc5 | |||
| 0df0a6650d | |||
| 6c39da6943 | |||
| 089fa765b8 | |||
| 92197d6286 | |||
| 9937ea27bc | |||
| b5bff0cb9c | |||
| 3d166de175 | |||
| 7007973c76 | |||
| 7537a3c2a9 | |||
| 81c652292a | |||
| f4c312e2c0 | |||
| 975d001ea7 | |||
| fe9a4e9714 | |||
| 52689695ff | |||
| 2a19c613c1 | |||
| dc8e786d58 | |||
| b8e24b78cd | |||
| 4244921383 | |||
| afebadcbdf | |||
| d74409c2d7 | |||
| 1fefc4720b | |||
| 09f6243c6a | |||
| 390328ec97 | |||
| bfd1a8da8c | |||
| 4ac807870e | |||
| 5acfd592f0 | |||
| e4e73aeee9 | |||
| 8e69930cc4 | |||
| 3b39f37f49 | |||
| 4f36c3e49f | |||
| e42ec54920 | |||
| 6a3234eaa7 | |||
| ce5d67a9c0 | |||
| d396c8e058 | |||
| 904a390fba | |||
| 9548e08935 | |||
| 696c2b2b33 | |||
| ce125b1c54 | |||
| 82a68420f4 | |||
| d9f6f5aef4 | |||
| 24f84214c8 | |||
| 38f39bdb23 | |||
| 906683714b | |||
| a536fc09a0 | |||
| dea7c80996 | |||
| 3e3a84b3a0 | |||
| 866289b38a | |||
| c9e894982f | |||
| 6b7adfd6bd | |||
| fcd1fdb2fe | |||
| a5d92cc940 | |||
| 9fcef7fbd6 | |||
| effdc5642d | |||
| fe5439f6a0 | |||
| 58fba68aff | |||
| 89dfa3a268 | |||
| 0d620e77db | |||
| 55b826d6cb | |||
| 385b342deb | |||
| 2e9baa1635 | |||
| 67236d7757 | |||
| 66edb39863 | |||
| 00a349f68c | |||
| 370bae4b98 | |||
| 323f0df30c | |||
| aa93404278 | |||
| 1e4739c862 | |||
| aa2f784ae6 | |||
| 529eda5aab | |||
| 629ebcbd54 | |||
| d8d7861244 | |||
| bc4209e380 | |||
| e36a0d43a4 | |||
| c3ad68156e | |||
| 6697806185 | |||
| 412a2f79b9 | |||
| 0bf60679e4 | |||
| 0329608f69 | |||
| b113a02584 | |||
| 49d00285c8 | |||
| 2cd70f4342 | |||
| 7689059dbc | |||
| 3b2a47a6d0 | |||
| e28692492b | |||
| 2c97841e92 | |||
| bb27adcfd3 | |||
| 5e6cb5da04 | |||
| cd029a67c5 | |||
| addc323ec8 | |||
| 2217b14095 | |||
| 6a84facae0 | |||
| 66a116841a | |||
| bacb6c0f72 | |||
| 40fc8bbf80 | |||
| 13f672ab4d | |||
| 2967f9a224 | |||
| eac7536f6a | |||
| 78f64a3e08 | |||
| cf77a17399 | |||
| 7a2ec0ff86 | |||
| 48733c84ec | |||
| b020aa0197 | |||
| e95b66fc51 | |||
| 678049bc09 | |||
| 2f102f0fcd | |||
| d0f6bb440a | |||
| 8f5f383e3c | |||
| 2ca49e3485 | |||
| 004862850d | |||
| d2d09d97f8 | |||
| fb75510c0f | |||
| 8d0f9b3300 | |||
| 76ed90f514 | |||
| b79dea94b2 | |||
| cf1c44ef5b | |||
| 6d61cc09c3 | |||
| f1ece0ae12 | |||
| 9df9183a0c | |||
| 75933db69b | |||
| f373b20c1b | |||
| efa3c670a5 | |||
| 22acdd87c3 | |||
| c46ee642fe | |||
| cca1f21471 | |||
| 27888e73bc | |||
| 4dd7582240 | |||
| 03c0a4e18c | |||
| c2b768cd6d | |||
| 097e3d9056 | |||
| 63cf700593 | |||
| 0132ce6b81 | |||
| 17201984a6 | |||
| a7b7b26d08 | |||
| 0a9e03df57 | |||
| 90830dc765 | |||
| 0b39455a4b | |||
| d2dd143d2e | |||
| b71b44dbd6 | |||
| 83294e2198 | |||
| 46862e23a9 | |||
| 077288407f | |||
| 05d16707d4 | |||
| 3fe1a734ac | |||
| 9c2745ecb3 | |||
| e79b38f907 | |||
| fdc6ee56de | |||
| 36f8e5d349 | |||
| 5bed4f01ad | |||
| 020de10f38 | |||
| 7343c0d67c | |||
| b28f2ea807 | |||
| 9aa54d2344 | |||
| 6141a5656f | |||
| dc817e24e4 | |||
| d1ff1fe77c | |||
| 51fff1fdc5 | |||
| 47d36c0690 | |||
| 07d326535d | |||
| bb75f06c6d | |||
| 04acc8a0af | |||
| 0514a5c0d1 | |||
| f1cd0f4780 | |||
| ece90f975b | |||
| 89611a222c | |||
| 2c72c31e1c | |||
| cf3a1674a3 | |||
| 64c66c81ae | |||
| bc993807d1 | |||
| 3ac22e4bc7 | |||
| 3d1b0b5971 | |||
| 7e0d5956b5 | |||
| a186932c03 | |||
| 79e9990669 | |||
| 31ba6341cf | |||
| 6b71d75c33 | |||
| 4ff2483f07 | |||
| d8f41a28fa | |||
| 482a9ba09f | |||
| f7403d30e9 | |||
| 639af87e53 | |||
| 6a45ca2dd6 | |||
| 78abb7fed1 | |||
| 2da20f984e | |||
| 1b4d8f9626 | |||
| a0ce6c09a6 | |||
| 4bcf7f4f5e | |||
| 45d2d0bd49 | |||
| 26581c74c1 | |||
| 7fe2fb1584 | |||
| d4cbe5294d | |||
| 0cbc11b536 | |||
| d4a3ec0224 | |||
| f50358b284 | |||
| 4f601fda79 | |||
| 8ed8ee9f81 | |||
| 2178422d90 | |||
| f1852cd222 | |||
| 47125b9c38 | |||
| 9ad22ab8ff | |||
| ba30dcd7cf | |||
| 4632053301 | |||
| 309711025b | |||
| 53edee3e06 | |||
| cfc4984c3a | |||
| 6a399cd927 | |||
| be95b82d29 | |||
| 74ea256036 | |||
| 79517e61aa | |||
| 222018e395 | |||
| 18d51a60a1 | |||
| e58f3975f1 | |||
| 002833f7b7 | |||
| 0626dcf783 | |||
| f51b280cbf | |||
| 4c29d3b714 | |||
| 28634f2c8c | |||
| 007d83e904 | |||
| 5b7a2b5e95 | |||
| 1c1993acef | |||
| 1fc70a733d | |||
| ee859a6137 | |||
| 4d1f5dce67 | |||
| 6dfd2fe0cd | |||
| 89213982d5 | |||
| 2d8036e3a8 | |||
| a2ad162fe3 | |||
| 21944b941a | |||
| 41d49b7c18 | |||
| 3c4d21d34c | |||
| 0d648119d2 | |||
| 9a9dcb88f7 | |||
| 58727fe7fd | |||
| f0da99b5c3 | |||
| c55f5611a9 | |||
| 52530d5538 | |||
| 8d4aed7dae | |||
| 7b38cc29aa | |||
| 31495b06be | |||
| 413becea38 |
@@ -0,0 +1,7 @@
|
||||
;;; Directory Local Variables
|
||||
;;; For more information see (info "(emacs) Directory Variables")
|
||||
|
||||
((c++-mode
|
||||
(flycheck-clang-language-standard . "c++11")
|
||||
(flycheck-gcc-language-standard . "c++11")))
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [rakshasa]
|
||||
patreon: rtorrent
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: ['https://rakshasa.github.io/rtorrent/donate.html']
|
||||
+67
-4
@@ -1,9 +1,72 @@
|
||||
# Compiled source #
|
||||
###################
|
||||
*.o
|
||||
*.lo
|
||||
*.a
|
||||
*.la
|
||||
*.so
|
||||
*.in
|
||||
*.sub
|
||||
*.pc
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Autoconf files #
|
||||
##################
|
||||
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
compile
|
||||
config.h
|
||||
config.guess
|
||||
config.status
|
||||
confdefs.h
|
||||
conftest.dir
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
|
||||
src/rtorrent
|
||||
scripts/libtool.m4
|
||||
scripts/ltoptions.m4
|
||||
scripts/ltsugar.m4
|
||||
scripts/ltversion.m4
|
||||
scripts/lt~obsolete.m4
|
||||
scripts/lt*.m4
|
||||
|
||||
# Editor poo #
|
||||
##############
|
||||
.#*
|
||||
\#*#
|
||||
*~
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.gz
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store?
|
||||
.dirstamp
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
TAGS
|
||||
|
||||
# rTorrent specific files
|
||||
###########################
|
||||
src/rtorrent
|
||||
test/rtorrentTest
|
||||
test-driver
|
||||
test/rtorrentTest.trs
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j 12"
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++ SKIP_CHECK=true
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.6
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- clang-3.7
|
||||
- libcppunit-dev
|
||||
- compiler: clang
|
||||
env: COMPILER=clang++-3.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages:
|
||||
- clang-3.8
|
||||
- libcppunit-dev
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.7 SKIP_CHECK=true
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.7
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.7
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.7
|
||||
- libcppunit-dev
|
||||
- compiler: gcc
|
||||
env: COMPILER=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- libcppunit-dev
|
||||
|
||||
# TODO: Use the same branch name if libtorrent has it.
|
||||
before_install:
|
||||
- git clone https://github.com/rakshasa/libtorrent.git
|
||||
- |
|
||||
pushd libtorrent \
|
||||
&& (git checkout ${TRAVIS_BRANCH} || true) \
|
||||
&& ./autogen.sh \
|
||||
&& CXX="$COMPILER" ./configure --prefix=/usr \
|
||||
&& make \
|
||||
&& sudo make install \
|
||||
&& popd
|
||||
|
||||
script:
|
||||
- ./autogen.sh && CXX="$COMPILER" ./configure && make
|
||||
- if [ ! $SKIP_CHECK ]; then make check; fi
|
||||
@@ -1 +1 @@
|
||||
Jari Sundell <jaris@ifi.uio.no>
|
||||
Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
@@ -1,81 +1,109 @@
|
||||
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
Briefly, the shell command './configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the 'README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
'INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
The 'configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
those values to create a 'Makefile' in each directory of the package.
|
||||
It may also create one or more '.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script 'config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
file 'config.log' containing compiler output (useful mainly for
|
||||
debugging 'configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. (Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.)
|
||||
It can also use an optional file (typically called 'config.cache' and
|
||||
enabled with '--cache-file=config.cache' or simply '-C') that saves the
|
||||
results of its tests to speed up reconfiguring. Caching is disabled by
|
||||
default to prevent problems with accidental use of stale cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
to figure out how 'configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the 'README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
some point 'config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You only need
|
||||
`configure.ac' if you want to change it or regenerate `configure' using
|
||||
a newer version of `autoconf'.
|
||||
The file 'configure.ac' (or 'configure.in') is used to create
|
||||
'configure' by a program called 'autoconf'. You need 'configure.ac' if
|
||||
you want to change it or regenerate 'configure' using a newer version of
|
||||
'autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
1. 'cd' to the directory containing the package's source code and type
|
||||
'./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
Running 'configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
2. Type 'make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
3. Optionally, type 'make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
4. Type 'make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the 'make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
5. Optionally, type 'make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior 'make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing 'make clean'. To also remove the
|
||||
files that 'configure' created (so you can compile the package for
|
||||
a different kind of computer), type 'make distclean'. There is
|
||||
also a 'make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type 'make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide 'make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like 'make install' and 'make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
the 'configure' script does not know about. Run './configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
You can give 'configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here is
|
||||
an example:
|
||||
|
||||
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
@@ -84,146 +112,257 @@ Compiling For Multiple Architectures
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
own directory. To do this, you can use GNU 'make'. 'cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
the 'configure' script. 'configure' automatically checks for the source
|
||||
code in the directory that 'configure' is in and in '..'. This is known
|
||||
as a "VPATH" build.
|
||||
|
||||
If you have to use a `make' that does not support the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a
|
||||
time in the source code directory. After you have installed the
|
||||
package for one architecture, use `make distclean' before reconfiguring
|
||||
for another architecture.
|
||||
With a non-GNU 'make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use 'make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple '-arch' options to the
|
||||
compiler but only a single '-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the 'lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
By default, 'make install' installs the package's commands under
|
||||
'/usr/local/bin', include files under '/usr/local/include', etc. You
|
||||
can specify an installation prefix other than '/usr/local' by giving
|
||||
'configure' the option '--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=PATH' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
options like '--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run 'configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the default
|
||||
for these options is expressed in terms of '${prefix}', so that
|
||||
specifying just '--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to 'configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
'make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, 'make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
'${prefix}'. Any directories that were specified during 'configure',
|
||||
but not in terms of '${prefix}', must each be overridden at install time
|
||||
for the entire installation to be relocated. The approach of makefile
|
||||
variable overrides for each directory variable is required by the GNU
|
||||
Coding Standards, and ideally causes no recompilation. However, some
|
||||
platforms have known limitations with the semantics of shared libraries
|
||||
that end up requiring recompilation when using this method, particularly
|
||||
noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the 'DESTDIR' variable. For
|
||||
example, 'make install DESTDIR=/alternate/directory' will prepend
|
||||
'/alternate/directory' before all installation names. The approach of
|
||||
'DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of '${prefix}'
|
||||
at 'configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving 'configure' the
|
||||
option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to '--enable-FEATURE' options to
|
||||
'configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to '--with-PACKAGE' options, where PACKAGE
|
||||
is something like 'gnu-as' or 'x' (for the X Window System). The
|
||||
'README' should mention any '--enable-' and '--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
For packages that use the X Window System, 'configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
you can use the 'configure' options '--x-includes=DIR' and
|
||||
'--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of 'make' will be. For these packages, running './configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with 'make V=1'; while running './configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with 'make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
|
||||
is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX 'make' updates targets which have the same time stamps as their
|
||||
prerequisites, which makes it generally unusable when shipped generated
|
||||
files such as 'configure' are involved. Use GNU 'make' instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
|
||||
workaround. If GNU CC is not installed, it is therefore recommended to
|
||||
try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
|
||||
in your 'PATH', put it _after_ '/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in '/boot/common',
|
||||
not '/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
There may be some features 'configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
_same_ architectures, 'configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
'--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as 'sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
See the file 'config.sub' for the possible values of each field. If
|
||||
'config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the `--target=TYPE' option to select the type of system they will
|
||||
use the option '--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
eventually be run) with '--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
If you want to set default values for 'configure' scripts to share,
|
||||
you can create a site shell script called 'config.site' that gives
|
||||
default values for variables like 'CC', 'cache_file', and 'prefix'.
|
||||
'configure' looks for 'PREFIX/share/config.site' if it exists, then
|
||||
'PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
'CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all 'configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
environment passed to 'configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
them in the 'configure' command line, using 'VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
will cause the specified gcc to be used as the C compiler (unless it is
|
||||
causes the specified 'gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
`configure' Invocation
|
||||
Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
|
||||
Autoconf limitation. Until the limitation is lifted, you can use this
|
||||
workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
'configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
'configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
'--help'
|
||||
'-h'
|
||||
Print a summary of all of the options to 'configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
'--help=short'
|
||||
'--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
'configure', and exit. The 'short' variant lists options used only
|
||||
in the top level, while the 'recursive' variant lists options also
|
||||
present in any nested packages.
|
||||
|
||||
'--version'
|
||||
'-V'
|
||||
Print the version of Autoconf used to generate the 'configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
'--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
traditionally 'config.cache'. FILE defaults to '/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
'--config-cache'
|
||||
'-C'
|
||||
Alias for '--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
'--quiet'
|
||||
'--silent'
|
||||
'-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
suppress all normal output, redirect it to '/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
'--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
'configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
'--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names:: for
|
||||
more details, including other options available for fine-tuning the
|
||||
installation locations.
|
||||
|
||||
'--no-create'
|
||||
'-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
'configure' also accepts some other, not widely useful, options. Run
|
||||
'configure --help' for more details.
|
||||
|
||||
@@ -4,7 +4,6 @@ SUBDIRS = \
|
||||
test
|
||||
|
||||
EXTRA_DIST= \
|
||||
autogen.sh \
|
||||
rak/address_info.h \
|
||||
rak/algorithm.h \
|
||||
rak/allocators.h \
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
BUILDING
|
||||
|
||||
Run "./autogen.sh" to generate the configure scripts if
|
||||
nessesary. The man page "doc/rtorrent.1" must be generated with
|
||||
"docbook2man rtorrent.1.xml" if it is missing.
|
||||
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
|
||||
@@ -32,5 +32,10 @@ DEPENDENCIES
|
||||
|
||||
CONTACT
|
||||
|
||||
Send bug reports, suggestions and patches to <jaris@ifi.uio.no> or
|
||||
to the mailinglist.
|
||||
Jari Sundell
|
||||
|
||||
Skomakerveien 33
|
||||
3185 Skoppum, NORWAY
|
||||
|
||||
Send bug reports, suggestions and patches to
|
||||
<sundell.software@gmail.com> or to the mailinglist.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
[](https://paypal.me/jarisundelljp)
|
||||
|
||||
RTorrent BitTorrent Client
|
||||
========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
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)
|
||||
|
||||
Related Projects
|
||||
----------------
|
||||
|
||||
* [https://github.com/rakshasa/rbedit](https://github.com/rakshasa/rbedit): A dependency-free bencode editor.
|
||||
|
||||
Donate to rTorrent development
|
||||
------------------------------
|
||||
|
||||
* [Paypal](https://paypal.me/jarisundellno)
|
||||
* [Patreon](https://www.patreon.com/rtorrent)
|
||||
* [SubscribeStar](https://www.subscribestar.com/rtorrent)
|
||||
* Bitcoin: 1MpmXm5AHtdBoDaLZstJw8nupJJaeKu8V8
|
||||
* Etherium: 0x9AB1e3C3d8a875e870f161b3e9287Db0E6DAfF78
|
||||
* Litecoin: LdyaVR67LBnTf6mAT4QJnjSG2Zk67qxmfQ
|
||||
* Cardano: addr1qytaslmqmk6dspltw06sp0zf83dh09u79j49ceh5y26zdcccgq4ph7nmx6kgmzeldauj43254ey97f3x4xw49d86aguqwfhlte
|
||||
|
||||
|
||||
Help keep rTorrent development going by donating to its creator.
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
echo aclocal...
|
||||
(aclocal --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo aclocal not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
aclocal -I ./scripts -I . ${ACLOCAL_FLAGS}
|
||||
|
||||
echo autoheader...
|
||||
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo autoheader not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
autoheader
|
||||
|
||||
echo -n "libtoolize... "
|
||||
if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then
|
||||
echo "using glibtoolize"
|
||||
glibtoolize --automake --copy --force
|
||||
|
||||
elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then
|
||||
echo "using libtoolize"
|
||||
libtoolize --automake --copy --force
|
||||
|
||||
else
|
||||
echo "libtoolize nor glibtoolize not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo automake...
|
||||
(automake --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo automake not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
automake --add-missing --copy --gnu
|
||||
|
||||
echo autoconf...
|
||||
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo autoconf not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
autoconf
|
||||
|
||||
echo ready to configure
|
||||
|
||||
exit 0
|
||||
Regular → Executable
+53
-44
@@ -1,47 +1,55 @@
|
||||
AC_INIT(rtorrent, 0.9.0, jaris@ifi.uio.no)
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AM_INIT_AUTOMAKE
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_PATH_CPPUNIT(1.9.6)
|
||||
AC_INIT([rtorrent], [0.10.0], [sundell.software@gmail.com])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIRS([scripts])
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
|
||||
AC_DEFINE([API_VERSION], [10], [api version])
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
TORRENT_CHECK_CXXFLAGS()
|
||||
TORRENT_ENABLE_DEBUG()
|
||||
TORRENT_ENABLE_EXTRA_DEBUG()
|
||||
TORRENT_ENABLE_WERROR()
|
||||
|
||||
TORRENT_DISABLE_IPV6
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
TORRENT_CHECK_EXECINFO()
|
||||
TORRENT_OTFD()
|
||||
AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory])
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
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_NCURSESW()
|
||||
TORRENT_WITHOUT_STATVFS()
|
||||
TORRENT_WITHOUT_STATFS()
|
||||
TORRENT_WITHOUT_VARIABLE_FDSET
|
||||
TORRENT_WITHOUT_STATVFS
|
||||
TORRENT_WITHOUT_STATFS
|
||||
|
||||
ACX_PTHREAD(CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS";
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
)
|
||||
AC_ARG_ENABLE(execinfo,
|
||||
AS_HELP_STRING([--disable-execinfo],
|
||||
[disable libexecinfo [[default=enable]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AX_EXECINFO
|
||||
fi
|
||||
],[
|
||||
AX_EXECINFO
|
||||
])
|
||||
|
||||
PKG_CHECK_MODULES(sigc, sigc++-2.0,
|
||||
CXXFLAGS="$CXXFLAGS $sigc_CFLAGS";
|
||||
LIBS="$LIBS $sigc_LIBS")
|
||||
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
|
||||
AX_WITH_CURSES
|
||||
|
||||
PKG_CHECK_MODULES(libcurl, libcurl >= 7.15.4,
|
||||
CXXFLAGS="$CXXFLAGS $libcurl_CFLAGS";
|
||||
LIBS="$LIBS $libcurl_LIBS")
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(libtorrent, libtorrent >= 0.13.0,
|
||||
CXXFLAGS="$CXXFLAGS $libtorrent_CFLAGS";
|
||||
LIBS="$LIBS $libtorrent_LIBS")
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl],, [LIBCURL_CHECK_CONFIG])
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.14.0])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
@@ -55,19 +63,20 @@ TORRENT_CHECK_CACHELINE()
|
||||
TORRENT_CHECK_POPCOUNT()
|
||||
|
||||
CC_ATTRIBUTE_UNUSED(
|
||||
AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
|
||||
AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
|
||||
AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]),
|
||||
AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported])
|
||||
)
|
||||
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
src/core/Makefile
|
||||
src/display/Makefile
|
||||
src/input/Makefile
|
||||
src/rpc/Makefile
|
||||
src/ui/Makefile
|
||||
src/utils/Makefile
|
||||
test/Makefile
|
||||
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"
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
test/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
#man_MANS = rtorrent.1
|
||||
|
||||
EXTRA_DIST= \
|
||||
faq.xml \
|
||||
rtorrent.1 \
|
||||
rtorrent.1.xml \
|
||||
rtorrent.rc
|
||||
|
||||
Regular → Executable
Regular → Executable
@@ -0,0 +1,28 @@
|
||||
# Choke Groups
|
||||
|
||||
## Settings
|
||||
|
||||
choke_group.insert = "leech_fast"
|
||||
|
||||
Create a new group named "leech_fast", accessible by the string or
|
||||
index / reverse index according to order of insertion. E.g. '-1'
|
||||
refers to the last inserted choke group, while 0 refers to the first.
|
||||
|
||||
All commands that applies to a group requires the first argument to be
|
||||
the index, reverse index or the group name.
|
||||
|
||||
choke_group.tracker.mode.set = -1,"aggressive"
|
||||
|
||||
Set the tracker mode for torrents in this group.
|
||||
|
||||
choke_group.up.heuristics.set = -1,"upload_leech_experimental"
|
||||
choke_group.down.heuristics.set = -1,"download_leech"
|
||||
|
||||
Set the heuristics used when deciding on which peers to choke and
|
||||
unchoke. Use "strings.choke_heuristics{,.upload,.download}" to get a
|
||||
list of the available heuristics.
|
||||
|
||||
choke_group.up.max.set = -1,250
|
||||
choke_group.down.max.set = -1,500
|
||||
|
||||
Set the max total number of unchoked peers for all torrents in this choke group.
|
||||
@@ -0,0 +1,64 @@
|
||||
# IP filtering
|
||||
|
||||
## Introduction
|
||||
|
||||
## Make a new ip table
|
||||
|
||||
ip_tables.insert_table = <table_name>
|
||||
|
||||
Create a new empty table with the name ’table\_name’, with the default
|
||||
value returned being $0$.
|
||||
|
||||
There is currently no use of the generic ip tables commands.
|
||||
|
||||
## Add a new address block
|
||||
|
||||
ip_tables.add_address = <table_name>, 10.0.0.0/8, <value>
|
||||
|
||||
Set <value\> for all addresses in the address block, overwriting prior
|
||||
values.
|
||||
|
||||
## Add a new address block
|
||||
|
||||
ip_tables.load = <table_name>, ~/foo.txt, <value>
|
||||
|
||||
Set <value\> for all addresses in the file ’foo.txt’ separated by
|
||||
newline, similar to ’add\_address’.
|
||||
|
||||
## Get value for address
|
||||
|
||||
ip_tables.get = <table_name>, 10.10.10.10
|
||||
|
||||
Returns the value set for an address, or the address block it belongs
|
||||
to. The default is $0$.
|
||||
|
||||
## Size of data structures
|
||||
|
||||
ip_tables.size_data = <table_name>
|
||||
|
||||
Returns the size in bytes of all data structures for this table,
|
||||
excluding the root class object itself. Note that the in-memory table is
|
||||
dynamically consolidated, as such memory use will always be based on
|
||||
actual fragmentation.
|
||||
|
||||
The table is a b-tree with 1024 nodes per branch.
|
||||
|
||||
## IPv4 filtering table
|
||||
|
||||
ipv4_filter.add_address = 10.0.0.0/8, unwanted
|
||||
ipv4_filter.add_address = 11.0.0.0/8, preferred
|
||||
ipv4_filter.load = ~/filters.txt, unwanted
|
||||
ipv4_filter.get = 10.10.10.10
|
||||
ipv4_filter.size_data =
|
||||
|
||||
The main ip filter, currently supporting ’unwanted’ (do not allow
|
||||
connections) and ’preferred’ (currently used only in private code).
|
||||
|
||||
## Constants
|
||||
|
||||
strings.ip_filter =
|
||||
=>
|
||||
{ "unwanted", PeerInfo::flag_unwanted },
|
||||
{ "preferred", PeerInfo::flag_preferred },
|
||||
|
||||
Constants used by ipv4\_filter values.
|
||||
@@ -0,0 +1,85 @@
|
||||
\section{IP filtering}
|
||||
|
||||
\subsection{Introduction}
|
||||
|
||||
\subsection{Make a new ip table}
|
||||
|
||||
\begin{verbatim}
|
||||
ip_tables.insert_table = <table_name>
|
||||
\end{verbatim}
|
||||
|
||||
Create a new empty table with the name 'table\_name', with the default
|
||||
value returned being $0$.
|
||||
|
||||
There is currently no use of the generic ip tables commands.
|
||||
|
||||
|
||||
\subsection{Add a new address block}
|
||||
|
||||
\begin{verbatim}
|
||||
ip_tables.add_address = <table_name>, 10.0.0.0/8, <value>
|
||||
\end{verbatim}
|
||||
|
||||
Set <value> for all addresses in the address block, overwriting prior
|
||||
values.
|
||||
|
||||
|
||||
\subsection{Add a new address block}
|
||||
|
||||
\begin{verbatim}
|
||||
ip_tables.load = <table_name>, ~/foo.txt, <value>
|
||||
\end{verbatim}
|
||||
|
||||
Set <value> for all addresses in the file 'foo.txt' separated by
|
||||
newline, similar to 'add\_address'.
|
||||
|
||||
|
||||
\subsection{Get value for address}
|
||||
|
||||
\begin{verbatim}
|
||||
ip_tables.get = <table_name>, 10.10.10.10
|
||||
\end{verbatim}
|
||||
|
||||
Returns the value set for an address, or the address block it belongs
|
||||
to. The default is $0$.
|
||||
|
||||
|
||||
\subsection{Size of data structures}
|
||||
|
||||
\begin{verbatim}
|
||||
ip_tables.size_data = <table_name>
|
||||
\end{verbatim}
|
||||
|
||||
Returns the size in bytes of all data structures for this table,
|
||||
excluding the root class object itself. Note that the in-memory table
|
||||
is dynamically consolidated, as such memory use will always be based
|
||||
on actual fragmentation.
|
||||
|
||||
The table is a b-tree with 1024 nodes per branch.
|
||||
|
||||
|
||||
\subsection{IPv4 filtering table}
|
||||
|
||||
\begin{verbatim}
|
||||
ipv4_filter.add_address = 10.0.0.0/8, unwanted
|
||||
ipv4_filter.add_address = 11.0.0.0/8, preferred
|
||||
ipv4_filter.load = ~/filters.txt, unwanted
|
||||
ipv4_filter.get = 10.10.10.10
|
||||
ipv4_filter.size_data =
|
||||
\end{verbatim}
|
||||
|
||||
The main ip filter, currently supporting 'unwanted' (do not allow
|
||||
connections) and 'preferred' (currently used only in private code).
|
||||
|
||||
|
||||
|
||||
\subsection{Constants}
|
||||
|
||||
\begin{verbatim}
|
||||
strings.ip_filter =
|
||||
=>
|
||||
{ "unwanted", PeerInfo::flag_unwanted },
|
||||
{ "preferred", PeerInfo::flag_preferred },
|
||||
\end{verbatim}
|
||||
|
||||
Constants used by ipv4_filter values.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Logging
|
||||
|
||||
## Opening log files
|
||||
|
||||
# log.open_file = "log name", "file path"
|
||||
|
||||
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.
|
||||
|
||||
## 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"
|
||||
|
||||
Each log handle can be added to multiple different logging events.
|
||||
|
||||
## Logging events
|
||||
|
||||
"critical"
|
||||
"error"
|
||||
"warn"
|
||||
"notice"
|
||||
"info"
|
||||
"debug"
|
||||
|
||||
The above events receive logging events from all the sub-groups
|
||||
displayed below, and each event also reciving events from the event
|
||||
above in importance.
|
||||
|
||||
Thus some high-volume sub-group events such as “tracker\_debug” are not
|
||||
part of “debug” and every “warn” event will receive events from “error”,
|
||||
“critical”.
|
||||
|
||||
"connection_*"
|
||||
"dht_*"
|
||||
"peer_*"
|
||||
"rpc_*"
|
||||
"storage_*"
|
||||
"thread_*"
|
||||
"tracker_*"
|
||||
"torrent_*"
|
||||
|
||||
All sub-groups have events from “critical” to “debug” defined.
|
||||
@@ -52,7 +52,7 @@ Decrease the download throttle by 1/5/50 KB.
|
||||
\fB->\fR
|
||||
View download.
|
||||
.TP
|
||||
\fB1 - 7\fR
|
||||
\fB0 - 9\fR
|
||||
Change view.
|
||||
.TP
|
||||
\fB^S\fR
|
||||
@@ -99,6 +99,9 @@ Delete the file the torrent is tied to, and clear the association.
|
||||
.TP
|
||||
\fBI\fR
|
||||
Toggle whether torrent ignores ratio settings.
|
||||
.TP
|
||||
\fBF\fR
|
||||
Add a temporary name based regex filter to the current view.
|
||||
.SS "DOWNLOAD VIEW KEYS"
|
||||
.TP
|
||||
\fB->\fR
|
||||
@@ -122,7 +122,7 @@ View download.
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>1 - 7</term>
|
||||
<term>0 - 9</term>
|
||||
<listitem><para>
|
||||
Change view.
|
||||
</para></listitem>
|
||||
@@ -225,6 +225,13 @@ Toggle whether torrent ignores ratio settings.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>F</term>
|
||||
<listitem><para>
|
||||
Add a temporary name based regex filter to the current view.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect2>
|
||||
@@ -507,29 +514,6 @@ Enable/disable peer exchange for torrents that aren't marked private. Disabled b
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>schedule = <replaceable>id</replaceable>,<replaceable>start</replaceable>,<replaceable>interval</replaceable>,<replaceable>command</replaceable></term>
|
||||
<listitem><para>
|
||||
Call <emphasis>command</emphasis> every <emphasis>interval</emphasis>
|
||||
seconds, starting from <emphasis>start</emphasis>. An
|
||||
<emphasis>interval</emphasis> of zero calls the task once, while a
|
||||
<emphasis>start</emphasis> of zero calls it immediately. Currently
|
||||
<emphasis>command</emphasis> is forwarded to the option handler.
|
||||
|
||||
<emphasis>start</emphasis> and <emphasis>interval</emphasis> may
|
||||
optionally use a time format, <emphasis>dd:hh:mm:ss</emphasis>. F.ex to
|
||||
start a task every day at <emphasis>18:00</emphasis>, use
|
||||
<emphasis>18:00:00,24:00:00</emphasis>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>schedule_remove = <replaceable>id</replaceable></term>
|
||||
<listitem><para>
|
||||
Delete <emphasis>id</emphasis> from the scheduler.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>start_tied =</term>
|
||||
<listitem><para>
|
||||
@@ -580,40 +564,6 @@ torrent::input_error exception on bad input.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>stop_on_ratio = <replaceable>min_ratio</replaceable></term>
|
||||
<term>stop_on_ratio = <replaceable>min_ratio</replaceable>,<replaceable>min_upload</replaceable></term>
|
||||
<term>stop_on_ratio = <replaceable>min_ratio</replaceable>,<replaceable>min_upload</replaceable>,<replaceable>max_ratio</replaceable></term>
|
||||
<listitem><para>
|
||||
Stop torrents when they reach the given upload ratio
|
||||
<emphasis>min_ratio</emphasis> in percent. If the optional
|
||||
<emphasis>min_upload</emphasis> is given, require a total
|
||||
upload amount of this many bytes as well. If the optional
|
||||
<emphasis>max_ratio</emphasis> is given, stop the torrent
|
||||
when reaching this ratio regardless of the total upload
|
||||
amount. Exclude certain torrent by pressing
|
||||
<emphasis>Shift+I</emphasis> in the downlist list.
|
||||
Use with the <emphasis>schedule</emphasis> option.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>on_insert = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_erase = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_open = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_close = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_start = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_stop = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_hash_queued = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_hash_removed = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_hash_done = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<term>on_finished = <replaceable>id</replaceable>,<replaceable>command</replaceable></term>
|
||||
<listitem><para>
|
||||
Call a command on a download when its state changes. Only a subset of
|
||||
commands are available.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
@@ -629,6 +579,8 @@ commands are available.
|
||||
<varlistentry>
|
||||
<term>upload_rate = <replaceable>KB</replaceable></term>
|
||||
<term>download_rate = <replaceable>KB</replaceable></term>
|
||||
<term>set_upload_rate = <replaceable>TODO</replaceable></term>
|
||||
<term>set_download_rate = <replaceable>TODO</replaceable></term>
|
||||
<listitem><para>
|
||||
Set the maximum global uploand and download rates.
|
||||
</para></listitem>
|
||||
@@ -653,14 +605,19 @@ Set the minimum nad maximum number of peers to allow while seeding, or
|
||||
|
||||
<varlistentry>
|
||||
<term>max_uploads = <replaceable>value</replaceable></term>
|
||||
<term>max_downloads = <replaceable>value</replaceable></term>
|
||||
<term>min_uploads = <replaceable>value</replaceable></term>
|
||||
<term>min_downloads = <replaceable>value</replaceable></term>
|
||||
<listitem><para>
|
||||
Set the maximum number of simultaneous uploads per download.
|
||||
Set the maximum/minimum number of simultaneous uploads/downloads per download/upload.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>max_uploads_div = <replaceable>value</replaceable></term>
|
||||
<term>max_downloads_div = <replaceable>value</replaceable></term>
|
||||
<term>set_max_uploads_div = <replaceable>value</replaceable></term>
|
||||
<term>set_max_downloads_div = <replaceable>value</replaceable></term>
|
||||
<listitem><para>
|
||||
Change the divider used to calculate the max upload and download slots
|
||||
to use when the throttle is changed. Disable by
|
||||
@@ -671,6 +628,8 @@ setting <emphasis>0</emphasis>.
|
||||
<varlistentry>
|
||||
<term>max_uploads_global = <replaceable>value</replaceable></term>
|
||||
<term>max_downloads_global = <replaceable>value</replaceable></term>
|
||||
<term>set_max_uploads_global = <replaceable>value</replaceable></term>
|
||||
<term>set_max_downloads_global = <replaceable>value</replaceable></term>
|
||||
<listitem><para>
|
||||
Max upload and download slots allowed. Disable by
|
||||
setting <emphasis>0</emphasis>.
|
||||
@@ -746,6 +705,27 @@ not allow connections to UDP trackers.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>http_capath = <replaceable>path</replaceable></term>
|
||||
<term>http_cacert = <replaceable>filename</replaceable></term>
|
||||
<listitem><para>
|
||||
Set the certificates to use in http requests. See Curl's
|
||||
CURLOPT_CAPATH and CURLOPT_CAINFO options for further information.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>DHT-RELATED SETTINGS</title>
|
||||
<para>
|
||||
Settings related to DHT
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>dht = <replaceable>disabled|off|auto|on</replaceable></term>
|
||||
<listitem><para>
|
||||
@@ -779,11 +759,23 @@ The port is optional, with port 6881 being used by default.
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>http_capath = <replaceable>path</replaceable></term>
|
||||
<term>http_cacert = <replaceable>filename</replaceable></term>
|
||||
<term>dht_statistics = <replaceable>TODO</replaceable></term>
|
||||
<listitem><para>
|
||||
Set the certificates to use in http requests. See Curl's
|
||||
CURLOPT_CAPATH and CURLOPT_CAINFO options for further information.
|
||||
TODO
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>set_dht_port = <replaceable>TODO</replaceable></term>
|
||||
<listitem><para>
|
||||
TODO
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>set_dht_throttle = <replaceable>TODO</replaceable></term>
|
||||
<listitem><para>
|
||||
TODO
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -791,7 +783,6 @@ CURLOPT_CAPATH and CURLOPT_CAINFO options for further information.
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>USER-INTERFACE SETTINGS</title>
|
||||
<para>
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#/bin/bash
|
||||
gnuplot << EOF
|
||||
|
||||
set terminal png size 1024 * 1, 768 enhanced
|
||||
set xdata time
|
||||
set timefmt "%s"
|
||||
set format x "%H:%M"
|
||||
set y2tics
|
||||
set autoscale xfix
|
||||
set key autotitle columnhead
|
||||
|
||||
set format y "%.0f"
|
||||
set format y2 "%.0f"
|
||||
|
||||
set output "output_$1_incore_sync.png"
|
||||
plot \
|
||||
"instrumentation_mincore.log.$1" using 1:6 title 'success' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_mincore.log.$1" using 1:7 title 'failed' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_mincore.log.$1" using 1:8 title 'not synced' with lines lw 4 axis x1y2,\
|
||||
"instrumentation_mincore.log.$1" using 1:9 title 'not deallocated' with lines lw 4 axis x1y2
|
||||
|
||||
set format y "%.0g"
|
||||
|
||||
set output "output_$1_incore_alloc.png"
|
||||
plot \
|
||||
"instrumentation_mincore.log.$1" using 1:12 title 'allocations' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_mincore.log.$1" using 1:13 title 'deallocations' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_mincore.log.$1" using 1:10 title 'alloc failed' with lines lw 2 axis x1y2
|
||||
|
||||
EOF
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#/bin/bash
|
||||
gnuplot << EOF
|
||||
|
||||
set terminal png size 1024,768 enhanced
|
||||
set xdata time
|
||||
set timefmt "%s"
|
||||
set format x "%H:%M"
|
||||
set y2tics
|
||||
set autoscale xfix
|
||||
set key autotitle columnhead
|
||||
|
||||
# set datafile missing '0'
|
||||
|
||||
set format y "%.0f"
|
||||
set format y2 "%.0f"
|
||||
|
||||
set yrange [0:]
|
||||
set y2range [0:]
|
||||
|
||||
set output "output_$1_transfer_requests.png"
|
||||
plot \
|
||||
"instrumentation_transfers.log.$1" using 1:2 title 'delegated' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:3 title 'downloading' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:4 title 'finished' with lines lw 4 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:5 title 'skipped' with lines lw 2 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:6 title 'unknown' with lines lw 2 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:7 title 'unordered' with lines lw 2 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:19 title 'unaccounted' with lines lw 2 axis x1y2
|
||||
|
||||
set output "output_$1_transfer_queues.png"
|
||||
plot \
|
||||
"instrumentation_transfers.log.$1" using 1:8 title 'queue added' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:9 title 'queue moved' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:10 title 'queue removed' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:11 title 'queue total' with lines lw 4 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:12 title 'unordered added' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:13 title 'unordered moved' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:14 title 'unordered removed' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:15 title 'unordered total' with lines lw 4 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:16 title 'stalled added' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:17 title 'stalled moved' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:18 title 'stalled removed' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:19 title 'stalled total' with lines lw 4 axis x1y2,\
|
||||
"instrumentation_transfers.log.$1" using 1:20 title 'choked added' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:21 title 'choked moved' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:22 title 'choked removed' with lines lw 2 axis x1y1,\
|
||||
"instrumentation_transfers.log.$1" using 1:23 title 'choked total' with lines lw 4 axis x1y2
|
||||
|
||||
EOF
|
||||
+85
-59
@@ -1,102 +1,128 @@
|
||||
# This is an example resource file for rTorrent. Copy to
|
||||
# ~/.rtorrent.rc and enable/modify the options as needed. Remember to
|
||||
# uncomment the options you wish to enable.
|
||||
#############################################################################
|
||||
# This is an (old) example resource file for rTorrent.
|
||||
# Copy to ~/.rtorrent.rc and enable/modify the options as needed.
|
||||
# Remember to uncomment the options you wish to enable.
|
||||
#
|
||||
# See 'rtorrent.rc-example' for a newer, basic configuration.
|
||||
#
|
||||
# Sample: https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
|
||||
# Complete: https://rtorrent-docs.readthedocs.io/en/latest/cmd-ref.html
|
||||
# Useful: https://rtorrent-docs.readthedocs.io/en/latest/use-cases.html
|
||||
# Manual: https://rtorrent-docs.readthedocs.io/en/latest/
|
||||
# Convert: https://github.com/rakshasa/rtorrent/wiki/rTorrent-0.9-Comprehensive-Command-list-(WIP)
|
||||
# Handbook: https://media.readthedocs.org/pdf/rtorrent-docs/latest/rtorrent-docs.pdf
|
||||
# File: https://github.com/rakshasa/rtorrent/blob/master/doc/rtorrent.rc
|
||||
#############################################################################
|
||||
|
||||
# Maximum and minimum number of peers to connect to per torrent.
|
||||
#min_peers = 40
|
||||
#max_peers = 100
|
||||
#
|
||||
#throttle.min_peers.normal.set = 40
|
||||
#throttle.max_peers.normal.set = 100
|
||||
|
||||
# Same as above but for seeding completed torrents (-1 = same as downloading)
|
||||
#min_peers_seed = 10
|
||||
#max_peers_seed = 50
|
||||
# Same as above but for seeding completed torrents.
|
||||
# "-1" = same as downloading.
|
||||
#
|
||||
#throttle.min_peers.seed.set = 10
|
||||
#throttle.max_peers.seed.set = 50
|
||||
|
||||
# Maximum number of simultanious uploads per torrent.
|
||||
#max_uploads = 15
|
||||
# Maximum number of simultaneous uploads per torrent.
|
||||
#
|
||||
#throttle.max_uploads.set = 15
|
||||
|
||||
# Global upload and download rate in KiB. "0" for unlimited.
|
||||
#download_rate = 0
|
||||
#upload_rate = 0
|
||||
# Global upload and download rate in KiB.
|
||||
# "0" for unlimited.
|
||||
#
|
||||
#throttle.global_down.max_rate.set_kb = 0
|
||||
#throttle.global_up.max_rate.set_kb = 0
|
||||
|
||||
# Default directory to save the downloaded torrents.
|
||||
#directory = ./
|
||||
#
|
||||
#directory.default.set = ./
|
||||
|
||||
# Default session directory. Make sure you don't run multiple instance
|
||||
# of rtorrent using the same session directory. Perhaps using a
|
||||
# of rTorrent using the same session directory. Perhaps using a
|
||||
# relative path?
|
||||
#session = ./session
|
||||
#
|
||||
#session.path.set = ./session
|
||||
|
||||
# Watch a directory for new torrents, and stop those that have been
|
||||
# deleted.
|
||||
#schedule = watch_directory,5,5,load_start=./watch/*.torrent
|
||||
#schedule = untied_directory,5,5,stop_untied=
|
||||
#
|
||||
#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent
|
||||
|
||||
# Close torrents when diskspace is low.
|
||||
#schedule = low_diskspace,5,60,close_low_diskspace=100M
|
||||
# Close torrents when disk-space is low.
|
||||
#
|
||||
#schedule2 = low_diskspace,5,60,close_low_diskspace=100M
|
||||
|
||||
# The ip address reported to the tracker.
|
||||
#ip = 127.0.0.1
|
||||
#ip = rakshasa.no
|
||||
# The IP address reported to the tracker.
|
||||
#
|
||||
#network.local_address.set = 127.0.0.1
|
||||
#network.local_address.set = rakshasa.no
|
||||
|
||||
# The ip address the listening socket and outgoing connections is
|
||||
# The IP address the listening socket and outgoing connections is
|
||||
# bound to.
|
||||
#bind = 127.0.0.1
|
||||
#bind = rakshasa.no
|
||||
#
|
||||
#network.bind_address.set = 127.0.0.1
|
||||
#network.bind_address.set = rakshasa.no
|
||||
|
||||
# Port range to use for listening.
|
||||
#port_range = 6890-6999
|
||||
#
|
||||
#network.port_range.set = 6890-6999
|
||||
|
||||
# Start opening ports at a random position within the port range.
|
||||
#port_random = no
|
||||
#
|
||||
#network.port_random.set = no
|
||||
|
||||
# Check hash for finished torrents. Might be usefull until the bug is
|
||||
# fixed that causes lack of diskspace not to be properly reported.
|
||||
#check_hash = no
|
||||
# Check hash for finished torrents. Might be useful until the bug is
|
||||
# fixed that causes lack of disk-space not to be properly reported.
|
||||
#
|
||||
#pieces.hash.on_completion.set = no
|
||||
|
||||
# Set whetever the client should try to connect to UDP trackers.
|
||||
#use_udp_trackers = yes
|
||||
# Set whether the client should try to connect to UDP trackers.
|
||||
#
|
||||
#trackers.use_udp.set = yes
|
||||
|
||||
# Alternative calls to bind and ip that should handle dynamic ip's.
|
||||
#schedule = ip_tick,0,1800,ip=rakshasa
|
||||
#schedule = bind_tick,0,1800,bind=rakshasa
|
||||
# Alternative calls to bind and IP that should handle dynamic IP's.
|
||||
#
|
||||
#schedule2 = ip_tick,0,1800,ip=rakshasa
|
||||
#schedule2 = bind_tick,0,1800,bind=rakshasa
|
||||
|
||||
# Encryption options, set to none (default) or any combination of the following:
|
||||
# allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext
|
||||
#
|
||||
# The example value allows incoming encrypted connections, starts unencrypted
|
||||
# outgoing connections but retries with encryption if they fail, preferring
|
||||
# plaintext to RC4 encryption after the encrypted handshake
|
||||
# plain-text to RC4 encryption after the encrypted handshake.
|
||||
#
|
||||
# encryption = allow_incoming,enable_retry,prefer_plaintext
|
||||
# protocol.encryption.set = allow_incoming,enable_retry,prefer_plaintext
|
||||
|
||||
# Enable DHT support for trackerless torrents or when all trackers are down.
|
||||
# May be set to "disable" (completely disable DHT), "off" (do not start DHT),
|
||||
# "auto" (start and stop DHT as needed), or "on" (start DHT immediately).
|
||||
# The default is "off". For DHT to work, a session directory must be defined.
|
||||
#
|
||||
# dht = auto
|
||||
|
||||
# UDP port to use for DHT.
|
||||
#
|
||||
# dht_port = 6881
|
||||
|
||||
# Enable peer exchange (for torrents not marked private)
|
||||
#
|
||||
# peer_exchange = yes
|
||||
# dht.mode.set = auto
|
||||
|
||||
# UDP port to use for DHT.
|
||||
#
|
||||
# Do not modify the following parameters unless you know what you're doing.
|
||||
#dht.port.set = 6881
|
||||
|
||||
# Enable peer exchange (for torrents not marked private).
|
||||
#
|
||||
#protocol.pex.set = yes
|
||||
|
||||
# Hash read-ahead controls how many MB to request the kernel to read
|
||||
# ahead. If the value is too low the disk may not be fully utilized,
|
||||
# while if too high the kernel might not be able to keep the read
|
||||
# pages in memory thus end up trashing.
|
||||
#hash_read_ahead = 10
|
||||
# Set download list layout style ("full", "compact").
|
||||
#
|
||||
#ui.torrent_list.layout.set = "full"
|
||||
|
||||
# Interval between attempts to check the hash, in milliseconds.
|
||||
#hash_interval = 100
|
||||
# Run rTorrent as a daemon, controlled via XMLRPC.
|
||||
#
|
||||
#system.daemon.set = false
|
||||
|
||||
# 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.
|
||||
#hash_max_tries = 10
|
||||
# SCGI Connectivity (for alternative rtorrent interfaces, XMLRPC)
|
||||
# Use a IP socket with scgi_port, or a Unix socket with scgi_local.
|
||||
# schedule can be used to set permissions on the unix socket.
|
||||
#
|
||||
#network.scgi.open_port = "127.0.0.1:5000"
|
||||
#network.scgi.open_local = (cat,(session.path),/rpc.sock)
|
||||
#schedule2 = socket_chmod, 0, 0, "execute.nothrow=chmod,770,(cat,(session.path),/rpc.sock)"
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#############################################################################
|
||||
# A minimal rTorrent configuration that provides the basic features
|
||||
# you want to have in addition to the built-in defaults.
|
||||
#
|
||||
# See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
|
||||
# for an up-to-date version.
|
||||
#############################################################################
|
||||
|
||||
# Instance layout (base paths)
|
||||
method.insert = cfg.basedir, private|const|string, (cat,"/home/USERNAME/rtorrent/")
|
||||
method.insert = cfg.download, private|const|string, (cat,(cfg.basedir),"download/")
|
||||
method.insert = cfg.logs, private|const|string, (cat,(cfg.basedir),"log/")
|
||||
method.insert = cfg.logfile, private|const|string, (cat,(cfg.logs),"rtorrent-",(system.time),".log")
|
||||
method.insert = cfg.session, private|const|string, (cat,(cfg.basedir),".session/")
|
||||
method.insert = cfg.watch, private|const|string, (cat,(cfg.basedir),"watch/")
|
||||
|
||||
# Create instance directories
|
||||
execute.throw = sh, -c, (cat,\
|
||||
"mkdir -p \"",(cfg.download),"\" ",\
|
||||
"\"",(cfg.logs),"\" ",\
|
||||
"\"",(cfg.session),"\" ",\
|
||||
"\"",(cfg.watch),"/load\" ",\
|
||||
"\"",(cfg.watch),"/start\" ")
|
||||
|
||||
# Listening port for incoming peer traffic (fixed; you can also randomize it)
|
||||
network.port_range.set = 50000-50000
|
||||
network.port_random.set = no
|
||||
|
||||
# Tracker-less torrent and UDP tracker support
|
||||
# (conservative settings for 'private' trackers, change for 'public')
|
||||
dht.mode.set = disable
|
||||
protocol.pex.set = no
|
||||
trackers.use_udp.set = no
|
||||
|
||||
# Peer settings
|
||||
throttle.max_uploads.set = 100
|
||||
throttle.max_uploads.global.set = 250
|
||||
|
||||
throttle.min_peers.normal.set = 20
|
||||
throttle.max_peers.normal.set = 60
|
||||
throttle.min_peers.seed.set = 30
|
||||
throttle.max_peers.seed.set = 80
|
||||
trackers.numwant.set = 80
|
||||
|
||||
protocol.encryption.set = allow_incoming,try_outgoing,enable_retry
|
||||
|
||||
# Limits for file handle resources, this is optimized for
|
||||
# an `ulimit` of 1024 (a common default). You MUST leave
|
||||
# a ceiling of handles reserved for rTorrent's internal needs!
|
||||
network.http.max_open.set = 50
|
||||
network.max_open_files.set = 600
|
||||
network.max_open_sockets.set = 300
|
||||
|
||||
# Memory resource usage (increase if you have a large number of items loaded,
|
||||
# and/or the available resources to spend)
|
||||
pieces.memory.max.set = 1800M
|
||||
network.xmlrpc.size_limit.set = 4M
|
||||
|
||||
# Basic operational settings (no need to change these)
|
||||
session.path.set = (cat, (cfg.session))
|
||||
directory.default.set = (cat, (cfg.download))
|
||||
log.execute = (cat, (cfg.logs), "execute.log")
|
||||
##log.xmlrpc = (cat, (cfg.logs), "xmlrpc.log")
|
||||
execute.nothrow = sh, -c, (cat, "echo >",\
|
||||
(session.path), "rtorrent.pid", " ", (system.pid))
|
||||
|
||||
# Other operational settings (check & adapt)
|
||||
encoding.add = utf8
|
||||
system.umask.set = 0027
|
||||
system.cwd.set = (directory.default)
|
||||
network.http.dns_cache_timeout.set = 25
|
||||
schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M))
|
||||
##pieces.hash.on_completion.set = no
|
||||
##view.sort_current = seeding, greater=d.ratio=
|
||||
##keys.layout.set = qwerty
|
||||
##network.http.capath.set = "/etc/ssl/certs"
|
||||
##network.http.ssl_verify_peer.set = 0
|
||||
##network.http.ssl_verify_host.set = 0
|
||||
|
||||
# Some additional values and commands
|
||||
method.insert = system.startup_time, value|const, (system.time)
|
||||
method.insert = d.data_path, simple,\
|
||||
"if=(d.is_multi_file),\
|
||||
(cat, (d.directory), /),\
|
||||
(cat, (d.directory), /, (d.name))"
|
||||
method.insert = d.session_file, simple, "cat=(session.path), (d.hash), .torrent"
|
||||
|
||||
# Watch directories (add more as you like, but use unique schedule names)
|
||||
schedule2 = watch_start, 10, 10, ((load.start_verbose, (cat, (cfg.watch), "start/*.torrent")))
|
||||
schedule2 = watch_load, 11, 10, ((load.verbose, (cat, (cfg.watch), "load/*.torrent")))
|
||||
|
||||
# Run the rTorrent process as a daemon in the background
|
||||
# (and control via XMLRPC sockets)
|
||||
#system.daemon.set = true
|
||||
#network.scgi.open_local = (cat,(session.path),rtorrent.sock)
|
||||
#execute.nothrow = chmod,770,(cat,(session.path),rtorrent.sock)
|
||||
|
||||
# Logging:
|
||||
# Levels = critical error warn notice info debug
|
||||
# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
|
||||
print = (cat, "Logging to ", (cfg.logfile))
|
||||
log.open_file = "log", (cfg.logfile)
|
||||
log.add_output = "info", "log"
|
||||
##log.add_output = "tracker_debug", "log"
|
||||
|
||||
### END of rtorrent.rc ###
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Perl script to add rTorrent fast resume data to torrent files.
|
||||
#
|
||||
# Usage:
|
||||
# rtorrent_fast_resume.pl [base-directory] < plain.torrent > with_fast_resume.torrent
|
||||
# -OR-
|
||||
# rtorrent_fast_resume.pl [base-directory] plain.torrent [with_fast_resume.torrent]
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Convert::Bencode_XS qw(bencode bdecode);
|
||||
use File::Spec; # core module
|
||||
use POSIX; # core module
|
||||
|
||||
$/ = undef;
|
||||
$| = 1;
|
||||
|
||||
# Process ARGV
|
||||
my $d = $ARGV[0];
|
||||
if ($d and not -d $d) {
|
||||
if (-f $d and -s $d and not $ARGV[2]) { # missing directory, but has file
|
||||
$ARGV[2] = $ARGV[1];
|
||||
$ARGV[1] = $ARGV[0];
|
||||
$d = '';
|
||||
}
|
||||
else { die "$d is not a directory\n"; }
|
||||
}
|
||||
$d ||= ".";
|
||||
$d .= "/" unless $d =~ m#/$#;
|
||||
|
||||
my ($in, $out, $msg);
|
||||
my ($in_file, $out_file) = ('', '');
|
||||
if ($ARGV[1]) {
|
||||
$in_file = $ARGV[1];
|
||||
open($in, ($ARGV[2] ? '<' : '+<'), $in_file) || die "Cannot open $in_file for input!\n";
|
||||
unless ($ARGV[2]) {
|
||||
$out = $in;
|
||||
$out_file = $in_file;
|
||||
}
|
||||
}
|
||||
else { $in = *STDIN; }
|
||||
if ($ARGV[2]) {
|
||||
$out_file = $ARGV[2];
|
||||
open($out, '>', $out_file) || die "Cannot open $out_file for output!\n";
|
||||
$msg = *STDOUT;
|
||||
}
|
||||
elsif (!$ARGV[1]) { $out = *STDOUT; }
|
||||
$msg //= *STDERR;
|
||||
|
||||
print {$msg} "Total input torrent size: ".sprintf('%.2f', (-s $in_file) / 1024)." KB\n" if $in_file;
|
||||
print {$msg} "Decoding ".($in_file || 'torrent from standard input')."...";
|
||||
my $t = bdecode(scalar <$in>);
|
||||
|
||||
die "No info key.\n" unless ref $t eq "HASH" and exists $t->{info};
|
||||
my $psize = $t->{info}{"piece length"} or die "No piece length key.\n";
|
||||
print {$msg} "done\n\n";
|
||||
|
||||
my @files;
|
||||
my $tsize = 0;
|
||||
if (exists $t->{info}{files}) {
|
||||
print {$msg} "Multi file torrent: $t->{info}{name}\n";
|
||||
for (@{$t->{info}{files}}) {
|
||||
push @files, join "/", $t->{info}{name},@{$_->{path}};
|
||||
$tsize += $_->{length};
|
||||
}
|
||||
}
|
||||
else {
|
||||
print {$msg} "Single file torrent: $t->{info}{name}\n";
|
||||
@files = ($t->{info}{name});
|
||||
$tsize = $t->{info}{length};
|
||||
}
|
||||
my $chunks = int(($tsize + $psize - 1) / $psize);
|
||||
print {$msg} "Total size: ".sprintf('%.2f', $tsize / 1024**2)." MB; $chunks chunks; ", scalar @files, " files.\n\n";
|
||||
|
||||
die "Inconsistent piece information!\n" if $chunks*20 != length $t->{info}{pieces};
|
||||
|
||||
print {$msg} "Adding fast resume information...";
|
||||
# flags => 1+16+
|
||||
|
||||
my $pmod = 0;
|
||||
$t->{libtorrent_resume}{bitfield} = $chunks;
|
||||
foreach my $f (0..$#files) {
|
||||
die "$d$files[$f] not found.\n" unless -e "$d$files[$f]";
|
||||
my $mtime = (stat "$d$files[$f]")[9];
|
||||
|
||||
# Compute number of chunks per file
|
||||
my $fsize = (exists $t->{info}{files}) ? $t->{info}{files}[$f]{length} : 1;
|
||||
my $fchunks = ($pmod ? 1 : 0);
|
||||
if ($pmod >= $fsize) { ($fsize, $pmod ) = (0, $pmod-$fsize); }
|
||||
else { ($pmod, $fsize) = (0, $fsize-$pmod); }
|
||||
$fchunks += ceil($fsize / $psize);
|
||||
$pmod ||= $psize - ($fsize % $psize);
|
||||
|
||||
$t->{libtorrent_resume}{files}[$f] = {
|
||||
priority => 0, # Don't download; we already have the file, so don't clobber it!
|
||||
mtime => $mtime,
|
||||
completed => $fchunks,
|
||||
};
|
||||
};
|
||||
$t->{libtorrent_resume}{'uncertain_pieces.timestamp'} = time;
|
||||
|
||||
# Some extra information to re-enforce the fact that this is a finished torrent
|
||||
if (exists $t->{info}{files}) {
|
||||
$d .= $t->{info}{name};
|
||||
}
|
||||
|
||||
$t->{rtorrent} = {
|
||||
state => 1, # started
|
||||
state_changed => time,
|
||||
state_counter => 1,
|
||||
chunks_wanted => 0,
|
||||
chunks_done => $chunks,
|
||||
complete => 1,
|
||||
hashing => 0, # Not hashing
|
||||
directory => File::Spec->file_name_is_absolute($d) ? $d : File::Spec->rel2abs($d),
|
||||
((tied_to_file => File::Spec->file_name_is_absolute($out_file) ? $out_file : File::Spec->rel2abs($out_file)) x!! $out_file),
|
||||
'timestamp.finished' => 0,
|
||||
'timestamp.started' => time,
|
||||
};
|
||||
|
||||
print {$msg} "done\n";
|
||||
|
||||
print {$msg} "Encoding ".($out_file || 'torrent from standard output')."...";
|
||||
seek($out, 0, 0); # just in case files are the same
|
||||
print {$out} bencode($t);
|
||||
|
||||
close($in);
|
||||
close($out);
|
||||
print {$msg} "done\n";
|
||||
exit;
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
#!/bin/bash
|
||||
#############
|
||||
###<Notes>###
|
||||
#############
|
||||
# This script depends on screen.
|
||||
# For the stop function to work, you must set an
|
||||
# explicit session directory using absolute paths (no, ~ is not absolute) in your rtorrent.rc.
|
||||
# If you typically just start rtorrent with just "rtorrent" on the
|
||||
# command line, all you need to change is the "user" option.
|
||||
# Attach to the screen session as your user with
|
||||
# "screen -dr rtorrent". Change "rtorrent" with srnname option.
|
||||
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
|
||||
##############
|
||||
###</Notes>###
|
||||
##############
|
||||
|
||||
#######################
|
||||
##Start Configuration##
|
||||
#######################
|
||||
# You can specify your configuration in a different file
|
||||
# (so that it is saved with upgrades, saved in your home directory,
|
||||
# or whatever reason you want to)
|
||||
# by commenting out/deleting the configuration lines and placing them
|
||||
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
|
||||
# have written them here (you can leave the comments if you desire
|
||||
# and then uncommenting the following line correcting the path/filename
|
||||
# for the one you used. note the space after the ".".
|
||||
# . /etc/rtorrent.init.conf
|
||||
|
||||
|
||||
#Do not put a space on either side of the equal signs e.g.
|
||||
# user = user
|
||||
# will not work
|
||||
# system user to run as (can only use one)
|
||||
user="user"
|
||||
|
||||
# system user to run as # not implemented, see d_start for beginning implementation
|
||||
# group=$(id -ng "$user")
|
||||
|
||||
# the full path to the filename where you store your rtorrent configuration
|
||||
# must keep parentheses around the entire statement, quotations around each config file
|
||||
config=("$(su -c 'echo $HOME' $user)/.rtorrent.rc")
|
||||
# Examples:
|
||||
# config=("/home/user/.rtorrent.rc")
|
||||
# config=("/home/user/.rtorrent.rc" "/mnt/some/drive/.rtorrent2.rc")
|
||||
# config=("/home/user/.rtorrent.rc"
|
||||
# "/mnt/some/drive/.rtorrent2.rc"
|
||||
# "/mnt/another/drive/.rtorrent3.rc")
|
||||
|
||||
# set of options to run with each instance, separated by a new line
|
||||
# must keep parentheses around the entire statement
|
||||
#if no special options, specify with: ""
|
||||
options=("")
|
||||
# Examples:
|
||||
# starts one instance, sourcing both .rtorrent.rc and .rtorrent2.rc
|
||||
# options=("-o import=~/.rtorrent2.rc")
|
||||
# starts two instances, ignoring .rtorrent.rc for both, and using
|
||||
# .rtorrent2.rc for the first, and .rtorrent3.rc for the second
|
||||
# we do not check for valid options
|
||||
# options=("-n -o import=~/.rtorrent2.rc" "-n -o import=~/rtorrent3.rc")
|
||||
|
||||
# default directory for screen, needs to be an absolute path
|
||||
base=$(su -c 'echo $HOME' $user)
|
||||
|
||||
# name of screen session
|
||||
srnname="rtorrent"
|
||||
|
||||
# file to log to (makes for easier debugging if something goes wrong)
|
||||
logfile="/var/log/rtorrentInit.log"
|
||||
#######################
|
||||
###END CONFIGURATION###
|
||||
#######################
|
||||
|
||||
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
|
||||
DESC="rtorrent"
|
||||
NAME=rtorrent
|
||||
DAEMON=$NAME
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
checkcnfg() {
|
||||
exists=0
|
||||
for i in `echo "$PATH" | tr ':' '\n'` ; do
|
||||
if [ -f $i/$NAME ] ; then
|
||||
exists=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ $exists -eq 0 ] ; then
|
||||
echo "cannot find $NAME binary in PATH: $PATH" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
for (( i=0 ; i < ${#config[@]} ; i++ )) ; do
|
||||
if ! [ -r "${config[i]}" ] ; then
|
||||
echo "cannot find readable config ${config[i]}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
session=$(getsession "${config[i]}")
|
||||
if ! [ -d "${session}" ] ; then
|
||||
echo "cannot find readable session directory ${session} from config ${config[i]}. check permissions" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
d_start() {
|
||||
[ -d "${base}" ] && cd "${base}"
|
||||
stty stop undef && stty start undef
|
||||
su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
|
||||
# this works for the screen command, but starting rtorrent below adopts screen session gid
|
||||
# even if it is not the screen session we started (e.g. running under an undesirable gid
|
||||
#su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2
|
||||
for (( i=0 ; i < ${#options[@]} ; i++ )) ; do
|
||||
sleep 3
|
||||
su -c "screen -S "${srnname}" -X screen rtorrent ${options[i]} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
|
||||
done
|
||||
}
|
||||
|
||||
d_stop() {
|
||||
for (( i=0 ; i < ${#config[@]} ; i++ )) ; do
|
||||
session=$(getsession "${config[i]}")
|
||||
if ! [ -s ${session}/rtorrent.lock ] ; then
|
||||
return
|
||||
fi
|
||||
pid=$(cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g")
|
||||
# make sure the pid doesn't belong to another process
|
||||
if ps -A | grep -sq ${pid}.*rtorrent ; then
|
||||
kill -s INT ${pid}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
getsession() {
|
||||
session=$(cat "$1" | grep "^[[:space:]]*session.path.set[[:space:]]*=" | sed "s/^[[:space:]]*session.path.set[[:space:]]*=[[:space:]]*//" )
|
||||
#session=${session/#~/`getent passwd ${user}|cut -d: -f6`}
|
||||
echo $session
|
||||
}
|
||||
|
||||
checkcnfg
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $DESC: $NAME"
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: $NAME"
|
||||
d_stop
|
||||
echo "."
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $DESC: $NAME"
|
||||
d_stop
|
||||
sleep 1
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Executable
+137
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
#############
|
||||
###<Notes>###
|
||||
#############
|
||||
# This script depends on screen.
|
||||
# For the stop function to work, you must set an
|
||||
# explicit session directory using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc.
|
||||
# If you typically just start rtorrent with just "rtorrent" on the
|
||||
# command line, all you need to change is the "user" option.
|
||||
# Attach to the screen session as your user with
|
||||
# "screen -dr rtorrent". Change "rtorrent" with srnname option.
|
||||
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
|
||||
##############
|
||||
###</Notes>###
|
||||
##############
|
||||
|
||||
#######################
|
||||
##Start Configuration##
|
||||
#######################
|
||||
# You can specify your configuration in a different file
|
||||
# (so that it is saved with upgrades, saved in your home directory,
|
||||
# or whateve reason you want to)
|
||||
# by commenting out/deleting the configuration lines and placing them
|
||||
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
|
||||
# have written them here (you can leave the comments if you desire
|
||||
# and then uncommenting the following line correcting the path/filename
|
||||
# for the one you used. note the space after the ".".
|
||||
# . /etc/rtorrent.init.conf
|
||||
|
||||
#Do not put a space on either side of the equal signs e.g.
|
||||
# user = user
|
||||
# will not work
|
||||
# system user to run as
|
||||
user="user"
|
||||
|
||||
# the system group to run as, not implemented, see d_start for beginning implementation
|
||||
# group=`id -ng "$user"`
|
||||
|
||||
# the full path to the filename where you store your rtorrent configuration
|
||||
config="`su -c 'echo $HOME' $user`/.rtorrent.rc"
|
||||
|
||||
# set of options to run with
|
||||
options=""
|
||||
|
||||
# default directory for screen, needs to be an absolute path
|
||||
base="`su -c 'echo $HOME' $user`"
|
||||
|
||||
# name of screen session
|
||||
srnname="rtorrent"
|
||||
|
||||
# file to log to (makes for easier debugging if something goes wrong)
|
||||
logfile="/var/log/rtorrentInit.log"
|
||||
#######################
|
||||
###END CONFIGURATION###
|
||||
#######################
|
||||
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
|
||||
DESC="rtorrent"
|
||||
NAME=rtorrent
|
||||
DAEMON=$NAME
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
checkcnfg() {
|
||||
exists=0
|
||||
for i in `echo "$PATH" | tr ':' '\n'` ; do
|
||||
if [ -f $i/$NAME ] ; then
|
||||
exists=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ $exists -eq 0 ] ; then
|
||||
echo "cannot find rtorrent binary in PATH $PATH" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
if ! [ -r "${config}" ] ; then
|
||||
echo "cannot find readable config ${config}. check that it is there and permissions are appropriate" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
session=`getsession "$config"`
|
||||
if ! [ -d "${session}" ] ; then
|
||||
echo "cannot find readable session directory ${session} from config ${config}. check permissions" | tee -a "$logfile" >&2
|
||||
exit 3
|
||||
fi
|
||||
}
|
||||
|
||||
d_start() {
|
||||
[ -d "${base}" ] && cd "${base}"
|
||||
stty stop undef && stty start undef
|
||||
su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "screen -dm -S ${srnname} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
|
||||
# this works for the screen command, but starting rtorrent below adopts screen session gid
|
||||
# even if it is not the screen session we started (e.g. running under an undesirable gid
|
||||
#su -c "screen -ls | grep -sq "\.${srnname}[[:space:]]" " ${user} || su -c "sg \"$group\" -c \"screen -fn -dm -S ${srnname} 2>&1 1>/dev/null\"" ${user} | tee -a "$logfile" >&2
|
||||
su -c "screen -S "${srnname}" -X screen rtorrent ${options} 2>&1 1>/dev/null" ${user} | tee -a "$logfile" >&2
|
||||
}
|
||||
|
||||
d_stop() {
|
||||
session=`getsession "$config"`
|
||||
if ! [ -s ${session}/rtorrent.lock ] ; then
|
||||
return
|
||||
fi
|
||||
pid=`cat ${session}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"`
|
||||
if ps -A | grep -sq ${pid}.*rtorrent ; then # make sure the pid doesn't belong to another process
|
||||
kill -s INT ${pid}
|
||||
fi
|
||||
}
|
||||
|
||||
getsession() {
|
||||
session=`cat "$1" | grep "^[[:space:]]*session.path.set[[:space:]]*=" | sed "s/^[[:space:]]*session.path.set[[:space:]]*=[[:space:]]*//" `
|
||||
echo $session
|
||||
}
|
||||
|
||||
checkcnfg
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $DESC: $NAME"
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: $NAME"
|
||||
d_stop
|
||||
echo "."
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $DESC: $NAME"
|
||||
d_stop
|
||||
sleep 1
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Executable
+166
@@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: rtorrent_autostart
|
||||
# Required-Start: $local_fs $remote_fs $network $syslog $netdaemons
|
||||
# Required-Stop: $local_fs $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: rtorrent script using tmux
|
||||
# Description: rtorrent script using tmux
|
||||
### END INIT INFO
|
||||
|
||||
#############
|
||||
###<Notes>###
|
||||
#############
|
||||
# This script depends on tmux and is based on 'rtorrentInitScreen.sh' script
|
||||
# with the following enhancements:
|
||||
# - init script 'start' option can be called without breaking anything
|
||||
# - init script 'status' option can be used in scripts to determine whether rtorrent is running or not
|
||||
# - auto removes damaged/stuck 'rtorrent.lock' file if necessary
|
||||
# - saves session (just in case) before stopping with 'rtxmlrp' if it exists
|
||||
# - provides examples how to script tmux windows
|
||||
#
|
||||
# For the stop function to work, you must set an explicit session directory
|
||||
# using ABSOLUTE paths (no, ~ is not absolute) in your rtorrent.rc and with
|
||||
# "sessiondir" option.
|
||||
# If you typically just start rtorrent with just "rtorrent" on the
|
||||
# command line, all you need to change is the "user" and "sessiondir" option.
|
||||
# Attach to the tmux session as your user with
|
||||
# "tmux -2u new-session -A -s rtorrent". Change "rtorrent" with "tmuxname" option.
|
||||
# Licensed under the GPLv2 by lostnihilist: lostnihilist _at_ gmail _dot_ com
|
||||
##############
|
||||
###</Notes>###
|
||||
##############
|
||||
|
||||
#######################
|
||||
##Start Configuration##
|
||||
#######################
|
||||
# You can specify your configuration in a different file.
|
||||
# (so that it is saved with upgrades, saved in your home directory,
|
||||
# or whatever reason you want to)
|
||||
# by commenting out/deleting the configuration lines and placing them
|
||||
# in a text file (say /home/user/.rtorrent.init.conf) exactly as you would
|
||||
# have written them here (you can leave the comments if you desire
|
||||
# and then uncommenting the following line correcting the path/filename.
|
||||
# for the one you used. note the space after the ".".
|
||||
# . /etc/rtorrent.init.conf
|
||||
|
||||
# system user to run as
|
||||
user="username"
|
||||
|
||||
# default directory for tmux, needs to be an absolute path
|
||||
base=$(su -c 'echo $HOME' $user)
|
||||
|
||||
# the full path to the filename where you store your rtorrent configuration
|
||||
config="$base/.rtorrent.rc"
|
||||
|
||||
# the full path to the session directory of rtorrent
|
||||
sessiondir="/mnt/Torrents/.rtorrent/.session"
|
||||
|
||||
# options to pass to rtorrent; e.g. don't read config from $HOME but load alternate
|
||||
#options="-n -O import=$config"
|
||||
options=""
|
||||
|
||||
# name of tmux session
|
||||
tmuxname="rtorrent"
|
||||
|
||||
# name of window in tmux session
|
||||
tmuxwindowname="rT"
|
||||
#######################
|
||||
###END CONFIGURATION###
|
||||
#######################
|
||||
PATH=/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin
|
||||
NAME=rtorrent
|
||||
DAEMON=$NAME
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
RTXMLRPCBIN="$base/bin/rtxmlrpc"
|
||||
|
||||
|
||||
checkcnfg() {
|
||||
if [ -z "$(which $DAEMON)" ] ; then
|
||||
echo "Cannot find $DAEMON binary in PATH: $PATH"
|
||||
exit 3
|
||||
fi
|
||||
if ! [ -r "$config" ] ; then
|
||||
echo "Cannot find readable config $config. Check that it is there and permissions are appropriate"
|
||||
exit 3
|
||||
fi
|
||||
if ! [ -d "$sessiondir" ] ; then
|
||||
echo "Cannot find readable session directory $sessiondir from config $config. Check permissions"
|
||||
exit 3
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
status() {
|
||||
if [ -e "${sessiondir}/rtorrent.lock" ] ; then
|
||||
pid=`cat ${sessiondir}/rtorrent.lock | awk -F: '{print($2)}' | sed "s/[^0-9]//g"`
|
||||
# make sure the pid isn't empty and doesn't belong to another process : this will match lines containing rtorrent, which grep '[r]torrent' does not!
|
||||
# if there is no process as the 'pid' suggests then delete the stuck "rtorrent.lock" file (to be able to start rtorrent)
|
||||
[[ -n "$pid" ]] && ps aux | grep -sq ${pid}.*[r]torrent && echo -e ${pid} || rm -f "${sessiondir}/rtorrent.lock"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
d_start() {
|
||||
[ -d "$base" ] && cd "$base"
|
||||
# if STDIN is a terminal (we are using interactive mode)
|
||||
[ -t 0 ] && stty stop undef && stty start undef
|
||||
# start the default 2 tmux window (bash and mc) if there isn't tmux session called "tmuxname" option (rtorrent)
|
||||
if ! su -c "tmux ls | grep -sq ${tmuxname}: " $user ; then
|
||||
# 1st window (0): split it into 3 panes, display 'date' in the last one
|
||||
su -c "tmux -2u new-session -d -s ${tmuxname} -n 'shell1'" $user
|
||||
su -c "tmux -2u split-window -v -t ${tmuxname}:0 'bash'" $user
|
||||
su -c "tmux -2u split-window -h -t ${tmuxname}:0 'date; bash'" $user
|
||||
# 2nd window (1): start 'mc' if it exists
|
||||
su -c "tmux -2u new-window -t ${tmuxname}:1 -n 'mc1' 'command which mc && mc ~/; bash'" $user
|
||||
fi
|
||||
# start rtorrent always in the 3rd tmux window (2) if it's not running and leave shell behind to be able to see reason of a crash
|
||||
if [ "$(status)" == "" ]; then
|
||||
su -c "tmux -2u list-panes -t ${tmuxname}:2 &>/dev/null && tmux -2u respawn-pane -t ${tmuxname}:2 -k \"${DAEMON} ${options}; bash\" || tmux -2u new-window -t ${tmuxname}:2 -n ${tmuxwindowname} \"${DAEMON} ${options}; bash\"" $user
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
d_stop() {
|
||||
pid=$(status)
|
||||
if [ "$pid" != "" ]; then
|
||||
# save session before stopping explicitly (just in case) if rtxmlrpc util exists then wait for 5 seconds to be able to complete it
|
||||
[ -L "$RTXMLRPCBIN" ] && "$RTXMLRPCBIN" session.save &>/dev/null && sleep 5
|
||||
# INT (2, Interrupt from keyboard): normal shutdown
|
||||
kill -s INT $pid
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
checkcnfg
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $tmuxwindowname: $NAME"
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $tmuxwindowname: $NAME"
|
||||
d_stop
|
||||
echo "."
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $tmuxwindowname: $NAME"
|
||||
d_stop
|
||||
sleep 1
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PORT_NUMBER=${1:-5001}
|
||||
|
||||
echo "Option Strings"
|
||||
echo "=============="
|
||||
echo
|
||||
echo "Introduction"
|
||||
echo "------------"
|
||||
echo
|
||||
echo "Client version: " `xmlrpc2scgi.py -p scgi://127.0.0.1:${PORT_NUMBER} system.client_version`
|
||||
echo
|
||||
echo "Generated by 'rtorrent/doc/scripts/print_option_string.sh' on `date -u`."
|
||||
|
||||
for i in strings.choke_heuristics strings.choke_heuristics.upload strings.choke_heuristics.download strings.connection_type strings.encryption strings.ip_filter strings.ip_tos strings.log_group strings.tracker_event strings.tracker_mode; do
|
||||
echo
|
||||
echo $i
|
||||
echo `echo $i | tr 'a-z_.' '-'`
|
||||
echo
|
||||
echo '```'
|
||||
xmlrpc2scgi.py -p scgi://127.0.0.1:${PORT_NUMBER} $i | tr , '\n' | tr '[' ' ' | tr ']' ' '
|
||||
echo '```'
|
||||
done
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Perl script to read torrent data
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Convert::Bencode_XS qw(bdecode);
|
||||
use Data::Dumper;
|
||||
|
||||
$/ = undef;
|
||||
$| = 1;
|
||||
|
||||
my $in;
|
||||
my $in_file = $ARGV[0];
|
||||
if ($in_file) { open($in, '<', $in_file) || die "Cannot open $in_file for input!\n"; }
|
||||
else { $in = *STDIN; }
|
||||
|
||||
print "Total input torrent size: ".sprintf('%.2f', (-s $in_file) / 1024)." KB\n" if $in_file;
|
||||
print "Decoding ".($in_file || 'torrent from standard input')."...";
|
||||
my $t = bdecode(scalar <$in>);
|
||||
print "done\n\n";
|
||||
|
||||
print Data::Dumper->new([$t], ['*Torrent'])->Indent(1)->Useqq(1)->Quotekeys(0)->Sortkeys(1)->Dump;
|
||||
+21
-4
@@ -159,10 +159,7 @@ make_base(_InputIter __first, _InputIter __last, _Ftor __ftor) {
|
||||
template<typename T>
|
||||
inline int popcount_wrapper(T t) {
|
||||
#if USE_BUILTIN_POPCOUNT
|
||||
if (std::numeric_limits<T>::digits <= std::numeric_limits<unsigned int>::digits)
|
||||
return __builtin_popcount(t);
|
||||
else
|
||||
return __builtin_popcountll(t);
|
||||
return __builtin_popcountll(t);
|
||||
#else
|
||||
#error __builtin_popcount not found.
|
||||
unsigned int count = 0;
|
||||
@@ -176,6 +173,26 @@ inline int popcount_wrapper(T t) {
|
||||
#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
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
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;
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@
|
||||
#define RAK_FILE_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@
|
||||
#define RAK_FS_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
|
||||
#include <rak/error_number.h>
|
||||
|
||||
|
||||
@@ -627,6 +627,57 @@ 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
|
||||
|
||||
+11
-10
@@ -53,6 +53,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace rak {
|
||||
|
||||
@@ -96,13 +97,13 @@ public:
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::auto_ptr<base_type>(base); }
|
||||
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::auto_ptr<base_type> m_base;
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1>
|
||||
@@ -113,13 +114,13 @@ public:
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::auto_ptr<base_type>(base); }
|
||||
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::auto_ptr<base_type> m_base;
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2>
|
||||
@@ -130,13 +131,13 @@ public:
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::auto_ptr<base_type>(base); }
|
||||
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::auto_ptr<base_type> m_base;
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg2>
|
||||
@@ -147,7 +148,7 @@ public:
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::auto_ptr<base_type>(base); }
|
||||
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); }
|
||||
@@ -156,7 +157,7 @@ public:
|
||||
Result operator () (Discard discard, Arg2 arg2) { return (*m_base)(arg2); }
|
||||
|
||||
private:
|
||||
std::auto_ptr<base_type> m_base;
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
|
||||
@@ -167,13 +168,13 @@ public:
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::auto_ptr<base_type>(base); }
|
||||
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::auto_ptr<base_type> m_base;
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
|
||||
namespace rak {
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
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) {}
|
||||
|
||||
@@ -37,44 +37,45 @@
|
||||
#ifndef RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
#define RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <rak/allocators.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.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 std::logic_error("priority_item::~priority_item() called on a queued item.");
|
||||
throw torrent::internal_error("priority_item::~priority_item() called on a queued item.");
|
||||
|
||||
m_time = timer();
|
||||
m_slot.set(NULL);
|
||||
m_slot = slot_void();
|
||||
}
|
||||
|
||||
bool is_valid() const { return m_slot.is_valid(); }
|
||||
bool is_queued() const { return m_time != timer(); }
|
||||
bool is_valid() const { return (bool)m_slot; }
|
||||
bool is_queued() const { return m_time != timer(); }
|
||||
|
||||
void call() { m_slot(); }
|
||||
void set_slot(function0<void>::base_type* s) { m_slot.set(s); }
|
||||
|
||||
const timer& time() const { return m_time; }
|
||||
void clear_time() { m_time = timer(); }
|
||||
void set_time(const timer& t) { m_time = t; }
|
||||
slot_void& slot() { return m_slot; }
|
||||
|
||||
bool compare(const timer& t) const { return m_time > t; }
|
||||
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;
|
||||
function0<void> m_slot;
|
||||
slot_void m_slot;
|
||||
};
|
||||
|
||||
struct priority_compare {
|
||||
@@ -94,23 +95,23 @@ priority_queue_perform(priority_queue_default* queue, timer t) {
|
||||
queue->pop();
|
||||
|
||||
v->clear_time();
|
||||
v->call();
|
||||
v->slot()();
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) {
|
||||
if (t == timer())
|
||||
throw std::logic_error("priority_queue_insert(...) received a bad timer.");
|
||||
throw torrent::internal_error("priority_queue_insert(...) received a bad timer.");
|
||||
|
||||
if (!item->is_valid())
|
||||
throw std::logic_error("priority_queue_insert(...) called on an invalid item.");
|
||||
throw torrent::internal_error("priority_queue_insert(...) called on an invalid item.");
|
||||
|
||||
if (item->is_queued())
|
||||
throw std::logic_error("priority_queue_insert(...) called on an already queued item.");
|
||||
throw torrent::internal_error("priority_queue_insert(...) called on an already queued item.");
|
||||
|
||||
if (queue->find(item) != queue->end())
|
||||
throw std::logic_error("priority_queue_insert(...) item found in queue.");
|
||||
throw torrent::internal_error("priority_queue_insert(...) item found in queue.");
|
||||
|
||||
item->set_time(t);
|
||||
queue->push(item);
|
||||
@@ -124,16 +125,16 @@ priority_queue_erase(priority_queue_default* queue, priority_item* item) {
|
||||
// Check is_valid() after is_queued() so that it is safe to call
|
||||
// erase on untouched instances.
|
||||
if (!item->is_valid())
|
||||
throw std::logic_error("priority_queue_erase(...) called on an invalid item.");
|
||||
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 std::logic_error("priority_queue_erase(...) could not find item in queue.");
|
||||
throw torrent::internal_error("priority_queue_erase(...) could not find item in queue.");
|
||||
|
||||
if (queue->find(item) != queue->end())
|
||||
throw std::logic_error("priority_queue_erase(...) item still in queue.");
|
||||
throw torrent::internal_error("priority_queue_erase(...) item still in queue.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+196
-48
@@ -47,9 +47,12 @@
|
||||
#ifndef RAK_SOCKET_ADDRESS_H
|
||||
#define RAK_SOCKET_ADDRESS_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
@@ -77,11 +80,13 @@ public:
|
||||
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;
|
||||
|
||||
// Should we need to set AF_UNSPEC?
|
||||
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; }
|
||||
@@ -93,6 +98,8 @@ public:
|
||||
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()); }
|
||||
@@ -109,18 +116,17 @@ public:
|
||||
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
|
||||
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
|
||||
|
||||
#ifdef RAK_USE_INET6
|
||||
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
|
||||
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
|
||||
|
||||
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
|
||||
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
|
||||
#endif
|
||||
|
||||
// Copy a socket address which has the length 'length. Zero out any
|
||||
// extranous bytes and ensure it does not go beyond the size of this
|
||||
// struct.
|
||||
void copy(const socket_address& src, size_t length);
|
||||
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); }
|
||||
@@ -139,13 +145,11 @@ private:
|
||||
union {
|
||||
sockaddr m_sockaddr;
|
||||
sockaddr_in m_sockaddrInet;
|
||||
#ifdef RAK_USE_INET6
|
||||
sockaddr_in6 m_sockaddrInet6;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// Remeber to set the AF_INET.
|
||||
// Remember to set the AF_INET.
|
||||
|
||||
class socket_address_inet {
|
||||
public:
|
||||
@@ -184,6 +188,8 @@ public:
|
||||
|
||||
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;
|
||||
@@ -192,57 +198,70 @@ private:
|
||||
struct sockaddr_in m_sockaddr;
|
||||
};
|
||||
|
||||
// Unique key for the address, excluding port numbers etc.
|
||||
class socket_address_key {
|
||||
class socket_address_inet6 {
|
||||
public:
|
||||
// socket_address_host_key() {}
|
||||
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; }
|
||||
|
||||
socket_address_key(const socket_address& sa) {
|
||||
*this = sa;
|
||||
}
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
|
||||
|
||||
socket_address_key& operator = (const socket_address& sa) {
|
||||
if (sa.family() == 0) {
|
||||
std::memset(this, 0, sizeof(socket_address_key));
|
||||
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; }
|
||||
|
||||
} else if (sa.family() == socket_address::af_inet) {
|
||||
// Using hardware order as we use operator < to compare when
|
||||
// using inet only.
|
||||
m_addr.s_addr = sa.sa_inet()->address_h();
|
||||
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;
|
||||
|
||||
} else {
|
||||
// When we implement INET6 handling, embed the ipv4 address in
|
||||
// the ipv6 address.
|
||||
throw std::logic_error("socket_address_key(...) received an unsupported protocol family.");
|
||||
}
|
||||
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);
|
||||
|
||||
return *this;
|
||||
}
|
||||
void set_address_any() { set_port(0); set_address(in6addr_any); }
|
||||
|
||||
// socket_address_key& operator = (const socket_address_key& sa) {
|
||||
// }
|
||||
std::string pretty_address_str() const;
|
||||
|
||||
bool operator < (const socket_address_key& sa) const {
|
||||
// Compare the memory area instead.
|
||||
return m_addr.s_addr < sa.m_addr.s_addr;
|
||||
}
|
||||
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:
|
||||
union {
|
||||
in_addr m_addr;
|
||||
// #ifdef RAK_USE_INET6
|
||||
// in_addr6 m_addr6;
|
||||
// #endif
|
||||
};
|
||||
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();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_valid();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -253,6 +272,8 @@ 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;
|
||||
}
|
||||
@@ -263,6 +284,8 @@ 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;
|
||||
}
|
||||
@@ -273,6 +296,8 @@ socket_address::port() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->port();
|
||||
case af_inet6:
|
||||
return sa_inet6()->port();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -283,6 +308,8 @@ 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;
|
||||
}
|
||||
@@ -293,6 +320,8 @@ 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();
|
||||
}
|
||||
@@ -303,17 +332,38 @@ 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;
|
||||
}
|
||||
@@ -325,6 +375,8 @@ socket_address::length() const {
|
||||
switch(family()) {
|
||||
case af_inet:
|
||||
return sizeof(sockaddr_in);
|
||||
case af_inet6:
|
||||
return sizeof(sockaddr_in6);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -333,13 +385,16 @@ socket_address::length() const {
|
||||
inline void
|
||||
socket_address::copy(const socket_address& src, size_t length) {
|
||||
length = std::min(length, sizeof(socket_address));
|
||||
|
||||
// Does this get properly optimized?
|
||||
|
||||
std::memset(this, 0, sizeof(socket_address));
|
||||
std::memcpy(this, &src, length);
|
||||
}
|
||||
|
||||
// Should we be able to compare af_unspec?
|
||||
inline 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 {
|
||||
@@ -349,8 +404,8 @@ socket_address::operator == (const socket_address& rhs) const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() == *rhs.sa_inet();
|
||||
// case af_inet6:
|
||||
// return *sa_inet6() == *rhs.sa_inet6();
|
||||
case af_inet6:
|
||||
return *sa_inet6() == *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
|
||||
}
|
||||
@@ -364,8 +419,8 @@ socket_address::operator < (const socket_address& rhs) const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() < *rhs.sa_inet();
|
||||
// case af_inet6:
|
||||
// return *sa_inet6() < *rhs.sa_inet6();
|
||||
case af_inet6:
|
||||
return *sa_inet6() < *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
|
||||
}
|
||||
@@ -391,6 +446,21 @@ 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
|
||||
@@ -406,6 +476,84 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
|
||||
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
|
||||
|
||||
+54
-3
@@ -39,9 +39,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <locale>
|
||||
#include <random>
|
||||
|
||||
|
||||
namespace rak {
|
||||
|
||||
@@ -312,11 +316,13 @@ transform_hex_str(const Sequence& seq) {
|
||||
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, &::random);
|
||||
|
||||
std::generate_n(std::back_inserter(s), length, std::ref(bytes));
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -371,6 +377,51 @@ 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
|
||||
|
||||
+4
-1
@@ -38,7 +38,7 @@
|
||||
#define RAK_TIMER_H
|
||||
|
||||
#include <limits>
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
#include <sys/time.h>
|
||||
|
||||
namespace rak {
|
||||
@@ -49,6 +49,9 @@ class timer {
|
||||
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; }
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
dnl PGSGL: When updating, comment out port-specific part below;
|
||||
dnl see the comment below with the word "PostgreSQL".
|
||||
dnl
|
||||
dnl Available from the GNU Autoconf Macro Archive at:
|
||||
dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html
|
||||
dnl
|
||||
AC_DEFUN([ACX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
acx_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config pthreadGC2"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthread or
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
for flag in $acx_pthread_flags; do
|
||||
|
||||
tryPTHREAD_CFLAGS=""
|
||||
tryPTHREAD_LIBS=""
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
tryPTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
# skip this if we already have flags defined, for PostgreSQL
|
||||
if test x"$PTHREAD_CFLAGS" != x -o x"$PTHREAD_LIBS" != x; then continue; fi
|
||||
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
|
||||
if test x"$acx_pthread_config" = xno; then continue; fi
|
||||
tryPTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
tryPTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
tryPTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$tryPTHREAD_LIBS $PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $tryPTHREAD_CFLAGS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
AC_TRY_LINK([#include <pthread.h>],
|
||||
[pthread_t th; pthread_join(th, 0);
|
||||
pthread_attr_init(0); pthread_cleanup_push(0, 0);
|
||||
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
|
||||
[acx_pthread_ok=yes], [acx_pthread_ok=no])
|
||||
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
# Don't use options that are ignored by the compiler.
|
||||
# We find them by checking stderror.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if test "`(eval $ac_link 2>&1 1>&5)`" = ""; then
|
||||
# we continue with more flags because Linux needs -lpthread
|
||||
# for libpq builds on PostgreSQL. The test above only
|
||||
# tests for building binaries, not shared libraries.
|
||||
PTHREAD_LIBS=" $tryPTHREAD_LIBS $PTHREAD_LIBS"
|
||||
PTHREAD_CFLAGS="$PTHREAD_CFLAGS $tryPTHREAD_CFLAGS"
|
||||
else acx_pthread_ok=no
|
||||
fi
|
||||
fi
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: threads are created detached by default
|
||||
# and the JOINABLE attribute has a nonstandard name (UNDETACHED).
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
AC_TRY_LINK([#include <pthread.h>],
|
||||
[int attr=PTHREAD_CREATE_JOINABLE;],
|
||||
ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
|
||||
if test x"$ok" = xunknown; then
|
||||
AC_TRY_LINK([#include <pthread.h>],
|
||||
[int attr=PTHREAD_CREATE_UNDETACHED;],
|
||||
ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
|
||||
fi
|
||||
if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
|
||||
[Define to the necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
AC_MSG_RESULT(${ok})
|
||||
if test x"$ok" = xunknown; then
|
||||
AC_MSG_WARN([we do not know how to create joinable pthreads])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
# We always add these in PostgreSQL
|
||||
# case "${host_cpu}-${host_os}" in
|
||||
# *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||||
# *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||||
# esac
|
||||
AC_MSG_RESULT(${flag})
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# Supporting cc_r would require a special CC in all places that
|
||||
# use libpq, and that is ugly, so we don't do it. Users can still
|
||||
# define their compiler as cc_r to do thread builds of everything.
|
||||
# More AIX lossage: must compile with cc_r
|
||||
AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
|
||||
else
|
||||
PTHREAD_CC="$CC"
|
||||
fi
|
||||
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_CC)
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$acx_pthread_ok" = xyes; then
|
||||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||
:
|
||||
else
|
||||
acx_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
])dnl ACX_PTHREAD
|
||||
+14
-14
@@ -3,10 +3,10 @@
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((constructor))],
|
||||
[cc_cv_attribute_constructor],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void ctor() __attribute__((constructor));
|
||||
void ctor() { };
|
||||
],
|
||||
])],
|
||||
[cc_cv_attribute_constructor=yes],
|
||||
[cc_cv_attribute_constructor=no])
|
||||
])
|
||||
@@ -23,9 +23,9 @@ AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((format(printf, n, n)))],
|
||||
[cc_cv_attribute_format],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { }
|
||||
],
|
||||
])],
|
||||
[cc_cv_attribute_format=yes],
|
||||
[cc_cv_attribute_format=no])
|
||||
])
|
||||
@@ -42,9 +42,9 @@ AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
|
||||
AC_DEFUN([CC_ATTRIBUTE_INTERNAL], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((visibility("internal")))],
|
||||
[cc_cv_attribute_internal],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void __attribute__((visibility("internal"))) internal_function() { }
|
||||
],
|
||||
])],
|
||||
[cc_cv_attribute_internal=yes],
|
||||
[cc_cv_attribute_internal=no])
|
||||
])
|
||||
@@ -66,9 +66,9 @@ AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
|
||||
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((visibility("default")))],
|
||||
[cc_cv_attribute_visibility],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void __attribute__((visibility("default"))) visibility_function() { }
|
||||
],
|
||||
])],
|
||||
[cc_cv_attribute_visibility=yes],
|
||||
[cc_cv_attribute_visibility=no])
|
||||
])
|
||||
@@ -90,10 +90,10 @@ AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
|
||||
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((nonnull()))],
|
||||
[cc_cv_attribute_nonnull],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void some_function(void *foo, void *bar) __attribute__((nonnull()));
|
||||
void some_function(void *foo, void *bar) { }
|
||||
],
|
||||
])],
|
||||
[cc_cv_attribute_nonnull=yes],
|
||||
[cc_cv_attribute_nonnull=no])
|
||||
])
|
||||
@@ -110,9 +110,9 @@ AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
|
||||
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((unused))],
|
||||
[cc_cv_attribute_unused],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[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])
|
||||
])
|
||||
@@ -129,13 +129,13 @@ AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
|
||||
AC_DEFUN([CC_FUNC_EXPECT], [
|
||||
AC_CACHE_CHECK([if compiler has __builtin_expect function],
|
||||
[cc_cv_func_expect],
|
||||
[AC_COMPILE_IFELSE([
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int some_function()
|
||||
{
|
||||
int a = 3;
|
||||
return (int)__builtin_expect(a, 3);
|
||||
}
|
||||
],
|
||||
])],
|
||||
[cc_cv_func_expect=yes],
|
||||
[cc_cv_func_expect=no])
|
||||
])
|
||||
|
||||
Executable
+141
@@ -0,0 +1,141 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_check_zlib.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_ZLIB([action-if-found], [action-if-not-found])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro searches for an installed zlib library. If nothing was
|
||||
# specified when calling configure, it searches first in /usr/local and
|
||||
# then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified,
|
||||
# it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If
|
||||
# --without-zlib is specified, the library is not searched at all.
|
||||
#
|
||||
# If either the header file (zlib.h) or the library (libz) is not found,
|
||||
# shell commands 'action-if-not-found' is run. If 'action-if-not-found' is
|
||||
# not specified, the configuration exits on error, asking for a valid zlib
|
||||
# installation directory or --without-zlib.
|
||||
#
|
||||
# If both header file and library are found, shell commands
|
||||
# 'action-if-found' is run. If 'action-if-found' is not specified, the
|
||||
# default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends
|
||||
# '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls
|
||||
# AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition
|
||||
# for this symbol in a config.h file. Sample usage in a C/C++ source is as
|
||||
# follows:
|
||||
#
|
||||
# #ifdef HAVE_LIBZ
|
||||
# #include <zlib.h>
|
||||
# #endif /* HAVE_LIBZ */
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Loic Dachary <loic@senga.org>
|
||||
# Copyright (c) 2010 Bastien Chevreux <bach@chevreux.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 16
|
||||
|
||||
AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB])
|
||||
AC_DEFUN([AX_CHECK_ZLIB],
|
||||
#
|
||||
# Handle user hints
|
||||
#
|
||||
[AC_MSG_CHECKING(if zlib is wanted)
|
||||
zlib_places="/usr/local /usr /opt/local /sw"
|
||||
AC_ARG_WITH([zlib],
|
||||
[ --with-zlib=DIR root directory path of zlib installation @<:@defaults to
|
||||
/usr/local or /usr if not found in /usr/local@:>@
|
||||
--without-zlib to disable zlib usage completely],
|
||||
[if test "$withval" != no ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
if test -d "$withval"
|
||||
then
|
||||
zlib_places="$withval $zlib_places"
|
||||
else
|
||||
AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])
|
||||
fi
|
||||
else
|
||||
zlib_places=
|
||||
AC_MSG_RESULT(no)
|
||||
fi],
|
||||
[AC_MSG_RESULT(yes)])
|
||||
|
||||
#
|
||||
# Locate zlib, if wanted
|
||||
#
|
||||
if test -n "${zlib_places}"
|
||||
then
|
||||
# check the user supplied or any other more or less 'standard' place:
|
||||
# Most UNIX systems : /usr/local and /usr
|
||||
# MacPorts / Fink on OSX : /opt/local respectively /sw
|
||||
for ZLIB_HOME in ${zlib_places} ; do
|
||||
if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi
|
||||
ZLIB_HOME=""
|
||||
done
|
||||
|
||||
ZLIB_OLD_LDFLAGS=$LDFLAGS
|
||||
ZLIB_OLD_CPPFLAGS=$CPPFLAGS
|
||||
if test -n "${ZLIB_HOME}"; then
|
||||
LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
|
||||
CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
|
||||
fi
|
||||
AC_LANG_PUSH([C])
|
||||
AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no])
|
||||
AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no])
|
||||
AC_LANG_POP([C])
|
||||
if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes"
|
||||
then
|
||||
#
|
||||
# If both library and header were found, action-if-found
|
||||
#
|
||||
m4_ifblank([$1],[
|
||||
CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
|
||||
LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
|
||||
LIBS="-lz $LIBS"
|
||||
AC_DEFINE([HAVE_LIBZ], [1],
|
||||
[Define to 1 if you have `z' library (-lz)])
|
||||
],[
|
||||
# Restore variables
|
||||
LDFLAGS="$ZLIB_OLD_LDFLAGS"
|
||||
CPPFLAGS="$ZLIB_OLD_CPPFLAGS"
|
||||
$1
|
||||
])
|
||||
else
|
||||
#
|
||||
# If either header or library was not found, action-if-not-found
|
||||
#
|
||||
m4_default([$2],[
|
||||
AC_MSG_ERROR([either specify a valid zlib installation with --with-zlib=DIR or disable zlib usage with --without-zlib])
|
||||
])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
Executable
+962
@@ -0,0 +1,962 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# 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).
|
||||
#
|
||||
# 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.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for no added switch, and then for an extended mode.
|
||||
#
|
||||
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline support for the specified C++ standard is
|
||||
# required and that the macro should error out if no mode with that
|
||||
# support is found. If specified 'optional', then configuration proceeds
|
||||
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||
# supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
# 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>
|
||||
#
|
||||
# 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
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
|
||||
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"],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
[$2], [noext], [],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
|
||||
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
|
||||
m4_if([$2], [], [dnl
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
|
||||
ax_cv_cxx_compile_cxx$1,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[ax_cv_cxx_compile_cxx$1=yes],
|
||||
[ax_cv_cxx_compile_cxx$1=no])])
|
||||
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
|
||||
ac_success=yes
|
||||
fi])
|
||||
|
||||
m4_if([$2], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||
switch="-std=gnu++${alternative}"
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$2], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
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"
|
||||
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])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test x$ac_success = xyes; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
|
||||
fi
|
||||
fi
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX$1=0
|
||||
AC_MSG_NOTICE([No compiler with C++$1 support was found])
|
||||
else
|
||||
HAVE_CXX$1=1
|
||||
AC_DEFINE(HAVE_CXX$1,1,
|
||||
[define if the compiler supports basic C++$1 syntax])
|
||||
fi
|
||||
AC_SUBST(HAVE_CXX$1)
|
||||
])
|
||||
|
||||
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++11, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx11
|
||||
{
|
||||
|
||||
namespace test_static_assert
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_final_override
|
||||
{
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base() {}
|
||||
virtual void f() {}
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{
|
||||
virtual ~Derived() override {}
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_double_right_angle_brackets
|
||||
{
|
||||
|
||||
template < typename T >
|
||||
struct check {};
|
||||
|
||||
typedef check<void> single_type;
|
||||
typedef check<check<void>> double_type;
|
||||
typedef check<check<check<void>>> triple_type;
|
||||
typedef check<check<check<check<void>>>> quadruple_type;
|
||||
|
||||
}
|
||||
|
||||
namespace test_decltype
|
||||
{
|
||||
|
||||
int
|
||||
f()
|
||||
{
|
||||
int a = 1;
|
||||
decltype(a) b = 2;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_type_deduction
|
||||
{
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
auto
|
||||
add(T1 a1, T2 a2) -> decltype(a1 + a2)
|
||||
{
|
||||
return a1 + a2;
|
||||
}
|
||||
|
||||
int
|
||||
test(const int c, volatile int v)
|
||||
{
|
||||
static_assert(is_same<int, decltype(0)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(c)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(v)>::value == false, "");
|
||||
auto ac = c;
|
||||
auto av = v;
|
||||
auto sumi = ac + av + 'x';
|
||||
auto sumf = ac + av + 1.0;
|
||||
static_assert(is_same<int, decltype(ac)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(av)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumi)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumf)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
|
||||
return (sumf > 0.0) ? sumi : add(c, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_noexcept
|
||||
{
|
||||
|
||||
int f() { return 0; }
|
||||
int g() noexcept { return 0; }
|
||||
|
||||
static_assert(noexcept(f()) == false, "");
|
||||
static_assert(noexcept(g()) == true, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
|
||||
{
|
||||
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
|
||||
}
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
return strlen_c_r(s, 0UL);
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("1") == 1UL, "");
|
||||
static_assert(strlen_c("example") == 7UL, "");
|
||||
static_assert(strlen_c("another\0example") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_rvalue_references
|
||||
{
|
||||
|
||||
template < int N >
|
||||
struct answer
|
||||
{
|
||||
static constexpr int value = N;
|
||||
};
|
||||
|
||||
answer<1> f(int&) { return answer<1>(); }
|
||||
answer<2> f(const int&) { return answer<2>(); }
|
||||
answer<3> f(int&&) { return answer<3>(); }
|
||||
|
||||
void
|
||||
test()
|
||||
{
|
||||
int i = 0;
|
||||
const int c = 0;
|
||||
static_assert(decltype(f(i))::value == 1, "");
|
||||
static_assert(decltype(f(c))::value == 2, "");
|
||||
static_assert(decltype(f(0))::value == 3, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_uniform_initialization
|
||||
{
|
||||
|
||||
struct test
|
||||
{
|
||||
static const int zero {};
|
||||
static const int one {1};
|
||||
};
|
||||
|
||||
static_assert(test::zero == 0, "");
|
||||
static_assert(test::one == 1, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambdas
|
||||
{
|
||||
|
||||
void
|
||||
test1()
|
||||
{
|
||||
auto lambda1 = [](){};
|
||||
auto lambda2 = lambda1;
|
||||
lambda1();
|
||||
lambda2();
|
||||
}
|
||||
|
||||
int
|
||||
test2()
|
||||
{
|
||||
auto a = [](int i, int j){ return i + j; }(1, 2);
|
||||
auto b = []() -> int { return '0'; }();
|
||||
auto c = [=](){ return a + b; }();
|
||||
auto d = [&](){ return c; }();
|
||||
auto e = [a, &b](int x) mutable {
|
||||
const auto identity = [](int y){ return y; };
|
||||
for (auto i = 0; i < a; ++i)
|
||||
a += b--;
|
||||
return x + identity(a + b);
|
||||
}(0);
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
int
|
||||
test3()
|
||||
{
|
||||
const auto nullary = [](){ return 0; };
|
||||
const auto unary = [](int x){ return x; };
|
||||
using nullary_t = decltype(nullary);
|
||||
using unary_t = decltype(unary);
|
||||
const auto higher1st = [](nullary_t f){ return f(); };
|
||||
const auto higher2nd = [unary](nullary_t f1){
|
||||
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
|
||||
};
|
||||
return higher1st(nullary) + higher2nd(nullary)(unary);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_variadic_templates
|
||||
{
|
||||
|
||||
template <int...>
|
||||
struct sum;
|
||||
|
||||
template <int N0, int... N1toN>
|
||||
struct sum<N0, N1toN...>
|
||||
{
|
||||
static constexpr auto value = N0 + sum<N1toN...>::value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct sum<>
|
||||
{
|
||||
static constexpr auto value = 0;
|
||||
};
|
||||
|
||||
static_assert(sum<>::value == 0, "");
|
||||
static_assert(sum<1>::value == 1, "");
|
||||
static_assert(sum<23>::value == 23, "");
|
||||
static_assert(sum<1, 2>::value == 3, "");
|
||||
static_assert(sum<5, 5, 11>::value == 21, "");
|
||||
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
|
||||
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
{
|
||||
|
||||
struct foo {};
|
||||
|
||||
template<typename T>
|
||||
using member = typename T::member_type;
|
||||
|
||||
template<typename T>
|
||||
void func(...) {}
|
||||
|
||||
template<typename T>
|
||||
void func(member<T>*) {}
|
||||
|
||||
void test();
|
||||
|
||||
void test() { func<foo>(0); }
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx11
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++14
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++14, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201402L
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx14
|
||||
{
|
||||
|
||||
namespace test_polymorphic_lambdas
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
const auto lambda = [](auto&&... args){
|
||||
const auto istiny = [](auto x){
|
||||
return (sizeof(x) == 1UL) ? 1 : 0;
|
||||
};
|
||||
const int aretiny[] = { istiny(args)... };
|
||||
return aretiny[0];
|
||||
};
|
||||
return lambda(1, 1L, 1.0f, '1');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_binary_literals
|
||||
{
|
||||
|
||||
constexpr auto ivii = 0b0000000000101010;
|
||||
static_assert(ivii == 42, "wrong value");
|
||||
|
||||
}
|
||||
|
||||
namespace test_generalized_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
constexpr unsigned long
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
auto length = 0UL;
|
||||
for (auto p = s; *p; ++p)
|
||||
++length;
|
||||
return length;
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("x") == 1UL, "");
|
||||
static_assert(strlen_c("test") == 4UL, "");
|
||||
static_assert(strlen_c("another\0test") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambda_init_capture
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
const auto lambda1 = [a = x](int b){ return a + b; };
|
||||
const auto lambda2 = [a = lambda1(x)](){ return a; };
|
||||
return lambda2();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_digit_separators
|
||||
{
|
||||
|
||||
constexpr auto ten_million = 100'000'000;
|
||||
static_assert(ten_million == 100000000, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_return_type_deduction
|
||||
{
|
||||
|
||||
auto f(int& x) { return x; }
|
||||
decltype(auto) g(int& x) { return x; }
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
static_assert(is_same<int, decltype(f(x))>::value, "");
|
||||
static_assert(is_same<int&, decltype(g(x))>::value, "");
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx14
|
||||
|
||||
#endif // __cplusplus >= 201402L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++17
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++17, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201703L
|
||||
|
||||
#error "This is not a C++17 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
namespace cxx17
|
||||
{
|
||||
|
||||
namespace test_constexpr_lambdas
|
||||
{
|
||||
|
||||
constexpr int foo = [](){return 42;}();
|
||||
|
||||
}
|
||||
|
||||
namespace test::nested_namespace::definitions
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace test_fold_expression
|
||||
{
|
||||
|
||||
template<typename... Args>
|
||||
int multiply(Args... args)
|
||||
{
|
||||
return (args * ... * 1);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
bool all(Args... args)
|
||||
{
|
||||
return (args && ...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_extended_static_assert
|
||||
{
|
||||
|
||||
static_assert (true);
|
||||
|
||||
}
|
||||
|
||||
namespace test_auto_brace_init_list
|
||||
{
|
||||
|
||||
auto foo = {5};
|
||||
auto bar {5};
|
||||
|
||||
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
|
||||
static_assert(std::is_same<int, decltype(bar)>::value);
|
||||
}
|
||||
|
||||
namespace test_typename_in_template_template_parameter
|
||||
{
|
||||
|
||||
template<template<typename> typename X> struct D;
|
||||
|
||||
}
|
||||
|
||||
namespace test_fallthrough_nodiscard_maybe_unused_attributes
|
||||
{
|
||||
|
||||
int f1()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
[[nodiscard]] int f2()
|
||||
{
|
||||
[[maybe_unused]] auto unused = f1();
|
||||
|
||||
switch (f1())
|
||||
{
|
||||
case 17:
|
||||
f1();
|
||||
[[fallthrough]];
|
||||
case 42:
|
||||
f1();
|
||||
}
|
||||
return f1();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_extended_aggregate_initialization
|
||||
{
|
||||
|
||||
struct base1
|
||||
{
|
||||
int b1, b2 = 42;
|
||||
};
|
||||
|
||||
struct base2
|
||||
{
|
||||
base2() {
|
||||
b3 = 42;
|
||||
}
|
||||
int b3;
|
||||
};
|
||||
|
||||
struct derived : base1, base2
|
||||
{
|
||||
int d;
|
||||
};
|
||||
|
||||
derived d1 {{1, 2}, {}, 4}; // full initialization
|
||||
derived d2 {{}, {}, 4}; // value-initialized bases
|
||||
|
||||
}
|
||||
|
||||
namespace test_general_range_based_for_loop
|
||||
{
|
||||
|
||||
struct iter
|
||||
{
|
||||
int i;
|
||||
|
||||
int& operator* ()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
const int& operator* () const
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
iter& operator++()
|
||||
{
|
||||
++i;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct sentinel
|
||||
{
|
||||
int i;
|
||||
};
|
||||
|
||||
bool operator== (const iter& i, const sentinel& s)
|
||||
{
|
||||
return i.i == s.i;
|
||||
}
|
||||
|
||||
bool operator!= (const iter& i, const sentinel& s)
|
||||
{
|
||||
return !(i == s);
|
||||
}
|
||||
|
||||
struct range
|
||||
{
|
||||
iter begin() const
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
|
||||
sentinel end() const
|
||||
{
|
||||
return {5};
|
||||
}
|
||||
};
|
||||
|
||||
void f()
|
||||
{
|
||||
range r {};
|
||||
|
||||
for (auto i : r)
|
||||
{
|
||||
[[maybe_unused]] auto v = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambda_capture_asterisk_this_by_value
|
||||
{
|
||||
|
||||
struct t
|
||||
{
|
||||
int i;
|
||||
int foo()
|
||||
{
|
||||
return [*this]()
|
||||
{
|
||||
return i;
|
||||
}();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_enum_class_construction
|
||||
{
|
||||
|
||||
enum class byte : unsigned char
|
||||
{};
|
||||
|
||||
byte foo {42};
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr_if
|
||||
{
|
||||
|
||||
template <bool cond>
|
||||
int f ()
|
||||
{
|
||||
if constexpr(cond)
|
||||
{
|
||||
return 13;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_selection_statement_with_initializer
|
||||
{
|
||||
|
||||
int f()
|
||||
{
|
||||
return 13;
|
||||
}
|
||||
|
||||
int f2()
|
||||
{
|
||||
if (auto i = f(); i > 0)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
switch (auto i = f(); i + 4)
|
||||
{
|
||||
case 17:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_template_argument_deduction_for_class_templates
|
||||
{
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
pair (T1 p1, T2 p2)
|
||||
: m1 {p1},
|
||||
m2 {p2}
|
||||
{}
|
||||
|
||||
T1 m1;
|
||||
T2 m2;
|
||||
};
|
||||
|
||||
void f()
|
||||
{
|
||||
[[maybe_unused]] auto p = pair{13, 42u};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_non_type_auto_template_parameters
|
||||
{
|
||||
|
||||
template <auto n>
|
||||
struct B
|
||||
{};
|
||||
|
||||
B<5> b1;
|
||||
B<'a'> b2;
|
||||
|
||||
}
|
||||
|
||||
namespace test_structured_bindings
|
||||
{
|
||||
|
||||
int arr[2] = { 1, 2 };
|
||||
std::pair<int, int> pr = { 1, 2 };
|
||||
|
||||
auto f1() -> int(&)[2]
|
||||
{
|
||||
return arr;
|
||||
}
|
||||
|
||||
auto f2() -> std::pair<int, int>&
|
||||
{
|
||||
return pr;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
int x1 : 2;
|
||||
volatile double y1;
|
||||
};
|
||||
|
||||
S f3()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto [ x1, y1 ] = f1();
|
||||
auto& [ xr1, yr1 ] = f1();
|
||||
auto [ x2, y2 ] = f2();
|
||||
auto& [ xr2, yr2 ] = f2();
|
||||
const auto [ x3, y3 ] = f3();
|
||||
|
||||
}
|
||||
|
||||
namespace test_exception_spec_type_system
|
||||
{
|
||||
|
||||
struct Good {};
|
||||
struct Bad {};
|
||||
|
||||
void g1() noexcept;
|
||||
void g2();
|
||||
|
||||
template<typename T>
|
||||
Bad
|
||||
f(T*, T*);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
Good
|
||||
f(T1*, T2*);
|
||||
|
||||
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
|
||||
|
||||
}
|
||||
|
||||
namespace test_inline_variables
|
||||
{
|
||||
|
||||
template<class T> void f(T)
|
||||
{}
|
||||
|
||||
template<class T> inline T g(T)
|
||||
{
|
||||
return T{};
|
||||
}
|
||||
|
||||
template<> inline void f<>(int)
|
||||
{}
|
||||
|
||||
template<> int g<>(int)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx17
|
||||
|
||||
#endif // __cplusplus < 201703L
|
||||
|
||||
]])
|
||||
@@ -0,0 +1,67 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_execinfo.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_EXECINFO([ACTION-IF-EXECINFO-H-IS-FOUND], [ACTION-IF-EXECINFO-H-IS-NOT-FOUND], [ADDITIONAL-TYPES-LIST])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Checks for execinfo.h header and if the len parameter/return type can be
|
||||
# found from a list, also define backtrace_size_t to that type.
|
||||
#
|
||||
# By default the list of types to try contains int and size_t, but should
|
||||
# some yet undiscovered system use e.g. unsigned, the 3rd argument can be
|
||||
# used for extensions. I'd like to hear of further suggestions.
|
||||
#
|
||||
# Executes ACTION-IF-EXECINFO-H-IS-FOUND when present and the execinfo.h
|
||||
# header is found or ACTION-IF-EXECINFO-H-IS-NOT-FOUND in case the header
|
||||
# seems unavailable.
|
||||
#
|
||||
# Also adds -lexecinfo to LIBS on BSD if needed.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2014 Thomas Jahns <jahns@dkrz.de>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 2
|
||||
|
||||
AC_DEFUN([AX_EXECINFO],
|
||||
[AC_CHECK_HEADERS([execinfo.h])
|
||||
AS_IF([test x"$ac_cv_header_execinfo_h" = xyes],
|
||||
[AC_CACHE_CHECK([size parameter type for backtrace()],
|
||||
[ax_cv_proto_backtrace_type],
|
||||
[AC_LANG_PUSH([C])
|
||||
for ax_cv_proto_backtrace_type in size_t int m4_ifnblank([$3],[$3 ])none; do
|
||||
AS_IF([test "${ax_cv_proto_backtrace_type}" = none],
|
||||
[ax_cv_proto_backtrace_type= ; break])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
|
||||
#include <execinfo.h>
|
||||
extern
|
||||
${ax_cv_proto_backtrace_type} backtrace(void **addrlist, ${ax_cv_proto_backtrace_type} len);
|
||||
char **backtrace_symbols(void *const *buffer, ${ax_cv_proto_backtrace_type} size);
|
||||
])],
|
||||
[break])
|
||||
done
|
||||
AC_LANG_POP([C])])])
|
||||
AS_IF([test x${ax_cv_proto_backtrace_type} != x],
|
||||
[AC_DEFINE_UNQUOTED([backtrace_size_t], [$ax_cv_proto_backtrace_type],
|
||||
[Defined to return type of backtrace().])])
|
||||
AC_SEARCH_LIBS([backtrace],[execinfo])
|
||||
AS_IF([test x"${ax_cv_proto_backtrace_type}" != x -a x"$ac_cv_header_execinfo_h" = xyes -a x"$ac_cv_search_backtrace" != xno],
|
||||
[AC_DEFINE([HAVE_BACKTRACE],[1],
|
||||
[Defined if backtrace() could be fully identified.])
|
||||
]m4_ifnblank([$1],[$1
|
||||
]),m4_ifnblank([$2],[$2
|
||||
]))])
|
||||
dnl
|
||||
dnl Local Variables:
|
||||
dnl mode: autoconf
|
||||
dnl End:
|
||||
dnl
|
||||
Executable
+522
@@ -0,0 +1,522 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
|
||||
# needed for multi-threaded programs (defaults to the value of CC
|
||||
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
|
||||
# special cc_r/CC_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
# CXX="$PTHREAD_CXX"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
# PTHREAD_CFLAGS.
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# Updated for Autoconf 2.68 by Daniel Richard G.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# 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 31
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items with a "," contain both
|
||||
# C compiler flags (before ",") and linker flags (after ","). Other items
|
||||
# starting with a "-" are C compiler flags, and remaining items are
|
||||
# library names, except for "none" which indicates that we try without
|
||||
# any flags at all, and "pthread-config" which is a program returning
|
||||
# the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
# Note that for GCC and Clang -pthread generally implies -lpthread,
|
||||
# except when -nostdlib is passed.
|
||||
# This is problematic using libtool to build C++ shared libraries with pthread:
|
||||
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
|
||||
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
|
||||
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
|
||||
# To solve this, first try -pthread together with -lpthread for GCC
|
||||
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
|
||||
|
||||
AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread"])
|
||||
|
||||
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
*,*)
|
||||
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
|
||||
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
|
||||
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void *some_global = NULL;
|
||||
static void routine(void *a)
|
||||
{
|
||||
/* To avoid any unused-parameter or
|
||||
unused-but-set-parameter warning. */
|
||||
some_global = a;
|
||||
}
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;
|
||||
return i;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[
|
||||
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
|
||||
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
|
||||
],
|
||||
[
|
||||
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
|
||||
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
|
||||
]
|
||||
)
|
||||
])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
AC_SUBST([PTHREAD_CXX])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_POP
|
||||
])dnl AX_PTHREAD
|
||||
Executable
+582
@@ -0,0 +1,582 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_with_curses.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro checks whether a SysV or X/Open-compatible Curses library is
|
||||
# present, along with the associated header file. The NcursesW
|
||||
# (wide-character) library is searched for first, followed by Ncurses,
|
||||
# then the system-default plain Curses. The first library found is the
|
||||
# one returned. Finding libraries will first be attempted by using
|
||||
# pkg-config, and should the pkg-config files not be available, will
|
||||
# fallback to combinations of known flags itself.
|
||||
#
|
||||
# The following options are understood: --with-ncursesw, --with-ncurses,
|
||||
# --without-ncursesw, --without-ncurses. The "--with" options force the
|
||||
# macro to use that particular library, terminating with an error if not
|
||||
# found. The "--without" options simply skip the check for that library.
|
||||
# The effect on the search pattern is:
|
||||
#
|
||||
# (no options) - NcursesW, Ncurses, Curses
|
||||
# --with-ncurses --with-ncursesw - NcursesW only [*]
|
||||
# --without-ncurses --with-ncursesw - NcursesW only [*]
|
||||
# --with-ncursesw - NcursesW only [*]
|
||||
# --with-ncurses --without-ncursesw - Ncurses only [*]
|
||||
# --with-ncurses - NcursesW, Ncurses [**]
|
||||
# --without-ncurses --without-ncursesw - Curses only
|
||||
# --without-ncursesw - Ncurses, Curses
|
||||
# --without-ncurses - NcursesW, Curses
|
||||
#
|
||||
# [*] If the library is not found, abort the configure script.
|
||||
#
|
||||
# [**] If the second library (Ncurses) is not found, abort configure.
|
||||
#
|
||||
# The following preprocessor symbols may be defined by this macro if the
|
||||
# appropriate conditions are met:
|
||||
#
|
||||
# HAVE_CURSES - if any SysV or X/Open Curses library found
|
||||
# HAVE_CURSES_ENHANCED - if library supports X/Open Enhanced functions
|
||||
# HAVE_CURSES_COLOR - if library supports color (enhanced functions)
|
||||
# HAVE_CURSES_OBSOLETE - if library supports certain obsolete features
|
||||
# HAVE_NCURSESW - if NcursesW (wide char) library is to be used
|
||||
# HAVE_NCURSES - if the Ncurses library is to be used
|
||||
#
|
||||
# HAVE_CURSES_H - if <curses.h> is present and should be used
|
||||
# HAVE_NCURSESW_H - if <ncursesw.h> should be used
|
||||
# HAVE_NCURSES_H - if <ncurses.h> should be used
|
||||
# HAVE_NCURSESW_CURSES_H - if <ncursesw/curses.h> should be used
|
||||
# HAVE_NCURSES_CURSES_H - if <ncurses/curses.h> should be used
|
||||
#
|
||||
# (These preprocessor symbols are discussed later in this document.)
|
||||
#
|
||||
# The following output variables are defined by this macro; they are
|
||||
# precious and may be overridden on the ./configure command line:
|
||||
#
|
||||
# CURSES_LIBS - library to add to xxx_LDADD
|
||||
# CURSES_CFLAGS - include paths to add to xxx_CPPFLAGS
|
||||
#
|
||||
# In previous versions of this macro, the flags CURSES_LIB and
|
||||
# CURSES_CPPFLAGS were defined. These have been renamed, in keeping with
|
||||
# AX_WITH_CURSES's close bigger brother, PKG_CHECK_MODULES, which should
|
||||
# eventually supersede the use of AX_WITH_CURSES. Neither the library
|
||||
# listed in CURSES_LIBS, nor the flags in CURSES_CFLAGS are added to LIBS,
|
||||
# respectively CPPFLAGS, by default. You need to add both to the
|
||||
# appropriate xxx_LDADD/xxx_CPPFLAGS line in your Makefile.am. For
|
||||
# example:
|
||||
#
|
||||
# prog_LDADD = @CURSES_LIBS@
|
||||
# prog_CPPFLAGS = @CURSES_CFLAGS@
|
||||
#
|
||||
# If CURSES_LIBS is set on the configure command line (such as by running
|
||||
# "./configure CURSES_LIBS=-lmycurses"), then the only header searched for
|
||||
# is <curses.h>. If the user needs to specify an alternative path for a
|
||||
# library (such as for a non-standard NcurseW), the user should use the
|
||||
# LDFLAGS variable.
|
||||
#
|
||||
# The following shell variables may be defined by this macro:
|
||||
#
|
||||
# ax_cv_curses - set to "yes" if any Curses library found
|
||||
# ax_cv_curses_enhanced - set to "yes" if Enhanced functions present
|
||||
# ax_cv_curses_color - set to "yes" if color functions present
|
||||
# ax_cv_curses_obsolete - set to "yes" if obsolete features present
|
||||
#
|
||||
# ax_cv_ncursesw - set to "yes" if NcursesW library found
|
||||
# ax_cv_ncurses - set to "yes" if Ncurses library found
|
||||
# ax_cv_plaincurses - set to "yes" if plain Curses library found
|
||||
# ax_cv_curses_which - set to "ncursesw", "ncurses", "plaincurses" or "no"
|
||||
#
|
||||
# These variables can be used in your configure.ac to determine the level
|
||||
# of support you need from the Curses library. For example, if you must
|
||||
# have either Ncurses or NcursesW, you could include:
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
# if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
# AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
# fi
|
||||
#
|
||||
# If any Curses library will do (but one must be present and must support
|
||||
# color), you could use:
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
# if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then
|
||||
# AC_MSG_ERROR([requires an X/Open-compatible Curses library with color])
|
||||
# fi
|
||||
#
|
||||
# Certain preprocessor symbols and shell variables defined by this macro
|
||||
# can be used to determine various features of the Curses library. In
|
||||
# particular, HAVE_CURSES and ax_cv_curses are defined if the Curses
|
||||
# library found conforms to the traditional SysV and/or X/Open Base Curses
|
||||
# definition. Any working Curses library conforms to this level.
|
||||
#
|
||||
# HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the
|
||||
# library supports the X/Open Enhanced Curses definition. In particular,
|
||||
# the wide-character types attr_t, cchar_t and wint_t, the functions
|
||||
# wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES
|
||||
# are checked. The Ncurses library does NOT conform to this definition,
|
||||
# although NcursesW does.
|
||||
#
|
||||
# HAVE_CURSES_COLOR and ax_cv_curses_color are defined if the library
|
||||
# supports color functions and macros such as COLOR_PAIR, A_COLOR,
|
||||
# COLOR_WHITE, COLOR_RED and init_pair(). These are NOT part of the
|
||||
# X/Open Base Curses definition, but are part of the Enhanced set of
|
||||
# functions. The Ncurses library DOES support these functions, as does
|
||||
# NcursesW.
|
||||
#
|
||||
# HAVE_CURSES_OBSOLETE and ax_cv_curses_obsolete are defined if the
|
||||
# library supports certain features present in SysV and BSD Curses but not
|
||||
# defined in the X/Open definition. In particular, the functions
|
||||
# getattrs(), getcurx() and getmaxx() are checked.
|
||||
#
|
||||
# To use the HAVE_xxx_H preprocessor symbols, insert the following into
|
||||
# your system.h (or equivalent) header file:
|
||||
#
|
||||
# #if defined HAVE_NCURSESW_CURSES_H
|
||||
# # include <ncursesw/curses.h>
|
||||
# #elif defined HAVE_NCURSESW_H
|
||||
# # include <ncursesw.h>
|
||||
# #elif defined HAVE_NCURSES_CURSES_H
|
||||
# # include <ncurses/curses.h>
|
||||
# #elif defined HAVE_NCURSES_H
|
||||
# # include <ncurses.h>
|
||||
# #elif defined HAVE_CURSES_H
|
||||
# # include <curses.h>
|
||||
# #else
|
||||
# # error "SysV or X/Open-compatible Curses header file required"
|
||||
# #endif
|
||||
#
|
||||
# For previous users of this macro: you should not need to change anything
|
||||
# in your configure.ac or Makefile.am, as the previous (serial 10)
|
||||
# semantics are still valid. However, you should update your system.h (or
|
||||
# equivalent) header file to the fragment shown above. You are encouraged
|
||||
# also to make use of the extended functionality provided by this version
|
||||
# of AX_WITH_CURSES, as well as in the additional macros
|
||||
# AX_WITH_CURSES_PANEL, AX_WITH_CURSES_MENU and AX_WITH_CURSES_FORM.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Mark Pulford <mark@kyne.com.au>
|
||||
# Copyright (c) 2009 Damian Pietras <daper@daper.net>
|
||||
# Copyright (c) 2012 Reuben Thomas <rrt@sc3d.org>
|
||||
# Copyright (c) 2011 John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
#
|
||||
# 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 18
|
||||
|
||||
# internal function to factorize common code that is used by both ncurses
|
||||
# and ncursesw
|
||||
AC_DEFUN([_FIND_CURSES_FLAGS], [
|
||||
AC_MSG_CHECKING([for $1 via pkg-config])
|
||||
|
||||
AX_REQUIRE_DEFINED([PKG_CHECK_EXISTS])
|
||||
_PKG_CONFIG([_ax_cv_$1_libs], [libs], [$1])
|
||||
_PKG_CONFIG([_ax_cv_$1_cppflags], [cflags], [$1])
|
||||
|
||||
AS_IF([test "x$pkg_failed" = "xyes" || test "x$pkg_failed" = "xuntried"],[
|
||||
AC_MSG_RESULT([no])
|
||||
# No suitable .pc file found, have to find flags via fallback
|
||||
AC_CACHE_CHECK([for $1 via fallback], [ax_cv_$1], [
|
||||
AS_ECHO()
|
||||
pkg_cv__ax_cv_$1_libs="-l$1"
|
||||
pkg_cv__ax_cv_$1_cppflags="-D_GNU_SOURCE $CURSES_CFLAGS"
|
||||
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
|
||||
CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags"
|
||||
|
||||
AC_MSG_CHECKING([for initscr() with $pkg_cv__ax_cv_$1_libs])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[
|
||||
ax_cv_$1=yes
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
m4_if(
|
||||
[$1],[ncursesw],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfow"],
|
||||
[$1],[ncurses],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfo"]
|
||||
)
|
||||
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
|
||||
|
||||
AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[
|
||||
ax_cv_$1=yes
|
||||
],[
|
||||
ax_cv_$1=no
|
||||
])
|
||||
])
|
||||
],[
|
||||
ax_cv_$1=no
|
||||
])
|
||||
])
|
||||
],[
|
||||
AC_MSG_RESULT([yes])
|
||||
# Found .pc file, using its information
|
||||
LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs"
|
||||
CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags"
|
||||
ax_cv_$1=yes
|
||||
])
|
||||
])
|
||||
|
||||
AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES])
|
||||
AC_DEFUN([AX_WITH_CURSES], [
|
||||
AC_ARG_VAR([CURSES_LIBS], [linker library for Curses, e.g. -lcurses])
|
||||
AC_ARG_VAR([CURSES_CFLAGS], [preprocessor flags for Curses, e.g. -I/usr/include/ncursesw])
|
||||
AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses],
|
||||
[force the use of Ncurses or NcursesW])],
|
||||
[], [with_ncurses=check])
|
||||
AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw],
|
||||
[do not use NcursesW (wide character support)])],
|
||||
[], [with_ncursesw=check])
|
||||
|
||||
ax_saved_LIBS=$LIBS
|
||||
ax_saved_CPPFLAGS=$CPPFLAGS
|
||||
|
||||
AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes],
|
||||
[ax_with_plaincurses=no], [ax_with_plaincurses=check])
|
||||
|
||||
ax_cv_curses_which=no
|
||||
|
||||
# Test for NcursesW
|
||||
AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncursesw" != xno], [
|
||||
_FIND_CURSES_FLAGS([ncursesw])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncursesw
|
||||
CURSES_LIBS="$pkg_cv__ax_cv_ncursesw_libs"
|
||||
CURSES_CFLAGS="$pkg_cv__ax_cv_ncursesw_cppflags"
|
||||
AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
AC_CACHE_CHECK([for working ncursesw/curses.h], [ax_cv_header_ncursesw_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncursesw/curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncursesw_curses_h=yes],
|
||||
[ax_cv_header_ncursesw_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSESW_CURSES_H], [1], [Define to 1 if <ncursesw/curses.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncursesw.h], [ax_cv_header_ncursesw_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncursesw.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncursesw_h=yes],
|
||||
[ax_cv_header_ncursesw_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_h" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSESW_H], [1], [Define to 1 if <ncursesw.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h_with_ncursesw], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncurses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_h_with_ncursesw=yes],
|
||||
[ax_cv_header_ncurses_h_with_ncursesw=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_h_with_ncursesw" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if <ncurses.h> is present])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [
|
||||
AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
unset pkg_cv__ax_cv_ncursesw_libs
|
||||
unset pkg_cv__ax_cv_ncursesw_cppflags
|
||||
|
||||
# Test for Ncurses
|
||||
AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
_FIND_CURSES_FLAGS([ncurses])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncurses" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncurses
|
||||
CURSES_LIBS="$pkg_cv__ax_cv_ncurses_libs"
|
||||
CURSES_CFLAGS="$pkg_cv__ax_cv_ncurses_cppflags"
|
||||
AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses/curses.h], [ax_cv_header_ncurses_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <ncurses/curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_curses_h=yes],
|
||||
[ax_cv_header_ncurses_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_CURSES_H], [1], [Define to 1 if <ncurses/curses.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <ncurses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_h=yes],
|
||||
[ax_cv_header_ncurses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_h" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if <ncurses.h> is present])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xno && test "x$ax_cv_header_ncurses_h" = xno], [
|
||||
AC_MSG_WARN([could not find a working ncurses/curses.h or ncurses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
unset pkg_cv__ax_cv_ncurses_libs
|
||||
unset pkg_cv__ax_cv_ncurses_cppflags
|
||||
|
||||
# Test for plain Curses (or if CURSES_LIBS was set by user)
|
||||
AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
AS_IF([test "x$CURSES_LIBS" != x], [
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIBS"
|
||||
], [
|
||||
LIBS="$ax_saved_LIBS -lcurses"
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for Curses library], [ax_cv_plaincurses], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_plaincurses=yes], [ax_cv_plaincurses=no])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_plaincurses" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=plaincurses
|
||||
AS_IF([test "x$CURSES_LIBS" = x], [
|
||||
CURSES_LIBS="-lcurses"
|
||||
])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
# Check for base conformance (and header file)
|
||||
|
||||
AC_CACHE_CHECK([for working curses.h], [ax_cv_header_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
initscr();
|
||||
]])],
|
||||
[ax_cv_header_curses_h=yes],
|
||||
[ax_cv_header_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_curses_h" = xyes], [
|
||||
AC_DEFINE([HAVE_CURSES_H], [1], [Define to 1 if <curses.h> is present])
|
||||
|
||||
# Check for X/Open Enhanced conformance
|
||||
|
||||
AC_CACHE_CHECK([for X/Open Enhanced Curses conformance], [ax_cv_plaincurses_enhanced], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <curses.h>
|
||||
@%:@ifndef _XOPEN_CURSES
|
||||
@%:@error "this Curses library is not enhanced"
|
||||
"this Curses library is not enhanced"
|
||||
@%:@endif
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_plaincurses_enhanced=yes],
|
||||
[ax_cv_plaincurses_enhanced=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_enhanced" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
])
|
||||
|
||||
# Check for color functions
|
||||
|
||||
AC_CACHE_CHECK([for Curses color functions], [ax_cv_plaincurses_color], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_plaincurses_color=yes],
|
||||
[ax_cv_plaincurses_color=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_color" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
])
|
||||
|
||||
# Check for obsolete functions
|
||||
|
||||
AC_CACHE_CHECK([for obsolete Curses functions], [ax_cv_plaincurses_obsolete], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
]])],
|
||||
[ax_cv_plaincurses_obsolete=yes],
|
||||
[ax_cv_plaincurses_obsolete=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_obsolete" = xyes], [
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_curses_h" = xno], [
|
||||
AC_MSG_WARN([could not find a working curses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_curses" != xyes], [ax_cv_curses=no])
|
||||
AS_IF([test "x$ax_cv_curses_enhanced" != xyes], [ax_cv_curses_enhanced=no])
|
||||
AS_IF([test "x$ax_cv_curses_color" != xyes], [ax_cv_curses_color=no])
|
||||
AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no])
|
||||
|
||||
LIBS=$ax_saved_LIBS
|
||||
CPPFLAGS=$ax_saved_CPPFLAGS
|
||||
|
||||
unset ax_saved_LIBS
|
||||
unset ax_saved_CPPFLAGS
|
||||
])dnl
|
||||
+143
-121
@@ -1,15 +1,15 @@
|
||||
AC_DEFUN([TORRENT_CHECK_XFS], [
|
||||
AC_MSG_CHECKING(for XFS support)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <xfs/libxfs.h>
|
||||
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)
|
||||
@@ -21,9 +21,9 @@ AC_DEFUN([TORRENT_CHECK_XFS], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
[ --without-xfs Do not check for XFS filesystem support],
|
||||
AS_HELP_STRING([--without-xfs],[do not check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
fi
|
||||
], [
|
||||
@@ -34,7 +34,7 @@ AC_DEFUN([TORRENT_WITHOUT_XFS], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
[ --with-xfs Check for XFS filesystem support],
|
||||
AS_HELP_STRING([--with-xfs],[check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
@@ -46,13 +46,13 @@ AC_DEFUN([TORRENT_WITH_XFS], [
|
||||
AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
AC_MSG_CHECKING(for epoll support)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <sys/epoll.h>
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/epoll.h>
|
||||
int main() {
|
||||
int fd = epoll_create(100);
|
||||
return 0;
|
||||
}
|
||||
]],
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_EPOLL, 1, Use epoll.)
|
||||
AC_MSG_RESULT(yes)
|
||||
@@ -63,7 +63,7 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_EPOLL], [
|
||||
AC_ARG_WITH(epoll,
|
||||
[ --without-epoll Do not check for epoll support.],
|
||||
AS_HELP_STRING([--without-epoll],[do not check for epoll support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_EPOLL
|
||||
@@ -77,17 +77,18 @@ AC_DEFUN([TORRENT_WITHOUT_EPOLL], [
|
||||
AC_DEFUN([TORRENT_CHECK_KQUEUE], [
|
||||
AC_MSG_CHECKING(for kqueue support)
|
||||
|
||||
AC_LINK_IFELSE(
|
||||
[[#include <sys/time.h> /* Because OpenBSD's sys/event.h fails to compile otherwise. Yeah... */
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/time.h> /* Because OpenBSD's sys/event.h fails to compile otherwise. Yeah... */
|
||||
#include <sys/event.h>
|
||||
int main() {
|
||||
int fd = kqueue();
|
||||
return 0;
|
||||
}
|
||||
]],
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
|
||||
AC_MSG_RESULT(yes)
|
||||
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
@@ -96,33 +97,33 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
|
||||
AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
|
||||
AC_MSG_CHECKING(whether kqueue supports pipes and ptys)
|
||||
|
||||
AC_RUN_IFELSE(
|
||||
[[#include <fcntl.h>
|
||||
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 kevent ev@<:@2@:>@, ev_out@<:@2@:>@;
|
||||
struct timespec ts = { 0, 0 };
|
||||
int pfd[2], pty[2], kfd, n;
|
||||
char buffer[9001];
|
||||
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 (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 (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)
|
||||
], [
|
||||
@@ -133,20 +134,31 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_KQUEUE], [
|
||||
AC_ARG_WITH(kqueue,
|
||||
[ --with-kqueue enable kqueue. [[default=no]]],
|
||||
AS_HELP_STRING([--with-kqueue],[enable kqueue [[default=no]]]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_KQUEUE
|
||||
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
|
||||
AC_ARG_WITH(kqueue,
|
||||
AS_HELP_STRING([--without-kqueue],[do not check for kqueue support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_KQUEUE
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_KQUEUE
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
|
||||
AC_ARG_WITH(variable-fdset,
|
||||
|
||||
[ --without-variable-fdset do not use non-portable variable sized fd_set's.],
|
||||
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)
|
||||
@@ -160,14 +172,13 @@ AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
|
||||
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for fallocate)
|
||||
|
||||
AC_TRY_LINK([#include <fcntl.h>
|
||||
#include <linux/falloc.h>
|
||||
],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
|
||||
],
|
||||
[
|
||||
AC_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)
|
||||
])
|
||||
])
|
||||
@@ -176,13 +187,12 @@ AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for posix_fallocate)
|
||||
|
||||
AC_TRY_LINK([#include <fcntl.h>
|
||||
],[ posix_fallocate(0, 0, 0);
|
||||
],
|
||||
[
|
||||
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)
|
||||
])
|
||||
])
|
||||
@@ -190,7 +200,7 @@ AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
|
||||
AC_ARG_WITH(posix-fallocate,
|
||||
[ --with-posix-fallocate Check for and use posix_fallocate to allocate files.],
|
||||
AS_HELP_STRING([--with-posix-fallocate],[check for and use posix_fallocate to allocate files]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_POSIX_FALLOCATE
|
||||
@@ -198,33 +208,12 @@ AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_NCURSESW], [
|
||||
AC_ARG_WITH(ncursesw,
|
||||
[ --without-ncursesw Don't try to use wide char ncurses.],
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
AC_SEARCH_LIBS(add_wch, ncursesw,
|
||||
AC_DEFINE(HAVE_NCURSESW, 1, defined if ncurses wide character support is available),
|
||||
AC_SEARCH_LIBS(wbkgdset, ncurses curses,,echo "*** The ncurses library is required!";exit 1)
|
||||
)
|
||||
else
|
||||
AC_SEARCH_LIBS(wbkgdset, ncurses curses,,echo "*** The ncurses library is required!";exit 1)
|
||||
fi
|
||||
],[
|
||||
AC_SEARCH_LIBS(add_wch, ncursesw,
|
||||
AC_DEFINE(HAVE_NCURSESW, 1, defined if ncurses wide character support is available),
|
||||
AC_SEARCH_LIBS(wbkgdset, ncurses curses,,echo "*** The ncurses library is required!";exit 1)
|
||||
)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_STATVFS], [
|
||||
AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h)
|
||||
|
||||
AC_MSG_CHECKING(for statvfs)
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#if HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
@@ -234,12 +223,11 @@ AC_DEFUN([TORRENT_CHECK_STATVFS], [
|
||||
#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)
|
||||
@@ -248,8 +236,7 @@ AC_DEFUN([TORRENT_CHECK_STATVFS], [
|
||||
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
|
||||
])
|
||||
@@ -260,8 +247,7 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
|
||||
|
||||
AC_MSG_CHECKING(for statfs)
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
@@ -271,12 +257,11 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
|
||||
#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)
|
||||
@@ -285,8 +270,7 @@ AC_DEFUN([TORRENT_CHECK_STATFS], [
|
||||
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
|
||||
])
|
||||
@@ -304,7 +288,7 @@ AC_DEFUN([TORRENT_DISABLED_STATFS], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
|
||||
AC_ARG_WITH(statvfs,
|
||||
[ --without-statvfs Don't try to use statvfs to find free diskspace.],
|
||||
AS_HELP_STRING([--without-statvfs],[don't try to use statvfs to find free diskspace]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_STATVFS
|
||||
@@ -319,7 +303,7 @@ AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATFS], [
|
||||
AC_ARG_WITH(statfs,
|
||||
[ --without-statfs Don't try to use statfs to find free diskspace.],
|
||||
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
|
||||
@@ -341,7 +325,7 @@ AC_DEFUN([TORRENT_WITHOUT_STATFS], [
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_ARG_WITH(address-space,
|
||||
AC_HELP_STRING([--with-address-space=MB], [Change the default address space size, default 1024 MB.]),
|
||||
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
|
||||
[
|
||||
if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
|
||||
@@ -360,30 +344,9 @@ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_TR1], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(for TR1 support)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <tr1/unordered_map>
|
||||
class Foo;
|
||||
typedef std::tr1::unordered_map<Foo*, int> Bar;
|
||||
]],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_TR1, 1, Define to 1 if your C++ library supports the extensions from Technical Report 1)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
]
|
||||
)
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
AC_ARG_WITH(fastcgi,
|
||||
[ --with-fastcgi=PATH Enable FastCGI RPC support. (DO NOT USE)],
|
||||
AS_HELP_STRING([--with-fastcgi=PATH],[enable FastCGI RPC support (DO NOT USE)]),
|
||||
[
|
||||
AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
|
||||
|
||||
@@ -394,13 +357,10 @@ AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
LIBS="$LIBS -lfcgi"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <fcgiapp.h>
|
||||
],[ FCGX_Init(); ],
|
||||
[
|
||||
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.)
|
||||
])
|
||||
@@ -411,13 +371,10 @@ AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
CXXFLAGS="$CXXFLAGS -I$withval/include"
|
||||
LIBS="$LIBS -lfcgi -L$withval/lib"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <fcgiapp.h>
|
||||
],[ FCGX_Init(); ],
|
||||
[
|
||||
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.)
|
||||
])
|
||||
@@ -432,7 +389,7 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
|
||||
AC_MSG_CHECKING(for XMLRPC-C)
|
||||
|
||||
AC_ARG_WITH(xmlrpc-c,
|
||||
[ --with-xmlrpc-c=PATH Enable XMLRPC-C support.],
|
||||
AS_HELP_STRING([--with-xmlrpc-c=PATH],[enable XMLRPC-C support]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -448,12 +405,10 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
|
||||
CXXFLAGS="$CXXFLAGS `$xmlrpc_cc_prg --cflags server-util`"
|
||||
LIBS="$LIBS `$xmlrpc_cc_prg server-util --libs`"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <xmlrpc-c/server.h>
|
||||
],[ xmlrpc_registry_new(NULL); ],
|
||||
[
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <xmlrpc-c/server.h>
|
||||
]], [[ xmlrpc_registry_new(NULL); ]])],[
|
||||
AC_MSG_RESULT(ok)
|
||||
], [
|
||||
],[
|
||||
AC_MSG_RESULT(failed)
|
||||
AC_MSG_ERROR(Could not compile XMLRPC-C test.)
|
||||
])
|
||||
@@ -470,3 +425,70 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
|
||||
AC_MSG_RESULT(ignored)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_INOTIFY], [
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
AC_CHECK_HEADERS([sys/inotify.h mcheck.h])
|
||||
AC_MSG_CHECKING([whether sys/inotify.h actually works])
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/inotify.h>
|
||||
int main(int,const char**) { return (-1 == inotify_init()); }])
|
||||
],[
|
||||
AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
|
||||
AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(failed)]
|
||||
)
|
||||
|
||||
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([[
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
]], [[
|
||||
pthread_t t;
|
||||
pthread_setname_np(t, "foo");
|
||||
]])],[
|
||||
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_GENERIC, 1, The function to set pthread name has a pthread_t argumet.)
|
||||
AC_MSG_RESULT(generic)
|
||||
],[
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
]],[[
|
||||
pthread_t t;
|
||||
pthread_setname_np("foo");
|
||||
]])],[
|
||||
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_DARWIN, 1, The function to set pthread name has no pthread argument.)
|
||||
AC_MSG_RESULT(darwin)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
AC_MSG_CHECKING([for pthread_setname_no])
|
||||
|
||||
AC_ARG_ENABLE(pthread-setname-np,
|
||||
AS_HELP_STRING([--disable-pthread-setname-np],[disable pthread_setname_np]),
|
||||
[
|
||||
if test "$enableval" = "no"; then
|
||||
AC_MSG_RESULT(disabled)
|
||||
else
|
||||
AC_MSG_RESULT(checking)
|
||||
TORRENT_CHECK_PTHREAD_SETNAME_NP
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_PTHREAD_SETNAME_NP
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
+63
-127
@@ -1,56 +1,7 @@
|
||||
AC_DEFUN([TORRENT_CHECK_CXXFLAGS], [
|
||||
|
||||
AC_MSG_CHECKING([for user-defined CXXFLAGS])
|
||||
|
||||
if test -n "$CXXFLAGS"; then
|
||||
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
|
||||
else
|
||||
CXXFLAGS="-O2 -Wall"
|
||||
AC_MSG_RESULT([default "$CXXFLAGS"])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_DEBUG], [
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug enable debug information [[default=yes]]],
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -DNDEBUG"
|
||||
fi
|
||||
],[
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_WERROR], [
|
||||
AC_ARG_ENABLE(werror,
|
||||
[ --enable-werror enable the -Werror and -Wall flag [[default=no]]],
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -Werror -Wall"
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_EXTRA_DEBUG], [
|
||||
AC_ARG_ENABLE(extra-debug,
|
||||
[ --enable-extra-debug enable extra debugging checks. [[default=no]]],
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_SYSROOT], [
|
||||
AC_ARG_WITH(sysroot,
|
||||
[ --with-sysroot=PATH compile and link with a specific sysroot.],
|
||||
AS_HELP_STRING([--with-sysroot=PATH],
|
||||
[compile and link with a specific sysroot]),
|
||||
[
|
||||
AC_MSG_CHECKING(for sysroot)
|
||||
|
||||
@@ -72,7 +23,8 @@ AC_DEFUN([TORRENT_WITH_SYSROOT], [
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ARCH], [
|
||||
AC_ARG_ENABLE(arch,
|
||||
[ --enable-arch=ARCH comma seprated list of architectures to compile for.],
|
||||
AS_HELP_STRING([--enable-arch=ARCH],
|
||||
[comma seprated list of architectures to compile for]),
|
||||
[
|
||||
AC_MSG_CHECKING(for target architectures)
|
||||
|
||||
@@ -95,48 +47,28 @@ AC_DEFUN([TORRENT_ENABLE_ARCH], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_OTFD], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(for proper overloaded template function disambiguation)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[template <typename T> void f(T&) {}
|
||||
template <typename T> void f(T*) {}
|
||||
int main() { int *i = 0; f(*i); f(i); }
|
||||
]],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR([your compiler does not properly handle overloaded template function disambiguation])
|
||||
])
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(signedness of mincore parameter)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <sys/types.h>
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
void f() { mincore((char*)0, 0, (unsigned char*)0); }
|
||||
]],
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_MINCORE, 1, Use mincore)
|
||||
AC_DEFINE(USE_MINCORE_UNSIGNED, 1, use unsigned char* in mincore)
|
||||
AC_MSG_RESULT(unsigned)
|
||||
],
|
||||
[
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <sys/types.h>
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
void f() { mincore((char*)0, 0, (char*)0); }
|
||||
]],
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_MINCORE, 1, Use mincore)
|
||||
AC_DEFINE(USE_MINCORE_UNSIGNED, 0, use char* in mincore)
|
||||
@@ -152,7 +84,8 @@ AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
|
||||
|
||||
AC_DEFUN([TORRENT_MINCORE], [
|
||||
AC_ARG_ENABLE(mincore,
|
||||
[ --disable-mincore disable mincore check [[default=enable]]],
|
||||
AS_HELP_STRING([--disable-mincore],
|
||||
[disable mincore check [[default=enable]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
TORRENT_MINCORE_SIGNEDNESS()
|
||||
@@ -168,11 +101,11 @@ AC_DEFUN([TORRENT_MINCORE], [
|
||||
AC_DEFUN([TORRENT_CHECK_MADVISE], [
|
||||
AC_MSG_CHECKING(for madvise)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
void f() { static char test[1024]; madvise((void *)test, sizeof(test), MADV_NORMAL); }
|
||||
]],
|
||||
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); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_MADVISE, 1, Use madvise)
|
||||
@@ -184,10 +117,9 @@ AC_DEFUN([TORRENT_CHECK_MADVISE], [
|
||||
AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
|
||||
AC_MSG_CHECKING(for __builtin_popcount)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[
|
||||
void f() { __builtin_popcount(0); }
|
||||
]],
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int f() { return __builtin_popcount(0); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_BUILTIN_POPCOUNT, 1, Use __builtin_popcount.)
|
||||
@@ -199,12 +131,12 @@ AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
|
||||
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
|
||||
AC_MSG_CHECKING(for cacheline)
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[[#include <stdlib.h>
|
||||
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.)
|
||||
@@ -221,34 +153,19 @@ dnl Need to fix this so that it uses the stuff defined by the system.
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_EXECINFO], [
|
||||
AC_MSG_CHECKING(for execinfo.h)
|
||||
|
||||
AC_RUN_IFELSE(
|
||||
[[#include <execinfo.h>
|
||||
int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
|
||||
]],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_EXECINFO, 1, Use execinfo.h)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_ALIGNED], [
|
||||
AC_MSG_CHECKING(the byte alignment)
|
||||
|
||||
AC_RUN_IFELSE(
|
||||
[[#include <inttypes.h>
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
#include <inttypes.h>
|
||||
int main() {
|
||||
char buf[8] = { 0, 0, 0, 0, 1, 0, 0, 0 };
|
||||
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)
|
||||
], [
|
||||
@@ -260,7 +177,8 @@ AC_DEFUN([TORRENT_CHECK_ALIGNED], [
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
|
||||
AC_ARG_ENABLE(aligned,
|
||||
[ --enable-aligned enable alignment safe code [[default=check]]],
|
||||
AS_HELP_STRING([--enable-aligned],
|
||||
[enable alignment safe code [[default=check]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
@@ -271,27 +189,45 @@ AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
|
||||
AC_MSG_CHECKING([if instrumentation should be included])
|
||||
|
||||
AC_ARG_ENABLE(instrumentation,
|
||||
AS_HELP_STRING([--disable-instrumentation],
|
||||
[disable instrumentation [[default=enabled]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],[
|
||||
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
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_DISABLE_IPV6], [
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --enable-ipv6 disable ipv6 [[default=no]]],
|
||||
AS_HELP_STRING([--enable-ipv6],
|
||||
[enable ipv6 [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(RAK_USE_INET6, 1, enable ipv6 stuff)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_TR1], [
|
||||
AC_ARG_ENABLE(std_tr1,
|
||||
[ --disable-std_tr1 disable check for support for TR1 [[default=enable]]],
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
TORRENT_CHECK_TR1()
|
||||
else
|
||||
AC_MSG_CHECKING(for TR1 support)
|
||||
AC_MSG_RESULT(disabled)
|
||||
fi
|
||||
],[
|
||||
TORRENT_CHECK_TR1()
|
||||
])
|
||||
])
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
AC_DEFUN([RAK_CHECK_CFLAGS], [
|
||||
|
||||
AC_MSG_CHECKING([for user-defined CFLAGS])
|
||||
|
||||
if test "$CFLAGS" = ""; then
|
||||
unset CFLAGS
|
||||
AC_MSG_RESULT([undefined])
|
||||
else
|
||||
AC_MSG_RESULT([user-defined "$CFLAGS"])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_CHECK_CXXFLAGS], [
|
||||
|
||||
AC_MSG_CHECKING([for user-defined CXXFLAGS])
|
||||
|
||||
if test "$CXXFLAGS" = ""; then
|
||||
unset CXXFLAGS
|
||||
AC_MSG_RESULT([undefined])
|
||||
else
|
||||
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_ENABLE_DEBUG], [
|
||||
AC_ARG_ENABLE(debug,
|
||||
AS_HELP_STRING([--enable-debug],[enable debug information [[default=yes]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -DNDEBUG"
|
||||
fi
|
||||
],[
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_ENABLE_WERROR], [
|
||||
AC_ARG_ENABLE(werror,
|
||||
AS_HELP_STRING([--enable-werror],[enable the -Werror and -Wall flags [[default -Wall only]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -Werror -Wall"
|
||||
fi
|
||||
],[
|
||||
CXXFLAGS="$CXXFLAGS -Wall"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_ENABLE_EXTRA_DEBUG], [
|
||||
AC_ARG_ENABLE(extra-debug,
|
||||
AS_HELP_STRING([--enable-extra-debug],[enable extra debugging checks [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,38 @@
|
||||
AC_DEFUN([TORRENT_CHECK_OPENSSL],
|
||||
[
|
||||
PKG_CHECK_MODULES(OPENSSL, libcrypto,
|
||||
CXXFLAGS="$CXXFLAGS $OPENSSL_CFLAGS";
|
||||
LIBS="$LIBS $OPENSSL_LIBS")
|
||||
|
||||
AC_DEFINE(USE_OPENSSL, 1, Using OpenSSL.)
|
||||
AC_DEFINE(USE_OPENSSL_SHA, 1, Using OpenSSL's SHA1 implementation.)
|
||||
]
|
||||
)
|
||||
|
||||
AC_DEFUN([TORRENT_ARG_OPENSSL],
|
||||
[
|
||||
AC_ARG_ENABLE(openssl,
|
||||
[ --disable-openssl Don't use OpenSSL's SHA1 implementation.],
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
TORRENT_CHECK_OPENSSL
|
||||
else
|
||||
AC_DEFINE(USE_NSS_SHA, 1, Using Mozilla's SHA1 implementation.)
|
||||
fi
|
||||
],[
|
||||
TORRENT_CHECK_OPENSSL
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
AC_DEFUN([TORRENT_ARG_CYRUS_RC4],
|
||||
[
|
||||
AC_ARG_ENABLE(cyrus-rc4,
|
||||
[ --enable-cyrus-rc4=PFX Use Cyrus RC4 implementation.],
|
||||
[
|
||||
CXXFLAGS="$CXXFLAGS -I${enableval}/include";
|
||||
LIBS="$LIBS -lrc4 -L${enableval}/lib"
|
||||
AC_DEFINE(USE_CYRUS_RC4, 1, Using Cyrus RC4 implementation.)
|
||||
])
|
||||
]
|
||||
)
|
||||
+162
-25
@@ -1,14 +1,166 @@
|
||||
SUBDIRS = \
|
||||
core \
|
||||
display \
|
||||
input \
|
||||
rpc \
|
||||
ui \
|
||||
utils
|
||||
|
||||
noinst_LIBRARIES = libsub_root.a
|
||||
bin_PROGRAMS = rtorrent
|
||||
|
||||
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 \
|
||||
core/download.h \
|
||||
core/download_factory.cc \
|
||||
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 \
|
||||
core/view_manager.cc \
|
||||
core/view_manager.h \
|
||||
\
|
||||
display/attributes.h \
|
||||
display/canvas.cc \
|
||||
display/canvas.h \
|
||||
display/frame.cc \
|
||||
display/frame.h \
|
||||
display/manager.cc \
|
||||
display/manager.h \
|
||||
display/utils.cc \
|
||||
display/utils.h \
|
||||
display/text_element.h \
|
||||
display/text_element_list.cc \
|
||||
display/text_element_list.h \
|
||||
display/text_element_string.cc \
|
||||
display/text_element_string.h \
|
||||
display/text_element_value.cc \
|
||||
display/text_element_value.h \
|
||||
display/window.cc \
|
||||
display/window.h \
|
||||
display/window_download_chunks_seen.cc \
|
||||
display/window_download_chunks_seen.h \
|
||||
display/window_download_list.cc \
|
||||
display/window_download_list.h \
|
||||
display/window_download_statusbar.cc \
|
||||
display/window_download_statusbar.h \
|
||||
display/window_download_transfer_list.cc \
|
||||
display/window_download_transfer_list.h \
|
||||
display/window_file_list.cc \
|
||||
display/window_file_list.h \
|
||||
display/window_http_queue.cc \
|
||||
display/window_http_queue.h \
|
||||
display/window_input.cc \
|
||||
display/window_input.h \
|
||||
display/window_log.cc \
|
||||
display/window_log.h \
|
||||
display/window_log_complete.cc \
|
||||
display/window_log_complete.h \
|
||||
display/window_peer_list.cc \
|
||||
display/window_peer_list.h \
|
||||
display/window_statusbar.cc \
|
||||
display/window_statusbar.h \
|
||||
display/window_string_list.cc \
|
||||
display/window_string_list.h \
|
||||
display/window_text.cc \
|
||||
display/window_text.h \
|
||||
display/window_title.cc \
|
||||
display/window_title.h \
|
||||
display/window_tracker_list.cc \
|
||||
display/window_tracker_list.h \
|
||||
\
|
||||
input/bindings.cc \
|
||||
input/bindings.h \
|
||||
input/input_event.cc \
|
||||
input/input_event.h \
|
||||
input/manager.cc \
|
||||
input/manager.h \
|
||||
input/path_input.cc \
|
||||
input/path_input.h \
|
||||
input/text_input.cc \
|
||||
input/text_input.h \
|
||||
\
|
||||
rpc/command.h \
|
||||
rpc/command.cc \
|
||||
rpc/command_impl.h \
|
||||
rpc/command_map.cc \
|
||||
rpc/command_map.h \
|
||||
rpc/command_scheduler.cc \
|
||||
rpc/command_scheduler.h \
|
||||
rpc/command_scheduler_item.cc \
|
||||
rpc/command_scheduler_item.h \
|
||||
rpc/exec_file.cc \
|
||||
rpc/exec_file.h \
|
||||
rpc/fixed_key.h \
|
||||
rpc/ip_table_list.h \
|
||||
rpc/object_storage.cc \
|
||||
rpc/object_storage.h \
|
||||
rpc/parse.cc \
|
||||
rpc/parse.h \
|
||||
rpc/parse_commands.cc \
|
||||
rpc/parse_commands.h \
|
||||
rpc/parse_options.cc \
|
||||
rpc/parse_options.h \
|
||||
rpc/scgi.cc \
|
||||
rpc/scgi.h \
|
||||
rpc/scgi_task.cc \
|
||||
rpc/scgi_task.h \
|
||||
rpc/xmlrpc.h \
|
||||
rpc/xmlrpc.cc \
|
||||
\
|
||||
ui/download.cc \
|
||||
ui/download.h \
|
||||
ui/download_list.cc \
|
||||
ui/download_list.h \
|
||||
ui/element_base.h \
|
||||
ui/element_base.cc \
|
||||
ui/element_chunks_seen.cc \
|
||||
ui/element_chunks_seen.h \
|
||||
ui/element_download_list.cc \
|
||||
ui/element_download_list.h \
|
||||
ui/element_file_list.cc \
|
||||
ui/element_file_list.h \
|
||||
ui/element_log_complete.cc \
|
||||
ui/element_log_complete.h \
|
||||
ui/element_menu.cc \
|
||||
ui/element_menu.h \
|
||||
ui/element_peer_list.cc \
|
||||
ui/element_peer_list.h \
|
||||
ui/element_string_list.cc \
|
||||
ui/element_string_list.h \
|
||||
ui/element_text.cc \
|
||||
ui/element_text.h \
|
||||
ui/element_tracker_list.cc \
|
||||
ui/element_tracker_list.h \
|
||||
ui/element_transfer_list.cc \
|
||||
ui/element_transfer_list.h \
|
||||
ui/root.cc \
|
||||
ui/root.h \
|
||||
\
|
||||
utils/directory.cc \
|
||||
utils/directory.h \
|
||||
utils/file_status_cache.cc \
|
||||
utils/file_status_cache.h \
|
||||
utils/list_focus.h \
|
||||
utils/lockfile.cc \
|
||||
utils/lockfile.h \
|
||||
utils/socket_fd.cc \
|
||||
utils/socket_fd.h \
|
||||
\
|
||||
command_download.cc \
|
||||
command_dynamic.cc \
|
||||
command_events.cc \
|
||||
@@ -18,6 +170,7 @@ libsub_root_a_SOURCES = \
|
||||
command_helpers.h \
|
||||
command_groups.cc \
|
||||
command_local.cc \
|
||||
command_logging.cc \
|
||||
command_network.cc \
|
||||
command_peer.cc \
|
||||
command_throttle.cc \
|
||||
@@ -34,23 +187,7 @@ libsub_root_a_SOURCES = \
|
||||
signal_handler.h \
|
||||
thread_base.cc \
|
||||
thread_base.h \
|
||||
thread_main.cc \
|
||||
thread_main.h \
|
||||
thread_worker.cc \
|
||||
thread_worker.h
|
||||
|
||||
bin_PROGRAMS = rtorrent
|
||||
|
||||
rtorrent_LDADD = \
|
||||
libsub_root.a \
|
||||
ui/libsub_ui.a \
|
||||
core/libsub_core.a \
|
||||
display/libsub_display.a \
|
||||
input/libsub_input.a \
|
||||
rpc/libsub_rpc.a \
|
||||
utils/libsub_utils.a
|
||||
|
||||
rtorrent_SOURCES = \
|
||||
main.cc
|
||||
|
||||
INCLUDES = -I$(srcdir) -I$(top_srcdir)
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
|
||||
|
||||
+80
-27
@@ -138,10 +138,10 @@ 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)
|
||||
// control->core()->push_log("create_link failed: " + std::string(rak::error_number::current().c_str()));
|
||||
// control->core()->push_log("create_link failed: " + std::string(rak::error_number::current().c_str()) + " to " + target);
|
||||
; // Disabled.
|
||||
if (symlink(target.c_str(), link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@@ -150,9 +150,10 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
|
||||
rak::error_number::clear_global();
|
||||
|
||||
if (!fileStat.update_link(link) || !fileStat.is_link() ||
|
||||
unlink(link.c_str()) == -1)
|
||||
; // control->core()->push_log("delete_link failed: " + std::string(rak::error_number::current().c_str()));
|
||||
|
||||
unlink(link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -273,6 +274,41 @@ retrieve_d_custom_throw(core::Download* download, const std::string& key) {
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom_if_z(core::Download* download, const torrent::Object::list_type& args) {
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
if (itr == args.end())
|
||||
throw torrent::bencode_error("d.custom.if_z: Missing key argument.");
|
||||
const std::string& key = (itr++)->as_string();
|
||||
if (key.empty())
|
||||
throw torrent::bencode_error("d.custom.if_z: Empty key argument.");
|
||||
if (itr == args.end())
|
||||
throw torrent::bencode_error("d.custom.if_z: Missing default argument.");
|
||||
|
||||
try {
|
||||
const std::string& val = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
|
||||
return val.empty() ? itr->as_string() : val;
|
||||
} catch (torrent::bencode_error& e) {
|
||||
return itr->as_string();
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::Object::list_type& args) {
|
||||
if (args.begin() != args.end())
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_bitfield(core::Download* download) {
|
||||
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
|
||||
@@ -283,21 +319,12 @@ retrieve_d_bitfield(core::Download* download) {
|
||||
return torrent::Object(rak::transform_hex(bitField->begin(), bitField->end()));
|
||||
}
|
||||
|
||||
// Just a helper function atm.
|
||||
torrent::Object
|
||||
cmd_d_initialize_logs(core::Download* download) {
|
||||
download->info()->signal_network_log().connect(sigc::mem_fun(control->core(), &core::Manager::push_log_complete));
|
||||
download->info()->signal_storage_error().connect(sigc::mem_fun(control->core(), &core::Manager::push_log_complete));
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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_CONNECTION_WARN, "Could not resolve hostname for added peer.");
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "could not resolve hostname for added peer");
|
||||
} else {
|
||||
m_download->download()->add_peer(sa, m_port);
|
||||
}
|
||||
@@ -316,7 +343,10 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
if (download->download()->info()->is_private())
|
||||
throw torrent::input_error("Download is private.");
|
||||
|
||||
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
|
||||
ret = std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", host, &port, &dummy);
|
||||
|
||||
if (ret < 1)
|
||||
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
|
||||
|
||||
if (ret == 1)
|
||||
port = 6881;
|
||||
@@ -326,7 +356,23 @@ 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_inet, SOCK_STREAM, call_add_d_peer_t(download, port));
|
||||
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_chunks_seen(core::Download* download) {
|
||||
const uint8_t* seen = download->download()->chunks_seen();
|
||||
|
||||
if (seen == NULL)
|
||||
return std::string();
|
||||
|
||||
uint32_t size = download->download()->file_list()->size_chunks();
|
||||
|
||||
std::string result;
|
||||
result.resize(size * 2);
|
||||
|
||||
rak::transform_hex((const char*)seen, (const char*)seen + size, result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -362,7 +408,7 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(), cLast = args.end(); cItr != args.end(); cItr++) {
|
||||
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);
|
||||
}
|
||||
@@ -387,7 +433,7 @@ t_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
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();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(), cLast = args.end(); cItr != args.end(); cItr++) {
|
||||
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);
|
||||
|
||||
@@ -415,7 +461,7 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
itr != last; itr++) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(), cLast = args.end(); cItr != args.end(); cItr++) {
|
||||
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);
|
||||
@@ -675,6 +721,7 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.is_pex_active", CMD2_ON_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_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));
|
||||
@@ -698,6 +745,9 @@ initialize_command_download() {
|
||||
CMD2_DL_STRING("d.custom", std::bind(&retrieve_d_custom, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING("d.custom_throw", std::bind(&retrieve_d_custom_throw, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.set", std::bind(&apply_d_custom, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.if_z", std::bind(&retrieve_d_custom_if_z, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.keys", std::bind(&retrieve_d_custom_map, std::placeholders::_1, true, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.items", std::bind(&retrieve_d_custom_map, std::placeholders::_1, false, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom1", "rtorrent", "custom1");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom2", "rtorrent", "custom2");
|
||||
@@ -814,13 +864,18 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.size_pex", CMD2_ON_DL(size_pex));
|
||||
CMD2_DL ("d.max_size_pex", CMD2_ON_DL(max_size_pex));
|
||||
|
||||
CMD2_DL ("d.chunks_seen", std::bind(&d_chunks_seen, std::placeholders::_1));
|
||||
|
||||
CMD2_DL ("d.completed_bytes", CMD2_ON_FL(completed_bytes));
|
||||
CMD2_DL ("d.completed_chunks", CMD2_ON_FL(completed_chunks));
|
||||
CMD2_DL ("d.left_bytes", CMD2_ON_FL(left_bytes));
|
||||
|
||||
CMD2_DL ("d.wanted_chunks", CMD2_ON_DATA(wanted_chunks));
|
||||
|
||||
CMD2_DL_V ("d.tracker_announce", std::bind(&torrent::Download::manual_request, CMD2_BIND_DL, false));
|
||||
// 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 ("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));
|
||||
// TODO: Deprecate 'd.tracker_focus'.
|
||||
@@ -849,12 +904,10 @@ initialize_command_download() {
|
||||
// std::bind(&core::Download::main, std::placeholders::_1)),
|
||||
// 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", std::bind(&cg_d_group, std::placeholders::_1));
|
||||
CMD2_DL ("d.group.name", std::bind(&cg_d_group, std::placeholders::_1));
|
||||
CMD2_DL_V ("d.group.set", std::bind(&cg_d_group_set, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.initialize_logs", std::bind(&cmd_d_initialize_logs, std::placeholders::_1));
|
||||
|
||||
CMD2_DL_LIST ("f.multicall", std::bind(&f_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("p.multicall", std::bind(&p_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("t.multicall", std::bind(&t_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
+99
-82
@@ -37,11 +37,37 @@
|
||||
#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 "rpc/parse.h"
|
||||
#include "rpc/parse_options.h"
|
||||
|
||||
static std::vector<std::pair<const char*, int>> object_storage_flags = {
|
||||
{ "multi", rpc::object_storage::flag_multi_type },
|
||||
{ "simple", rpc::object_storage::flag_function_type },
|
||||
{ "value", rpc::object_storage::flag_value_type },
|
||||
{ "bool", rpc::object_storage::flag_bool_type },
|
||||
{ "string", rpc::object_storage::flag_string_type },
|
||||
{ "list", rpc::object_storage::flag_list_type },
|
||||
|
||||
{ "static", rpc::object_storage::flag_static },
|
||||
{ "private", rpc::object_storage::flag_private },
|
||||
{ "const", rpc::object_storage::flag_constant },
|
||||
{ "rlookup", rpc::object_storage::flag_rlookup }
|
||||
};
|
||||
|
||||
static int
|
||||
object_storage_parse_flag(const std::string& flag) {
|
||||
for (auto f : object_storage_flags)
|
||||
if (f.first == flag)
|
||||
return f.second;
|
||||
|
||||
throw torrent::input_error("unknown flag");
|
||||
}
|
||||
|
||||
std::string
|
||||
system_method_generate_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
|
||||
@@ -120,7 +146,7 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
const std::string& rawKey = (itrArgs++)->as_string();
|
||||
|
||||
if (rawKey.empty() ||
|
||||
control->object_storage()->find_local(torrent::raw_string::from_string(rawKey)) != control->object_storage()->end(0) ||
|
||||
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"))
|
||||
throw torrent::input_error("Invalid key.");
|
||||
|
||||
@@ -137,34 +163,47 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
case rpc::object_storage::flag_function_type:
|
||||
system_method_generate_command2(&value, itrArgs, args.end());
|
||||
break;
|
||||
case rpc::object_storage::flag_list_type:
|
||||
break;
|
||||
case rpc::object_storage::flag_multi_type:
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Invalid type.");
|
||||
}
|
||||
|
||||
int cmd_flags = 0;
|
||||
// We must initialize this varriable to prevent a critical memory leak
|
||||
int cmd_flags = rpc::CommandMap::flag_delete_key;
|
||||
|
||||
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;
|
||||
|
||||
rpc::object_storage::iterator obj_itr = control->object_storage()->insert_str(rawKey, value, flags);
|
||||
if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_list_type) {
|
||||
torrent::Object valueList = torrent::Object::create_list();
|
||||
torrent::Object::list_type& valueListType = valueList.as_list();
|
||||
|
||||
if ((itrArgs)->is_list())
|
||||
valueListType = (itrArgs)->as_list();
|
||||
|
||||
control->object_storage()->insert_str(rawKey, valueList, flags);
|
||||
} else {
|
||||
control->object_storage()->insert_str(rawKey, value, flags);
|
||||
}
|
||||
|
||||
if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_function_type ||
|
||||
(flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_multi_type) {
|
||||
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type> >::type>
|
||||
(create_new_key<0>(rawKey, ""),
|
||||
(create_new_key(rawKey),
|
||||
std::bind(&rpc::object_storage::call_function_str, control->object_storage(),
|
||||
rawKey, std::placeholders::_1, std::placeholders::_2),
|
||||
rawKey, 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<0>(rawKey, ""),
|
||||
(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);
|
||||
@@ -206,6 +245,13 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
&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);
|
||||
break;
|
||||
case rpc::object_storage::flag_function_type:
|
||||
case rpc::object_storage::flag_multi_type:
|
||||
default: break;
|
||||
@@ -242,88 +288,33 @@ system_method_insert(const torrent::Object::list_type& args) {
|
||||
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));
|
||||
|
||||
const std::string& options = itrArgs->as_string();
|
||||
|
||||
if (options.find("private") != std::string::npos)
|
||||
if ((new_flags & rpc::object_storage::flag_private))
|
||||
flags &= ~rpc::CommandMap::flag_public_xmlrpc;
|
||||
if (options.find("const") != std::string::npos)
|
||||
|
||||
if ((new_flags & rpc::object_storage::flag_constant))
|
||||
flags &= ~rpc::CommandMap::flag_modifiable;
|
||||
|
||||
if (options.find("multi") != std::string::npos) {
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
|
||||
if ((new_flags & rpc::object_storage::flag_function_type) ||
|
||||
(new_flags & rpc::object_storage::flag_multi_type)) {
|
||||
new_args.push_back(system_method_generate_command(++itrArgs, args.end()));
|
||||
|
||||
int new_flags = rpc::object_storage::flag_multi_type;
|
||||
|
||||
if (options.find("static") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_static;
|
||||
if (options.find("private") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_private;
|
||||
if (options.find("const") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_constant;
|
||||
if (options.find("rlookup") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_rlookup;
|
||||
|
||||
return system_method_insert_object(new_args, new_flags);
|
||||
|
||||
} else if (options.find("simple") != std::string::npos) {
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
new_args.push_back(system_method_generate_command(++itrArgs, args.end()));
|
||||
|
||||
int new_flags = rpc::object_storage::flag_function_type;
|
||||
|
||||
if (options.find("static") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_static;
|
||||
if (options.find("private") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_private;
|
||||
if (options.find("const") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_constant;
|
||||
|
||||
return system_method_insert_object(new_args, new_flags);
|
||||
|
||||
} else if (options.find("value") != std::string::npos ||
|
||||
options.find("bool") != std::string::npos ||
|
||||
options.find("string") != std::string::npos ||
|
||||
options.find("list") != std::string::npos ||
|
||||
options.find("simple") != std::string::npos) {
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
|
||||
} else if ((new_flags & rpc::object_storage::flag_value_type) ||
|
||||
(new_flags & rpc::object_storage::flag_bool_type) ||
|
||||
(new_flags & rpc::object_storage::flag_string_type) ||
|
||||
(new_flags & rpc::object_storage::flag_list_type)) {
|
||||
if (++itrArgs != args.end())
|
||||
new_args.insert(new_args.end(), itrArgs, args.end());
|
||||
|
||||
int new_flags;
|
||||
|
||||
if (options.find("value") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_value_type;
|
||||
else if (options.find("bool") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_bool_type;
|
||||
else if (options.find("string") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_string_type;
|
||||
else if (options.find("list") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_list_type;
|
||||
else if (options.find("simple") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_function_type;
|
||||
else
|
||||
throw torrent::input_error("No support for 'list' variable type.");
|
||||
|
||||
if (options.find("static") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_static;
|
||||
if (options.find("private") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_private;
|
||||
if (options.find("const") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_constant;
|
||||
|
||||
return system_method_insert_object(new_args, new_flags);
|
||||
|
||||
} else {
|
||||
// THROW.
|
||||
throw torrent::input_error("No object type specified.");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
return system_method_insert_object(new_args, new_flags);
|
||||
}
|
||||
|
||||
// method.erase <> {name}
|
||||
@@ -354,7 +345,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<0>(new_key, ""), create_new_key<0>(dest_key, ""),
|
||||
rpc::commands.create_redirect(create_new_key(new_key), create_new_key(dest_key),
|
||||
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable);
|
||||
|
||||
return torrent::Object();
|
||||
@@ -365,11 +356,11 @@ system_method_set_function(const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
rpc::object_storage::local_iterator itr =
|
||||
control->object_storage()->find_local(torrent::raw_string::from_string(args.front().as_string()));
|
||||
rpc::object_storage::iterator itr =
|
||||
control->object_storage()->find_raw_string(torrent::raw_string::from_string(args.front().as_string()));
|
||||
|
||||
if (itr == control->object_storage()->end(0) || itr->second.flags & rpc::object_storage::flag_constant)
|
||||
throw torrent::input_error("Command is not modifiable.");
|
||||
if (itr == control->object_storage()->end() || itr->second.flags & rpc::object_storage::flag_constant)
|
||||
throw torrent::input_error("Command is not modifiable.");
|
||||
|
||||
return control->object_storage()->set_str_function(args.front().as_string(),
|
||||
system_method_generate_command(++args.begin(), args.end()));
|
||||
@@ -401,7 +392,7 @@ system_method_set_key(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
if (itrArgs->is_dict_key())
|
||||
if (itrArgs->is_dict_key() || itrArgs->is_list())
|
||||
control->object_storage()->set_str_multi_key_obj(key.c_str(), cmd_key, *itrArgs);
|
||||
else
|
||||
control->object_storage()->set_str_multi_key(key, cmd_key, system_method_generate_command(itrArgs, args.end()));
|
||||
@@ -422,6 +413,16 @@ system_method_list_keys(const torrent::Object::string_type& args) {
|
||||
return rawResult;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_catch(rpc::target_type target, const torrent::Object& args) {
|
||||
try {
|
||||
return rpc::call_object(args, target);
|
||||
} catch (torrent::input_error& e) {
|
||||
lt_log_print(torrent::LOG_WARN, "Caught exception: '%s'.", e.what());
|
||||
return torrent::Object();
|
||||
}
|
||||
}
|
||||
|
||||
#define CMD2_METHOD_INSERT(key, flags) \
|
||||
CMD2_ANY_LIST(key, std::bind(&system_method_insert_object, std::placeholders::_2, flags));
|
||||
|
||||
@@ -432,6 +433,9 @@ initialize_command_dynamic() {
|
||||
|
||||
CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_value_type));
|
||||
CMD2_ANY_LIST ("method.insert.bool", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_bool_type));
|
||||
CMD2_ANY_LIST ("method.insert.string", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_string_type));
|
||||
CMD2_ANY_LIST ("method.insert.list", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_list_type));
|
||||
|
||||
CMD2_METHOD_INSERT("method.insert.simple", rpc::object_storage::flag_function_type);
|
||||
CMD2_METHOD_INSERT("method.insert.c_simple", rpc::object_storage::flag_constant | rpc::object_storage::flag_function_type);
|
||||
@@ -455,4 +459,17 @@ initialize_command_dynamic() {
|
||||
|
||||
CMD2_ANY_STRING ("method.rlookup", std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("method.rlookup.clear", std::bind(&rpc::object_storage::rlookup_clear, control->object_storage(), std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("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));
|
||||
}
|
||||
|
||||
+60
-6
@@ -38,13 +38,14 @@
|
||||
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/hash_string.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/directory_events.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
@@ -297,7 +298,7 @@ d_multicall(const torrent::Object::list_type& args) {
|
||||
for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(), cLast = args.end(); cItr != args.end(); cItr++) {
|
||||
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);
|
||||
}
|
||||
@@ -307,16 +308,65 @@ d_multicall(const torrent::Object::list_type& args) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
test_thread_locking() {
|
||||
worker_thread->queue_item(&ThreadWorker::start_log_counter);
|
||||
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();
|
||||
|
||||
// Find the given view
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator viewItr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
|
||||
if (viewItr == 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);
|
||||
|
||||
// Generate result by iterating over all items
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
++arg; // skip to first command
|
||||
|
||||
for (core::View::iterator item = dlist.begin(); item != dlist.end(); ++item) {
|
||||
// Add empty row to result
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
// Call the provided commands and assemble their results
|
||||
for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
static void
|
||||
call_watch_command(const std::string& command, const std::string& path) {
|
||||
rpc::commands.call_catch(command.c_str(), rpc::make_target(), path);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_added(const torrent::Object::list_type& args) {
|
||||
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();
|
||||
|
||||
if (!control->directory_events()->open())
|
||||
throw torrent::input_error("Could not open inotify:" + std::string(rak::error_number::current().c_str()));
|
||||
|
||||
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));
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_events() {
|
||||
CMD2_ANY("test.thread_locking", std::bind(&test_thread_locking));
|
||||
|
||||
CMD2_ANY_STRING ("on_ratio", std::bind(&apply_on_ratio, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("start_tied", std::bind(&apply_start_tied));
|
||||
@@ -339,9 +389,13 @@ initialize_command_events() {
|
||||
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_VALUE ("close_low_diskspace", std::bind(&apply_close_low_diskspace, std::placeholders::_2));
|
||||
|
||||
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 ("directory.watch.added", std::bind(&directory_watch_added, std::placeholders::_2));
|
||||
}
|
||||
|
||||
+43
-43
@@ -1,44 +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 <torrent/download/resource_manager.h>
|
||||
#include <torrent/download/choke_group.h>
|
||||
#include <torrent/download/choke_queue.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "ui/root.h"
|
||||
@@ -52,6 +17,9 @@
|
||||
// For cg_d_group.
|
||||
#include "core/download.h"
|
||||
|
||||
#define LT_LOG_SUBSYSTEM(log_fmt, ...) \
|
||||
lt_log_print_subsystem(torrent::LOG_TORRENT_INFO, "choke_queue", log_fmt, __VA_ARGS__);
|
||||
|
||||
// A hack to allow testing of the new choke_group API without the
|
||||
// working parts present.
|
||||
#define USE_CHOKE_GROUP 0
|
||||
@@ -122,6 +90,22 @@ apply_cg_insert(const std::string& arg) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_all_update_balance(bool is_up) {
|
||||
LT_LOG_SUBSYSTEM("apply update balance: resource_manager is_up:%i", (int)is_up);
|
||||
|
||||
for (torrent::ResourceManager::group_iterator
|
||||
itr = torrent::resource_manager()->group_begin(),
|
||||
last = torrent::resource_manager()->group_end(); itr != last; itr++) {
|
||||
if (is_up)
|
||||
itr->up_queue()->balance();
|
||||
else
|
||||
itr->down_queue()->balance();
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
//
|
||||
// The hacked version:
|
||||
//
|
||||
@@ -182,6 +166,11 @@ apply_cg_list() {
|
||||
return torrent::Object::from_list(result);
|
||||
}
|
||||
|
||||
int
|
||||
cg_get_can_unchoke(torrent::choke_queue* cq) {
|
||||
return cq->max_unchoked_signed() - (int)cq->size_unchoked();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_insert(const std::string& arg) {
|
||||
int64_t dummy;
|
||||
@@ -214,6 +203,20 @@ apply_cg_index_of(const std::string& arg) {
|
||||
return std::distance(cg_list_hack.begin(), itr);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_all_update_balance(bool is_up) {
|
||||
LT_LOG_SUBSYSTEM("apply update balance: hack is_up:%i", (int)is_up);
|
||||
|
||||
for (auto itr : cg_list_hack) {
|
||||
if (is_up)
|
||||
itr->up_queue()->balance();
|
||||
else
|
||||
itr->down_queue()->balance();
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
//
|
||||
// End of choke group hack.
|
||||
//
|
||||
@@ -335,15 +338,9 @@ options.
|
||||
|
||||
void
|
||||
initialize_command_groups() {
|
||||
// Move somewhere else?
|
||||
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.tracker_mode", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
|
||||
|
||||
CMD2_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD2_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));
|
||||
@@ -362,6 +359,9 @@ initialize_command_groups() {
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
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()));
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ void initialize_command_file();
|
||||
void initialize_command_ip();
|
||||
void initialize_command_peer();
|
||||
void initialize_command_local();
|
||||
void initialize_command_logging();
|
||||
void initialize_command_network();
|
||||
void initialize_command_groups();
|
||||
void initialize_command_throttle();
|
||||
@@ -63,6 +64,7 @@ initialize_commands() {
|
||||
initialize_command_network();
|
||||
initialize_command_groups();
|
||||
initialize_command_local();
|
||||
initialize_command_logging();
|
||||
initialize_command_ui();
|
||||
initialize_command_download();
|
||||
initialize_command_file();
|
||||
|
||||
+23
-12
@@ -98,42 +98,42 @@ void initialize_commands();
|
||||
|
||||
#define CMD2_VAR_BOOL(key, value) \
|
||||
control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_bool_type); \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key))); \
|
||||
CMD2_ANY_VALUE(key ".set", std::bind(&rpc::object_storage::set_bool, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
|
||||
#define CMD2_VAR_VALUE(key, value) \
|
||||
control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_value_type); \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key))); \
|
||||
CMD2_ANY_VALUE(key ".set", std::bind(&rpc::object_storage::set_value, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
|
||||
#define CMD2_VAR_STRING(key, value) \
|
||||
control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key))); \
|
||||
CMD2_ANY_STRING(key ".set", std::bind(&rpc::object_storage::set_string, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
|
||||
|
||||
#define CMD2_VAR_C_STRING(key, value) \
|
||||
control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key)));
|
||||
|
||||
#define CMD2_VAR_LIST(key) \
|
||||
control->object_storage()->insert_c_str(key, torrent::Object::create_list(), rpc::object_storage::flag_list_type); \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key))); \
|
||||
CMD2_ANY_LIST(key ".set", std::bind(&rpc::object_storage::set_list, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2)); \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2)); \
|
||||
CMD2_ANY_VOID(key ".push_back", std::bind(&rpc::object_storage::list_push_back, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
|
||||
#define CMD2_FUNC_SINGLE(key, cmds) \
|
||||
CMD2_ANY(key, std::bind(&rpc::command_function_call, torrent::raw_string::from_c_str(cmds), \
|
||||
#define CMD2_FUNC_SINGLE(key, cmds) \
|
||||
CMD2_ANY(key, std::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
#define CMD2_REDIRECT(from_key, to_key) \
|
||||
@@ -148,11 +148,11 @@ void initialize_commands();
|
||||
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<0>(from_key, ""), create_new_key<0>(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<0>(from_key, ""), create_new_key<0>(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);
|
||||
|
||||
//
|
||||
@@ -175,7 +175,11 @@ struct object_convert_type<Functor, void> {
|
||||
template <typename Arg1>
|
||||
torrent::Object operator () (Arg1& arg1) { m_slot(arg1); return torrent::Object(); }
|
||||
template <typename Arg1, typename Arg2>
|
||||
torrent::Object operator () (const Arg1& arg1) { m_slot(arg1); return torrent::Object(); }
|
||||
template <typename Arg1, typename Arg2>
|
||||
torrent::Object operator () (Arg1& arg1, Arg2& arg2) { m_slot(arg1, arg2); return torrent::Object(); }
|
||||
template <typename Arg1, typename Arg2>
|
||||
torrent::Object operator () (const Arg1& arg1, const Arg2& arg2) { m_slot(arg1, arg2); return torrent::Object(); }
|
||||
|
||||
Functor m_slot;
|
||||
};
|
||||
@@ -197,4 +201,11 @@ create_new_key(const std::string& key, const char 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
|
||||
|
||||
+240
-76
@@ -45,39 +45,14 @@
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
void
|
||||
ipv4_filter_parse(const char* address, int value) {
|
||||
uint32_t ip_values[4] = { 0, 0, 0, 0 };
|
||||
unsigned int block = rpc::ipv4_table::mask_bits;
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
char ip_dot;
|
||||
int values_read;
|
||||
|
||||
if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u",
|
||||
ip_values + 0, &ip_dot,
|
||||
ip_values + 1, &ip_dot,
|
||||
ip_values + 2, &ip_dot,
|
||||
ip_values + 3,
|
||||
&block)) < 2 ||
|
||||
|
||||
// Make sure the dot is included.
|
||||
(values_read < 7 && values_read % 2) ||
|
||||
|
||||
ip_values[0] >= 256 ||
|
||||
ip_values[1] >= 256 ||
|
||||
ip_values[2] >= 256 ||
|
||||
ip_values[3] >= 256 ||
|
||||
|
||||
block > rpc::ipv4_table::mask_bits)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
// E.g. '10.10.' will be '10.10.0.0/16'.
|
||||
if (values_read < 7)
|
||||
block = 8 * (values_read / 2);
|
||||
|
||||
torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
|
||||
rpc::ipv4_table::mask_bits - block, value);
|
||||
}
|
||||
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
|
||||
|
||||
torrent::Object
|
||||
apply_ip_tables_insert_table(const std::string& args) {
|
||||
@@ -88,6 +63,17 @@ apply_ip_tables_insert_table(const std::string& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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())
|
||||
throw torrent::input_error("IP table does not exist.");
|
||||
|
||||
uint32_t size = itr->table.sizeof_data();
|
||||
return size;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ip_tables_get(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
@@ -97,20 +83,21 @@ apply_ip_tables_get(const torrent::Object::list_type& args) {
|
||||
|
||||
const std::string& name = (args_itr++)->as_string();
|
||||
const std::string& address = (args_itr++)->as_string();
|
||||
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
|
||||
if (sscanf(address.c_str(), "%u.%u.%u.%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
rpc::ip_table_list::iterator table_itr = ip_tables.find(name);
|
||||
|
||||
if (table_itr == ip_tables.end())
|
||||
throw torrent::input_error("Could not find ip table.");
|
||||
|
||||
return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
|
||||
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
if(!table_itr->table.defined(address_start, address_end))
|
||||
throw torrent::input_error("No value defined for specified IP(s).");
|
||||
|
||||
return table_itr->table.at(address_start, address_end);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -123,15 +110,6 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
const std::string& name = (args_itr++)->as_string();
|
||||
const std::string& address = (args_itr++)->as_string();
|
||||
const std::string& value_str = (args_itr++)->as_string();
|
||||
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
unsigned int block = rpc::ipv4_table::mask_bits;
|
||||
|
||||
if (sscanf(address.c_str(), "%u.%u.%u.%u/%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 ||
|
||||
block > rpc::ipv4_table::mask_bits)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
int value;
|
||||
|
||||
@@ -145,8 +123,13 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
if (table_itr == ip_tables.end())
|
||||
throw torrent::input_error("Could not find ip table.");
|
||||
|
||||
table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
|
||||
rpc::ipv4_table::mask_bits - block, value);
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
table_itr->table.insert(address_start, address_end, value);
|
||||
else
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -155,6 +138,158 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
// IPv4 filter functions:
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// IPV4_RANGE_PARSE parses string into an ip range
|
||||
//
|
||||
// should be compatible with lines in p2p files
|
||||
// everything in address before colon is ignored
|
||||
//
|
||||
// ip range can be single ip in which case start=end
|
||||
// ip range can be cidr notation a.b.c.d/e
|
||||
// ip range can be explicit range like in p2p line a.b.c.d-w.x.y.z
|
||||
//
|
||||
// returns false if line does not contain valid ip or ip range
|
||||
// address_start and address_end will contain start and end ip
|
||||
//
|
||||
// addresses parsed are returned in host byte order
|
||||
// to get network byte order call htonl(address)
|
||||
///////////////////////////////////////////////////////////
|
||||
bool
|
||||
ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end) {
|
||||
// same length as buffer used to do reads so no worries about overflow
|
||||
char address_copy[4096];
|
||||
bool valid = false;
|
||||
char address_start_str[20];
|
||||
int address_start_index=0;
|
||||
struct sockaddr_in sa_start;
|
||||
*address_start=0;
|
||||
*address_end=0;
|
||||
|
||||
// get rid of everything after '#' comments
|
||||
// copy everything up to '#' to address_copy and work from there
|
||||
while(address[address_start_index] != '#' && address[address_start_index] != '\r' &&
|
||||
address[address_start_index] != '\n' && address[address_start_index] != '\0' &&
|
||||
address_start_index < 4096 ) {
|
||||
|
||||
address_copy[address_start_index] = address[address_start_index];
|
||||
address_start_index++;
|
||||
}
|
||||
|
||||
address_copy[address_start_index] = '\0';
|
||||
address_start_index=0;
|
||||
|
||||
// skip everything up to and including last ':' character and whitespace
|
||||
const char* addr = strrchr(address_copy, ':');
|
||||
|
||||
addr = (addr == NULL) ? address_copy : addr + 1;
|
||||
|
||||
while(addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_start_index < 19) {
|
||||
address_start_str[address_start_index] = addr[0];
|
||||
address_start_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
address_start_str[address_start_index] = '\0';
|
||||
|
||||
if(strchr(addr, '-') != NULL) {
|
||||
// explicit range
|
||||
char address_end_str[20];
|
||||
int address_end_index=0;
|
||||
struct sockaddr_in sa_end;
|
||||
|
||||
while(addr[0] == '-' || addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_end_index < 19) {
|
||||
address_end_str[address_end_index] = addr[0];
|
||||
address_end_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
address_end_str[address_end_index] = '\0';
|
||||
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && inet_pton(AF_INET, address_end_str, &(sa_end.sin_addr)) != 0) {
|
||||
*address_start = ntohl(sa_start.sin_addr.s_addr);
|
||||
*address_end = ntohl(sa_end.sin_addr.s_addr);
|
||||
|
||||
if(*address_start <= *address_end)
|
||||
valid=true;
|
||||
}
|
||||
} else if(strchr(addr, '/') != NULL) {
|
||||
// cidr range
|
||||
char mask_bits_str[20];
|
||||
int mask_bits_index=0;
|
||||
uint32_t mask_bits;
|
||||
|
||||
while(addr[0] == '/' || addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while( (addr[0] >= '0' && addr[0] <= '9') && mask_bits_index < 19) {
|
||||
mask_bits_str[mask_bits_index] = addr[0];
|
||||
mask_bits_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
mask_bits_str[mask_bits_index] = '\0';
|
||||
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && sscanf(mask_bits_str, "%u", &mask_bits) != 0) {
|
||||
if(mask_bits <=32) {
|
||||
uint32_t ip=ntohl(sa_start.sin_addr.s_addr);
|
||||
uint32_t mask=0;
|
||||
uint32_t end_mask=0;
|
||||
|
||||
mask = (~mask) << (32-mask_bits);
|
||||
*address_start = ip & mask;
|
||||
end_mask = (~end_mask) >> mask_bits;
|
||||
*address_end = (ip & mask) | end_mask;
|
||||
|
||||
valid=true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// single ip
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0) {
|
||||
*address_start = ntohl(sa_start.sin_addr.s_addr);
|
||||
*address_end = *address_start;
|
||||
|
||||
valid=true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// IPV4_FILTER_PARSE
|
||||
//
|
||||
// should now be compatible with lines in p2p files
|
||||
//
|
||||
// addresses in table MUST be in host byte order
|
||||
// ntohl is called after parsing ip address(es)
|
||||
///////////////////////////////////////////////////////////
|
||||
void
|
||||
ipv4_filter_parse(const char* address, int value) {
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (ipv4_range_parse(address, &address_start, &address_end) ) {
|
||||
torrent::PeerList::ipv4_filter()->insert(address_start, address_end, value);
|
||||
|
||||
char start_str[INET_ADDRSTRLEN];
|
||||
char end_str[INET_ADDRSTRLEN];
|
||||
uint32_t net_start = htonl(address_start);
|
||||
uint32_t net_end = htonl(address_end);
|
||||
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
lt_log_print(torrent::LOG_CONNECTION_FILTER, "Adding ip filter for %s-%s.", start_str, end_str);
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_size_data() {
|
||||
return torrent::PeerList::ipv4_filter()->sizeof_data();
|
||||
@@ -162,14 +297,16 @@ apply_ipv4_filter_size_data() {
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_get(const std::string& args) {
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (sscanf(args.c_str(), "%u.%u.%u.%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
|
||||
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
|
||||
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
|
||||
throw torrent::input_error("No value defined for specified IP(s).");
|
||||
|
||||
return torrent::PeerList::ipv4_filter()->at(address_start, address_end);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -187,30 +324,23 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
torrent::Object::list_const_iterator args_itr = args.begin();
|
||||
std::string filename = args.front().as_string();
|
||||
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(args.front().as_string()).c_str(), std::ios::in);
|
||||
std::fstream file(rak::path_expand(filename).c_str(), std::ios::in);
|
||||
|
||||
if (!file.is_open())
|
||||
throw torrent::input_error("Could not open ip filter file: " + args.front().as_string());
|
||||
throw torrent::input_error("Could not open ip filter file: " + filename);
|
||||
|
||||
int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str());
|
||||
|
||||
char buffer[4096];
|
||||
unsigned int lineNumber = 0;
|
||||
char buffer[4096];
|
||||
|
||||
try {
|
||||
while (file.good() && !file.getline(buffer, 4096).fail()) {
|
||||
if (file.gcount() == 0)
|
||||
throw torrent::internal_error("parse_command_file(...) file.gcount() == 0.");
|
||||
|
||||
int lineLength = file.gcount() - 1;
|
||||
// In case we are at the end of the file and the last character is
|
||||
// not a line feed, we'll just increase the read character count so
|
||||
// that the last would also be included in option line.
|
||||
if (file.eof() && file.get() != '\n')
|
||||
lineLength++;
|
||||
|
||||
lineNumber++;
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == '#')
|
||||
@@ -220,28 +350,62 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
}
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", args.front().as_string().c_str(), lineNumber, e.what());
|
||||
snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", filename.c_str(), lineNumber, e.what());
|
||||
|
||||
throw torrent::input_error(buffer);
|
||||
}
|
||||
|
||||
lt_log_print(torrent::LOG_CONNECTION_INFO, "Loaded %u %s address blocks (%u kb in-memory) from '%s'.",
|
||||
lt_log_print(torrent::LOG_CONNECTION_FILTER, "loaded %u %s address blocks (%u kb in-memory) from '%s'",
|
||||
lineNumber,
|
||||
args.back().as_string().c_str(),
|
||||
value_name.c_str(),
|
||||
torrent::PeerList::ipv4_filter()->sizeof_data() / 1024,
|
||||
args.front().as_string().c_str());
|
||||
filename.c_str());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_dump() {
|
||||
torrent::Object raw_result = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = raw_result.as_list();
|
||||
|
||||
torrent::ipv4_table::range_map_type range_map = torrent::PeerList::ipv4_filter()->range_map;
|
||||
torrent::ipv4_table::range_map_type::iterator iter = range_map.begin();
|
||||
|
||||
while(iter != range_map.end()) {
|
||||
char buffer[64];
|
||||
uint32_t address_start = iter->first;
|
||||
uint32_t address_end = (iter->second).first;
|
||||
int value = (iter->second).second;
|
||||
|
||||
char start_str[INET_ADDRSTRLEN];
|
||||
char end_str[INET_ADDRSTRLEN];
|
||||
uint32_t net_start = htonl(address_start);
|
||||
uint32_t net_end = htonl(address_end);
|
||||
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
return raw_result;
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_ip() {
|
||||
CMD2_ANY_STRING ("ip_tables.insert_table", std::bind(&apply_ip_tables_insert_table, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ip_tables.get", std::bind(&apply_ip_tables_get, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ip_tables.add_address", std::bind(&apply_ip_tables_add_address, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("ip_tables.insert_table", std::bind(&apply_ip_tables_insert_table, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("ip_tables.size_data", std::bind(&apply_ip_tables_size_data, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ip_tables.get", std::bind(&apply_ip_tables_get, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ip_tables.add_address", std::bind(&apply_ip_tables_add_address, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("ipv4_filter.size_data", std::bind(&apply_ipv4_filter_size_data));
|
||||
CMD2_ANY_STRING ("ipv4_filter.get", std::bind(&apply_ipv4_filter_get, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ipv4_filter.add_address", std::bind(&apply_ipv4_filter_add_address, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ipv4_filter.load", std::bind(&apply_ipv4_filter_load, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ipv4_filter.dump", std::bind(&apply_ipv4_filter_dump));
|
||||
}
|
||||
|
||||
+27
-116
@@ -5,12 +5,12 @@
|
||||
// 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
|
||||
@@ -48,8 +48,6 @@
|
||||
#include <torrent/chunk_manager.h>
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/log_files.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "core/download.h"
|
||||
@@ -81,60 +79,12 @@ apply_pieces_stats_total_size() {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log(const torrent::Object::string_type& arg, int logType) {
|
||||
if (rpc::execFile.log_fd() != -1) {
|
||||
switch (logType) {
|
||||
case 0: ::close(rpc::execFile.log_fd()); rpc::execFile.set_log_fd(-1); break;
|
||||
case 1:
|
||||
// if (control->scgi()) {
|
||||
// ::close(control->scgi()->log_fd());
|
||||
// control->scgi()->set_log_fd(-1);
|
||||
// }
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
system_env(const torrent::Object::string_type& arg) {
|
||||
if (arg.empty())
|
||||
throw torrent::input_error("system.env: Missing variable name.");
|
||||
|
||||
if (!arg.empty()) {
|
||||
int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||
|
||||
if (logFd < 0)
|
||||
throw torrent::input_error("Could not open execute log file.");
|
||||
|
||||
switch (logType) {
|
||||
case 0: rpc::execFile.set_log_fd(logFd); break;
|
||||
// case 1: if (control->scgi()) control->scgi()->set_log_fd(logFd); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
control->core()->push_log("Opened log file.");
|
||||
|
||||
} else {
|
||||
control->core()->push_log("Closed log file.");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log_libtorrent(const torrent::Object::list_type& args) {
|
||||
if (args.empty() || args.size() > 2)
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
torrent::log_file* log_file = torrent::find_log_file(args.front().as_string().c_str());
|
||||
|
||||
if (log_file == NULL)
|
||||
throw torrent::input_error("Invalid log name.");
|
||||
|
||||
if (args.size() == 1) {
|
||||
log_file->close();
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
if (!log_file->open_file(args.back().as_string().c_str()))
|
||||
throw torrent::input_error("Could not open log file.");
|
||||
|
||||
return torrent::Object();
|
||||
char* val = getenv(arg.c_str());
|
||||
return std::string(val ? val : "");
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -185,7 +135,7 @@ check_name(const std::string& str) {
|
||||
throw torrent::input_error("Non-alphanumeric characters found.");
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
group_insert(const torrent::Object::list_type& args) {
|
||||
@@ -208,7 +158,7 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
|
||||
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");
|
||||
@@ -220,7 +170,7 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
|
||||
} 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");
|
||||
@@ -234,27 +184,6 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
return name;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
fclose(log_file);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
static const int file_print_use_space = 0x1;
|
||||
static const int file_print_delim_space = 0x2;
|
||||
|
||||
@@ -263,10 +192,10 @@ file_print_list(torrent::Object::list_const_iterator first, torrent::Object::lis
|
||||
while (first != last) {
|
||||
switch (first->type()) {
|
||||
case torrent::Object::TYPE_STRING:
|
||||
fprintf(output, " %s" + !(flags & file_print_use_space), first->as_string().c_str());
|
||||
fprintf(output, (const char*)" %s" + !(flags & file_print_use_space), first->as_string().c_str());
|
||||
break;
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
fprintf(output, " %lli" + !(flags & file_print_use_space), first->as_value());
|
||||
fprintf(output, (const char*)" %" PRIi64 + !(flags & file_print_use_space), first->as_value());
|
||||
break;
|
||||
case torrent::Object::TYPE_LIST:
|
||||
file_print_list(first->as_list().begin(), first->as_list().end(), output, 0);
|
||||
@@ -286,9 +215,9 @@ torrent::Object
|
||||
cmd_file_append(const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
|
||||
FILE* output = fopen(args.front().as_string().c_str(), "a");
|
||||
|
||||
|
||||
if (output == NULL)
|
||||
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + rak::error_number::current().c_str());
|
||||
|
||||
@@ -299,44 +228,26 @@ cmd_file_append(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log_open_file(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
torrent::log_open_file_output(args.front().as_string().c_str(), args.back().as_string().c_str());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log_add_output(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
torrent::log_add_group_output(torrent::option_find_string(torrent::OPTION_LOG_GROUP, args.front().as_string().c_str()),
|
||||
args.back().as_string().c_str());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_local() {
|
||||
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
core::DownloadStore* dStore = control->core()->download_store();
|
||||
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));
|
||||
|
||||
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)64 << 30);
|
||||
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");
|
||||
|
||||
CMD2_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
|
||||
(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()));
|
||||
|
||||
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
@@ -347,12 +258,20 @@ initialize_command_local() {
|
||||
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));
|
||||
|
||||
CMD2_ANY_STRING ("system.env", std::bind(&system_env, std::placeholders::_2));
|
||||
|
||||
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));
|
||||
|
||||
CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2));
|
||||
|
||||
CMD2_VAR_BOOL ("system.daemon", false);
|
||||
|
||||
CMD2_ANY_V ("system.shutdown.normal", std::bind(&Control::receive_normal_shutdown, control));
|
||||
CMD2_ANY_V ("system.shutdown.quick", std::bind(&Control::receive_quick_shutdown, control));
|
||||
CMD2_REDIRECT_GENERIC_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
|
||||
CMD2_ANY ("system.cwd", std::bind(&system_get_cwd));
|
||||
CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2));
|
||||
|
||||
@@ -411,14 +330,6 @@ initialize_command_local() {
|
||||
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);
|
||||
|
||||
CMD2_ANY_LIST ("log.open_file", std::bind(&apply_log_open_file, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
|
||||
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("log.xmlrpc", std::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.libtorrent", std::bind(&apply_log_libtorrent, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
|
||||
// TODO: Convert to new command types:
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/manager.h"
|
||||
#include "rak/path.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
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();
|
||||
|
||||
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());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// TODO: Deprecated.
|
||||
torrent::Object
|
||||
apply_log(const torrent::Object::string_type& arg, int logType) {
|
||||
if (rpc::execFile.log_fd() != -1) {
|
||||
switch (logType) {
|
||||
case 0: ::close(rpc::execFile.log_fd()); rpc::execFile.set_log_fd(-1); break;
|
||||
case 1:
|
||||
// if (control->scgi()) {
|
||||
// ::close(control->scgi()->log_fd());
|
||||
// control->scgi()->set_log_fd(-1);
|
||||
// }
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg.empty()) {
|
||||
int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||
|
||||
if (logFd < 0)
|
||||
throw torrent::input_error("Could not open execute log file.");
|
||||
|
||||
switch (logType) {
|
||||
case 0: rpc::execFile.set_log_fd(logFd); break;
|
||||
// case 1: if (control->scgi()) control->scgi()->set_log_fd(logFd); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
control->core()->push_log("Opened log file.");
|
||||
|
||||
} else {
|
||||
control->core()->push_log("Closed log file.");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
fclose(log_file);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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_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_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));
|
||||
}
|
||||
+47
-48
@@ -92,8 +92,6 @@ apply_tos(const torrent::Object::string_type& arg) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object apply_hash_read_ahead(int arg) { torrent::set_hash_read_ahead(arg << 20); return torrent::Object(); }
|
||||
torrent::Object apply_hash_interval(int arg) { torrent::set_hash_interval(arg * 1000); return torrent::Object(); }
|
||||
torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); }
|
||||
|
||||
torrent::File*
|
||||
@@ -126,10 +124,10 @@ xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) {
|
||||
void
|
||||
initialize_xmlrpc() {
|
||||
rpc::xmlrpc.initialize();
|
||||
rpc::xmlrpc.set_slot_find_download(rak::mem_fn(control->core()->download_list(), &core::DownloadList::find_hex_ptr));
|
||||
rpc::xmlrpc.set_slot_find_file(rak::ptr_fn(&xmlrpc_find_file));
|
||||
rpc::xmlrpc.set_slot_find_tracker(rak::ptr_fn(&xmlrpc_find_tracker));
|
||||
rpc::xmlrpc.set_slot_find_peer(rak::ptr_fn(&xmlrpc_find_peer));
|
||||
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);
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
@@ -140,7 +138,7 @@ initialize_xmlrpc() {
|
||||
rpc::xmlrpc.insert_command(itr->first, itr->second.m_parm, itr->second.m_doc);
|
||||
}
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_INFO, "XMLRPC initialized with %u functions.", count);
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "XMLRPC initialized with %u functions.", count);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -169,15 +167,16 @@ apply_scgi(const std::string& arg, int type) {
|
||||
sa.sa_inet()->clear();
|
||||
saPtr = &sa;
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_WARN, "The SCGI socket has not been bound to any address and likely poses a security risk.");
|
||||
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) {
|
||||
if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0)
|
||||
} 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();
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_WARN, "The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'.");
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
|
||||
|
||||
} else {
|
||||
throw torrent::input_error("Could not parse address.");
|
||||
@@ -236,14 +235,6 @@ initialize_command_network() {
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
core::CurlStack* httpStack = control->core()->http_stack();
|
||||
|
||||
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_VAR_BOOL ("log.handshake", false);
|
||||
|
||||
// CMD2_ANY_STRING ("encoding_list", std::bind(&apply_encoding_list, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
|
||||
|
||||
// Isn't port_open used?
|
||||
@@ -251,7 +242,9 @@ initialize_command_network() {
|
||||
CMD2_VAR_BOOL ("network.port_random", true);
|
||||
CMD2_VAR_STRING ("network.port_range", "6881-6999");
|
||||
|
||||
CMD2_ANY ("network.listen.port", std::bind(&torrent::ConnectionManager::listen_port, cm));
|
||||
CMD2_ANY ("network.listen.port", std::bind(&torrent::ConnectionManager::listen_port, cm));
|
||||
CMD2_ANY ("network.listen.backlog", std::bind(&torrent::ConnectionManager::listen_backlog, cm));
|
||||
CMD2_ANY_VALUE_V ("network.listen.backlog.set", std::bind(&torrent::ConnectionManager::set_listen_backlog, cm, std::placeholders::_2));
|
||||
|
||||
CMD2_VAR_BOOL ("protocol.pex", true);
|
||||
CMD2_ANY_LIST ("protocol.encryption.set", std::bind(&apply_encryption, std::placeholders::_2));
|
||||
@@ -264,18 +257,21 @@ initialize_command_network() {
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
|
||||
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.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.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.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.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.capath", std::bind(&core::CurlStack::http_capath, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack));
|
||||
CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", std::bind(&core::CurlStack::set_http_proxy, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_host", std::bind(&core::CurlStack::ssl_verify_host, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", std::bind(&core::CurlStack::set_ssl_verify_host, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.send_buffer.size", 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));
|
||||
@@ -283,31 +279,34 @@ initialize_command_network() {
|
||||
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", std::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("network.tos.set", std::bind(&apply_tos, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.bind_address", std::bind(&core::Manager::bind_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.bind_address.set", std::bind(&core::Manager::set_bind_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.local_address", std::bind(&core::Manager::local_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.local_address.set", std::bind(&core::Manager::set_local_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.proxy_address", std::bind(&core::Manager::proxy_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.proxy_address.set", std::bind(&core::Manager::set_proxy_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.bind_address", std::bind(&core::Manager::bind_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.bind_address.set", std::bind(&core::Manager::set_bind_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.local_address", std::bind(&core::Manager::local_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.local_address.set", std::bind(&core::Manager::set_local_address, control->core(), std::placeholders::_2));
|
||||
CMD2_ANY ("network.proxy_address", std::bind(&core::Manager::proxy_address, control->core()));
|
||||
CMD2_ANY_STRING_V("network.proxy_address.set", std::bind(&core::Manager::set_proxy_address, control->core(), std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.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.open_sockets", std::bind(&torrent::ConnectionManager::size, cm));
|
||||
CMD2_ANY ("network.max_open_sockets", std::bind(&torrent::ConnectionManager::max_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", std::bind(&torrent::ConnectionManager::set_max_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY ("network.open_files", std::bind(&torrent::FileManager::open_files, fileManager));
|
||||
CMD2_ANY ("network.max_open_files", std::bind(&torrent::FileManager::max_open_files, fileManager));
|
||||
CMD2_ANY_VALUE_V ("network.max_open_files.set", std::bind(&torrent::FileManager::set_max_open_files, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("network.total_handshakes", std::bind(&torrent::total_handshakes));
|
||||
CMD2_ANY ("network.open_sockets", std::bind(&torrent::ConnectionManager::size, cm));
|
||||
CMD2_ANY ("network.max_open_sockets", std::bind(&torrent::ConnectionManager::max_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", std::bind(&torrent::ConnectionManager::set_max_size, cm, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
|
||||
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
|
||||
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
|
||||
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", 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));
|
||||
|
||||
CMD2_ANY ("system.hash.read_ahead", std::bind(&torrent::hash_read_ahead));
|
||||
CMD2_ANY_VALUE_V ("system.hash.read_ahead.set", std::bind(&apply_hash_read_ahead, std::placeholders::_2));
|
||||
CMD2_ANY ("system.hash.interval", std::bind(&torrent::hash_interval));
|
||||
CMD2_ANY_VALUE_V ("system.hash.interval.set", std::bind(&apply_hash_interval, std::placeholders::_2));
|
||||
CMD2_ANY ("system.hash.max_tries", std::bind(&torrent::hash_max_tries));
|
||||
CMD2_ANY_VALUE_V ("system.hash.max_tries.set", std::bind(&torrent::set_hash_max_tries, std::placeholders::_2));
|
||||
CMD2_ANY ("network.block.ipv4", std::bind(&torrent::ConnectionManager::is_block_ipv4, cm));
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4.set", std::bind(&torrent::ConnectionManager::set_block_ipv4, cm, std::placeholders::_2));
|
||||
CMD2_ANY ("network.block.ipv6", std::bind(&torrent::ConnectionManager::is_block_ipv6, cm));
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv6.set", std::bind(&torrent::ConnectionManager::set_block_ipv6, cm, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.prefer.ipv6", std::bind(&torrent::ConnectionManager::is_prefer_ipv6, cm));
|
||||
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", std::bind(&torrent::ConnectionManager::set_prefer_ipv6, cm, std::placeholders::_2));
|
||||
}
|
||||
|
||||
+6
-1
@@ -69,7 +69,12 @@ retrieve_p_id_html(torrent::Peer* peer) {
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_address(torrent::Peer* peer) {
|
||||
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
|
||||
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
|
||||
|
||||
if (addr->family() == rak::socket_address::af_inet6)
|
||||
return "[" + addr->address_str() + "]";
|
||||
else
|
||||
return addr->address_str();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
|
||||
+34
-10
@@ -89,19 +89,22 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
|
||||
|
||||
// convert to [begin, end) making sure the end doesn't overflow
|
||||
// (this precludes 255.255.255.255 from ever matching, but that's not a real IP anyway)
|
||||
return std::make_pair<uint32_t, uint32_t>(begin, std::max(end, end + 1));
|
||||
return std::make_pair((uint32_t)begin, (uint32_t)std::max(end, end + 1));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_throttle(const torrent::Object::list_type& args, bool up) {
|
||||
torrent::Object::list_const_iterator argItr = args.begin();
|
||||
|
||||
if (argItr == args.end())
|
||||
throw torrent::input_error("Missing throttle name.");
|
||||
|
||||
const std::string& name = argItr->as_string();
|
||||
if (name.empty() || name == "NULL")
|
||||
throw torrent::input_error("Invalid throttle name.");
|
||||
throw torrent::input_error("Invalid throttle name '" + name + "'.");
|
||||
|
||||
if ((++argItr)->as_string().empty())
|
||||
return torrent::Object();
|
||||
if (++argItr == args.end() || argItr->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);
|
||||
@@ -162,10 +165,21 @@ apply_address_throttle(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
throttle_update(const char* variable, int64_t value) {
|
||||
rpc::commands.call_command(variable, value);
|
||||
|
||||
control->ui()->adjust_up_throttle(0);
|
||||
control->ui()->adjust_down_throttle(0);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_throttle() {
|
||||
CMD2_ANY ("throttle.unchoked_uploads", std::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager()));
|
||||
CMD2_ANY ("throttle.unchoked_downloads", std::bind(&torrent::ResourceManager::currently_download_unchoked, torrent::resource_manager()));
|
||||
CMD2_ANY ("throttle.unchoked_uploads", std::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager()));
|
||||
CMD2_ANY ("throttle.max_unchoked_uploads", std::bind(&torrent::ResourceManager::max_upload_unchoked, torrent::resource_manager()));
|
||||
CMD2_ANY ("throttle.unchoked_downloads", std::bind(&torrent::ResourceManager::currently_download_unchoked, torrent::resource_manager()));
|
||||
CMD2_ANY ("throttle.max_unchoked_downloads", std::bind(&torrent::ResourceManager::max_download_unchoked, torrent::resource_manager()));
|
||||
|
||||
CMD2_VAR_VALUE ("throttle.min_peers.normal", 100);
|
||||
CMD2_VAR_VALUE ("throttle.max_peers.normal", 200);
|
||||
@@ -177,10 +191,20 @@ initialize_command_throttle() {
|
||||
CMD2_VAR_VALUE ("throttle.min_downloads", 0);
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads", 50);
|
||||
|
||||
CMD2_VAR_VALUE ("throttle.max_uploads.div", 1);
|
||||
CMD2_VAR_VALUE ("throttle.max_uploads.global", 0);
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads.div", 1);
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads.global", 0);
|
||||
CMD2_VAR_VALUE ("throttle.max_uploads.div._val", 1);
|
||||
CMD2_VAR_VALUE ("throttle.max_uploads.global._val", 0);
|
||||
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_ANY_VALUE ("throttle.max_uploads.div.set", std::bind(&throttle_update, "throttle.max_uploads.div._val.set", std::placeholders::_2));
|
||||
CMD2_ANY_VALUE ("throttle.max_uploads.global.set", std::bind(&throttle_update, "throttle.max_uploads.global._val.set", std::placeholders::_2));
|
||||
CMD2_ANY_VALUE ("throttle.max_downloads.div.set", std::bind(&throttle_update, "throttle.max_downloads.div._val.set", std::placeholders::_2));
|
||||
CMD2_ANY_VALUE ("throttle.max_downloads.global.set", std::bind(&throttle_update, "throttle.max_downloads.global._val.set", std::placeholders::_2));
|
||||
|
||||
// TODO: Move the logic into some libtorrent function.
|
||||
CMD2_ANY ("throttle.global_up.rate", std::bind(&torrent::Rate::rate, torrent::up_rate()));
|
||||
|
||||
+13
-1
@@ -113,10 +113,16 @@ 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_VALUE_V("t.is_enabled.set", std::bind(&tracker_set_enabled, std::placeholders::_1, std::placeholders::_2));
|
||||
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_V ("t.enable", std::bind(&torrent::Tracker::enable, std::placeholders::_1));
|
||||
CMD2_TRACKER_V ("t.disable", std::bind(&torrent::Tracker::disable, std::placeholders::_1));
|
||||
|
||||
CMD2_TRACKER_VALUE_V("t.is_enabled.set", std::bind(&tracker_set_enabled, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
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));
|
||||
@@ -131,9 +137,14 @@ initialize_command_tracker() {
|
||||
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.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.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.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));
|
||||
|
||||
@@ -146,6 +157,7 @@ initialize_command_tracker() {
|
||||
|
||||
CMD2_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1)));
|
||||
CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0)));
|
||||
CMD2_VAR_BOOL ("trackers.delay_scrape", false);
|
||||
CMD2_VAR_VALUE ("trackers.numwant", -1);
|
||||
CMD2_VAR_BOOL ("trackers.use_udp", true);
|
||||
|
||||
|
||||
+324
-31
@@ -39,9 +39,12 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <regex>
|
||||
|
||||
#include <rak/algorithm.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "core/view_manager.h"
|
||||
@@ -53,8 +56,7 @@
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
typedef void (core::ViewManager::*view_cfilter_slot)(const std::string&, const torrent::Object&);
|
||||
typedef void (core::ViewManager::*view_event_slot)(const std::string&, const std::string&);
|
||||
typedef void (core::ViewManager::*view_event_slot)(const std::string&, const torrent::Object&);
|
||||
|
||||
torrent::Object
|
||||
apply_view_filter_on(const torrent::Object::list_type& args) {
|
||||
@@ -76,33 +78,12 @@ apply_view_filter_on(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
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.");
|
||||
|
||||
(control->view_manager()->*viewFilterSlot)(name, args.back());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_event(view_event_slot viewFilterSlot, const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
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.");
|
||||
|
||||
(control->view_manager()->*viewFilterSlot)(name, args.back().as_string());
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
(control->view_manager()->*viewFilterSlot)(args.front().as_string(), args.back());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
@@ -170,6 +151,41 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_value(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
if (args.size() < 1)
|
||||
throw torrent::input_error("'value' takes at least a number argument!");
|
||||
if (args.size() > 2)
|
||||
throw torrent::input_error("'value' takes at most two arguments!");
|
||||
|
||||
torrent::Object::value_type val = 0;
|
||||
if (args.front().is_value()) {
|
||||
val = args.front().as_value();
|
||||
} else {
|
||||
int base = args.size() > 1 ? args.back().is_value() ?
|
||||
args.back().as_value() : strtol(args.back().as_string().c_str(), NULL, 10) : 10;
|
||||
char* endptr = 0;
|
||||
|
||||
val = strtoll(args.front().as_string().c_str(), &endptr, base);
|
||||
while (*endptr == ' ' || *endptr == '\n') ++endptr;
|
||||
if (*endptr)
|
||||
throw torrent::input_error("Junk at end of number: " + args.front().as_string());
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_try(rpc::target_type target, const torrent::Object& args) {
|
||||
try {
|
||||
return rpc::call_object(args, target);
|
||||
} catch (torrent::input_error& e) {
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "try command caught input_error: %s", e.what());
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// Move these boolean operators to a new file.
|
||||
|
||||
inline bool
|
||||
@@ -305,6 +321,103 @@ torrent::Object apply_equal(rpc::target_type target, const torrent::Object::list
|
||||
return result.is_value() ? result.as_value() == 0 : (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_compare(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
if (!rpc::is_target_pair(target))
|
||||
throw torrent::input_error("Can only compare a target pair.");
|
||||
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("Need at least order and one field.");
|
||||
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
std::string order = (itr++)->as_string();
|
||||
const char* current = order.c_str();
|
||||
|
||||
torrent::Object result1;
|
||||
torrent::Object result2;
|
||||
|
||||
for (torrent::Object::list_const_iterator last = args.end(); itr != last; itr++) {
|
||||
std::string field = itr->as_string();
|
||||
result1 = rpc::parse_command_single(rpc::get_target_left(target), field);
|
||||
result2 = rpc::parse_command_single(rpc::get_target_right(target), field);
|
||||
|
||||
if (result1.type() != result2.type())
|
||||
throw torrent::input_error(std::string("Type mismatch in compare of ") + field);
|
||||
|
||||
bool descending = *current == 'd' || *current == 'D' || *current == '-';
|
||||
if (*current) {
|
||||
if (!descending && !(*current == 'a' || *current == 'A' || *current == '+'))
|
||||
throw torrent::input_error(std::string("Bad order '") + *current + "' in " + order);
|
||||
++current;
|
||||
}
|
||||
|
||||
switch (result1.type()) {
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
if (result1.as_value() != result2.as_value())
|
||||
return (int64_t) (descending ^ (result1.as_value() < result2.as_value()));
|
||||
break;
|
||||
|
||||
case torrent::Object::TYPE_STRING:
|
||||
if (result1.as_string() != result2.as_string())
|
||||
return (int64_t) (descending ^ (result1.as_string() < result2.as_string()));
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // treat unknown types as equal
|
||||
}
|
||||
}
|
||||
|
||||
// if all else is equal, ensure stable sort order based on memory location
|
||||
return (int64_t) (target.second < target.third);
|
||||
}
|
||||
|
||||
// Regexp based 'match' function.
|
||||
// arg1: the text to match.
|
||||
// arg2: the regexp pattern.
|
||||
// eg: match{d.name=,.*linux.*iso}
|
||||
torrent::Object apply_match(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count for 'match': 2 arguments needed.");
|
||||
|
||||
// This really should be converted to using args flagged as
|
||||
// commands, so that we can compare commands and statics values.
|
||||
|
||||
torrent::Object result1;
|
||||
torrent::Object result2;
|
||||
|
||||
rpc::target_type target1 = rpc::is_target_pair(target) ? rpc::get_target_left(target) : target;
|
||||
rpc::target_type target2 = rpc::is_target_pair(target) ? rpc::get_target_right(target) : target;
|
||||
|
||||
if (args.front().is_dict_key())
|
||||
result1 = rpc::commands.call_command(args.front().as_dict_key().c_str(), args.front().as_dict_obj(), target1);
|
||||
else
|
||||
result1 = rpc::parse_command_single(target1, args.front().as_string());
|
||||
|
||||
if (args.back().is_dict_key())
|
||||
result2 = rpc::commands.call_command(args.back().as_dict_key().c_str(), args.back().as_dict_obj(), target2);
|
||||
else
|
||||
result2 = args.back().as_string();
|
||||
|
||||
if (result1.type() != result2.type())
|
||||
throw torrent::input_error("Type mismatch for 'match' arguments.");
|
||||
|
||||
std::string text = result1.as_string();
|
||||
std::string pattern = result2.as_string();
|
||||
|
||||
std::transform(text.begin(), text.end(), text.begin(), ::tolower);
|
||||
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
|
||||
|
||||
bool isAMatch = false;
|
||||
try {
|
||||
std::regex re(pattern);
|
||||
isAMatch = std::regex_match(text, re);
|
||||
} catch (const std::regex_error& exc) {
|
||||
control->core()->push_log_std("regex_error: " + std::string(exc.what()));
|
||||
}
|
||||
|
||||
return isAMatch ? (int64_t)true : (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_time(const torrent::Object& rawArgs, int flags) {
|
||||
std::tm *u;
|
||||
@@ -472,7 +585,7 @@ 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->get_event_added().empty() || !view->get_event_removed().empty())
|
||||
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.");
|
||||
|
||||
view->set_filter("d.views.has=" + args);
|
||||
@@ -489,6 +602,11 @@ cmd_ui_set_view(const torrent::Object::string_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_ui_current_view() {
|
||||
return control->ui()->download_list()->current_view()->name();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_ui_unfocus_download(core::Download* download) {
|
||||
control->ui()->download_list()->unfocus_download(download);
|
||||
@@ -537,6 +655,148 @@ apply_elapsed_greater(const torrent::Object::list_type& args) {
|
||||
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
inline std::vector<int64_t>
|
||||
as_vector(const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in as_vector.");
|
||||
|
||||
std::vector<int64_t> result;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
result.push_back(itr->as_value());
|
||||
} else if (itr->is_string()) {
|
||||
result.push_back(rpc::convert_to_value(itr->as_string()));
|
||||
} else if (itr->is_list()) {
|
||||
std::vector<int64_t> subResult = as_vector(itr->as_list());
|
||||
result.insert(result.end(), subResult.begin(), subResult.end());
|
||||
} else {
|
||||
throw torrent::input_error("Wrong type supplied to as_vector.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_math_basic(const char* name, const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
int64_t val = 0, rhs = 0;
|
||||
bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod");
|
||||
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error(std::string(name) + ": No arguments provided!");
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
rhs = itr->as_value();
|
||||
} else if (itr->is_string()) {
|
||||
rhs = rpc::convert_to_value(itr->as_string());
|
||||
} else if (itr->is_list()) {
|
||||
rhs = apply_math_basic(name, op, itr->as_list());
|
||||
} else {
|
||||
throw torrent::input_error(std::string(name) + ": Wrong argument type");
|
||||
}
|
||||
|
||||
if (divides && !rhs && itr != args.begin())
|
||||
throw torrent::input_error(std::string(name) + ": Division by zero!");
|
||||
|
||||
val = itr == args.begin() ? rhs : op(val, rhs);
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_basic(const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_basic.");
|
||||
|
||||
int64_t val = 0;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
val = itr == args.begin() ? itr->as_value() : (op(val, itr->as_value()) ? val : itr->as_value());
|
||||
} else if (itr->is_string()) {
|
||||
int64_t cval = rpc::convert_to_value(itr->as_string());
|
||||
val = itr == args.begin() ? cval : (op(val, cval) ? val : cval);
|
||||
} else if (itr->is_list()) {
|
||||
int64_t fval = apply_arith_basic(op, itr->as_list());
|
||||
val = itr == args.begin() ? fval : (op(val, fval) ? val : fval);
|
||||
} else {
|
||||
throw torrent::input_error("Wrong type supplied to apply_arith_basic.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_count(const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_count.");
|
||||
|
||||
int64_t val = 0;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
switch (itr->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());
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Wrong type supplied to apply_arith_count.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_other(const char* op, const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_other.");
|
||||
|
||||
if (strcmp(op, "average") == 0) {
|
||||
return (int64_t)(apply_math_basic(op, std::plus<int64_t>(), args) / apply_arith_count(args));
|
||||
} else if (strcmp(op, "median") == 0) {
|
||||
std::vector<int64_t> result = as_vector(args);
|
||||
return (int64_t)rak::median(result.begin(), result.end());
|
||||
} else {
|
||||
throw torrent::input_error("Wrong operation supplied to apply_arith_other.");
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
return torrent::Object();
|
||||
|
||||
std::vector<std::string> throttle_name_list;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
if (itr->is_string())
|
||||
throttle_name_list.push_back(itr->as_string());
|
||||
}
|
||||
|
||||
if (up)
|
||||
control->ui()->set_status_throttle_up_names(throttle_name_list);
|
||||
else
|
||||
control->ui()->set_status_throttle_down_names(throttle_name_list);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_ui() {
|
||||
CMD2_VAR_STRING("keys.layout", "qwerty");
|
||||
@@ -546,12 +806,15 @@ initialize_command_ui() {
|
||||
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_cfilter, &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", 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_cfilter, &core::ViewManager::set_sort_new, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_current", std::bind(&apply_view_cfilter, &core::ViewManager::set_sort_current, 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));
|
||||
@@ -570,11 +833,28 @@ initialize_command_ui() {
|
||||
|
||||
// Commands that affect the default rtorrent UI.
|
||||
CMD2_DL ("ui.unfocus_download", std::bind(&cmd_ui_unfocus_download, std::placeholders::_1));
|
||||
CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view));
|
||||
CMD2_ANY_STRING("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("ui.input.history.size", std::bind(&ui::Root::get_input_history_size, control->ui()));
|
||||
CMD2_ANY_VALUE_V("ui.input.history.size.set", std::bind(&ui::Root::set_input_history_size, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY_V ("ui.input.history.clear", std::bind(&ui::Root::clear_input_history, control->ui()));
|
||||
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
|
||||
|
||||
CMD2_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));
|
||||
|
||||
// TODO: Add 'option_string' for rtorrent-specific options.
|
||||
CMD2_VAR_STRING("ui.torrent_list.layout", "full");
|
||||
|
||||
// Move.
|
||||
CMD2_ANY("print", &apply_print);
|
||||
CMD2_ANY("cat", &apply_cat);
|
||||
CMD2_ANY_LIST("value", &apply_value);
|
||||
CMD2_ANY("try", &apply_try);
|
||||
CMD2_ANY("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_ANY("not", &apply_not);
|
||||
CMD2_ANY("false", &apply_false);
|
||||
@@ -588,6 +868,8 @@ initialize_command_ui() {
|
||||
CMD2_ANY_LIST("less", &apply_less);
|
||||
CMD2_ANY_LIST("greater", &apply_greater);
|
||||
CMD2_ANY_LIST("equal", &apply_equal);
|
||||
CMD2_ANY_LIST("compare", &apply_compare);
|
||||
CMD2_ANY_LIST("match", &apply_match);
|
||||
|
||||
CMD2_ANY_VALUE("convert.gm_time", std::bind(&apply_to_time, std::placeholders::_2, 0));
|
||||
CMD2_ANY_VALUE("convert.gm_date", std::bind(&apply_to_time, std::placeholders::_2, 0x2));
|
||||
@@ -599,6 +881,17 @@ 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.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));
|
||||
}
|
||||
|
||||
+28
-8
@@ -5,12 +5,12 @@
|
||||
// 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
|
||||
@@ -39,11 +39,13 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/connection_manager.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 "display/canvas.h"
|
||||
#include "display/window.h"
|
||||
@@ -66,6 +68,7 @@ Control::Control() :
|
||||
|
||||
m_commandScheduler(new rpc::CommandScheduler()),
|
||||
m_objectStorage(new rpc::object_storage()),
|
||||
m_directory_events(new torrent::directory_events()),
|
||||
|
||||
m_tick(0),
|
||||
m_shutdownReceived(false),
|
||||
@@ -75,9 +78,9 @@ Control::Control() :
|
||||
m_viewManager = new core::ViewManager();
|
||||
m_dhtManager = new core::DhtManager();
|
||||
|
||||
m_inputStdin->slot_pressed(sigc::mem_fun(m_input, &input::Manager::pressed));
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input, std::placeholders::_1));
|
||||
|
||||
m_taskShutdown.set_slot(rak::mem_fn(this, &Control::handle_shutdown));
|
||||
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));
|
||||
}
|
||||
@@ -93,6 +96,7 @@ Control::~Control() {
|
||||
delete m_core;
|
||||
delete m_dhtManager;
|
||||
|
||||
delete m_directory_events;
|
||||
delete m_commandScheduler;
|
||||
delete m_objectStorage;
|
||||
}
|
||||
@@ -114,7 +118,9 @@ Control::initialize() {
|
||||
|
||||
m_ui->init(this);
|
||||
|
||||
m_inputStdin->insert(main_thread->poll());
|
||||
if(!display::Canvas::daemon()) {
|
||||
m_inputStdin->insert(torrent::main_thread()->poll());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -124,13 +130,15 @@ Control::cleanup() {
|
||||
|
||||
priority_queue_erase(&taskScheduler, &m_taskShutdown);
|
||||
|
||||
m_inputStdin->remove(main_thread->poll());
|
||||
if(!display::Canvas::daemon()) {
|
||||
m_inputStdin->remove(torrent::main_thread()->poll());
|
||||
}
|
||||
|
||||
m_core->download_store()->disable();
|
||||
|
||||
m_ui->cleanup();
|
||||
m_core->cleanup();
|
||||
|
||||
|
||||
display::Canvas::erase_std();
|
||||
display::Canvas::refresh_std();
|
||||
display::Canvas::do_update();
|
||||
@@ -146,17 +154,29 @@ Control::cleanup_exception() {
|
||||
|
||||
bool
|
||||
Control::is_shutdown_completed() {
|
||||
return m_shutdownQuick && !worker_thread->is_active() && torrent::is_inactive();
|
||||
if (!m_shutdownQuick || worker_thread->is_active())
|
||||
return false;
|
||||
|
||||
// Tracker requests can be disowned, so wait for these to
|
||||
// finish. The edge case of torrent http downloads may delay
|
||||
// shutdown.
|
||||
if (!core()->http_stack()->empty() || !core()->http_queue()->empty())
|
||||
return false;
|
||||
|
||||
return torrent::is_inactive();
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_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);
|
||||
|
||||
torrent::connection_manager()->listen_close();
|
||||
m_directory_events->close();
|
||||
m_core->shutdown(false);
|
||||
|
||||
if (!m_taskShutdown.is_queued())
|
||||
|
||||
+10
-4
@@ -37,7 +37,7 @@
|
||||
#ifndef RTORRENT_CONTROL_H
|
||||
#define RTORRENT_CONTROL_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
#include <sys/types.h>
|
||||
#include <rak/timer.h>
|
||||
#include <rak/priority_queue_default.h>
|
||||
@@ -68,6 +68,10 @@ namespace rpc {
|
||||
class object_storage;
|
||||
}
|
||||
|
||||
namespace torrent {
|
||||
class directory_events;
|
||||
}
|
||||
|
||||
class Control {
|
||||
public:
|
||||
Control();
|
||||
@@ -90,7 +94,6 @@ public:
|
||||
core::ViewManager* view_manager() { return m_viewManager; }
|
||||
core::DhtManager* dht_manager() { return m_dhtManager; }
|
||||
|
||||
|
||||
ui::Root* ui() { return m_ui; }
|
||||
display::Manager* display() { return m_display; }
|
||||
input::Manager* input() { return m_input; }
|
||||
@@ -99,6 +102,8 @@ public:
|
||||
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; }
|
||||
rpc::object_storage* object_storage() { return m_objectStorage; }
|
||||
|
||||
torrent::directory_events* directory_events() { return m_directory_events; }
|
||||
|
||||
uint64_t tick() const { return m_tick; }
|
||||
void inc_tick() { m_tick++; }
|
||||
|
||||
@@ -118,8 +123,9 @@ private:
|
||||
input::Manager* m_input;
|
||||
input::InputEvent* m_inputStdin;
|
||||
|
||||
rpc::CommandScheduler* m_commandScheduler;
|
||||
rpc::object_storage* m_objectStorage;
|
||||
rpc::CommandScheduler* m_commandScheduler;
|
||||
rpc::object_storage* m_objectStorage;
|
||||
torrent::directory_events* m_directory_events;
|
||||
|
||||
uint64_t m_tick;
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
noinst_LIBRARIES = libsub_core.a
|
||||
|
||||
libsub_core_a_SOURCES = \
|
||||
curl_get.cc \
|
||||
curl_get.h \
|
||||
curl_socket.cc \
|
||||
curl_socket.h \
|
||||
curl_stack.cc \
|
||||
curl_stack.h \
|
||||
dht_manager.cc \
|
||||
dht_manager.h \
|
||||
download.cc \
|
||||
download.h \
|
||||
download_factory.cc \
|
||||
download_factory.h \
|
||||
download_list.cc \
|
||||
download_list.h \
|
||||
download_slot_map.h \
|
||||
download_store.cc \
|
||||
download_store.h \
|
||||
http_queue.cc \
|
||||
http_queue.h \
|
||||
log.cc \
|
||||
log.h \
|
||||
manager.cc \
|
||||
manager.h \
|
||||
poll_manager.cc \
|
||||
poll_manager.h \
|
||||
poll_manager_epoll.cc \
|
||||
poll_manager_epoll.h \
|
||||
poll_manager_kqueue.cc \
|
||||
poll_manager_kqueue.h \
|
||||
poll_manager_select.cc \
|
||||
poll_manager_select.h \
|
||||
range_map.h \
|
||||
view.cc \
|
||||
view.h \
|
||||
view_manager.cc \
|
||||
view_manager.h
|
||||
|
||||
INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
|
||||
+17
-2
@@ -82,7 +82,7 @@ CurlGet::start() {
|
||||
|
||||
// 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.set_slot(rak::mem_fn(this, &CurlGet::receive_timeout));
|
||||
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));
|
||||
}
|
||||
@@ -91,9 +91,13 @@ CurlGet::start() {
|
||||
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
|
||||
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
|
||||
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
|
||||
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
|
||||
|
||||
m_ipv6 = false;
|
||||
|
||||
m_stack->add_get(this);
|
||||
}
|
||||
|
||||
@@ -110,6 +114,17 @@ CurlGet::close() {
|
||||
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");
|
||||
|
||||
+4
-1
@@ -40,7 +40,6 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <torrent/http.h>
|
||||
|
||||
#include "rak/priority_queue_default.h"
|
||||
@@ -59,6 +58,9 @@ public:
|
||||
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; }
|
||||
|
||||
@@ -76,6 +78,7 @@ private:
|
||||
void receive_timeout();
|
||||
|
||||
bool m_active;
|
||||
bool m_ipv6;
|
||||
|
||||
rak::priority_item m_taskTimeout;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include <torrent/poll.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/utils/thread_base.h>
|
||||
|
||||
#include "control.h"
|
||||
|
||||
@@ -69,22 +70,22 @@ CurlSocket::receive_socket(void* easy_handle, curl_socket_t fd, int what, void*
|
||||
|
||||
if (socket == NULL) {
|
||||
socket = stack->new_socket(fd);
|
||||
main_thread->poll()->open(socket);
|
||||
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.
|
||||
main_thread->poll()->insert_error(socket);
|
||||
torrent::main_thread()->poll()->insert_error(socket);
|
||||
}
|
||||
|
||||
if (what == CURL_POLL_NONE || what == CURL_POLL_OUT)
|
||||
main_thread->poll()->remove_read(socket);
|
||||
torrent::main_thread()->poll()->remove_read(socket);
|
||||
else
|
||||
main_thread->poll()->insert_read(socket);
|
||||
torrent::main_thread()->poll()->insert_read(socket);
|
||||
|
||||
if (what == CURL_POLL_NONE || what == CURL_POLL_IN)
|
||||
main_thread->poll()->remove_write(socket);
|
||||
torrent::main_thread()->poll()->remove_write(socket);
|
||||
else
|
||||
main_thread->poll()->insert_write(socket);
|
||||
torrent::main_thread()->poll()->insert_write(socket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -99,7 +100,7 @@ CurlSocket::close() {
|
||||
if (m_fileDesc == -1)
|
||||
throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1.");
|
||||
|
||||
main_thread->poll()->closed(this);
|
||||
torrent::main_thread()->poll()->closed(this);
|
||||
m_fileDesc = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ 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);
|
||||
@@ -62,7 +64,7 @@ private:
|
||||
virtual void event_write();
|
||||
virtual void event_error();
|
||||
|
||||
CurlStack* m_stack;
|
||||
CurlStack* m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+47
-18
@@ -38,7 +38,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <curl/multi.h>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rak/functional.h"
|
||||
@@ -46,18 +45,17 @@
|
||||
#include "curl_socket.h"
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace std { using namespace tr1; }
|
||||
|
||||
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.set_slot(rak::mem_fn(this, &CurlStack::receive_timeout));
|
||||
m_taskTimeout.slot() = std::bind(&CurlStack::receive_timeout, this);
|
||||
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071000)
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
|
||||
@@ -94,29 +92,27 @@ CurlStack::receive_action(CurlSocket* socket, int events) {
|
||||
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);
|
||||
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);
|
||||
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 might be removed when cleaning handles below, future
|
||||
// calls should not use it.
|
||||
socket = NULL;
|
||||
events = 0;
|
||||
|
||||
if ((unsigned int)count != size()) {
|
||||
// Done with some handles.
|
||||
int t;
|
||||
CURLMsg* msg;
|
||||
|
||||
while ((msg = curl_multi_info_read((CURLM*)m_handle, &t)) != NULL) {
|
||||
if (msg->msg != CURLMSG_DONE)
|
||||
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
|
||||
|
||||
transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
|
||||
}
|
||||
while (process_done_handle())
|
||||
; // Do nothing.
|
||||
|
||||
if (empty())
|
||||
priority_queue_erase(&taskScheduler, &m_taskTimeout);
|
||||
@@ -125,6 +121,38 @@ CurlStack::receive_action(CurlSocket* socket, int events) {
|
||||
} 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)));
|
||||
@@ -168,7 +196,8 @@ CurlStack::add_get(CurlGet* get) {
|
||||
if (!m_httpCaCert.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_httpCaCert.c_str());
|
||||
|
||||
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)m_ssl_verify_peer);
|
||||
curl_easy_setopt(get->handle(), CURLOPT_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);
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <sigc++/functors/slot.h>
|
||||
|
||||
#include "rak/priority_queue_default.h"
|
||||
|
||||
@@ -101,7 +100,9 @@ class CurlStack : std::deque<CurlGet*> {
|
||||
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; }
|
||||
@@ -126,6 +127,8 @@ class CurlStack : std::deque<CurlGet*> {
|
||||
|
||||
void receive_timeout();
|
||||
|
||||
bool process_done_handle();
|
||||
|
||||
void* m_handle;
|
||||
|
||||
unsigned int m_active;
|
||||
@@ -139,6 +142,7 @@ class CurlStack : std::deque<CurlGet*> {
|
||||
std::string m_httpCaPath;
|
||||
std::string m_httpCaCert;
|
||||
|
||||
bool m_ssl_verify_host;
|
||||
bool m_ssl_verify_peer;
|
||||
long m_dns_timeout;
|
||||
};
|
||||
|
||||
+51
-39
@@ -54,6 +54,9 @@
|
||||
#include "download_store.h"
|
||||
#include "manager.h"
|
||||
|
||||
#define LT_LOG_THIS(log_fmt, ...) \
|
||||
lt_log_print_subsystem(torrent::LOG_DHT_MANAGER, "dht_manager", log_fmt, __VA_ARGS__);
|
||||
|
||||
namespace core {
|
||||
|
||||
const char* DhtManager::dht_settings[dht_settings_num] = { "disable", "off", "auto", "on" };
|
||||
@@ -65,69 +68,77 @@ DhtManager::~DhtManager() {
|
||||
|
||||
void
|
||||
DhtManager::load_dht_cache() {
|
||||
if (m_start == dht_disable || !control->core()->download_store()->is_enabled())
|
||||
if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) {
|
||||
LT_LOG_THIS("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);
|
||||
|
||||
torrent::Object cache = torrent::Object::create_map();
|
||||
std::fstream cache_file((control->core()->download_store()->path() + "rtorrent.dht_cache").c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (cache_file.is_open()) {
|
||||
cache_file >> cache;
|
||||
if (cache_stream.is_open()) {
|
||||
cache_stream >> cache;
|
||||
|
||||
// If the cache file is corrupted we will just discard it with an
|
||||
// error message.
|
||||
if (cache_file.fail()) {
|
||||
lt_log_print(torrent::LOG_DHT_WARN, "DHT cache file corrupted, discarding.");
|
||||
if (cache_stream.fail()) {
|
||||
LT_LOG_THIS("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());
|
||||
}
|
||||
|
||||
} else {
|
||||
LT_LOG_THIS("could not open cache file (path:%s)", cache_filename.c_str());
|
||||
}
|
||||
|
||||
try {
|
||||
torrent::dht_manager()->initialize(cache);
|
||||
torrent::dht_manager()->initialize(cache);
|
||||
|
||||
if (m_start == dht_on)
|
||||
start_dht();
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
lt_log_print(torrent::LOG_DHT_WARN, "DHT failed: %s", e.what());
|
||||
}
|
||||
if (m_start == dht_on)
|
||||
start_dht();
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::start_dht() {
|
||||
priority_queue_erase(&taskScheduler, &m_stopTimeout);
|
||||
|
||||
if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active())
|
||||
if (!torrent::dht_manager()->is_valid()) {
|
||||
LT_LOG_THIS("server start skipped, manager is uninitialized", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (torrent::dht_manager()->is_active()) {
|
||||
LT_LOG_THIS("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;
|
||||
|
||||
lt_log_print(torrent::LOG_DHT_INFO, "Starting DHT server on port %d.", port);
|
||||
|
||||
try {
|
||||
torrent::dht_manager()->start(port);
|
||||
torrent::dht_manager()->reset_statistics();
|
||||
|
||||
m_updateTimeout.set_slot(rak::mem_fn(this, &DhtManager::update));
|
||||
priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds());
|
||||
|
||||
m_dhtPrevCycle = 0;
|
||||
m_dhtPrevQueriesSent = 0;
|
||||
m_dhtPrevRepliesReceived = 0;
|
||||
m_dhtPrevQueriesReceived = 0;
|
||||
m_dhtPrevBytesUp = 0;
|
||||
m_dhtPrevBytesDown = 0;
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
lt_log_print(torrent::LOG_DHT_ERROR, "DHT start failed: %s", e.what());
|
||||
if (!torrent::dht_manager()->start(port)) {
|
||||
m_start = dht_off;
|
||||
return;
|
||||
}
|
||||
|
||||
torrent::dht_manager()->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_dhtPrevCycle = 0;
|
||||
m_dhtPrevQueriesSent = 0;
|
||||
m_dhtPrevRepliesReceived = 0;
|
||||
m_dhtPrevQueriesReceived = 0;
|
||||
m_dhtPrevBytesUp = 0;
|
||||
m_dhtPrevBytesDown = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -136,8 +147,9 @@ DhtManager::stop_dht() {
|
||||
priority_queue_erase(&taskScheduler, &m_stopTimeout);
|
||||
|
||||
if (torrent::dht_manager()->is_active()) {
|
||||
LT_LOG_THIS("stopping server", 0);
|
||||
|
||||
log_statistics(true);
|
||||
lt_log_print(torrent::LOG_DHT_INFO, "Stopping DHT server.");
|
||||
torrent::dht_manager()->stop();
|
||||
}
|
||||
}
|
||||
@@ -197,7 +209,7 @@ DhtManager::update() {
|
||||
break;
|
||||
|
||||
if (itr == end) {
|
||||
m_stopTimeout.set_slot(rak::mem_fn(this, &DhtManager::stop_dht));
|
||||
m_stopTimeout.slot() = std::bind(&DhtManager::stop_dht, this);
|
||||
priority_queue_insert(&taskScheduler, &m_stopTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds());
|
||||
}
|
||||
}
|
||||
@@ -219,7 +231,7 @@ DhtManager::log_statistics(bool force) {
|
||||
// We should have had clients ping us at least but have received
|
||||
// nothing, that means the UDP port is probably unreachable.
|
||||
if (torrent::dht_manager()->can_receive_queries())
|
||||
lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be unreachable, no queries received.");
|
||||
LT_LOG_THIS("listening port appears to be unreachable, no queries received", 0);
|
||||
|
||||
torrent::dht_manager()->set_can_receive(false);
|
||||
}
|
||||
@@ -227,7 +239,7 @@ DhtManager::log_statistics(bool force) {
|
||||
if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) {
|
||||
// No replies to over 20 queries plus two per node we have. Probably firewalled.
|
||||
if (!m_warned)
|
||||
lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be firewalled, no replies received.");
|
||||
LT_LOG_THIS("listening port appears to be firewalled, no replies received", 0);
|
||||
|
||||
m_warned = true;
|
||||
return false;
|
||||
@@ -248,7 +260,7 @@ DhtManager::log_statistics(bool force) {
|
||||
if (m_dhtPrevCycle == 1) {
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "DHT bootstrap complete, have %d nodes in %d buckets.", stats.num_nodes, stats.num_buckets);
|
||||
control->core()->get_log_complete().push_front(buffer);
|
||||
control->core()->push_log_complete(buffer);
|
||||
m_dhtPrevCycle = stats.cycle;
|
||||
return false;
|
||||
};
|
||||
@@ -271,7 +283,7 @@ DhtManager::log_statistics(bool force) {
|
||||
stats.max_peers,
|
||||
stats.num_trackers);
|
||||
|
||||
control->core()->get_log_complete().push_front(buffer);
|
||||
control->core()->push_log_complete(buffer);
|
||||
|
||||
m_dhtPrevCycle = stats.cycle;
|
||||
m_dhtPrevQueriesSent = stats.queries_sent;
|
||||
|
||||
+3
-23
@@ -36,9 +36,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <sigc++/adaptors/hide.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <list>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/path.h>
|
||||
@@ -61,25 +59,17 @@ Download::Download(download_type d) :
|
||||
m_download(d),
|
||||
m_hashFailed(false),
|
||||
|
||||
m_chunksFailed(0),
|
||||
m_resumeFlags(~uint32_t()),
|
||||
m_group(0) {
|
||||
|
||||
m_connTrackerSucceeded = m_download.info()->signal_tracker_success().connect(sigc::bind(sigc::mem_fun(*this, &Download::receive_tracker_msg), ""));
|
||||
m_connTrackerFailed = m_download.info()->signal_tracker_failed().connect(sigc::mem_fun(*this, &Download::receive_tracker_msg));
|
||||
m_connStorageError = m_download.info()->signal_storage_error().connect(sigc::mem_fun(*this, &Download::receive_storage_error));
|
||||
|
||||
m_download.info()->signal_chunk_failed().connect(sigc::mem_fun(*this, &Download::receive_chunk_failed));
|
||||
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));
|
||||
}
|
||||
|
||||
Download::~Download() {
|
||||
if (!m_download.is_valid())
|
||||
return;
|
||||
|
||||
m_connTrackerSucceeded.disconnect();
|
||||
m_connTrackerFailed.disconnect();
|
||||
m_connStorageError.disconnect();
|
||||
|
||||
m_download = download_type();
|
||||
}
|
||||
|
||||
@@ -125,11 +115,6 @@ Download::receive_tracker_msg(std::string msg) {
|
||||
m_message = "Tracker: [" + msg + "]";
|
||||
}
|
||||
|
||||
void
|
||||
Download::receive_storage_error(std::string msg) {
|
||||
m_message = "Storage error: [" + msg + "]";
|
||||
}
|
||||
|
||||
float
|
||||
Download::distributed_copies() const {
|
||||
const uint8_t* avail = m_download.chunks_seen();
|
||||
@@ -154,11 +139,6 @@ Download::distributed_copies() const {
|
||||
return minAvail + 1 - bitfield->is_all_set() - (float)num / m_download.file_list()->size_chunks();
|
||||
}
|
||||
|
||||
void
|
||||
Download::receive_chunk_failed(__UNUSED uint32_t idx) {
|
||||
m_chunksFailed++;
|
||||
}
|
||||
|
||||
void
|
||||
Download::set_throttle_name(const std::string& throttleName) {
|
||||
if (m_download.info()->is_active())
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_H
|
||||
|
||||
#include <sigc++/connection.h>
|
||||
#include <torrent/download.h>
|
||||
#include <torrent/download_info.h>
|
||||
#include <torrent/hash_string.h>
|
||||
@@ -114,8 +113,6 @@ public:
|
||||
const std::string& message() const { return m_message; }
|
||||
void set_message(const std::string& msg) { m_message = msg; }
|
||||
|
||||
uint32_t chunks_failed() const { return m_chunksFailed; }
|
||||
|
||||
void enable_udp_trackers(bool state);
|
||||
|
||||
uint32_t priority();
|
||||
@@ -141,24 +138,14 @@ private:
|
||||
void operator () (const Download&);
|
||||
|
||||
void receive_tracker_msg(std::string msg);
|
||||
void receive_storage_error(std::string msg);
|
||||
|
||||
void receive_chunk_failed(uint32_t idx);
|
||||
|
||||
// Store the FileList instance so we can use slots etc on it.
|
||||
download_type m_download;
|
||||
|
||||
bool m_hashFailed;
|
||||
|
||||
std::string m_message;
|
||||
uint32_t m_chunksFailed;
|
||||
|
||||
uint32_t m_resumeFlags;
|
||||
|
||||
sigc::connection m_connTrackerSucceeded;
|
||||
sigc::connection m_connTrackerFailed;
|
||||
sigc::connection m_connStorageError;
|
||||
|
||||
unsigned int m_group;
|
||||
};
|
||||
|
||||
|
||||
@@ -38,9 +38,12 @@
|
||||
|
||||
#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>
|
||||
#include <torrent/object_stream.h>
|
||||
@@ -103,16 +106,17 @@ DownloadFactory::DownloadFactory(Manager* m) :
|
||||
m_session(false),
|
||||
m_start(false),
|
||||
m_printLog(true),
|
||||
m_isFile(false) {
|
||||
m_isFile(false),
|
||||
m_initLoad(false) {
|
||||
|
||||
m_taskLoad.set_slot(rak::mem_fn(this, &DownloadFactory::receive_load));
|
||||
m_taskCommit.set_slot(rak::mem_fn(this, &DownloadFactory::receive_commit));
|
||||
m_taskLoad.slot() = std::bind(&DownloadFactory::receive_load, this);
|
||||
m_taskCommit.slot() = std::bind(&DownloadFactory::receive_commit, this);
|
||||
|
||||
// m_variables["connection_leech"] = rpc::call_command_void("protocol.connection.leech");
|
||||
// m_variables["connection_seed"] = rpc::call_command_void("protocol.connection.seed");
|
||||
// m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech");
|
||||
// m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed");
|
||||
m_variables["connection_leech"] = std::string();
|
||||
m_variables["connection_seed"] = std::string();
|
||||
m_variables["directory"] = rpc::call_command_void("directory.default");
|
||||
m_variables["directory"] = rpc::call_command("directory.default");
|
||||
m_variables["tied_to_file"] = torrent::Object((int64_t)false);
|
||||
}
|
||||
|
||||
@@ -214,7 +218,7 @@ DownloadFactory::receive_success() {
|
||||
if (download == NULL) {
|
||||
// core::Manager should already have added the error message to
|
||||
// the log.
|
||||
m_slotFinished();
|
||||
m_slot_finished();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,26 +257,30 @@ DownloadFactory::receive_success() {
|
||||
if (!rtorrent->has_key_string("custom4")) rtorrent->insert_key("custom4", std::string());
|
||||
if (!rtorrent->has_key_string("custom5")) rtorrent->insert_key("custom5", std::string());
|
||||
|
||||
rpc::call_command("d.uploads_min.set", rpc::call_command_void("throttle.min_uploads"), rpc::make_target(download));
|
||||
rpc::call_command("d.uploads_max.set", rpc::call_command_void("throttle.max_uploads"), rpc::make_target(download));
|
||||
rpc::call_command("d.downloads_min.set", rpc::call_command_void("throttle.min_downloads"), rpc::make_target(download));
|
||||
rpc::call_command("d.downloads_max.set", rpc::call_command_void("throttle.max_downloads"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command_void("throttle.min_peers.normal"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command_void("throttle.max_peers.normal"), rpc::make_target(download));
|
||||
rpc::call_command("d.tracker_numwant.set", rpc::call_command_void("trackers.numwant"), rpc::make_target(download));
|
||||
rpc::call_command("d.max_file_size.set", rpc::call_command_void("system.file.max_size"), rpc::make_target(download));
|
||||
rpc::call_command("d.uploads_min.set", rpc::call_command("throttle.min_uploads"), rpc::make_target(download));
|
||||
rpc::call_command("d.uploads_max.set", rpc::call_command("throttle.max_uploads"), rpc::make_target(download));
|
||||
rpc::call_command("d.downloads_min.set", rpc::call_command("throttle.min_downloads"), rpc::make_target(download));
|
||||
rpc::call_command("d.downloads_max.set", rpc::call_command("throttle.max_downloads"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.normal"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.normal"), rpc::make_target(download));
|
||||
rpc::call_command("d.tracker_numwant.set", rpc::call_command("trackers.numwant"), rpc::make_target(download));
|
||||
rpc::call_command("d.max_file_size.set", rpc::call_command("system.file.max_size"), rpc::make_target(download));
|
||||
|
||||
if (rpc::call_command_value("d.complete", rpc::make_target(download)) != 0) {
|
||||
if (rpc::call_command_value("throttle.min_peers.seed") >= 0)
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command_void("throttle.min_peers.seed"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.seed"), rpc::make_target(download));
|
||||
|
||||
if (rpc::call_command_value("throttle.max_peers.seed") >= 0)
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command_void("throttle.max_peers.seed"), rpc::make_target(download));
|
||||
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);
|
||||
|
||||
// Check first if we already have these values set in the session
|
||||
// torrent, so that it is safe to change the values.
|
||||
//
|
||||
@@ -302,7 +310,7 @@ DownloadFactory::receive_success() {
|
||||
// ATM doesn't really ever get here.
|
||||
delete download;
|
||||
|
||||
m_slotFinished();
|
||||
m_slot_finished();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -310,6 +318,9 @@ DownloadFactory::receive_success() {
|
||||
torrent::HashString infohash = download->info()->hash();
|
||||
|
||||
try {
|
||||
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)));
|
||||
|
||||
@@ -325,10 +336,8 @@ DownloadFactory::receive_success() {
|
||||
} catch (torrent::input_error& e) {
|
||||
std::string msg = "Command on torrent creation failed: " + std::string(e.what());
|
||||
|
||||
if (m_printLog) {
|
||||
m_manager->get_log_important().push_front(msg);
|
||||
m_manager->get_log_complete().push_front(msg);
|
||||
}
|
||||
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?
|
||||
@@ -338,18 +347,42 @@ DownloadFactory::receive_success() {
|
||||
}
|
||||
}
|
||||
|
||||
m_slotFinished();
|
||||
m_slot_finished();
|
||||
}
|
||||
|
||||
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 << "session = " << (m_session ? "true" : "false") << std::endl;
|
||||
|
||||
if (download->download()->info()->is_meta_download())
|
||||
dump << "magnet = true" << std::endl;
|
||||
|
||||
if (!rtorrent->has_key_string("directory"))
|
||||
dump << "directory = \"" << (m_variables["directory"].is_string() ? m_variables["directory"].as_string() : std::string()) << '"' << std::endl;
|
||||
else
|
||||
dump << "directory_base = \"" << (rtorrent->get_key("directory").is_string() ? rtorrent->get_key("directory").as_string() : std::string()) << '"' << std::endl;
|
||||
|
||||
dump << "---COMMANDS---" << std::endl;
|
||||
|
||||
for (command_list_type::const_iterator itr = m_commands.begin(); itr != m_commands.end(); itr++) {
|
||||
dump << *itr << std::endl;
|
||||
}
|
||||
|
||||
std::string dump_str = dump.str();
|
||||
|
||||
lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:");
|
||||
}
|
||||
|
||||
void
|
||||
DownloadFactory::receive_failed(const std::string& msg) {
|
||||
// Add message to log.
|
||||
if (m_printLog) {
|
||||
m_manager->get_log_important().push_front(msg + ": \"" + m_uri + "\"");
|
||||
m_manager->get_log_complete().push_front(msg + ": \"" + m_uri + "\"");
|
||||
}
|
||||
if (m_printLog)
|
||||
m_manager->push_log_std(msg + ": \"" + m_uri + "\"");
|
||||
|
||||
m_slotFinished();
|
||||
m_slot_finished();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -391,6 +424,9 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
|
||||
if (rtorrent->has_key_value("total_uploaded"))
|
||||
download->info()->mutable_up_rate()->set_total(rtorrent->get_key_value("total_uploaded"));
|
||||
|
||||
if (rtorrent->has_key_value("total_downloaded"))
|
||||
download->info()->mutable_down_rate()->set_total(rtorrent->get_key_value("total_downloaded"));
|
||||
|
||||
if (rtorrent->has_key_value("chunks_done") && rtorrent->has_key_value("chunks_wanted"))
|
||||
download->download()->set_chunks_done(rtorrent->get_key_value("chunks_done"), rtorrent->get_key_value("chunks_wanted"));
|
||||
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_FACTORY_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_FACTORY_H
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <sigc++/functors/slot.h>
|
||||
|
||||
#include <rak/priority_queue_default.h>
|
||||
#include <torrent/object.h>
|
||||
|
||||
@@ -54,7 +55,7 @@ class Manager;
|
||||
|
||||
class DownloadFactory {
|
||||
public:
|
||||
typedef sigc::slot<void> Slot;
|
||||
typedef std::function<void ()> slot_void;
|
||||
typedef std::vector<std::string> command_list_type;
|
||||
|
||||
// Do not destroy this object while it is in a HttpQueue.
|
||||
@@ -77,10 +78,13 @@ public:
|
||||
bool get_start() const { return m_start; }
|
||||
void set_start(bool v) { m_start = v; }
|
||||
|
||||
bool get_init_load() const { return m_initLoad; }
|
||||
void set_init_load(bool v) { m_initLoad = v; }
|
||||
|
||||
bool print_log() const { return m_printLog; }
|
||||
void set_print_log(bool v) { m_printLog = v; }
|
||||
|
||||
void slot_finished(Slot s) { m_slotFinished = s; }
|
||||
void slot_finished(slot_void s) { m_slot_finished = s; }
|
||||
|
||||
private:
|
||||
void receive_load();
|
||||
@@ -89,6 +93,8 @@ private:
|
||||
void receive_success();
|
||||
void receive_failed(const std::string& msg);
|
||||
|
||||
void log_created(Download* download, torrent::Object* rtorrent);
|
||||
|
||||
void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
|
||||
|
||||
Manager* m_manager;
|
||||
@@ -103,11 +109,12 @@ private:
|
||||
bool m_start;
|
||||
bool m_printLog;
|
||||
bool m_isFile;
|
||||
bool m_initLoad;
|
||||
|
||||
command_list_type m_commands;
|
||||
torrent::Object::map_type m_variables;
|
||||
|
||||
Slot m_slotFinished;
|
||||
slot_void m_slot_finished;
|
||||
rak::priority_item m_taskLoad;
|
||||
rak::priority_item m_taskCommit;
|
||||
};
|
||||
|
||||
+55
-27
@@ -39,7 +39,6 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <torrent/data/file.h>
|
||||
@@ -64,6 +63,7 @@
|
||||
#include "download.h"
|
||||
#include "download_list.h"
|
||||
#include "download_store.h"
|
||||
#include "ui/root.h"
|
||||
|
||||
#define DL_TRIGGER_EVENT(download, event_name) \
|
||||
rpc::commands.call_catch(event_name, rpc::make_target(download), torrent::Object(), "Event '" event_name "' failed: ");
|
||||
@@ -94,6 +94,7 @@ DownloadList::session_save() {
|
||||
lt_log_print(torrent::LOG_ERROR, "Failed to save session torrents.");
|
||||
|
||||
control->dht_manager()->save_dht_cache();
|
||||
control->ui()->save_input_history();
|
||||
}
|
||||
|
||||
DownloadList::iterator
|
||||
@@ -178,6 +179,8 @@ DownloadList::iterator
|
||||
DownloadList::insert(Download* download) {
|
||||
iterator itr = base_type::insert(end(), download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download.");
|
||||
|
||||
try {
|
||||
(*itr)->data()->slot_initial_hash() = std::bind(&DownloadList::hash_done, this, download);
|
||||
(*itr)->data()->slot_download_done() = std::bind(&DownloadList::received_finished, this, download);
|
||||
@@ -208,6 +211,8 @@ DownloadList::erase(iterator itr) {
|
||||
if (itr == end())
|
||||
throw torrent::internal_error("DownloadList::erase(...) could not find download.");
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, (*itr)->info(), "download_list", "Erasing download.");
|
||||
|
||||
// Makes sure close doesn't restart hashing of this download.
|
||||
(*itr)->set_hash_failed(true);
|
||||
|
||||
@@ -242,6 +247,8 @@ void
|
||||
DownloadList::open_throw(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Opening download.");
|
||||
|
||||
if (download->download()->info()->is_open())
|
||||
return;
|
||||
|
||||
@@ -257,7 +264,6 @@ DownloadList::open_throw(Download* download) {
|
||||
void
|
||||
DownloadList::close(Download* download) {
|
||||
try {
|
||||
|
||||
close_throw(download);
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
@@ -267,6 +273,8 @@ DownloadList::close(Download* download) {
|
||||
|
||||
void
|
||||
DownloadList::close_directly(Download* download) {
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download directly.");
|
||||
|
||||
if (download->download()->info()->is_active()) {
|
||||
download->download()->stop(torrent::Download::stop_skip_tracker);
|
||||
|
||||
@@ -280,6 +288,7 @@ DownloadList::close_directly(Download* download) {
|
||||
|
||||
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
|
||||
@@ -293,6 +302,8 @@ void
|
||||
DownloadList::close_throw(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download with throw.");
|
||||
|
||||
// When pause gets called it will clear the initial hash check state
|
||||
// and set hash failed. This should ensure hashing doesn't restart
|
||||
// until resume gets called.
|
||||
@@ -324,6 +335,8 @@ void
|
||||
DownloadList::resume(Download* download, int flags) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Resuming download: flags:%0x.", flags);
|
||||
|
||||
try {
|
||||
|
||||
if (download->download()->info()->is_active())
|
||||
@@ -361,26 +374,26 @@ DownloadList::resume(Download* download, int flags) {
|
||||
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()) {
|
||||
torrent::Object conn_current = rpc::call_command_void("d.connection_seed", rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command_void("d.up.choke_heuristics.seed", rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command_void("d.down.choke_heuristics.seed", rpc::make_target(download));
|
||||
torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command_void("protocol.connection.seed", rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command_void("protocol.choke_heuristics.up.seed", rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command_void("protocol.choke_heuristics.down.seed", rpc::make_target(download));
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download));
|
||||
rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download));
|
||||
rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download));
|
||||
|
||||
} else {
|
||||
torrent::Object conn_current = rpc::call_command_void("d.connection_leech", rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command_void("d.up.choke_heuristics.leech", rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command_void("d.down.choke_heuristics.leech", rpc::make_target(download));
|
||||
torrent::Object conn_current = rpc::call_command("d.connection_leech", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.leech", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.leech", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command_void("protocol.connection.leech", rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command_void("protocol.choke_heuristics.up.leech", rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command_void("protocol.choke_heuristics.down.leech", rpc::make_target(download));
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.leech", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.leech", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.leech", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download));
|
||||
rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download));
|
||||
@@ -417,6 +430,8 @@ void
|
||||
DownloadList::pause(Download* download, int flags) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Pausing download: flags:%0x.", flags);
|
||||
|
||||
try {
|
||||
|
||||
download->set_resume_flags(~uint32_t());
|
||||
@@ -448,8 +463,8 @@ DownloadList::pause(Download* download, int flags) {
|
||||
|
||||
// If initial seeding is complete, don't try it again when restarting.
|
||||
if (download->is_done() &&
|
||||
rpc::call_command_void("d.connection_current", rpc::make_target(download)).as_string() == "initial_seed")
|
||||
rpc::call_command("d.connection_seed.set", rpc::call_command_void("d.connection_current", rpc::make_target(download)), rpc::make_target(download));
|
||||
rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)).as_string() == "initial_seed")
|
||||
rpc::call_command("d.connection_seed.set", rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)), rpc::make_target(download));
|
||||
|
||||
// Save the state after all the slots, etc have been called so we
|
||||
// include the modifications they may make.
|
||||
@@ -464,8 +479,9 @@ void
|
||||
DownloadList::check_hash(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
try {
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Checking hash.");
|
||||
|
||||
try {
|
||||
if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
|
||||
return;
|
||||
|
||||
@@ -480,6 +496,8 @@ void
|
||||
DownloadList::hash_done(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash done.");
|
||||
|
||||
if (download->is_hash_checking() || download->is_active())
|
||||
throw torrent::internal_error("DownloadList::hash_done(...) download in invalid state.");
|
||||
|
||||
@@ -554,6 +572,8 @@ void
|
||||
DownloadList::hash_queue(Download* download, int type) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash queue.");
|
||||
|
||||
if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped)
|
||||
throw torrent::internal_error("DownloadList::hash_queue(...) hashing already queued.");
|
||||
|
||||
@@ -583,6 +603,8 @@ void
|
||||
DownloadList::received_finished(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Received finished.");
|
||||
|
||||
if (rpc::call_command_value("pieces.hash.on_completion"))
|
||||
// Set some 'checking_finished_thingie' variable to make hash_done
|
||||
// trigger correctly, also so it can bork on missing data.
|
||||
@@ -596,19 +618,21 @@ void
|
||||
DownloadList::confirm_finished(Download* download) {
|
||||
check_contains(download);
|
||||
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Confirming finished.");
|
||||
|
||||
if (download->download()->info()->is_meta_download())
|
||||
return process_meta_download(download);
|
||||
|
||||
rpc::call_command("d.complete.set", (int64_t)1, rpc::make_target(download));
|
||||
|
||||
// Clean up these settings:
|
||||
torrent::Object conn_current = rpc::call_command_void("d.connection_seed", rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command_void("d.up.choke_heuristics.seed", rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command_void("d.down.choke_heuristics.seed", rpc::make_target(download));
|
||||
torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
|
||||
torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command_void("protocol.connection.seed", rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command_void("protocol.choke_heuristics.up.seed", rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command_void("protocol.choke_heuristics.down.seed", rpc::make_target(download));
|
||||
if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download));
|
||||
rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download));
|
||||
@@ -618,11 +642,11 @@ DownloadList::confirm_finished(Download* download) {
|
||||
|
||||
if (rpc::call_command_value("d.peers_min", rpc::make_target(download)) == rpc::call_command_value("throttle.min_peers.normal") &&
|
||||
rpc::call_command_value("throttle.min_peers.seed") >= 0)
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command_void("throttle.min_peers.seed"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.seed"), rpc::make_target(download));
|
||||
|
||||
if (rpc::call_command_value("d.peers_max", rpc::make_target(download)) == rpc::call_command_value("throttle.max_peers.normal") &&
|
||||
rpc::call_command_value("throttle.max_peers.seed") >= 0)
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command_void("throttle.max_peers.seed"), rpc::make_target(download));
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
|
||||
|
||||
// Do this before the slots are called in case one of them closes
|
||||
// the download.
|
||||
@@ -642,6 +666,9 @@ DownloadList::confirm_finished(Download* download) {
|
||||
|
||||
DL_TRIGGER_EVENT(download, "event.download.finished");
|
||||
|
||||
if (find(infohash) == end())
|
||||
return;
|
||||
|
||||
// if (download->resume_flags() != ~uint32_t())
|
||||
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
|
||||
|
||||
@@ -655,8 +682,7 @@ DownloadList::confirm_finished(Download* download) {
|
||||
// being hashed.
|
||||
download->set_resume_flags(~uint32_t());
|
||||
|
||||
if (find(infohash) != end() &&
|
||||
!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
|
||||
if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
|
||||
resume(download,
|
||||
torrent::Download::start_no_create |
|
||||
torrent::Download::start_skip_tracker |
|
||||
@@ -665,6 +691,8 @@ DownloadList::confirm_finished(Download* download) {
|
||||
|
||||
void
|
||||
DownloadList::process_meta_download(Download* download) {
|
||||
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Processing meta download.");
|
||||
|
||||
rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
|
||||
rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
|
||||
@@ -37,21 +37,21 @@
|
||||
#ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
|
||||
#define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sigc++/functors/slot.h>
|
||||
|
||||
#include "download.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class DownloadSlotMap : public std::map<std::string, sigc::slot1<void, Download*> > {
|
||||
class DownloadSlotMap : public std::map<std::string, std::function<void (Download*)> > {
|
||||
public:
|
||||
typedef sigc::slot1<void, Download*> SlotDownload;
|
||||
typedef std::map<std::string, SlotDownload> Base;
|
||||
typedef std::function<void (Download*)> slot_download;
|
||||
typedef std::map<std::string, slot_download> Base;
|
||||
|
||||
void insert(const std::string& key, SlotDownload s) { Base::operator[](key) = s; }
|
||||
void erase(const std::string& key) { Base::erase(key); }
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
@@ -100,6 +101,7 @@ DownloadStore::set_path(const std::string& 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);
|
||||
|
||||
@@ -121,6 +123,15 @@ DownloadStore::write_bencode(const std::string& filename, const torrent::Object&
|
||||
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:
|
||||
@@ -140,6 +151,7 @@ DownloadStore::save(Download* d, int flags) {
|
||||
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);
|
||||
@@ -182,7 +194,7 @@ DownloadStore::remove(Download* d) {
|
||||
// This also needs to check that it isn't a directory.
|
||||
bool
|
||||
not_correct_format(const utils::directory_entry& entry) {
|
||||
return !DownloadStore::is_correct_format(entry.d_name);
|
||||
return !DownloadStore::is_correct_format(entry.s_name);
|
||||
}
|
||||
|
||||
utils::Directory
|
||||
|
||||
+15
-16
@@ -38,45 +38,44 @@
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <sigc++/adaptors/hide.h>
|
||||
#include <torrent/http.h>
|
||||
|
||||
#include "rak/functional.h"
|
||||
#include "http_queue.h"
|
||||
#include "curl_get.h"
|
||||
|
||||
namespace std { using namespace tr1; }
|
||||
|
||||
namespace core {
|
||||
|
||||
HttpQueue::iterator
|
||||
HttpQueue::insert(const std::string& url, std::iostream* s) {
|
||||
std::auto_ptr<CurlGet> h(m_slotFactory());
|
||||
std::auto_ptr<CurlGet> h(m_slot_factory());
|
||||
|
||||
h->set_url(url);
|
||||
h->set_stream(s);
|
||||
h->set_timeout(5 * 60);
|
||||
|
||||
iterator itr = Base::insert(end(), h.get());
|
||||
iterator signal_itr = base_type::insert(end(), h.get());
|
||||
|
||||
h->signal_done().push_back(std::bind(&HttpQueue::erase, this, itr));
|
||||
h->signal_failed().push_back(std::bind(&HttpQueue::erase, this, itr));
|
||||
h->signal_done().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
|
||||
h->signal_failed().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
|
||||
|
||||
(*itr)->start();
|
||||
(*signal_itr)->start();
|
||||
|
||||
h.release();
|
||||
m_signalInsert.emit(*itr);
|
||||
|
||||
return itr;
|
||||
for (signal_curl_get::iterator itr = m_signal_insert.begin(), last = m_signal_insert.end(); itr != last; itr++)
|
||||
(*itr)(*signal_itr);
|
||||
|
||||
return signal_itr;
|
||||
}
|
||||
|
||||
void
|
||||
HttpQueue::erase(iterator itr) {
|
||||
m_signalErase.emit(*itr);
|
||||
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);
|
||||
|
||||
delete *itr;
|
||||
Base::erase(itr);
|
||||
delete *signal_itr;
|
||||
base_type::erase(signal_itr);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -84,7 +83,7 @@ HttpQueue::clear() {
|
||||
while (!empty())
|
||||
erase(begin());
|
||||
|
||||
Base::clear();
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-21
@@ -37,9 +37,9 @@
|
||||
#ifndef RTORRENT_CORE_HTTP_QUEUE_H
|
||||
#define RTORRENT_CORE_HTTP_QUEUE_H
|
||||
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <sigc++/signal.h>
|
||||
#include <list>
|
||||
|
||||
namespace core {
|
||||
|
||||
@@ -47,22 +47,23 @@ class CurlGet;
|
||||
|
||||
class HttpQueue : private std::list<CurlGet*> {
|
||||
public:
|
||||
typedef std::list<CurlGet*> Base;
|
||||
typedef sigc::signal1<void, CurlGet*> SignalHttp;
|
||||
typedef sigc::slot0<CurlGet*> SlotFactory;
|
||||
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::iterator;
|
||||
using Base::const_iterator;
|
||||
using Base::reverse_iterator;
|
||||
using Base::const_reverse_iterator;
|
||||
using base_type::iterator;
|
||||
using base_type::const_iterator;
|
||||
using base_type::reverse_iterator;
|
||||
using base_type::const_reverse_iterator;
|
||||
|
||||
using Base::begin;
|
||||
using Base::end;
|
||||
using Base::rbegin;
|
||||
using Base::rend;
|
||||
using base_type::begin;
|
||||
using base_type::end;
|
||||
using base_type::rbegin;
|
||||
using base_type::rend;
|
||||
|
||||
using Base::empty;
|
||||
using Base::size;
|
||||
using base_type::empty;
|
||||
using base_type::size;
|
||||
|
||||
HttpQueue() {}
|
||||
~HttpQueue() { clear(); }
|
||||
@@ -77,15 +78,15 @@ public:
|
||||
|
||||
void clear();
|
||||
|
||||
void slot_factory(SlotFactory s) { m_slotFactory = s; }
|
||||
void set_slot_factory(slot_factory s) { m_slot_factory = s; }
|
||||
|
||||
SignalHttp& signal_insert() { return m_signalInsert; }
|
||||
SignalHttp& signal_erase() { return m_signalErase; }
|
||||
signal_curl_get& signal_insert() { return m_signal_insert; }
|
||||
signal_curl_get& signal_erase() { return m_signal_erase; }
|
||||
|
||||
private:
|
||||
SlotFactory m_slotFactory;
|
||||
SignalHttp m_signalInsert;
|
||||
SignalHttp m_signalErase;
|
||||
slot_factory m_slot_factory;
|
||||
signal_curl_get m_signal_insert;
|
||||
signal_curl_get m_signal_erase;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,65 +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 <rak/functional.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void
|
||||
Log::push_front(const std::string& msg) {
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
Base::push_front(Type(cachedTime, msg));
|
||||
|
||||
if (size() > 50)
|
||||
Base::pop_back();
|
||||
|
||||
m_signalUpdate.emit();
|
||||
}
|
||||
|
||||
Log::iterator
|
||||
Log::find_older(rak::timer t) {
|
||||
return std::find_if(begin(), end(), rak::on(rak::mem_ref(&Type::first), std::bind2nd(std::less_equal<rak::timer>(), t)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +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_LOG_H
|
||||
#define RTORRENT_CORE_LOG_H
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <sigc++/signal.h>
|
||||
|
||||
#include <rak/timer.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
class Log : private std::deque<std::pair<rak::timer, std::string> > {
|
||||
public:
|
||||
typedef std::pair<rak::timer, std::string> Type;
|
||||
typedef std::deque<Type> Base;
|
||||
typedef sigc::signal0<void> Signal;
|
||||
|
||||
using Base::iterator;
|
||||
using Base::const_iterator;
|
||||
using Base::reverse_iterator;
|
||||
using Base::const_reverse_iterator;
|
||||
|
||||
using Base::begin;
|
||||
using Base::end;
|
||||
using Base::rbegin;
|
||||
using Base::rend;
|
||||
|
||||
using Base::empty;
|
||||
using Base::size;
|
||||
|
||||
Log() : m_enabled(true) {}
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
|
||||
void enable() { m_enabled = true; }
|
||||
void disable() { m_enabled = false; }
|
||||
|
||||
void push_front(const std::string& msg);
|
||||
|
||||
iterator find_older(rak::timer t);
|
||||
|
||||
Signal& signal_update() { return m_signalUpdate; }
|
||||
|
||||
private:
|
||||
bool m_enabled;
|
||||
|
||||
Signal m_signalUpdate;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+56
-85
@@ -47,8 +47,6 @@
|
||||
#include <rak/regex.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <sigc++/adaptors/hide.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
@@ -71,83 +69,26 @@
|
||||
#include "download_store.h"
|
||||
#include "http_queue.h"
|
||||
#include "manager.h"
|
||||
#include "poll_manager_epoll.h"
|
||||
#include "poll_manager_kqueue.h"
|
||||
#include "poll_manager_select.h"
|
||||
#include "poll_manager.h"
|
||||
#include "view.h"
|
||||
|
||||
namespace std { using namespace tr1; }
|
||||
|
||||
namespace core {
|
||||
|
||||
void
|
||||
Manager::handshake_log(const sockaddr* sa, int msg, int err, const torrent::HashString* hash) {
|
||||
if (!rpc::call_command_value("log.handshake"))
|
||||
return;
|
||||
|
||||
std::string peer;
|
||||
std::string download;
|
||||
|
||||
const rak::socket_address* socketAddress = rak::socket_address::cast_from(sa);
|
||||
|
||||
if (socketAddress->is_valid()) {
|
||||
char port[6];
|
||||
snprintf(port, sizeof(port), "%d", socketAddress->port());
|
||||
peer = socketAddress->address_str() + ":" + port;
|
||||
} else {
|
||||
peer = "(unknown)";
|
||||
}
|
||||
|
||||
// torrent::Download d = torrent::download_find(hash);
|
||||
|
||||
// if (d.is_valid())
|
||||
// download = ": " + d.name();
|
||||
// else
|
||||
download = "";
|
||||
|
||||
switch (msg) {
|
||||
case torrent::ConnectionManager::handshake_incoming:
|
||||
m_logComplete.push_front("Incoming connection from " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_outgoing:
|
||||
m_logComplete.push_front("Outgoing connection to " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_outgoing_encrypted:
|
||||
m_logComplete.push_front("Outgoing encrypted connection to " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_outgoing_proxy:
|
||||
m_logComplete.push_front("Outgoing proxy connection to " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_success:
|
||||
m_logComplete.push_front("Successful handshake: " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_dropped:
|
||||
m_logComplete.push_front("Dropped handshake: " + peer + " - " + torrent::strerror(err) + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_failed:
|
||||
m_logComplete.push_front("Handshake failed: " + peer + " - " + torrent::strerror(err) + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_retry_plaintext:
|
||||
m_logComplete.push_front("Trying again without encryption: " + peer + download);
|
||||
break;
|
||||
case torrent::ConnectionManager::handshake_retry_encrypted:
|
||||
m_logComplete.push_front("Trying again encrypted: " + peer + download);
|
||||
break;
|
||||
default:
|
||||
m_logComplete.push_front("Unknown handshake message for " + peer + download);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int Manager::create_start;
|
||||
const int Manager::create_tied;
|
||||
const int Manager::create_quiet;
|
||||
const int Manager::create_raw_data;
|
||||
|
||||
void
|
||||
Manager::push_log(const char* msg) {
|
||||
m_logImportant.push_front(msg);
|
||||
m_logComplete.push_front(msg);
|
||||
m_log_important->lock_and_push_log(msg, strlen(msg), 0);
|
||||
m_log_complete->lock_and_push_log(msg, strlen(msg), 0);
|
||||
}
|
||||
|
||||
Manager::Manager() :
|
||||
m_hashingView(NULL)
|
||||
// m_pollManager(NULL) {
|
||||
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();
|
||||
@@ -164,6 +105,8 @@ Manager::~Manager() {
|
||||
torrent::Throttle::destroy_throttle(m_throttles["NULL"].first);
|
||||
delete m_downloadList;
|
||||
|
||||
// TODO: Clean up logs objects.
|
||||
|
||||
delete m_downloadStore;
|
||||
delete m_httpQueue;
|
||||
delete m_fileStatusCache;
|
||||
@@ -175,7 +118,7 @@ Manager::set_hashing_view(View* v) {
|
||||
throw torrent::internal_error("Manager::set_hashing_view(...) received NULL or is already set.");
|
||||
|
||||
m_hashingView = v;
|
||||
v->signal_changed().connect(sigc::mem_fun(this, &Manager::receive_hashing_changed));
|
||||
m_hashingView->signal_changed().push_back(std::bind(&Manager::receive_hashing_changed, this));
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
@@ -195,7 +138,7 @@ Manager::get_throttle(const std::string& name) {
|
||||
void
|
||||
Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles) {
|
||||
m_addressThrottles.set_merge(begin, end, throttles);
|
||||
torrent::connection_manager()->set_address_throttle(sigc::mem_fun(control->core(), &core::Manager::get_address_throttle));
|
||||
torrent::connection_manager()->address_throttle() = std::bind(&core::Manager::get_address_throttle, control->core(), std::placeholders::_1);
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
@@ -203,15 +146,42 @@ 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);
|
||||
|
||||
if (itr == throttles().end()) {
|
||||
return (int64_t)-1;
|
||||
} else {
|
||||
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)
|
||||
return (int64_t)-1;
|
||||
|
||||
int64_t throttle_max = (int64_t)throttle->max_rate();
|
||||
|
||||
if (rate) {
|
||||
|
||||
if (throttle_max > 0)
|
||||
return (int64_t)throttle->rate()->rate();
|
||||
else
|
||||
return (int64_t)-1;
|
||||
|
||||
} else {
|
||||
return throttle_max;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Most of this should be possible to move out.
|
||||
void
|
||||
Manager::initialize_second() {
|
||||
torrent::Http::set_factory(std::bind(&CurlStack::new_object, m_httpStack));
|
||||
m_httpQueue->slot_factory(sigc::mem_fun(m_httpStack, &CurlStack::new_object));
|
||||
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();
|
||||
|
||||
torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -247,7 +217,7 @@ Manager::listen_open() {
|
||||
return;
|
||||
|
||||
int portFirst, portLast;
|
||||
torrent::Object portRange = rpc::call_command_void("network.port_range");
|
||||
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)
|
||||
@@ -287,7 +257,8 @@ 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)
|
||||
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 {
|
||||
@@ -321,7 +292,8 @@ 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)
|
||||
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 {
|
||||
@@ -373,8 +345,7 @@ Manager::set_proxy_address(const std::string& addr) {
|
||||
|
||||
void
|
||||
Manager::receive_http_failed(std::string msg) {
|
||||
m_logImportant.push_front("Http download error: \"" + msg + "\"");
|
||||
m_logComplete.push_front("Http download error: \"" + msg + "\"");
|
||||
push_log_std("Http download error: \"" + msg + "\"");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -395,7 +366,7 @@ 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(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
|
||||
f->slot_finished(std::bind(&rak::call_delete_func<core::DownloadFactory>, f));
|
||||
|
||||
if (flags & create_raw_data)
|
||||
f->load_raw_data(uri);
|
||||
@@ -419,7 +390,7 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
|
||||
|
||||
f->set_start(meta.get_key_value("start"));
|
||||
f->set_print_log(meta.get_key_value("print_log"));
|
||||
f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
|
||||
f->slot_finished(std::bind(&rak::call_delete_func<core::DownloadFactory>, f));
|
||||
|
||||
// Bit of a waste to create the bencode repesentation here
|
||||
// only to have the DownloadFactory decode it.
|
||||
@@ -432,7 +403,7 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
|
||||
|
||||
utils::Directory
|
||||
path_expand_transform(std::string path, const utils::directory_entry& entry) {
|
||||
return path + entry.d_name;
|
||||
return path + entry.s_name;
|
||||
}
|
||||
|
||||
// Move this somewhere better.
|
||||
@@ -472,9 +443,9 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
// 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::d_name), std::not1(r))), itr->end());
|
||||
itr->erase(std::remove_if(itr->begin(), itr->end(), rak::on(rak::mem_ref(&utils::directory_entry::s_name), std::not1(r))), itr->end());
|
||||
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + "/"));
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + (itr->path() == "/" ? "" : "/")));
|
||||
}
|
||||
|
||||
currentCache.clear();
|
||||
|
||||
+13
-45
@@ -1,51 +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
|
||||
|
||||
#ifndef RTORRENT_CORE_MANAGER_H
|
||||
#define RTORRENT_CORE_MANAGER_H
|
||||
|
||||
#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"
|
||||
#include "log.h"
|
||||
|
||||
namespace torrent {
|
||||
class Bencode;
|
||||
@@ -69,8 +35,8 @@ public:
|
||||
typedef DownloadList::iterator DListItr;
|
||||
typedef utils::FileStatusCache FileStatusCache;
|
||||
|
||||
typedef sigc::slot1<void, DownloadList::iterator> SlotReady;
|
||||
typedef sigc::slot0<void> SlotFailed;
|
||||
// typedef std::function<void (DownloadList::iterator)> slot_ready;
|
||||
// typedef std::function<void ()> slot_void;
|
||||
|
||||
Manager();
|
||||
~Manager();
|
||||
@@ -85,12 +51,14 @@ public:
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
void set_hashing_view(View* v);
|
||||
|
||||
Log& get_log_important() { return m_logImportant; }
|
||||
Log& get_log_complete() { return m_logComplete; }
|
||||
torrent::log_buffer* log_important() { return m_log_important.get(); }
|
||||
torrent::log_buffer* log_complete() { return m_log_complete.get(); }
|
||||
|
||||
ThrottleMap& throttles() { return m_throttles; }
|
||||
torrent::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);
|
||||
@@ -113,8 +81,8 @@ public:
|
||||
void shutdown(bool force);
|
||||
|
||||
void push_log(const char* msg);
|
||||
void push_log_std(const std::string& msg) { m_logImportant.push_front(msg); m_logComplete.push_front(msg); }
|
||||
void push_log_complete(const std::string& msg) { m_logComplete.push_front(msg); }
|
||||
void push_log_std(const std::string& msg) { m_log_important->lock_and_push_log(msg.c_str(), msg.size(), 0); m_log_complete->lock_and_push_log(msg.c_str(), msg.size(), 0); }
|
||||
void push_log_complete(const std::string& msg) { m_log_complete->lock_and_push_log(msg.c_str(), msg.size(), 0); }
|
||||
|
||||
void handshake_log(const sockaddr* sa, int msg, int err, const torrent::HashString* hash);
|
||||
|
||||
@@ -152,8 +120,8 @@ private:
|
||||
ThrottleMap m_throttles;
|
||||
AddressThrottleMap m_addressThrottles;
|
||||
|
||||
Log m_logImportant;
|
||||
Log m_logComplete;
|
||||
torrent::log_buffer_ptr m_log_important;
|
||||
torrent::log_buffer_ptr m_log_complete;
|
||||
};
|
||||
|
||||
// Meh, cleanup.
|
||||
|
||||
+28
-46
@@ -38,72 +38,54 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <rak/error_number.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"
|
||||
#include "poll_manager_epoll.h"
|
||||
#include "poll_manager_kqueue.h"
|
||||
#include "poll_manager_select.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
PollManager::PollManager(torrent::Poll* poll) :
|
||||
m_poll(poll) {
|
||||
|
||||
if (m_poll == NULL)
|
||||
throw std::logic_error("PollManager::PollManager(...) received poll == NULL");
|
||||
}
|
||||
|
||||
PollManager::~PollManager() {
|
||||
delete m_poll;
|
||||
}
|
||||
|
||||
PollManager*
|
||||
PollManager::create_poll_manager() {
|
||||
PollManager* pollManager = NULL;
|
||||
Log* log = &control->core()->get_log_important();
|
||||
|
||||
const char* poll = getenv("RTORRENT_POLL");
|
||||
torrent::Poll*
|
||||
create_poll() {
|
||||
const char* poll_name = getenv("RTORRENT_POLL");
|
||||
|
||||
int maxOpen = sysconf(_SC_OPEN_MAX);
|
||||
|
||||
if (poll != NULL) {
|
||||
if (!strcmp(poll, "epoll"))
|
||||
pollManager = PollManagerEPoll::create(maxOpen);
|
||||
else if (!strcmp(poll, "kqueue"))
|
||||
pollManager = PollManagerKQueue::create(maxOpen);
|
||||
else if (!strcmp(poll, "select"))
|
||||
pollManager = PollManagerSelect::create(maxOpen);
|
||||
torrent::Poll* poll = NULL;
|
||||
|
||||
if (pollManager == NULL)
|
||||
log->push_front(std::string("Cannot enable '") + poll + "' based polling.");
|
||||
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 (pollManager != NULL)
|
||||
log->push_front(std::string("Using '") + poll + "' based polling.");
|
||||
if (poll != NULL)
|
||||
control->core()->push_log_std(std::string("Using '") + poll_name + "' based polling.");
|
||||
|
||||
else if ((pollManager = PollManagerEPoll::create(maxOpen)) != NULL)
|
||||
log->push_front("Using 'epoll' based polling.");
|
||||
else if ((poll = torrent::PollEPoll::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'epoll' based polling.");
|
||||
|
||||
else if ((pollManager = PollManagerKQueue::create(maxOpen)) != NULL)
|
||||
log->push_front("Using 'kqueue' based polling.");
|
||||
else if ((poll = torrent::PollKQueue::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'kqueue' based polling.");
|
||||
|
||||
else if ((pollManager = PollManagerSelect::create(maxOpen)) != NULL)
|
||||
log->push_front("Using 'select' based polling.");
|
||||
else if ((poll = torrent::PollSelect::create(maxOpen)) != NULL)
|
||||
control->core()->push_log_std("Using 'select' based polling.");
|
||||
|
||||
else
|
||||
throw std::runtime_error("Could not create any PollManager.");
|
||||
throw torrent::internal_error("Could not create any Poll object.");
|
||||
|
||||
return pollManager;
|
||||
}
|
||||
|
||||
void
|
||||
PollManager::check_error() {
|
||||
if (rak::error_number::current().value() != rak::error_number::e_intr)
|
||||
throw std::runtime_error("Poll::work(): " + std::string(rak::error_number::current().c_str()));
|
||||
return poll;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-31
@@ -37,41 +37,15 @@
|
||||
#ifndef RTORRENT_CORE_POLL_MANAGER_H
|
||||
#define RTORRENT_CORE_POLL_MANAGER_H
|
||||
|
||||
#include <rak/timer.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <torrent/poll.h>
|
||||
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace torrent {
|
||||
class Poll;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
// CurlStack really should be somewhere else, but that won't happen
|
||||
// until they add an epoll friendly API.
|
||||
|
||||
class PollManager {
|
||||
public:
|
||||
typedef sigc::signal0<void> Signal;
|
||||
|
||||
PollManager(torrent::Poll* poll);
|
||||
virtual ~PollManager();
|
||||
|
||||
unsigned int get_open_max() const { return m_poll->open_max(); }
|
||||
|
||||
torrent::Poll* get_torrent_poll() { return m_poll; }
|
||||
|
||||
virtual void poll(rak::timer timeout) = 0;
|
||||
virtual void poll_simple(rak::timer timeout) = 0;
|
||||
|
||||
static PollManager* create_poll_manager();
|
||||
|
||||
protected:
|
||||
PollManager(const PollManager&);
|
||||
void operator = (const PollManager&);
|
||||
|
||||
void check_error();
|
||||
|
||||
torrent::Poll* m_poll;
|
||||
};
|
||||
torrent::Poll* create_poll();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,98 +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 <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <torrent/poll_epoll.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "poll_manager_epoll.h"
|
||||
#include "thread_base.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
PollManagerEPoll*
|
||||
PollManagerEPoll::create(int maxOpenSockets) {
|
||||
torrent::PollEPoll* p = torrent::PollEPoll::create(maxOpenSockets);
|
||||
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return new PollManagerEPoll(p);
|
||||
}
|
||||
|
||||
PollManagerEPoll::~PollManagerEPoll() {
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerEPoll::poll(rak::timer timeout) {
|
||||
// Add 1ms to ensure we don't idle loop due to the lack of
|
||||
// resolution.
|
||||
torrent::perform();
|
||||
timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000;
|
||||
|
||||
ThreadBase::release_global_lock();
|
||||
ThreadBase::entering_main_polling();
|
||||
|
||||
int status = static_cast<torrent::PollEPoll*>(m_poll)->poll((timeout.usec() + 999) / 1000);
|
||||
|
||||
ThreadBase::leaving_main_polling();
|
||||
ThreadBase::acquire_global_lock();
|
||||
|
||||
if (status == -1)
|
||||
return check_error();
|
||||
|
||||
torrent::perform();
|
||||
static_cast<torrent::PollEPoll*>(m_poll)->perform();
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerEPoll::poll_simple(rak::timer timeout) {
|
||||
// Add 1ms to ensure we don't idle loop due to the lack of
|
||||
// resolution.
|
||||
timeout = timeout + 1000;
|
||||
|
||||
if (static_cast<torrent::PollEPoll*>(m_poll)->poll((timeout.usec() + 999) / 1000) == -1)
|
||||
return check_error();
|
||||
|
||||
static_cast<torrent::PollEPoll*>(m_poll)->perform();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +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_EPOLL_H
|
||||
#define RTORRENT_CORE_POLL_MANAGER_EPOLL_H
|
||||
|
||||
#include "poll_manager.h"
|
||||
|
||||
namespace torrent {
|
||||
class PollEPoll;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
class PollManagerEPoll : public PollManager {
|
||||
public:
|
||||
static PollManagerEPoll* create(int maxOpenSockets);
|
||||
~PollManagerEPoll();
|
||||
|
||||
torrent::Poll* get_torrent_poll();
|
||||
|
||||
void poll(rak::timer timeout);
|
||||
void poll_simple(rak::timer timeout);
|
||||
|
||||
private:
|
||||
PollManagerEPoll(torrent::Poll* p) : PollManager(p) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,99 +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 <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/poll_kqueue.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "poll_manager_kqueue.h"
|
||||
#include "thread_base.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
PollManagerKQueue*
|
||||
PollManagerKQueue::create(int maxOpenSockets) {
|
||||
torrent::PollKQueue* p = torrent::PollKQueue::create(maxOpenSockets);
|
||||
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return new PollManagerKQueue(p);
|
||||
}
|
||||
|
||||
PollManagerKQueue::~PollManagerKQueue() {
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerKQueue::poll(rak::timer timeout) {
|
||||
// Add 1ms to ensure we don't idle loop due to the lack of
|
||||
// resolution.
|
||||
torrent::perform();
|
||||
timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000;
|
||||
|
||||
ThreadBase::release_global_lock();
|
||||
ThreadBase::entering_main_polling();
|
||||
|
||||
int status = static_cast<torrent::PollKQueue*>(m_poll)->poll((timeout.usec() + 999) / 1000);
|
||||
|
||||
ThreadBase::leaving_main_polling();
|
||||
ThreadBase::acquire_global_lock();
|
||||
|
||||
if (status == -1)
|
||||
return check_error();
|
||||
|
||||
torrent::perform();
|
||||
static_cast<torrent::PollKQueue*>(m_poll)->perform();
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerKQueue::poll_simple(rak::timer timeout) {
|
||||
// Add 1ms to ensure we don't idle loop due to the lack of
|
||||
// resolution.
|
||||
timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000;
|
||||
|
||||
if (static_cast<torrent::PollKQueue*>(m_poll)->poll((timeout.usec() + 999) / 1000) == -1)
|
||||
return check_error();
|
||||
|
||||
static_cast<torrent::PollKQueue*>(m_poll)->perform();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +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_KQUEUE_H
|
||||
#define RTORRENT_CORE_POLL_MANAGER_KQUEUE_H
|
||||
|
||||
#include "poll_manager.h"
|
||||
|
||||
namespace torrent {
|
||||
class PollKQueue;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
class PollManagerKQueue : public PollManager {
|
||||
public:
|
||||
static PollManagerKQueue* create(int maxOpenSockets);
|
||||
~PollManagerKQueue();
|
||||
|
||||
torrent::Poll* get_torrent_poll();
|
||||
|
||||
void poll(rak::timer timeout);
|
||||
void poll_simple(rak::timer timeout);
|
||||
|
||||
private:
|
||||
PollManagerKQueue(torrent::Poll* p) : PollManager(p) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,127 +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 <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <rak/allocators.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/poll_select.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "poll_manager_select.h"
|
||||
#include "thread_base.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
PollManagerSelect::PollManagerSelect(torrent::Poll* p) : PollManager(p) {
|
||||
#if defined USE_VARIABLE_FDSET
|
||||
m_setSize = (m_poll->open_max() + 7) / 8;
|
||||
|
||||
char* buffer = rak::cacheline_allocator<char>::alloc_size(3 * m_setSize);
|
||||
std::memset(buffer, 0, 3 * m_setSize);
|
||||
|
||||
m_readSet = (fd_set*)buffer;
|
||||
m_writeSet = (fd_set*)(buffer += m_setSize);
|
||||
m_errorSet = (fd_set*)(buffer += m_setSize);
|
||||
#else
|
||||
#error Only variable fdset supported atm.
|
||||
#endif
|
||||
}
|
||||
|
||||
PollManagerSelect*
|
||||
PollManagerSelect::create(int maxOpenSockets) {
|
||||
torrent::PollSelect* p = torrent::PollSelect::create(maxOpenSockets);
|
||||
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
return new PollManagerSelect(p);
|
||||
}
|
||||
|
||||
PollManagerSelect::~PollManagerSelect() {
|
||||
free(m_readSet);
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerSelect::poll(rak::timer timeout) {
|
||||
torrent::perform();
|
||||
timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000;
|
||||
|
||||
std::memset(m_readSet, 0, m_setSize);
|
||||
std::memset(m_writeSet, 0, m_setSize);
|
||||
std::memset(m_errorSet, 0, m_setSize);
|
||||
|
||||
unsigned int maxFd = static_cast<torrent::PollSelect*>(m_poll)->fdset(m_readSet, m_writeSet, m_errorSet);
|
||||
|
||||
timeval t = timeout.tval();
|
||||
|
||||
ThreadBase::entering_main_polling();
|
||||
ThreadBase::release_global_lock();
|
||||
|
||||
int status = select(maxFd + 1, m_readSet, m_writeSet, m_errorSet, &t);
|
||||
|
||||
ThreadBase::leaving_main_polling();
|
||||
ThreadBase::acquire_global_lock();
|
||||
|
||||
if (status == -1)
|
||||
return check_error();
|
||||
|
||||
torrent::perform();
|
||||
static_cast<torrent::PollSelect*>(m_poll)->perform(m_readSet, m_writeSet, m_errorSet);
|
||||
}
|
||||
|
||||
void
|
||||
PollManagerSelect::poll_simple(rak::timer timeout) {
|
||||
torrent::PollSelect* currentPoll = static_cast<torrent::PollSelect*>(m_poll);
|
||||
|
||||
timeout = timeout + 1000;
|
||||
std::memset(m_readSet, 0, 3 * m_setSize);
|
||||
|
||||
unsigned int maxFd = currentPoll->fdset(m_readSet, m_writeSet, m_errorSet);
|
||||
|
||||
timeval t = timeout.tval();
|
||||
|
||||
if (select(maxFd + 1, m_readSet, m_writeSet, m_errorSet, &t) == -1)
|
||||
return check_error();
|
||||
|
||||
currentPoll->perform(m_readSet, m_writeSet, m_errorSet);
|
||||
}
|
||||
|
||||
}
|
||||
+47
-22
@@ -40,7 +40,6 @@
|
||||
#include <functional>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
#include <sigc++/adaptors/bind.h>
|
||||
#include <torrent/download.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
@@ -90,17 +89,21 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
|
||||
};
|
||||
|
||||
struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
view_downloads_filter(const torrent::Object& cmd) : m_command(cmd) {}
|
||||
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) : m_command(cmd), m_command2(cmd2) {}
|
||||
|
||||
bool operator () (Download* d1) const {
|
||||
if (m_command.is_empty())
|
||||
return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1);
|
||||
}
|
||||
|
||||
bool evalCmd(const torrent::Object& cmd, Download* d1) const {
|
||||
if (cmd.is_empty())
|
||||
return true;
|
||||
|
||||
try {
|
||||
torrent::Object result;
|
||||
|
||||
if (m_command.is_dict_key()) {
|
||||
// torrent::Object tmp_command = m_command;
|
||||
if (cmd.is_dict_key()) {
|
||||
// torrent::Object tmp_command = cmd;
|
||||
|
||||
// uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
|
||||
// tmp_command.unset_flags(torrent::Object::mask_function);
|
||||
@@ -110,10 +113,10 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
// result = rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(),
|
||||
// rpc::make_target(d1));
|
||||
|
||||
result = rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target(d1));
|
||||
result = rpc::commands.call_command(cmd.as_dict_key().c_str(), cmd.as_dict_obj(), rpc::make_target(d1));
|
||||
|
||||
} else {
|
||||
result = rpc::parse_command_single(rpc::make_target(d1), m_command.as_string());
|
||||
result = rpc::parse_command_single(rpc::make_target(d1), cmd.as_string());
|
||||
}
|
||||
|
||||
switch (result.type()) {
|
||||
@@ -137,14 +140,21 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
}
|
||||
|
||||
const torrent::Object& m_command;
|
||||
const torrent::Object& m_command2;
|
||||
};
|
||||
|
||||
inline void
|
||||
void
|
||||
View::emit_changed() {
|
||||
priority_queue_erase(&taskScheduler, &m_delayChanged);
|
||||
priority_queue_insert(&taskScheduler, &m_delayChanged, cachedTime);
|
||||
}
|
||||
|
||||
void
|
||||
View::emit_changed_now() {
|
||||
for (signal_void::iterator itr = m_signal_changed.begin(), last = m_signal_changed.end(); itr != last; itr++)
|
||||
(*itr)();
|
||||
}
|
||||
|
||||
View::~View() {
|
||||
if (m_name.empty())
|
||||
return;
|
||||
@@ -172,7 +182,7 @@ View::initialize(const std::string& name) {
|
||||
m_focus = 0;
|
||||
|
||||
set_last_changed(rak::timer());
|
||||
m_delayChanged.set_slot(rak::mem_fn(&m_signalChanged, &signal_type::operator()));
|
||||
m_delayChanged.slot() = std::bind(&View::emit_changed_now, this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -184,7 +194,7 @@ View::erase(Download* download) {
|
||||
|
||||
} else {
|
||||
erase_internal(itr);
|
||||
rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved);
|
||||
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +210,7 @@ View::set_visible(Download* download) {
|
||||
base_type::erase(itr);
|
||||
insert_visible(download);
|
||||
|
||||
rpc::parse_command_multiple_d_nothrow(download, m_eventAdded);
|
||||
rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -218,7 +228,7 @@ View::set_not_visible(Download* download) {
|
||||
base_type::erase(itr);
|
||||
base_type::push_back(download);
|
||||
|
||||
rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved);
|
||||
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -252,9 +262,13 @@ View::sort() {
|
||||
|
||||
void
|
||||
View::filter() {
|
||||
// Do NOT allow filter STARTED and STOPPED views: they are special
|
||||
if (m_name == "started" || m_name == "stopped")
|
||||
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));
|
||||
iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_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());
|
||||
@@ -275,15 +289,27 @@ View::filter() {
|
||||
// done by using a base_type* member variable, and making sure we
|
||||
// set the elements to NULL as we trigger commands on them. Or
|
||||
// perhaps always clear them, thus not throwing anything.
|
||||
if (!m_eventRemoved.empty())
|
||||
std::for_each(changed.begin(), splitChanged, rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_d_nothrow), m_eventRemoved));
|
||||
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));
|
||||
|
||||
if (!m_eventAdded.empty())
|
||||
std::for_each(splitChanged, changed.end(), rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_d_nothrow), m_eventAdded));
|
||||
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));
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void
|
||||
View::filter_by(const torrent::Object& condition, View::base_type& result) {
|
||||
// std::copy_if(begin_visible(), end_visible(), result.begin(), view_downloads_filter(condition));
|
||||
view_downloads_filter matches = view_downloads_filter(condition, m_temp_filter);
|
||||
|
||||
for (iterator itr = begin_visible(); itr != end_visible(); ++itr)
|
||||
if (matches(*itr))
|
||||
result.push_back(*itr);
|
||||
}
|
||||
|
||||
void
|
||||
View::filter_download(core::Download* download) {
|
||||
iterator itr = std::find(base_type::begin(), base_type::end(), download);
|
||||
@@ -291,13 +317,12 @@ View::filter_download(core::Download* download) {
|
||||
if (itr == base_type::end())
|
||||
throw torrent::internal_error("View::filter_download(...) could not find download.");
|
||||
|
||||
if (view_downloads_filter(m_filter)(download)) {
|
||||
|
||||
if (view_downloads_filter(m_filter, m_temp_filter)(download)) {
|
||||
if (itr >= end_visible()) {
|
||||
erase_internal(itr);
|
||||
insert_visible(download);
|
||||
|
||||
rpc::parse_command_multiple_d_nothrow(download, m_eventAdded);
|
||||
rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
|
||||
|
||||
} else {
|
||||
// This makes sure the download is sorted even if it is
|
||||
@@ -315,7 +340,7 @@ View::filter_download(core::Download* download) {
|
||||
erase_internal(itr);
|
||||
base_type::push_back(download);
|
||||
|
||||
rpc::parse_command_multiple_d_nothrow(download, m_eventRemoved);
|
||||
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user