mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-08 19:22:29 +00:00
Compare commits
1110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 327164f9d8 | |||
| 5d22fdd4b6 | |||
| 7455f2eb86 | |||
| 53767cee92 | |||
| aa9e729ca7 | |||
| e43853b782 | |||
| 81932c0b12 | |||
| 61264c4f17 | |||
| 244a84dcf5 | |||
| c9a5736d5d | |||
| 9322acb33d | |||
| a5e722b48f | |||
| ba4828d226 | |||
| dfced79186 | |||
| dd2a4cc151 | |||
| fd372b5e48 | |||
| 3ea47d7acb | |||
| b82f3614c3 | |||
| 2987ba8081 | |||
| 33f8fe804b | |||
| 1a4f6dab1a | |||
| 943b576e1f | |||
| 2ec90c6892 | |||
| 63dfe341a6 | |||
| 321147cdb8 | |||
| 2097c9ca3e | |||
| 10ce6864b8 | |||
| 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 | |||
| 081b5e9cb2 | |||
| 1bbb7aa793 | |||
| 4353f1bfa8 | |||
| 6a444ab4de | |||
| 41d49b7c18 | |||
| 3c4d21d34c | |||
| 0b05196e32 | |||
| a120b8e9cf | |||
| d8aa1cd28b | |||
| b2c1fe2afb | |||
| ae14fcabde | |||
| 79c93762f5 | |||
| 5a2a2e8a68 | |||
| a40b2132fb | |||
| 2be9a874c7 | |||
| 0d648119d2 | |||
| 9a9dcb88f7 | |||
| 6c10f7e05d | |||
| 7b150ec834 | |||
| e11be5cdbe | |||
| 58727fe7fd | |||
| 9507bd82f4 | |||
| 308d91f817 | |||
| f0da99b5c3 | |||
| 00a42357d0 | |||
| f4c3758dcd | |||
| 575968b291 | |||
| c55f5611a9 | |||
| 52530d5538 | |||
| 8d4aed7dae | |||
| 7b38cc29aa | |||
| eb90b92930 | |||
| a73509a799 | |||
| ed6182589a | |||
| 47c03c8717 | |||
| 31495b06be | |||
| 682cd56d18 | |||
| 413becea38 | |||
| 931b9c848c | |||
| e9a065f9d8 | |||
| d7fddfe718 | |||
| 9c6aa138fd | |||
| dcf9c5a0fc | |||
| 4d313e6353 | |||
| fd82d21290 | |||
| 8a9187796c | |||
| 34d006c492 | |||
| 1f149b4b3a | |||
| 77016e4425 | |||
| 11c107560b | |||
| 83e898e032 | |||
| ba09df1afc | |||
| a3896f9094 | |||
| fa5224bf7f | |||
| 6a0c82529f | |||
| 670d459300 | |||
| aaa5586088 | |||
| 75124f79e1 | |||
| 92b7295303 | |||
| 3e244f9f93 | |||
| 0784d6540f | |||
| 5f21e207c3 | |||
| 80c97c398b | |||
| 1a3602012e | |||
| ecb77ad7bf | |||
| 4e3ecc01b2 | |||
| 3c75a150db | |||
| 4914d798f1 | |||
| 156d69c854 | |||
| 6faea70de2 | |||
| 1e83c626f8 | |||
| 1b49dcb9e0 | |||
| e239b673cf | |||
| c1eccb4bd7 | |||
| 7680277eee | |||
| dfc159f67a | |||
| 847d1ae081 | |||
| c7ad0a90da | |||
| ea192b342c | |||
| ce16621707 | |||
| 882a64af77 | |||
| 3f41f9384d | |||
| adef434bc3 | |||
| 88260e4989 | |||
| a6678a4591 | |||
| f5a141ac5f | |||
| 7ff232848a | |||
| b64b975ad4 | |||
| ca0e3f66a6 | |||
| 520d25a19d | |||
| a5ed856f01 | |||
| 9b0eb94c09 | |||
| 86a9c1051b | |||
| fa8ef65cd7 | |||
| f5d4924b22 | |||
| dbde781bc5 | |||
| 4ff2793efb | |||
| d0d52cdda1 | |||
| 90582b58c3 | |||
| c31b865046 | |||
| 1964ba5626 | |||
| db4a780893 | |||
| 1e206cb1c4 | |||
| ff477d3f7a | |||
| d2f328cc8e | |||
| 5200454cf7 | |||
| 9f738c58fe | |||
| 56a7546f46 | |||
| 2f485cdf42 | |||
| 1f200e7922 | |||
| 97f84f2c4d | |||
| c845863f30 | |||
| 8ae522b729 | |||
| 7d41393e5e | |||
| ea9dc35bbe | |||
| 8e15749d0c | |||
| 83a5213fac | |||
| 3aa7ed3000 | |||
| cb45e30aeb | |||
| 63ffc11bbc | |||
| b6cffa59c9 | |||
| 47efb608ab | |||
| d0c853034f | |||
| 6f71a8c1b1 | |||
| 18a6c61956 | |||
| a3b763aba8 | |||
| 8bf3ab6e91 | |||
| 86c508e212 | |||
| 386250bc87 | |||
| 9ed7596daf | |||
| 143de32dc4 | |||
| 18061c20c8 | |||
| 6e9df49912 | |||
| 5debd6f1be | |||
| 7b2fae35d5 | |||
| 5691233bf1 | |||
| 7e554e8b1b | |||
| 649248c909 | |||
| 6985fce321 | |||
| 220f59ee15 | |||
| 4013fd6b98 | |||
| 51db5e64c2 | |||
| 0098b1f0b9 | |||
| b8d319a2fc | |||
| 0e69677dbc | |||
| a0f3e95d20 | |||
| 49f61eeda3 | |||
| 033e30af04 | |||
| c12f698c95 | |||
| 56e126d8a0 | |||
| 9bc5470243 | |||
| e0068a3f42 | |||
| e1f0ee86b7 | |||
| 01738fd357 | |||
| 493843f223 | |||
| d9f409b223 | |||
| 8b03988612 | |||
| 7dad6d34f3 | |||
| c8fc6402bb | |||
| b530d35d94 | |||
| 9362453391 | |||
| 575cafc7a8 | |||
| 74bae32243 | |||
| 856228da3d | |||
| d17fa0c684 | |||
| 4b9c4d5bbe | |||
| 8da449f666 | |||
| 4c6c943669 | |||
| 90da65f8a1 | |||
| 4e4540e60f | |||
| 10f665e9c6 | |||
| bc96dbfa2d | |||
| db2b813fc4 | |||
| 28aabb7874 | |||
| 83e993a1eb | |||
| 8622100e09 | |||
| ee5b0819a1 | |||
| 589c8c147b | |||
| c5e839287d | |||
| 19be810642 | |||
| ded689d3ff | |||
| df4c0ce67b | |||
| 44e77016a9 | |||
| db8f217569 | |||
| 806941b6c7 | |||
| 6fe6dcd8d8 | |||
| 49cbbad5d7 | |||
| 0a76faa427 | |||
| 3cae3d37be | |||
| 31abf85846 | |||
| 8954393e52 | |||
| 6796e9ad34 | |||
| 222bf7ae8f | |||
| 2d3e12387d | |||
| 588f9e80c7 | |||
| 83ea813245 | |||
| 5ad2eff8c9 | |||
| 027edf9dcd | |||
| 8987be3001 | |||
| 6188d110c5 | |||
| 2c7563825c | |||
| 5a1d0be323 | |||
| 5470e50ffb | |||
| 2304983f4f | |||
| 6a94909647 | |||
| b635f8c852 | |||
| ef6e4deca9 | |||
| d71e0ccf9a | |||
| 76fd429f89 | |||
| 3359c2bbb0 | |||
| 667c4c3562 | |||
| a60c330d3b | |||
| f11c48d454 | |||
| 6c3a80636a | |||
| abcb2cea48 | |||
| 134ae81ae3 | |||
| b19bc576c4 | |||
| 63af7078a3 | |||
| 855bf9a781 | |||
| 05d7028f61 | |||
| 69d1c9700a | |||
| 3c670a7add | |||
| 6753b45627 | |||
| 15ae43a5ea | |||
| d05e889317 | |||
| eb74609cdc | |||
| 97b97261fd | |||
| 7600a51039 | |||
| de8a11c4fd | |||
| 66a2af991a | |||
| 5166253190 | |||
| ca9d0b1773 | |||
| 5648cf7dd0 | |||
| 29ba4ff4bc | |||
| 85f5b7dc46 | |||
| db4ba9fe68 | |||
| 07b9616ef6 | |||
| d7c2960d1e | |||
| 6385b995f3 | |||
| 879a019757 | |||
| 854d119ff2 | |||
| be8b59b00b | |||
| c627d6dc0c | |||
| 5a700f34d9 | |||
| bfa7523677 | |||
| 108ec969f7 | |||
| e3fa31b6df | |||
| 3f64e8b1fa | |||
| fcbad61577 | |||
| 3ddd04a9a5 | |||
| 12b43d78a3 | |||
| 41088740bd | |||
| aab493caad | |||
| 03c544d07d | |||
| a6045c9ea5 | |||
| e8e5ef337b | |||
| 8fbaca61b1 | |||
| 199bd1985c | |||
| 7062935724 | |||
| d22e1ae30e | |||
| f9ff1cf5ac | |||
| 8cc7c8430d | |||
| b21f465969 | |||
| 49bb643cf3 | |||
| afe1312eb6 | |||
| 1b96bd6016 | |||
| 805689c3af | |||
| 0fdb72b05b | |||
| 259cb77799 | |||
| 728c6ac9bd | |||
| c19af8f389 | |||
| 9e8b4add9d | |||
| 87e02737ce | |||
| 77a7d13b39 | |||
| 7abc459d74 | |||
| ce64ea89b1 | |||
| 7b053b969e | |||
| ccb3713a57 | |||
| 51e27e29c8 | |||
| 71ac2cc8e1 | |||
| 6db7ada26c | |||
| 4704c91a8f | |||
| f05dd5b152 | |||
| 4e3a867257 | |||
| 66037a7ae2 | |||
| d86505924b | |||
| 2fe964059f | |||
| 3f644aed8f | |||
| 04e6575e5d | |||
| 4a2ae4d339 | |||
| c326c7f43a | |||
| ff2c25bdeb | |||
| d13e502ee4 | |||
| 4038e78665 | |||
| 61098513c6 | |||
| 78f8b19aa4 | |||
| aad01906d3 | |||
| 099ec98210 | |||
| 9cb48a9f66 | |||
| 166e8e1357 | |||
| b32c07a638 | |||
| 81782e2e9f | |||
| 804eb769a0 | |||
| 3b82216a1b | |||
| 48f13fb7a3 | |||
| 95516fe3b5 | |||
| 1cc1374c7a | |||
| ac2f5a8882 | |||
| 332b4a303f | |||
| 73c41074ec | |||
| 32b74ffc48 | |||
| 02b790c0bf | |||
| c6a43429a2 | |||
| 85d14f0e96 | |||
| 38f8a00c0c | |||
| 0390b7ec00 | |||
| bac7d0ba3b | |||
| ded9e12ff1 | |||
| 5ec7790aa9 | |||
| f117b9dd16 | |||
| 11976871ac | |||
| 6ca373d293 | |||
| 788b496241 | |||
| 781e1ca7dc | |||
| ef794b8eda | |||
| 37bc4c85c4 | |||
| ba634e7d62 | |||
| ac92b56f37 | |||
| 1232cd44cb | |||
| 8617e205ea | |||
| e15aee3f77 | |||
| 465625692f | |||
| 7d0be56c83 | |||
| 535db16850 | |||
| a8bd405040 | |||
| 350bdfde7e | |||
| 3c7144092e | |||
| 3570602a08 | |||
| 36251a46bf | |||
| 2eaa34d989 | |||
| 17ebbf1b92 | |||
| d04ef5406b | |||
| 0c3038783e | |||
| a492cadf00 | |||
| c8e74a78ad | |||
| 9b95b51410 | |||
| e6e7e8a384 | |||
| 9f11a5ad92 | |||
| 93f1e349ff | |||
| 750ba89129 | |||
| 507ba5a7a0 | |||
| 8096b4f4ca | |||
| e9db89e6d6 | |||
| 297b4b5f1d | |||
| f8f2f80960 | |||
| 0de4bbea7a | |||
| 64e1d1f440 | |||
| 8a1220fd5b | |||
| 13dc0c942a | |||
| bebce18368 | |||
| 2db205a89d | |||
| 5f274b2619 | |||
| bc7d485391 | |||
| d33d283293 | |||
| 7d1bb524ba | |||
| 9fe72cb3b5 | |||
| 032bae7030 | |||
| 0182bfbfba | |||
| c986357bab | |||
| a864d5938d | |||
| 2ede6f03ab | |||
| 43fd2c92ec | |||
| c5beb24d6c | |||
| 7077aba019 | |||
| d0ae367dca | |||
| 81637ff5a0 | |||
| 7c121ac049 | |||
| 4a449bae67 | |||
| 8501832788 | |||
| 6691298fb4 | |||
| d6fd8f08dc | |||
| 93afd05e18 | |||
| 3bd0d6fb27 | |||
| ee6eae6c84 | |||
| 0ab5bae22e | |||
| 5450971273 | |||
| b009734d5c | |||
| 59c6f97cb9 | |||
| 3b13fc7f05 | |||
| 3ef8384c38 | |||
| f43cdad650 | |||
| b46caac088 | |||
| de3ab556e5 | |||
| ef3ecb0b97 | |||
| cdd2da8df5 | |||
| ecdfaed06f | |||
| 5a9fa2fdcd | |||
| 81921ba9a4 | |||
| 1d1b5710fa | |||
| b301faf3ca | |||
| e59b5bf7b6 | |||
| d030c5401e | |||
| e122cc928a | |||
| c1ac4a2319 | |||
| 2be918261e | |||
| 3b38c4ab9c | |||
| de744ad11d | |||
| fe7adfc999 | |||
| 0854e65775 | |||
| 06dad41ff8 | |||
| eabbf33a76 | |||
| 25702ea4b7 | |||
| c453565e8f | |||
| c65b6aa9ff | |||
| aab31e5ea5 | |||
| fbf1a8b8a6 | |||
| cc44fb175d | |||
| d8e5a59b92 | |||
| 16bb9a87c8 | |||
| fcb8154188 | |||
| 460aac5df0 | |||
| 407d570de3 | |||
| 59b6ed61ce | |||
| e4db1cacc2 | |||
| c992fa60df | |||
| 8b759a5c6e | |||
| 281f924556 | |||
| e3f59ee9e4 | |||
| 4819162ffa | |||
| f9916b574f | |||
| a5e7acc61b | |||
| cafd4c6090 | |||
| 1982429b8c | |||
| 6935c97e8f | |||
| b5cc7cff44 | |||
| 0c393e1cdb | |||
| 9d465de7e1 | |||
| c9d8a2406d | |||
| 5dfc986658 | |||
| 2781ce9698 | |||
| a72054d018 | |||
| 44a782e962 | |||
| dda5d0783d | |||
| 1736c8eaf7 | |||
| eb7c0b5874 | |||
| 29ef815d0e | |||
| 8f311cda47 | |||
| 3084847508 | |||
| 407824c9c8 | |||
| b90a220e15 | |||
| 66dd9a3304 | |||
| af6eb493a9 | |||
| ab3a0fead2 | |||
| bb0f13144b | |||
| a3f7be3278 | |||
| 8fe8fbbb31 | |||
| dbfb9f1165 | |||
| 708e89ebad | |||
| ee7016f547 | |||
| 4d988fccb9 | |||
| 34258bcfb2 | |||
| da0d5dbf22 | |||
| 3c634730c4 | |||
| ca58b43d8b | |||
| ba28df3ff2 | |||
| 0b45062eb3 | |||
| 62beb9d9ed | |||
| fa5ff92e24 | |||
| 4c9fc671be | |||
| fc76a11d71 | |||
| ef90f0f51e | |||
| 652fd25c07 | |||
| 345c57e9bc | |||
| b3fc488e5f | |||
| e8a8fc7e1a | |||
| 52bf80d704 | |||
| 63311270c9 | |||
| 082cbb6cc5 | |||
| 66bb95a26c | |||
| c957d1b4d1 | |||
| 26ffe74744 | |||
| 9f2f427e9d | |||
| 4b79a7c47f | |||
| ee353bfc9f | |||
| d35bef6791 | |||
| 8be667e935 | |||
| 70eacfe738 | |||
| d2fc993514 | |||
| f1c9188d55 | |||
| c95eb62802 | |||
| b3b4acaad8 | |||
| 38f0cdbce2 | |||
| 1e54882da4 | |||
| f0d94bc938 | |||
| ffb820f536 | |||
| beeea9fd3e | |||
| d0f6719e50 | |||
| 46dd41e956 | |||
| 18cd5342df | |||
| c573c8a9bc | |||
| 146c104eb3 | |||
| 932296ce52 | |||
| aaaf5d9a5d | |||
| e4c5c80688 | |||
| 770d205b9a | |||
| 271e8e6ccf | |||
| 14418244fb | |||
| ba4a1927ff | |||
| d4706da4d5 | |||
| 65f3dda9ab | |||
| a851264787 | |||
| 6d07bf3540 | |||
| 8387dbde6f | |||
| 0620ea88a7 | |||
| f01289ef12 | |||
| 2b420e95a0 | |||
| fff7838f13 | |||
| 236f689efc | |||
| 02a0510439 | |||
| 8ae5e51a0f | |||
| c5c9a1ddae | |||
| 19179bd160 | |||
| 598455a5df | |||
| 11c842308a | |||
| c4256079ae | |||
| 2f6b5affd1 | |||
| 7ad18cdac2 | |||
| dc1f6d4f23 | |||
| 8a8cfe5e3d | |||
| 3fa08503bb | |||
| f0d31900b7 | |||
| d9d27139d1 | |||
| 59a23ea9ed | |||
| 8ea6f78e21 | |||
| a811f53301 | |||
| b3051db2b2 | |||
| f953c8935e | |||
| 14475fd4c1 | |||
| 17d66c4a2f | |||
| 86a3f868df | |||
| 1c55348d45 | |||
| 571fe8b2f4 | |||
| 2863c10389 | |||
| 6822261199 | |||
| b00d083ac2 | |||
| c77ecb034f | |||
| a6a0c25fbc | |||
| e3571f249c | |||
| 1f769cc138 | |||
| 1a7fccf2d9 | |||
| 1e5146121e | |||
| 4dea195340 | |||
| e5c5f7ecb1 | |||
| 126bb511b8 | |||
| 8b934623d4 | |||
| 68502367ec | |||
| d06ecda46a | |||
| 6f44f8f920 | |||
| c89ae513ef | |||
| 305e3bdf2b | |||
| 825985b8ef | |||
| 52636178d1 | |||
| e8cd37ea3a | |||
| 4028ab2295 | |||
| b25af84ee8 | |||
| 310589c4bf | |||
| f32c15878a | |||
| 4431fd1652 | |||
| 5a8a402745 | |||
| 2c5151def5 | |||
| 3989ae8975 | |||
| 4e8e5a18df | |||
| e45f05ee98 | |||
| ca5b5e05ec | |||
| 7cc377b550 | |||
| 12ef47da3c | |||
| ba7d61b532 | |||
| 32a3619cd8 | |||
| a1a07c47aa | |||
| f9614c405d | |||
| 98a8fc8638 | |||
| 93c6369b69 | |||
| cbbad78b6a | |||
| e8deac9f79 | |||
| a97408328a | |||
| 3db8179274 | |||
| b28621f839 | |||
| 89e69adb7a | |||
| 1a68177eca | |||
| ce411252ac | |||
| 5137aade10 | |||
| da67bdfff1 | |||
| 7e861cf9f2 | |||
| eb8fecbc34 | |||
| dc2b1aa5d8 | |||
| 45781e8dbf | |||
| c99cc03d19 | |||
| ad80247ba6 | |||
| 881f515d03 | |||
| 65573ec1ee | |||
| 33b7217627 | |||
| 88b8afe025 | |||
| 108ad78d30 | |||
| 94d31cc681 | |||
| 5ada857c3e | |||
| c347ccc439 | |||
| 8732e457fa | |||
| 3bd99aee50 | |||
| c568306a5a | |||
| a1bffb4526 | |||
| 2a1f3e12cc | |||
| a28ed1c96b | |||
| abbe4dd675 | |||
| b0ac469262 | |||
| 7f2b66d601 | |||
| 4eb18663f5 | |||
| 8b1afe2485 | |||
| 52214aa992 | |||
| 407f3383f0 | |||
| 202ed7928b | |||
| 6590f5608f | |||
| 65d940484a | |||
| 287dfbf334 | |||
| dc5476e3f4 | |||
| e5aad7ed6a | |||
| 91a6950c01 | |||
| 89a090111d | |||
| 00e0da7aa5 | |||
| 3df7567ddf | |||
| 91f4f022a9 | |||
| 424a20b3f5 | |||
| a3521e974d | |||
| e877d3487b | |||
| 10ff3141d9 | |||
| 81c36a7d96 | |||
| 7a9010445b | |||
| d02ded1d4c | |||
| 568dcc0b91 | |||
| 8ca61a79ac | |||
| 26a7907f0a | |||
| a195933a2a | |||
| 0a56ce6fff | |||
| fc8ca7df20 | |||
| 0588e66eaf | |||
| 758bbc9faf | |||
| 98ad8e8791 | |||
| 52884c3c39 | |||
| d04adf81ae | |||
| 2c5ce1989a | |||
| 28b369dc83 | |||
| 088398d6d6 | |||
| bc27fd19cb | |||
| 7e77635353 | |||
| 9a3d75490f | |||
| 7b1e0ec085 | |||
| 2e83af28ac | |||
| fdc56e8f09 | |||
| 693ce38317 | |||
| 2e7333792f | |||
| 3092a583ca | |||
| 0206ee066d | |||
| 74930f86b3 | |||
| a2248f584f | |||
| 528646cc02 | |||
| d8398eae5f | |||
| d96173453d | |||
| 11bc3a9f80 | |||
| d898b9db01 | |||
| 98676e5531 | |||
| 2f77d1bafa | |||
| f139621c4c | |||
| 70a73ea441 | |||
| f8bbf8bfad | |||
| 472c19fe67 | |||
| 8bf6a42048 | |||
| 874e46fc64 | |||
| fe11d1936d | |||
| 2f49249378 | |||
| 74e3b4fc1c | |||
| 072a38c8fc | |||
| a16a88ebeb | |||
| 2eb534e423 | |||
| 73fb55ae42 | |||
| 2ded36e38e | |||
| cefa2b584d | |||
| 8090d4db26 | |||
| b5f218ffd9 | |||
| dfa6c9cd05 | |||
| 3efadf69ec | |||
| da764db3b9 | |||
| 010d5cfbe3 | |||
| c36ee96550 | |||
| ab69ae3fe6 | |||
| f664e1ce0c | |||
| a4dbdffcb8 | |||
| f379abb200 | |||
| 209581bd3f | |||
| c378ab638c | |||
| 1dc51a1b13 | |||
| ddf619f934 | |||
| 2dc7ffdb8f | |||
| c15d840962 | |||
| 9e0db66b58 | |||
| 8d36f7c374 | |||
| fd0c10d962 | |||
| b840476527 | |||
| ef3a8fcd83 | |||
| 9fe97ee490 | |||
| f66424f642 | |||
| 5ef6be4912 | |||
| 75ef138118 | |||
| c4d548bafd | |||
| fa9a2d7e86 | |||
| 91da0475e4 | |||
| 5b050b594b | |||
| a5f23adc7b | |||
| aa405810db | |||
| e0f21cce78 | |||
| 78d3d78ef3 | |||
| f9975ae9f2 | |||
| e3a0730b33 | |||
| ab065e598b | |||
| 46120cbb30 | |||
| f348196f2e | |||
| ce4c09c143 | |||
| 1f58b0074b | |||
| 73b1c58f4c | |||
| aec27deaeb | |||
| 8ec38be77e | |||
| deb1244d8c | |||
| f7144a333f | |||
| b01cd17a72 | |||
| b657554236 | |||
| 45404b7473 | |||
| fc903274ae | |||
| c2a0fd90dc | |||
| 11506c5a61 | |||
| ecb2fc7d57 | |||
| e02974571a | |||
| bd7849199c | |||
| 5f102a5dcf | |||
| 0ff36babee | |||
| cd9b014eb6 | |||
| c3a4a7d554 | |||
| 3357b5caab | |||
| b17dc37a3b | |||
| 53f32e74a1 | |||
| 96a28a78bb | |||
| 27109b542c | |||
| b994517819 | |||
| f9b95c6255 | |||
| 74b154f07e | |||
| f622f45f0b | |||
| 914c7c1aeb | |||
| 1c10f620f8 | |||
| 68788e904c | |||
| ca6a7e2d16 |
+72
@@ -0,0 +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/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
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
language: cpp
|
||||
|
||||
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
|
||||
- cd libtorrent && ./autogen.sh && CXX="$COMPILER" ./configure && make -j12 && sudo make install
|
||||
|
||||
script:
|
||||
- ./autogen.sh && CXX="$COMPILER" ./configure && make -j12
|
||||
- if [ ! $SKIP_CHECK ]; then make -j12 check; fi
|
||||
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,229 @@
|
||||
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
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
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
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.)
|
||||
|
||||
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
|
||||
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
|
||||
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 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.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
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:
|
||||
|
||||
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
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
|
||||
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 `..'.
|
||||
|
||||
If you have to use a `make' that does not support the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a
|
||||
time in the source code directory. After you have installed the
|
||||
package for one architecture, use `make distclean' before reconfiguring
|
||||
for another architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=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.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
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
|
||||
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
|
||||
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'.
|
||||
|
||||
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.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
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:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
will cause the specified gcc to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--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
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--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
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
SUBDIRS = \
|
||||
doc \
|
||||
src \
|
||||
test
|
||||
|
||||
EXTRA_DIST= \
|
||||
autogen.sh \
|
||||
rak/address_info.h \
|
||||
rak/algorithm.h \
|
||||
rak/allocators.h \
|
||||
rak/error_number.h \
|
||||
rak/file_stat.h \
|
||||
rak/fs_stat.h \
|
||||
rak/functional.h \
|
||||
rak/functional_fun.h \
|
||||
rak/path.h \
|
||||
rak/partial_queue.h \
|
||||
rak/priority_queue.h \
|
||||
rak/priority_queue_default.h \
|
||||
rak/regex.h \
|
||||
rak/socket_address.h \
|
||||
rak/string_manip.h \
|
||||
rak/timer.h \
|
||||
rak/unordered_vector.h \
|
||||
scripts/checks.m4 \
|
||||
scripts/common.m4 \
|
||||
scripts/attributes.m4
|
||||
|
||||
ACLOCAL_AMFLAGS = -I scripts
|
||||
@@ -0,0 +1,41 @@
|
||||
BUILDING
|
||||
|
||||
Run "./autogen.sh" to generate the configure scripts if
|
||||
nessesary. The man page "doc/rtorrent.1" must be generated with
|
||||
"docbook2man rtorrent.1.xml" if it is missing.
|
||||
|
||||
Note that rtorrent follows the development of libtorrent closely, and
|
||||
thus the versions must be in sync. This should not be nessesary in the
|
||||
future, when the library API stabilizes.
|
||||
|
||||
USAGE
|
||||
|
||||
See the man page or website for instructions.
|
||||
|
||||
LICENSE
|
||||
|
||||
GNU GPL, see COPYING. "libtorrent/src/utils/sha_fast.{cc,h}" is
|
||||
originally from the Mozilla NSS and is under a triple license; MPL,
|
||||
LGPL and GPL. An exception to non-NSS code has been added for linking
|
||||
to OpenSSL as requested by Debian, though the author considers that
|
||||
library to be part of the Operative System and thus linking is allowed
|
||||
according to the GPL.
|
||||
|
||||
Use whatever fits your purpose, the code required to compile with
|
||||
Mozilla's NSS implementation of SHA1 has been retained and can be
|
||||
compiled if the user wishes to avoid using OpenSSL.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
libcurl >= 7.12.0
|
||||
ncurses
|
||||
|
||||
CONTACT
|
||||
|
||||
Jari Sundell
|
||||
|
||||
Skomakerveien 33
|
||||
3185 Skoppum, NORWAY
|
||||
|
||||
Send bug reports, suggestions and patches to
|
||||
<sundell.software@gmail.com> or to the mailinglist.
|
||||
@@ -1,8 +0,0 @@
|
||||
title: Rtorrent
|
||||
description: rTorrent BitTorrent client
|
||||
google_analytics:
|
||||
show_downloads: true
|
||||
theme: jekyll-theme-minimal
|
||||
|
||||
gems:
|
||||
- jekyll-mentions
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#! /bin/sh
|
||||
|
||||
echo aclocal...
|
||||
(aclocal --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo aclocal not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
aclocal -I ./scripts -I . ${ACLOCAL_FLAGS} || exit 1
|
||||
|
||||
echo autoheader...
|
||||
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo autoheader not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
autoheader || exit 1
|
||||
|
||||
echo -n "libtoolize... "
|
||||
if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then
|
||||
echo "using glibtoolize"
|
||||
glibtoolize --automake --copy --force || exit 1
|
||||
|
||||
elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then
|
||||
echo "using libtoolize"
|
||||
libtoolize --automake --copy --force || exit 1
|
||||
|
||||
else
|
||||
echo "libtoolize nor glibtoolize not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo automake...
|
||||
(automake --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo automake not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
automake --add-missing --copy --gnu || exit 1
|
||||
|
||||
echo autoconf...
|
||||
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo autoconf not found
|
||||
exit 1
|
||||
}
|
||||
|
||||
autoconf || exit 1
|
||||
|
||||
echo ready to configure
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,76 @@
|
||||
AC_INIT(rtorrent, 0.9.7, sundell.software@gmail.com)
|
||||
|
||||
AC_DEFINE(API_VERSION, 9, api version)
|
||||
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
RAK_ENABLE_DEBUG
|
||||
RAK_ENABLE_EXTRA_DEBUG
|
||||
RAK_ENABLE_WERROR
|
||||
|
||||
RAK_CHECK_CXX11
|
||||
RAK_CHECK_TR1_LIB
|
||||
|
||||
TORRENT_DISABLE_IPV6
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
TORRENT_CHECK_EXECINFO
|
||||
|
||||
TORRENT_ENABLE_ARCH
|
||||
TORRENT_WITH_SYSROOT
|
||||
|
||||
TORRENT_WITHOUT_VARIABLE_FDSET
|
||||
TORRENT_WITHOUT_STATVFS
|
||||
TORRENT_WITHOUT_STATFS
|
||||
|
||||
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
|
||||
AX_WITH_CURSES
|
||||
|
||||
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([LIBCURL], [libcurl], , [LIBCURL_CHECK_CONFIG])
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.13.7])
|
||||
|
||||
LIBS="$PTHREAD_LIBS $CURSES_LIB $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_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included)
|
||||
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
|
||||
|
||||
AC_CHECK_FUNCS(posix_memalign)
|
||||
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_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
|
||||
])
|
||||
@@ -1,4 +0,0 @@
|
||||
Reddit
|
||||
======
|
||||
|
||||
Yes, I'm 'rasatsu'.
|
||||
@@ -0,0 +1,2 @@
|
||||
EXTRA_DIST= \
|
||||
rtorrent.rc
|
||||
@@ -0,0 +1,11 @@
|
||||
=== Dumping core files on mac ==
|
||||
|
||||
ulimit -c unlimited
|
||||
sysctl kern.corefile
|
||||
|
||||
|
||||
schedule = log_vmmap,5,600,"execute_nothrow=/Users/rakshasa/trunk/rtorrent/doc/log_vmmap.sh,\"$cat=/Users/rakshasa/Downloads/session/vmmap.system.,$system.pid="; log.vmmap.dump=\"$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid=\""
|
||||
|
||||
log.vmmap.dump="$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid="
|
||||
|
||||
print="$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid="
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
|
||||
|
||||
<article>
|
||||
<title>rTorrent Frequently Asked Questions</title>
|
||||
|
||||
<para>
|
||||
This is the user FAQ for Rakshasa's BitTorrent client. RTorrent is
|
||||
an ncurses based client that uses libTorrent and is written in
|
||||
C++. Efficiency and good code is the main goal of both projects.
|
||||
</para>
|
||||
|
||||
<qandaset>
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
How do I add new torrents while the client is running?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
Use the backspace key to enter file input mode. The bottom
|
||||
line will change into a prompt which allows you to enter URL's
|
||||
or file paths to torrents. File name completion and directory
|
||||
listing is supported with the tab key.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
I got the message "Could not create download, failed to parse the bencoded data" when adding a torrent, what does it mean?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
The torrent data the library received was not a valid torrent
|
||||
file. If this was a direct http download, try downloading the
|
||||
torrent file and add it manually. This usually happens when
|
||||
the torrent link uses some form of redirection that libcurl
|
||||
does not automatically redirect. If the failure still happens,
|
||||
make sure the file is infact an uncorrupted torrent.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
How does the session feature work?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
When you start the client you can use the "-s" switch to
|
||||
specify a session directory. The client will save all
|
||||
currently running torrents in the session directory and fast
|
||||
resume data will be written when the client exits. Upon
|
||||
restarting the client it will resume all the torrents in the
|
||||
session directory.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
How do i query the tracker for more peers?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
Go into the download view screen and press 't' to initiate a
|
||||
new tracker request. If the tracker requires a minimum timeout
|
||||
between requests you can override this by using the capital
|
||||
'T'. Don't abuse this feature.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
Why do I sometimes need to press ctrl-Q twice to exit the client?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
The first time you press ctrl-q you initiate the
|
||||
shutdown. This causes rTorrent to send a stop message to the
|
||||
trackers of each torrent, and if the tracker is slow it might
|
||||
take more than a few seconds or until the requests time
|
||||
out. The second time ctrl-q is pressed forces the client to
|
||||
shutdown.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
It doesn't help how much i press ctrl-q, it still won't quit.
|
||||
</para></question>
|
||||
<answer><para>
|
||||
Perhaps your terminal sends a different key-code to the
|
||||
application. There's no configuration files for keys yet, so
|
||||
modify rtorrent/src/ui/root.cc:56 to use whatever key you want
|
||||
for quitting.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
<qandaentry>
|
||||
<question><para>
|
||||
When I try downloading a torrent the client aborts (SIGABRT), what should I do?
|
||||
</para></question>
|
||||
<answer><para>
|
||||
Make sure you arn't using "-fomit-frame-pointer" when
|
||||
compiling libtorrent and rtorrent, this is known to produce
|
||||
bad code for C++ exception handling. If this doesn't help, run
|
||||
the client in gdb and use "bt -20" to get a backtrace. Send
|
||||
this with a bug report.
|
||||
</para></answer>
|
||||
</qandaentry>
|
||||
|
||||
</qandaset>
|
||||
|
||||
</article>
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
cat /proc/$PPID/maps > $1
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
args=($@)
|
||||
echo "${args[@]:1}" >> $1
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#/bin/bash
|
||||
gnuplot << EOF
|
||||
# 1) system.time_seconds=
|
||||
#
|
||||
# 2) throttle.global_up.rate
|
||||
# 3) throttle.global_up.total
|
||||
# 4) throttle.global_down.rate
|
||||
# 5) throttle.global_down.total
|
||||
#
|
||||
# 6) pieces.memory.current
|
||||
# 7) pieces.memory.sync_queue
|
||||
# 8) pieces.memory.block_count
|
||||
# 9) pieces.stats.total_size
|
||||
# 10) pieces.hash.queue_size
|
||||
#
|
||||
# file.append = (cat,/foo/bandwidth_stats.,(system.pid)),"timestamp","\"upload rate\"","\"upload total\"","\"download rate\"","\"download total\"","\"memory usage\"","\"sync queue\"","\"block count\"","\"total size\"","\"hash queue size\""
|
||||
# schedule = log_bandwidth_stats,5,10,((file.append,((cat,/foo/bandwidth_stats.,((system.pid)))),((system.time_seconds)),((throttle.global_up.rate)),((throttle.global_up.total)),((throttle.global_down.rate)),((throttle.global_down.total)),((pieces.memory.current)),((pieces.memory.sync_queue)),((pieces.memory.block_count)),((pieces.stats.total_size)),((pieces.hash.queue_size))))
|
||||
#
|
||||
# 1) system.time_seconds
|
||||
#
|
||||
# 2) throttle.unchoked_uploads
|
||||
# 3) throttle.unchoked_downloads
|
||||
# 4) network.open_sockets
|
||||
#
|
||||
# 5) view.size,leeching
|
||||
# 6) view.size,seeding
|
||||
# 7) view.size,active
|
||||
#
|
||||
# file.append = (cat,/foo/peer_stats.,(system.pid)),"timestamp","\"upload unchoked\"","\"download unchoked\"","\"open sockets\"","leeching","seeding","active"
|
||||
# schedule = log_peer_stats,5,10,((file.append,((cat,/foo/peer_stats.,((system.pid)))),((system.time_seconds)),((throttle.unchoked_uploads)),((throttle.unchoked_downloads)),((network.open_sockets)),((view.size,leeching)),((view.size,seeding)),((view.size,active))))
|
||||
#
|
||||
# Choke groups:
|
||||
#
|
||||
# file.append = (cat,/foo/choke_group_stats.,(system.pid)),"timestamp",\
|
||||
# "\"default up unchoked\"","\"default up queued\"","\"default up rate\"",\
|
||||
# "\"default down unchoked\"","\"default down queued\"","\"default down rate\"","\"default torrents\"",\
|
||||
# "\"leech up unchoked\"","\"leech up queued\"","\"leech up rate\"",\
|
||||
# "\"leech down unchoked\"","\"leech down queued\"","\"leech down rate\"","\"leech torrents\"",\
|
||||
# "\"seed boost up unchoked\"","\"seed boost up queued\"","\"seed boost up rate\"",\
|
||||
# "\"seed boost down unchoked\"","\"seed boost down queued\"","\"seed boost down rate\"","\"seed boost torrents\"",\
|
||||
# "\"seed up unchoked\"","\"seed up queued\"","\"seed up rate\"",\
|
||||
# "\"seed down unchoked\"","\"seed down queued\"","\"seed down rate\"","\"seed torrents\""
|
||||
#
|
||||
# schedule = log_choke_group_stats,5,10,((file.append,((cat,/foo/choke_group_stats.,((system.pid)))),((system.time_seconds)),\
|
||||
# ((choke_group.up.unchoked,0)),((choke_group.up.queued,0)),((choke_group.up.rate,0)),((choke_group.down.unchoked,0)),((choke_group.down.queued,0)),((choke_group.down.rate,0)),((choke_group.size,0)),\
|
||||
# ((choke_group.up.unchoked,1)),((choke_group.up.queued,1)),((choke_group.up.rate,1)),((choke_group.down.unchoked,1)),((choke_group.down.queued,1)),((choke_group.down.rate,1)),((choke_group.size,1)),\
|
||||
# ((choke_group.up.unchoked,2)),((choke_group.up.queued,2)),((choke_group.up.rate,2)),((choke_group.down.unchoked,2)),((choke_group.down.queued,2)),((choke_group.down.rate,2)),((choke_group.size,2)),\
|
||||
# ((choke_group.up.unchoked,3)),((choke_group.up.queued,3)),((choke_group.up.rate,3)),((choke_group.down.unchoked,3)),((choke_group.down.queued,3)),((choke_group.down.rate,3)),((choke_group.size,3)) ))
|
||||
#
|
||||
# Mincore stats:
|
||||
#
|
||||
# file.append = (cat,/foo/mincore_stats.,(system.pid)),"timestamp","\"incore cont. /10s\"","\"not incore cont. /10s\"","\"incore new /10s\"","\"not incore new /10s\"","\"incore break /10s\"","\"sync success /10s\"","\"sync failed /10s\"","\"sync not synced /10s\"","\"sync not deallocated /10s\"","\"alloc failed /10s\"","\"allocate velocity /10s\"","\"deallocate velocity /10s\""
|
||||
# log.libtorrent = mincore_stats,(cat,"/foo/mincore_stats.",(system.pid))
|
||||
|
||||
|
||||
set terminal png size 1024,768 enhanced
|
||||
#set terminal png size 2*1024,768 enhanced
|
||||
set xdata time
|
||||
set timefmt "%s"
|
||||
set format x "%H:%M"
|
||||
set format y2 "%.0f"
|
||||
set y2tics
|
||||
set autoscale xfix
|
||||
set key autotitle columnhead
|
||||
|
||||
set output "output_$1_sockets.png"
|
||||
plot "peer_stats.$1" using 1:7 smooth sbezier with lines lw 4,\
|
||||
"peer_stats.$1" using 1:5 smooth sbezier with lines lw 4,\
|
||||
"peer_stats.$1" using 1:6 smooth sbezier with lines lw 4,\
|
||||
"<awk '{x=1000; if (\$4 < 1000) x=\$4; print \$1,x}' peer_stats.$1" using 1:2 smooth sbezier with lines title "open sockets" lw 2 axis x1y2,\
|
||||
"peer_stats.$1" using 1:2 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
set output "output_$1_groups.png"
|
||||
plot "choke_group_stats.$1" \
|
||||
using 1:8 smooth sbezier with lines lw 4,\
|
||||
"" using 1:8+7*1 smooth sbezier with lines lw 4,\
|
||||
"" using 1:8+7*2 smooth sbezier with lines lw 4,\
|
||||
"" using 1:8+7*3 smooth sbezier with lines lw 4\
|
||||
|
||||
|
||||
set format y "%.0s %cb"
|
||||
|
||||
set output "output_$1_bandwidth.png"
|
||||
plot "bandwidth_stats.$1" using 1:2 smooth sbezier with lines lw 4,\
|
||||
"bandwidth_stats.$1" using 1:4 smooth sbezier with lines lw 4,\
|
||||
"choke_group_stats.$1" using 1:4+7*1 smooth sbezier with lines lw 3,\
|
||||
"choke_group_stats.$1" using 1:7+7*1 smooth sbezier with lines lw 3,\
|
||||
"choke_group_stats.$1" using 1:4+7*2 smooth sbezier with lines lw 3,\
|
||||
"choke_group_stats.$1" using 1:4+7*3 smooth sbezier with lines lw 3,\
|
||||
"peer_stats.$1" using 1:2 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
set output "output_$1_memory.png"
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth sbezier with lines lw 4 axis x1y1,\
|
||||
"peer_stats.$1" using 1:2 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
#set yrange [0:3900000000.0]
|
||||
#set y2range [0:2000]
|
||||
|
||||
set output "output_$1_pieces.png"
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth sbezier with lines lw 4 axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:7 smooth sbezier with lines lw 4 axis x1y1,\
|
||||
"<awk '{x=\$12*10; print \$1,x}' mincore_stats.$1" using 1:2 smooth sbezier with lines lw 4 title 'alloc /100s' axis x1y1,\
|
||||
"<awk '{x=\$13*10; print \$1,x}' mincore_stats.$1" using 1:2 smooth sbezier with lines lw 4 title 'dealloc /100s' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:7 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"mincore_stats.$1" using 1:8 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"mincore_stats.$1" using 1:11 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"<awk '{x=\$8/10; print \$1,x}' bandwidth_stats.$1" using 1:2 smooth sbezier with lines lw 2 title 'block count /10' axis x1y2,\
|
||||
"bandwidth_stats.$1" using 1:10 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
#set yrange [*:*]
|
||||
#set y2range [*:*]
|
||||
|
||||
set format y2 "%.0s %cb"
|
||||
set output "output_$1_torrents.png"
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth sbezier with lines lw 4 axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:9 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
set format y "%.0f"
|
||||
set format y2 "%.0f"
|
||||
|
||||
set output "output_$1_incore.png"
|
||||
#plot "bandwidth_stats.$1" using 1:(0) smooth sbezier with lines,
|
||||
plot \
|
||||
"mincore_stats.$1" using 1:2 smooth sbezier with lines lw 2 axis x1y1,\
|
||||
"mincore_stats.$1" using 1:3 smooth sbezier with lines lw 4 axis x1y2,\
|
||||
"mincore_stats.$1" using 1:4 smooth sbezier with lines lw 2 axis x1y1,\
|
||||
"mincore_stats.$1" using 1:5 smooth sbezier with lines lw 4 axis x1y2
|
||||
|
||||
#
|
||||
# Updated:
|
||||
#
|
||||
|
||||
set output "output_$1_choke.png"
|
||||
set style histogram columnstacked
|
||||
|
||||
plot "choke_group_stats.$1" \
|
||||
using 1:2+7*1 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:3+7*1 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:5+7*1 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:6+7*1 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:2+7*2 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:3+7*2 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:2+7*3 smooth sbezier with lines lw 2 axis x1y2,\
|
||||
"" using 1:3+7*3 smooth sbezier with lines lw 2 axis x1y2
|
||||
|
||||
EOF
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
vmmap -interleaved $PPID > $1
|
||||
@@ -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.
|
||||
@@ -0,0 +1,61 @@
|
||||
\section{Logging}
|
||||
|
||||
\subsection{Opening log files}
|
||||
|
||||
\begin{verbatim}
|
||||
# log.open_file = "log name", "file path"
|
||||
|
||||
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
|
||||
\end{verbatim}
|
||||
|
||||
A newly opened log file is not connected to any logging events.
|
||||
|
||||
Some control over formatting will be provided at a later date.
|
||||
|
||||
|
||||
\subsection{Adding outputs to events}
|
||||
|
||||
\begin{verbatim}
|
||||
# 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"
|
||||
\end{verbatim}
|
||||
|
||||
Each log handle can be added to multiple different logging events.
|
||||
|
||||
|
||||
\subsection{Logging events}
|
||||
|
||||
\begin{verbatim}
|
||||
"critical"
|
||||
"error"
|
||||
"warn"
|
||||
"notice"
|
||||
"info"
|
||||
"debug"
|
||||
\end{verbatim}
|
||||
|
||||
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''.
|
||||
|
||||
\begin{verbatim}
|
||||
"connection_*"
|
||||
"dht_*"
|
||||
"peer_*"
|
||||
"rpc_*"
|
||||
"storage_*"
|
||||
"thread_*"
|
||||
"tracker_*"
|
||||
"torrent_*"
|
||||
\end{verbatim}
|
||||
|
||||
All sub-groups have events from ``critical'' to ``debug'' defined.
|
||||
|
||||
@@ -0,0 +1,560 @@
|
||||
.\" This manpage has been automatically generated by docbook2man
|
||||
.\" from a DocBook document. This tool can be found at:
|
||||
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
|
||||
.\" Please send any bug reports, improvements, comments, patches,
|
||||
.\" etc. to Steve Cheng <steve@ggi-project.org>.
|
||||
.TH "RTORRENT" "1" "14 May 2009" "BitTorrent client for ncurses" ""
|
||||
|
||||
.SH NAME
|
||||
rtorrent \- a BitTorrent client for ncurses
|
||||
.SH SYNOPSIS
|
||||
|
||||
\fBrtorrent\fR [ \fB-h\fR ] [ \fB-n\fR ] [ \fB-o key1=opt1,...\fR ] [ \fB-O key=opt\fR ] [ \fBURL | FILE\fR\fI ...\fR ]
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBrtorrent\fR is a BitTorrent client for ncurses, using
|
||||
the \fBlibtorrent\fR library. The client and library is
|
||||
written in C++ with emphasis on speed and efficiency, while delivering
|
||||
equivalent features to those found in GUI based clients in an ncurses
|
||||
client.
|
||||
.PP
|
||||
Most of the options below have their own default unit in addition to
|
||||
supporting B, K, M and G suffixes.
|
||||
.SH "KEYBOARD CONTROL"
|
||||
.PP
|
||||
.SS "GLOBAL KEYS"
|
||||
.TP
|
||||
\fB^q\fR
|
||||
Initiate shutdown, press again to force the shutdown and
|
||||
skip sending the stop signal to trackers.
|
||||
.TP
|
||||
\fBup | down | left | right arrow keys\fR
|
||||
.TP
|
||||
\fB^P | ^N | ^B | ^F\fR
|
||||
Select entries or change windows. The right arrow key or ^F is often
|
||||
used for viewing details about the selected entry, while the left
|
||||
arrow key or ^B often returns to the previous screen.
|
||||
.TP
|
||||
\fBa | s | d\fR
|
||||
Increase the upload throttle by 1/5/50 KB.
|
||||
.TP
|
||||
\fBA | S | D\fR
|
||||
Increase the download throttle by 1/5/50 KB.
|
||||
.TP
|
||||
\fBz | x | c\fR
|
||||
Decrease the upload throttle by 1/5/50 KB.
|
||||
.TP
|
||||
\fBZ | X | C\fR
|
||||
Decrease the download throttle by 1/5/50 KB.
|
||||
.SS "MAIN VIEW KEYS"
|
||||
.TP
|
||||
\fB->\fR
|
||||
View download.
|
||||
.TP
|
||||
\fB1 - 7\fR
|
||||
Change view.
|
||||
.TP
|
||||
\fB^S\fR
|
||||
Start download.
|
||||
.TP
|
||||
\fB^D\fR
|
||||
Stop an active download, or remove a stopped download.
|
||||
.TP
|
||||
\fB^K\fR
|
||||
Close a torrent and its files.
|
||||
.TP
|
||||
\fB^E\fR
|
||||
Set the 'create/resize queued' flags on all files in a torrent. This
|
||||
is necessary if the underlying files in a torrent have been deleted or
|
||||
truncated, and thus rtorrent must recreate them.
|
||||
.TP
|
||||
\fB^R\fR
|
||||
Initiate hash check of torrent.
|
||||
.TP
|
||||
\fB^O\fR
|
||||
Change the destination directory of the download. The torrent must be
|
||||
closed.
|
||||
.TP
|
||||
\fB^X\fR
|
||||
Call commands or change settings.
|
||||
.TP
|
||||
\fB^B\fR
|
||||
Set download to perform initial seeding. Only use when
|
||||
you are the first and only seeder so far for the download.
|
||||
.TP
|
||||
\fB+ | -\fR
|
||||
Change the priority of the download.
|
||||
.TP
|
||||
\fBbackspace\fR
|
||||
Add torrent using an URL or file path. Use
|
||||
\fBtab\fR to view directory content and do
|
||||
auto-complete.
|
||||
.TP
|
||||
\fBl\fR
|
||||
View log. Exit by pressing the space-bar.
|
||||
.TP
|
||||
\fBU\fR
|
||||
Delete the file the torrent is tied to, and clear the association.
|
||||
.TP
|
||||
\fBI\fR
|
||||
Toggle whether torrent ignores ratio settings.
|
||||
.SS "DOWNLOAD VIEW KEYS"
|
||||
.TP
|
||||
\fB->\fR
|
||||
View torrent file list. Use the space-bar to change the file priority
|
||||
and \fB*\fR to change the priority of all
|
||||
files. Use \fB/\fR to collapse the directories. OUTDATED
|
||||
.TP
|
||||
\fB1 | 2\fR
|
||||
Adjust max uploads.
|
||||
.TP
|
||||
\fB3 | 4\fR
|
||||
Adjust min peers.
|
||||
.TP
|
||||
\fB5 | 6\fR
|
||||
Adjust max peers.
|
||||
.TP
|
||||
\fBu\fR
|
||||
Display transfering blocks.
|
||||
.TP
|
||||
\fBi\fR
|
||||
Display chunk rarity.
|
||||
.TP
|
||||
\fBo\fR
|
||||
Display the tracker list. Cycle the trackers in a group with the
|
||||
space-bar.
|
||||
.TP
|
||||
\fBp\fR
|
||||
View peer and torrent information.
|
||||
.TP
|
||||
\fBt | T\fR
|
||||
Initiate tracker request. Use capital T to force the request, ignoring
|
||||
the "min interval" set by the tracker.
|
||||
.TP
|
||||
\fBk\fR
|
||||
Disconnect peer.
|
||||
.TP
|
||||
\fB*\fR
|
||||
Choke/Snub peer.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
\fB-b \fIa.b.c.d\fB\fR
|
||||
Bind listening socket and outgoing connections to this network
|
||||
interface address.
|
||||
.TP
|
||||
\fB-d \fIdirectory\fB\fR
|
||||
Set the default download directory. Defaults to "./".
|
||||
.TP
|
||||
\fB-h\fR
|
||||
Display help and exit.
|
||||
.TP
|
||||
\fB-i \fIa.b.c.d\fB\fR
|
||||
Set the address reported to the tracker.
|
||||
.TP
|
||||
\fB-n\fR
|
||||
Don't load ~/.rtorrent.rc on startup.
|
||||
.TP
|
||||
\fB-o key1=opt1,...\fR
|
||||
.TP
|
||||
\fB-O key=opt\fR
|
||||
Set any number of options, see the SETTINGS section. The options given
|
||||
here override the resource files. Use capital \fB-O\fR
|
||||
to allow comma in the option.
|
||||
.TP
|
||||
\fB-p \fIa-b\fB\fR
|
||||
Try to open a listening port in the range \fBa\fR up to
|
||||
and including \fBb\fR\&.
|
||||
.TP
|
||||
\fB-s \fIdirectory\fB\fR
|
||||
Session management will be enabled and the torrent files for all open
|
||||
downloads will be stored in this directory. Only one instance of
|
||||
rtorrent should be used with each session directory, though at the
|
||||
moment no locking is done. An empty string will disable the session
|
||||
directory.
|
||||
.SH "GENERAL SETTINGS"
|
||||
.PP
|
||||
.TP
|
||||
\fBbind = \fIa.b.c.d\fB\fR
|
||||
Bind listening socket and outgoing connections to this network
|
||||
interface address.
|
||||
.TP
|
||||
\fBip = \fIa.b.c.d\fB\fR
|
||||
.TP
|
||||
\fBip = \fIhostname\fB\fR
|
||||
Set the address reported to the tracker.
|
||||
.TP
|
||||
\fBport_range = \fIa-b\fB\fR
|
||||
Try to open a listening port in the range \fBa\fR up to
|
||||
and including \fBb\fR\&.
|
||||
.TP
|
||||
\fBport_random = \fIyes | no\fB\fR
|
||||
Open the listening port at a random position in the port range.
|
||||
.TP
|
||||
\fBcheck_hash = \fIyes | no\fB\fR
|
||||
Perform hash check on torrents that have finished downloading.
|
||||
.TP
|
||||
\fBdirectory = \fIdirectory\fB\fR
|
||||
Set the default download directory. Defaults to "./".
|
||||
.TP
|
||||
\fBsession = \fIdirectory\fB\fR
|
||||
Session management will be enabled and the torrent files for all open
|
||||
downloads will be stored in this directory. Only one instance of
|
||||
rtorrent can be used per session directory. An empty string will
|
||||
disable the session directory.
|
||||
.TP
|
||||
\fBhttp_proxy = \fIurl\fB\fR
|
||||
Use a http proxy. Use an empty string to disable.
|
||||
.TP
|
||||
\fBencoding_list = \fIencoding\fB\fR
|
||||
Add a preferred filename encoding to the list. The encodings are
|
||||
attempted in the order they are inserted, if none match the torrent
|
||||
default is used.
|
||||
.TP
|
||||
\fBencryption = \fIoption\fB,\fI\&...\fB\fR
|
||||
Set how rtorrent should deal with encrypted Bittorrent connections. By
|
||||
default, encryption is disabled, equivalent to specifying the option
|
||||
\fBnone\fR\&. Alternatively, any number of the following
|
||||
options may be specified:
|
||||
|
||||
\fBallow_incoming\fR (allow incoming encrypted connections),
|
||||
\fBtry_outgoing\fR (use encryption for outgoing connections),
|
||||
\fBrequire\fR (disable unencrypted handshakes),
|
||||
\fBrequire_RC4\fR (also disable plaintext transmission after the
|
||||
initial encrypted handshake),
|
||||
\fBenable_retry\fR (if the initial outgoing connection fails, retry
|
||||
with encryption turned on if it was off or off if it was on),
|
||||
\fBprefer_plaintext\fR (choose plaintext when peer offers a choice
|
||||
between plaintext transmission and RC4 encryption, otherwise RC4 will be used).
|
||||
.TP
|
||||
\fBpeer_exchange = \fIyes | no\fB\fR
|
||||
Enable/disable peer exchange for torrents that aren't marked private. Disabled by default.
|
||||
.TP
|
||||
\fBschedule = \fIid\fB,\fIstart\fB,\fIinterval\fB,\fIcommand\fB\fR
|
||||
Call \fBcommand\fR every \fBinterval\fR
|
||||
seconds, starting from \fBstart\fR\&. An
|
||||
\fBinterval\fR of zero calls the task once, while a
|
||||
\fBstart\fR of zero calls it immediately. Currently
|
||||
\fBcommand\fR is forwarded to the option handler.
|
||||
\fBstart\fR and \fBinterval\fR may
|
||||
optionally use a time format, \fBdd:hh:mm:ss\fR\&. F.ex to
|
||||
start a task every day at \fB18:00\fR, use
|
||||
\fB18:00:00,24:00:00\fR\&.
|
||||
.TP
|
||||
\fBschedule_remove = \fIid\fB\fR
|
||||
Delete \fBid\fR from the scheduler.
|
||||
.TP
|
||||
\fBstart_tied =\fR
|
||||
Start torrents that are tied to filenames that have been re-added.
|
||||
.TP
|
||||
\fBstop_untied =\fR
|
||||
.TP
|
||||
\fBclose_untied =\fR
|
||||
.TP
|
||||
\fBremove_untied =\fR
|
||||
Stop, close or remove the torrents that are tied to filenames that
|
||||
have been deleted. Clear the association with the 'U' key.
|
||||
.TP
|
||||
\fBclose_low_diskspace = \fIspace\fB\fR
|
||||
Close any active torrents on filesystems with less than
|
||||
\fBspace\fR diskspace left. Use with
|
||||
the \fBschedule\fR option. A default scheduled event
|
||||
with id \fBlow_diskspace\fR is set to 500Mb.
|
||||
.TP
|
||||
\fBload = \fIfile\fB\fR
|
||||
.TP
|
||||
\fBload_verbose = \fIfile\fB\fR
|
||||
.TP
|
||||
\fBload_start = \fIfile\fB\fR
|
||||
.TP
|
||||
\fBload_start_verbose = \fIfile\fB\fR
|
||||
Load and possibly start a file, or possibly multiple files by using the
|
||||
wild-card "*". This is meant for use with
|
||||
\fBschedule\fR, though ensure that the
|
||||
\fBstart\fR is non-zero. The loaded file will be tied
|
||||
to the filename provided.
|
||||
.TP
|
||||
\fBimport = \fIfile\fB\fR
|
||||
.TP
|
||||
\fBtry_import = \fIfile\fB\fR
|
||||
Load a resource file. \fBtry_import\fR does not throw
|
||||
torrent::input_error exception on bad input.
|
||||
.TP
|
||||
\fBstop_on_ratio = \fImin_ratio\fB\fR
|
||||
.TP
|
||||
\fBstop_on_ratio = \fImin_ratio\fB,\fImin_upload\fB\fR
|
||||
.TP
|
||||
\fBstop_on_ratio = \fImin_ratio\fB,\fImin_upload\fB,\fImax_ratio\fB\fR
|
||||
Stop torrents when they reach the given upload ratio
|
||||
\fBmin_ratio\fR in percent. If the optional
|
||||
\fBmin_upload\fR is given, require a total
|
||||
upload amount of this many bytes as well. If the optional
|
||||
\fBmax_ratio\fR is given, stop the torrent
|
||||
when reaching this ratio regardless of the total upload
|
||||
amount. Exclude certain torrent by pressing
|
||||
\fBShift+I\fR in the downlist list.
|
||||
Use with the \fBschedule\fR option.
|
||||
.TP
|
||||
\fBon_insert = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_erase = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_open = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_close = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_start = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_stop = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_hash_queued = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_hash_removed = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_hash_done = \fIid\fB,\fIcommand\fB\fR
|
||||
.TP
|
||||
\fBon_finished = \fIid\fB,\fIcommand\fB\fR
|
||||
Call a command on a download when its state changes. Only a subset of
|
||||
commands are available.
|
||||
.SH "THROTTLE SETTINGS"
|
||||
.TP
|
||||
\fBupload_rate = \fIKB\fB\fR
|
||||
.TP
|
||||
\fBdownload_rate = \fIKB\fB\fR
|
||||
Set the maximum global uploand and download rates.
|
||||
.TP
|
||||
\fBmin_peers = \fIvalue\fB\fR
|
||||
.TP
|
||||
\fBmax_peers = \fIvalue\fB\fR
|
||||
Set the minimum and maximum number of peers to allow in each download.
|
||||
.TP
|
||||
\fBmin_peers_seed = \fIvalue\fB\fR
|
||||
.TP
|
||||
\fBmax_peers_seed = \fIvalue\fB\fR
|
||||
Set the minimum nad maximum number of peers to allow while seeding, or
|
||||
-1 (default) to use max_peers.
|
||||
.TP
|
||||
\fBmax_uploads = \fIvalue\fB\fR
|
||||
Set the maximum number of simultaneous uploads per download.
|
||||
.TP
|
||||
\fBmax_uploads_div = \fIvalue\fB\fR
|
||||
.TP
|
||||
\fBmax_downloads_div = \fIvalue\fB\fR
|
||||
Change the divider used to calculate the max upload and download slots
|
||||
to use when the throttle is changed. Disable by
|
||||
setting \fB0\fR\&.
|
||||
.TP
|
||||
\fBmax_uploads_global = \fIvalue\fB\fR
|
||||
.TP
|
||||
\fBmax_downloads_global = \fIvalue\fB\fR
|
||||
Max upload and download slots allowed. Disable by
|
||||
setting \fB0\fR\&.
|
||||
.TP
|
||||
\fBthrottle_up = \fIname\fB, \fIupload_rate\fB\fR
|
||||
.TP
|
||||
\fBthrottle_down = \fIname\fB, \fIdownload_rate\fB\fR
|
||||
Define secondary throttle and/or set the given upload or download rate. Attach to a download with the d.set_throttle_name=name command
|
||||
or switch throttles with Ctrl-T. Download must be stopped when changing throttles. Note that secondary throttles only work if the
|
||||
global upload/download is throttled. Setting a download to use the \fBNULL\fR throttle makes the download unthrottled
|
||||
even when there is a global throttle. Note that this special case bypasses the global throttle entirely, and as such its rate and
|
||||
transfer amounts are not included in the global statistics.
|
||||
.TP
|
||||
\fBthrottle_ip = \fIname\fB, \fIhost\fB\fR
|
||||
.TP
|
||||
\fBthrottle_ip = \fIname\fB, \fInetwork/prefix\fB\fR
|
||||
.TP
|
||||
\fBthrottle_ip = \fIname\fB, \fIstart\fB, \fIend\fB\fR
|
||||
Use the given secondary throttle for a host, CIDR network or IP range. All peers with a matching IP will use this throttle instead
|
||||
of the global throttle or a custom download throttle. The name may be \fBNULL\fR to make these peers unthrottled, with
|
||||
the same caveats as explained above.
|
||||
.SH "TRACKER RELATED SETTINGS"
|
||||
.PP
|
||||
Tracker related settings.
|
||||
.TP
|
||||
\fBenable_trackers = \fIyes\fB\fR
|
||||
Set to \fBno\fR to disable all tracker requests. Useful
|
||||
for disabling rtorrent with the \fBschedule\fR command.
|
||||
.TP
|
||||
\fBtracker_dump = \fIfilename\fB\fR
|
||||
Dump tracker requests to \fBfilename\fR, disable by
|
||||
supplying an empty string. Only torrents loaded while
|
||||
\fBtracker_dump\fR contains a non-empty string will be
|
||||
logged at the moment, although disabling it will work as expected.
|
||||
.TP
|
||||
\fBtracker_numwant = \fInumber\fB\fR
|
||||
Set the numwant field sent to the tracker, which indicates how many
|
||||
peers we want. A negative value disables this feature.
|
||||
.TP
|
||||
\fBuse_udp_trackers = \fIyes\fB\fR
|
||||
Use UDP trackers. Disable if you are behind a firewall, etc, that does
|
||||
not allow connections to UDP trackers.
|
||||
.TP
|
||||
\fBdht = \fIdisabled|off|auto|on\fB\fR
|
||||
Support for querying the distributed hash table (DHT) to find peers for trackerless
|
||||
torrents or when all trackers are down. Set to \fBdisable\fR to completely
|
||||
disable DHT, \fBoff\fR (default) to enable DHT but to not start the
|
||||
DHT server, \fBauto\fR to automatically start and stop the DHT server
|
||||
as needed or \fBon\fR for permanently keeping the DHT server running.
|
||||
When set to automatic, the DHT server will start up when the first non-private torrent
|
||||
is started, and will stop 15-30 minutes after the last non-private torrent is
|
||||
stopped (or when rTorrent quits). For DHT to work, a session directory must be set (for
|
||||
saving the DHT cache).
|
||||
.TP
|
||||
\fBdht_port = \fInumber\fB\fR
|
||||
Set the UDP listen port for DHT. Defaults to 6881.
|
||||
.TP
|
||||
\fBdht_add_node = \fIhost[:port]\fB\fR
|
||||
Not intended for use in the configuration file but as one-time option in the
|
||||
client or on the command line to bootstrap an empty DHT node table. Contacts
|
||||
the given node and attempts to bootstrap from it if it replies.
|
||||
The port is optional, with port 6881 being used by default.
|
||||
.TP
|
||||
\fBhttp_capath = \fIpath\fB\fR
|
||||
.TP
|
||||
\fBhttp_cacert = \fIfilename\fB\fR
|
||||
Set the certificates to use in http requests. See Curl's
|
||||
CURLOPT_CAPATH and CURLOPT_CAINFO options for further information.
|
||||
.SH "USER-INTERFACE SETTINGS"
|
||||
.PP
|
||||
Display related settings.
|
||||
.TP
|
||||
\fBview_add = \fIname\fB\fR
|
||||
Create a new view.
|
||||
.TP
|
||||
\fBview_sort = \fIname\fB\fR
|
||||
.TP
|
||||
\fBview_sort = \fIname\fB,\fIseconds\fB\fR
|
||||
Sort a view according the the criteria set by
|
||||
\fBview_sort_current\fR\&. If the optional argument is
|
||||
supplied, the view is not sorted if a change happened during the last
|
||||
\fBseconds\fR\&. This command is meant to be used with
|
||||
\fBschedule\fR\&.
|
||||
.TP
|
||||
\fBview_sort_new = \fIname\fB,\fI\&...\fB\fR
|
||||
.TP
|
||||
\fBview_sort_current = \fIname\fB,\fI\&...\fB\fR
|
||||
Set the sorting criteria for when new elements inserted or
|
||||
\fBview_sort\fR is called. The list can contain any
|
||||
number of criteria, including zero, from the following:
|
||||
|
||||
\fBname\fR, \fBname_reverse\fR,
|
||||
\fBstopped\fR, \fBstarted\fR,
|
||||
\fBcomplete\fR, \fBincomplete\fR,
|
||||
\fBstate_changed\fR,
|
||||
\fBstate_changed_reverse\fR
|
||||
.TP
|
||||
\fBkey_layout = \fIqwerty|azerty|qwertz|dvorak\fB\fR
|
||||
Change the key-bindings.
|
||||
.SH "FILE-SYSTEM SETTINGS"
|
||||
.PP
|
||||
File-system related settings.
|
||||
.TP
|
||||
\fBmax_file_size = \fIsize\fB\fR
|
||||
Set the maximum size a file can have. Disable by
|
||||
passing \fB-1\fR\&.
|
||||
.TP
|
||||
\fBsplit_file_size = \fIsize\fB\fR
|
||||
Split files in a torrent larger than \fBsize\fR into
|
||||
seperate files. Disable by passing \fB-1\fR\&.
|
||||
.TP
|
||||
\fBsplit_suffix = \fIstring\fB\fR
|
||||
Set the suffix used on split files. Defaults
|
||||
to \fB\&.part\fR\&.
|
||||
.SH "DOWNLOAD SETTINGS"
|
||||
.PP
|
||||
Settings that require a download as a target, the options need to be
|
||||
called through f.ex \fBon_finished\fR\&.
|
||||
.TP
|
||||
\fBcreate_link = \fItype\fB,\fIpath\fB,\fIsuffix\fB\fR
|
||||
.TP
|
||||
\fBdelete_link = \fItype\fB,\fIpath\fB,\fIsuffix\fB\fR
|
||||
Create or delete a symbolic link. The link path is the concatenation
|
||||
of \fBpath\fR, the result of
|
||||
the \fBtype\fR on the download,
|
||||
and \fBsuffix\fR\&.
|
||||
|
||||
Available types are; \fBbase_path\fR uses the base path
|
||||
of the download, \fBbase_filename\fR uses the base
|
||||
filename of the download, \fBtied\fR uses the path of
|
||||
the file the download is tied to, see \fBstart_tied\fR\&.
|
||||
.SH "ADVANCED SETTINGS"
|
||||
.PP
|
||||
This list contains settings users shouldn't need to touch, some may
|
||||
even cause crashes or similar if incorrectly set.
|
||||
.TP
|
||||
\fBhash_read_ahead = \fIMB\fB\fR
|
||||
Configure how far ahead we ask the kernel to read when doing hash
|
||||
checking. The hash checker uses madvise(..., MADV_WILLNEED) for the
|
||||
requests.
|
||||
.TP
|
||||
\fBhash_interval = \fIms\fB\fR
|
||||
Interval between attempts to check the hash when the chunk is not in
|
||||
memory, in milliseconds.
|
||||
.TP
|
||||
\fBhash_max_tries = \fItries\fB\fR
|
||||
Number of attempts to check the hash while using the mincore status,
|
||||
before forcing. Overworked systems might need lower values to get a
|
||||
decent hash checking rate.
|
||||
.TP
|
||||
\fBsafe_sync = \fIyes|no\fB\fR
|
||||
Always use MS_SYNC rather than MS_ASYNC when syncing chunks. This may
|
||||
be nessesary in case of filesystem bugs like NFS in linux ~2.6.13.
|
||||
.TP
|
||||
\fBmax_open_files = \fIvalue\fB\fR
|
||||
Number of files to simultaneously keep open. LibTorrent dynamically
|
||||
opens and closes files as necessary when mapping files to
|
||||
memory. Default is based on sysconf(_SC_OPEN_MAX).
|
||||
You probably only think you know what this option does, so don't touch
|
||||
it.
|
||||
.TP
|
||||
\fBmax_open_sockets = \fIvalue\fB\fR
|
||||
Number of network sockets to simultaneously keep open. This value is
|
||||
set to a reasonable value based on \fBsysconf(_SC_OPEN_MAX)\fR\&.
|
||||
.TP
|
||||
\fBmax_open_http = \fIvalue\fB\fR
|
||||
Number of sockets to simultaneously keep open. This value is set
|
||||
to \fB32\fR by default.
|
||||
.TP
|
||||
\fBmax_memory_usage = \fIbytes\fB\fR
|
||||
Set the max amount of memory space used to mapping file chunks. This
|
||||
may also be set using \fBulimit -m\fR where 3/4 will be
|
||||
allocated to file chunks.
|
||||
.TP
|
||||
\fBsend_buffer_size = \fIvalue\fB\fR
|
||||
.TP
|
||||
\fBreceive_buffer_size = \fIvalue\fB\fR
|
||||
Adjust the send and receive buffer size for socket.
|
||||
.TP
|
||||
\fBumask = \fI0022\fB\fR
|
||||
Set the umask for this process, which is applied to all files created
|
||||
by the program.
|
||||
.TP
|
||||
\fBcwd = \fIdirectory\fB\fR
|
||||
Changes the working directory of the process using
|
||||
\fBchdir\fR\&.
|
||||
.TP
|
||||
\fBsession_on_completion = \fIyes\fB\fR
|
||||
Controls if the session torrent is saved when a torrent finishes. By
|
||||
default on.
|
||||
.TP
|
||||
\fBsession_lock = \fIyes\fB\fR
|
||||
Controls if a lock file is created in the session directory on startup.
|
||||
.TP
|
||||
\fBsession_save = \fR
|
||||
Save the session files for all downloads.
|
||||
.TP
|
||||
\fBtos = \fIdefault|lowdelay|throughput|reliability|mincost\fB\fR
|
||||
.TP
|
||||
\fBtos = \fIhex\fB\fR
|
||||
Change the TOS of peer connections, by default set to
|
||||
\fBthroughput\fR\&. If the option is set to
|
||||
\fBdefault\fR then the system default TOS is used. A
|
||||
hex value may be used for non-standard settings.
|
||||
.TP
|
||||
\fBhandshake_log = \fIyes\fB\fR
|
||||
Enable logging of the peer handshake. This generates a large number of
|
||||
log messages, but may be useful to debug connection problems.
|
||||
.SH "AUTHORS"
|
||||
.PP
|
||||
|
||||
Jari "Rakshasa" Sundell <jaris@ifi.uio.no>
|
||||
File diff suppressed because it is too large
Load Diff
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
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# This is an example resource file for rTorrent. Copy to
|
||||
# ~/.rtorrent.rc and enable/modify the options as needed. Remember to
|
||||
# uncomment the options you wish to enable.
|
||||
|
||||
# Maximum and minimum number of peers to connect to per torrent.
|
||||
#
|
||||
#throttle.min_peers.normal.set = 40
|
||||
#throttle.max_peers.normal.set = 100
|
||||
|
||||
# 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.
|
||||
#
|
||||
#throttle.max_uploads.set = 15
|
||||
|
||||
# Global upload and download rate in KiB. "0" for unlimited.
|
||||
#
|
||||
#throttle.global_down.max_rate.set_kb = 0
|
||||
#throttle.global_up.max_rate.set_kb = 0
|
||||
|
||||
# Default directory to save the downloaded torrents.
|
||||
#
|
||||
#directory.default.set = ./
|
||||
|
||||
# Default session directory. Make sure you don't run multiple instance
|
||||
# of rtorrent using the same session directory. Perhaps using a
|
||||
# relative path?
|
||||
#
|
||||
#session.path.set = ./session
|
||||
|
||||
# Watch a directory for new torrents, and stop those that have been
|
||||
# deleted.
|
||||
#
|
||||
#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent
|
||||
#schedule2 = untied_directory,5,5,stop_untied=
|
||||
|
||||
# Close torrents when diskspace is low.
|
||||
#
|
||||
#schedule2 = low_diskspace,5,60,close_low_diskspace=100M
|
||||
|
||||
# The ip address reported to the tracker.
|
||||
#
|
||||
#network.local_address.set = 127.0.0.1
|
||||
#network.local_address.set = rakshasa.no
|
||||
|
||||
# The ip address the listening socket and outgoing connections is
|
||||
# bound to.
|
||||
#
|
||||
#network.bind_address.set = 127.0.0.1
|
||||
#network.bind_address.set = rakshasa.no
|
||||
|
||||
# Port range to use for listening.
|
||||
#
|
||||
#network.port_range.set = 6890-6999
|
||||
|
||||
# Start opening ports at a random position within the port range.
|
||||
#
|
||||
#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.
|
||||
#
|
||||
#pieces.hash.on_completion.set = no
|
||||
|
||||
# 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.
|
||||
#
|
||||
#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
|
||||
#
|
||||
# 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.mode.set = auto
|
||||
|
||||
# UDP port to use for DHT.
|
||||
#
|
||||
#dht.port.set = 6881
|
||||
|
||||
# Enable peer exchange (for torrents not marked private)
|
||||
#
|
||||
#protocol.pex.set = yes
|
||||
|
||||
# Set downlad list layout style. ("full", "compact")
|
||||
#
|
||||
#ui.torrent_list.layout.set = "full"
|
||||
|
||||
# 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.
|
||||
#
|
||||
#scgi_port = 127.0.0.1:5000
|
||||
#scgi_local = /home/user/rtorrent/rpc.socket
|
||||
#schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",/home/user/rtorrent/rpc.socket"
|
||||
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[[:space:]]*=" | sed "s/^[[:space:]]*session[[: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[[:space:]]*=" | sed "s/^[[:space:]]*session[[: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;
|
||||
@@ -1,14 +0,0 @@
|
||||
Donate to rTorrent development
|
||||
==============================
|
||||
|
||||
* [Paypal](https://paypal.me/jarisundellno)
|
||||
* [Patreon](https://www.patreon.com/rtorrent)
|
||||
* [SubscribeStar](https://www.subscribestar.com/rtorrent)
|
||||
* Bitcoin: 1MpmXm5AHtdBoDaLZstJw8nupJJaeKu8V8
|
||||
* Ethereum: 0x9AB1e3C3d8a875e870f161b3e9287Db0E6DAfF78
|
||||
* Litecoin: LdyaVR67LBnTf6mAT4QJnjSG2Zk67qxmfQ
|
||||
* Cardano: addr1qytaslmqmk6dspltw06sp0zf83dh09u79j49ceh5y26zdcccgq4ph7nmx6kgmzeldauj43254ey97f3x4xw49d86aguqwfhlte
|
||||
|
||||
Help keep rTorrent development going by donating to its creator.
|
||||
|
||||
(Note the old paypal account is defunct, please use the new one when sending donations)
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="96" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h49v20H0z"/><path fill="#97ca00" d="M49 0h47v20H49z"/><path fill="url(#b)" d="M0 0h96v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="255" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="390">Donate</text><text x="255" y="140" transform="scale(.1)" textLength="390">Donate</text><text x="715" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">PayPal</text><text x="715" y="140" transform="scale(.1)" textLength="370">PayPal</text></g> </svg>
|
||||
|
Before Width: | Height: | Size: 954 B |
Binary file not shown.
|
Before Width: | Height: | Size: 943 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,39 +0,0 @@
|
||||
RTorrent
|
||||
========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
To learn how to use rTorrent visit the [Wiki](https://github.com/rakshasa/rtorrent/wiki).
|
||||
|
||||
[Donate](https://rakshasa.github.io/rtorrent/donate.html) to help fund the development of this client.
|
||||
|
||||
Stable
|
||||
------
|
||||
|
||||
* [libtorrent-0.16.11.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/libtorrent-0.16.11.tar.gz)
|
||||
* [rtorrent-0.16.11.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/rtorrent-0.16.11.tar.gz)
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
* [libtorrent-0.16.13.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/libtorrent-0.16.13.tar.gz)
|
||||
* [rtorrent-0.16.13.tar.gz](https://github.com/rakshasa/rtorrent-archive/raw/master/rtorrent-0.16.13.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
|
||||
* Ethereum: 0x9AB1e3C3d8a875e870f161b3e9287Db0E6DAfF78
|
||||
* Litecoin: LdyaVR67LBnTf6mAT4QJnjSG2Zk67qxmfQ
|
||||
* Cardano: addr1qytaslmqmk6dspltw06sp0zf83dh09u79j49ceh5y26zdcccgq4ph7nmx6kgmzeldauj43254ey97f3x4xw49d86aguqwfhlte
|
||||
|
||||
Help keep rTorrent development going by donating to its creator.
|
||||
@@ -1 +0,0 @@
|
||||
console.log('This would be the main JS file.');
|
||||
@@ -1,17 +0,0 @@
|
||||
var metas = document.getElementsByTagName('meta');
|
||||
var i;
|
||||
if (navigator.userAgent.match(/iPhone/i)) {
|
||||
for (i=0; i<metas.length; i++) {
|
||||
if (metas[i].name == "viewport") {
|
||||
metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
|
||||
}
|
||||
}
|
||||
document.addEventListener("gesturestart", gestureStart, false);
|
||||
}
|
||||
function gestureStart() {
|
||||
for (i=0; i<metas.length; i++) {
|
||||
if (metas[i].name == "viewport") {
|
||||
metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// Wrapper for addrinfo with focus on zero-copy conversion to and from
|
||||
// the c-type and wrapper.
|
||||
//
|
||||
// Do use the wrapper on a pre-existing struct addrinfo, cast the
|
||||
// pointer rather than the base type.
|
||||
|
||||
#ifndef RAK_ADDRESS_INFO_H
|
||||
#define RAK_ADDRESS_INFO_H
|
||||
|
||||
#include <netdb.h>
|
||||
#include <rak/socket_address.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class address_info {
|
||||
public:
|
||||
void clear() { std::memset(this, 0, sizeof(address_info)); }
|
||||
|
||||
int flags() const { return m_addrinfo.ai_flags; }
|
||||
void set_flags(int f) { m_addrinfo.ai_flags = f; }
|
||||
|
||||
int family() const { return m_addrinfo.ai_family; }
|
||||
void set_family(int f) { m_addrinfo.ai_family = f; }
|
||||
|
||||
int socket_type() const { return m_addrinfo.ai_socktype; }
|
||||
void set_socket_type(int t) { m_addrinfo.ai_socktype = t; }
|
||||
|
||||
int protocol() const { return m_addrinfo.ai_protocol; }
|
||||
void set_protocol(int p) { m_addrinfo.ai_protocol = p; }
|
||||
|
||||
size_t length() const { return m_addrinfo.ai_addrlen; }
|
||||
|
||||
socket_address* address() { return reinterpret_cast<socket_address*>(m_addrinfo.ai_addr); }
|
||||
|
||||
addrinfo* c_addrinfo() { return &m_addrinfo; }
|
||||
const addrinfo* c_addrinfo() const { return &m_addrinfo; }
|
||||
|
||||
address_info* next() { return reinterpret_cast<address_info*>(m_addrinfo.ai_next); }
|
||||
|
||||
static int get_address_info(const char* node, int domain, int type, address_info** ai);
|
||||
|
||||
static void free_address_info(address_info* ai) { ::freeaddrinfo(ai->c_addrinfo()); }
|
||||
|
||||
static const char* strerror(int err) { return gai_strerror(err); }
|
||||
|
||||
private:
|
||||
addrinfo m_addrinfo;
|
||||
};
|
||||
|
||||
inline int
|
||||
address_info::get_address_info(const char* node, int pfamily, int stype, address_info** ai) {
|
||||
address_info hints;
|
||||
hints.clear();
|
||||
hints.set_family(pfamily);
|
||||
hints.set_socket_type(stype);
|
||||
|
||||
return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast<addrinfo**>(ai));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_ALGORITHM_H
|
||||
#define RAK_ALGORITHM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <typename _InputIter, typename _Function>
|
||||
_Function
|
||||
for_each_pre(_InputIter __first, _InputIter __last, _Function __f) {
|
||||
_InputIter __tmp;
|
||||
|
||||
while (__first != __last) {
|
||||
__tmp = __first++;
|
||||
|
||||
__f(*__tmp);
|
||||
}
|
||||
|
||||
return __f;
|
||||
}
|
||||
|
||||
// Return a range with a distance of no more than __distance and
|
||||
// between __first and __last, centered on __middle1.
|
||||
template <typename _InputIter, typename _Distance>
|
||||
std::pair<_InputIter, _InputIter>
|
||||
advance_bidirectional(_InputIter __first, _InputIter __middle1, _InputIter __last, _Distance __distance) {
|
||||
_InputIter __middle2 = __middle1;
|
||||
|
||||
do {
|
||||
if (!__distance)
|
||||
break;
|
||||
|
||||
if (__middle2 != __last) {
|
||||
++__middle2;
|
||||
--__distance;
|
||||
|
||||
} else if (__middle1 == __first) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!__distance)
|
||||
break;
|
||||
|
||||
if (__middle1 != __first) {
|
||||
--__middle1;
|
||||
--__distance;
|
||||
|
||||
} else if (__middle2 == __last) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (true);
|
||||
|
||||
return std::make_pair(__middle1, __middle2);
|
||||
}
|
||||
|
||||
template <typename _InputIter, typename _Distance>
|
||||
_InputIter
|
||||
advance_forward(_InputIter __first, _InputIter __last, _Distance __distance) {
|
||||
while (__first != __last && __distance != 0) {
|
||||
__first++;
|
||||
__distance--;
|
||||
}
|
||||
|
||||
return __first;
|
||||
}
|
||||
|
||||
template <typename _InputIter, typename _Distance>
|
||||
_InputIter
|
||||
advance_backward(_InputIter __first, _InputIter __last, _Distance __distance) {
|
||||
while (__first != __last && __distance != 0) {
|
||||
__first--;
|
||||
__distance--;
|
||||
}
|
||||
|
||||
return __first;
|
||||
}
|
||||
|
||||
template <typename _Value>
|
||||
struct compare_base : public std::binary_function<_Value, _Value, bool> {
|
||||
bool operator () (const _Value& complete, const _Value& base) const {
|
||||
return !complete.compare(0, base.size(), base);
|
||||
}
|
||||
};
|
||||
|
||||
// Count the number of elements from the start of the containers to
|
||||
// the first inequal element.
|
||||
template <typename _InputIter1, typename _InputIter2>
|
||||
typename std::iterator_traits<_InputIter1>::difference_type
|
||||
count_base(_InputIter1 __first1, _InputIter1 __last1,
|
||||
_InputIter2 __first2, _InputIter2 __last2) {
|
||||
|
||||
typename std::iterator_traits<_InputIter1>::difference_type __n = 0;
|
||||
|
||||
for ( ;__first1 != __last1 && __first2 != __last2; ++__first1, ++__first2, ++__n)
|
||||
if (*__first1 != *__first2)
|
||||
return __n;
|
||||
|
||||
return __n;
|
||||
}
|
||||
|
||||
template <typename _Return, typename _InputIter, typename _Ftor>
|
||||
_Return
|
||||
make_base(_InputIter __first, _InputIter __last, _Ftor __ftor) {
|
||||
if (__first == __last)
|
||||
return "";
|
||||
|
||||
_Return __base = __ftor(*__first++);
|
||||
|
||||
for ( ;__first != __last; ++__first) {
|
||||
typename std::iterator_traits<_InputIter>::difference_type __pos = count_base(__base.begin(), __base.end(),
|
||||
__ftor(*__first).begin(), __ftor(*__first).end());
|
||||
|
||||
if (__pos < (typename std::iterator_traits<_InputIter>::difference_type)__base.size())
|
||||
__base.resize(__pos);
|
||||
}
|
||||
|
||||
return __base;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline int popcount_wrapper(T t) {
|
||||
#if USE_BUILTIN_POPCOUNT
|
||||
if (std::numeric_limits<T>::digits <= std::numeric_limits<unsigned int>::digits)
|
||||
return __builtin_popcount(t);
|
||||
else
|
||||
return __builtin_popcountll(t);
|
||||
#else
|
||||
#error __builtin_popcount not found.
|
||||
unsigned int count = 0;
|
||||
|
||||
while (t) {
|
||||
count += t & 0x1;
|
||||
t >> 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// Some allocators for cacheline aligned chunks of memory, etc.
|
||||
|
||||
#ifndef RAK_ALLOCATORS_H
|
||||
#define RAK_ALLOCATORS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <class T = void*>
|
||||
class cacheline_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef const void* const_void_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
cacheline_allocator() throw() { }
|
||||
cacheline_allocator(const cacheline_allocator&) throw() { }
|
||||
template <class U>
|
||||
cacheline_allocator(const cacheline_allocator<U>&) throw() { }
|
||||
~cacheline_allocator() throw() { }
|
||||
|
||||
template <class U>
|
||||
struct rebind { typedef cacheline_allocator<U> other; };
|
||||
|
||||
// return address of values
|
||||
pointer address (reference value) const { return &value; }
|
||||
const_pointer address (const_reference value) const { return &value; }
|
||||
|
||||
size_type max_size () const throw() { return std::numeric_limits<size_t>::max() / sizeof(T); }
|
||||
|
||||
pointer allocate(size_type num, const_void_pointer hint = 0) { return alloc_size(num*sizeof(T)); }
|
||||
|
||||
static pointer alloc_size(size_type size) {
|
||||
pointer ptr = NULL;
|
||||
int __UNUSED result = posix_memalign((void**)&ptr, LT_SMP_CACHE_BYTES, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void construct (pointer p, const T& value) { new((void*)p)T(value); }
|
||||
void destroy (pointer p) { p->~T(); }
|
||||
void deallocate (pointer p, size_type num) { free((void*)p); }
|
||||
};
|
||||
|
||||
|
||||
template <class T1, class T2>
|
||||
bool operator== (const cacheline_allocator<T1>&, const cacheline_allocator<T2>&) throw() {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
bool operator!= (const cacheline_allocator<T1>&, const cacheline_allocator<T2>&) throw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Operator new with custom allocators:
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
void* operator new(size_t s, rak::cacheline_allocator<T> a) { return a.alloc_size(s); }
|
||||
|
||||
#endif // namespace rak
|
||||
@@ -0,0 +1,88 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_ERROR_NUMBER_H
|
||||
#define RAK_ERROR_NUMBER_H
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class error_number {
|
||||
public:
|
||||
static const int e_access = EACCES;
|
||||
static const int e_again = EAGAIN;
|
||||
static const int e_connreset = ECONNRESET;
|
||||
static const int e_connaborted = ECONNABORTED;
|
||||
static const int e_deadlk = EDEADLK;
|
||||
|
||||
static const int e_noent = ENOENT;
|
||||
static const int e_nodev = ENODEV;
|
||||
static const int e_nomem = ENOMEM;
|
||||
static const int e_notdir = ENOTDIR;
|
||||
static const int e_isdir = EISDIR;
|
||||
|
||||
static const int e_intr = EINTR;
|
||||
|
||||
error_number() : m_errno(0) {}
|
||||
error_number(int e) : m_errno(e) {}
|
||||
|
||||
bool is_valid() const { return m_errno != 0; }
|
||||
|
||||
int value() const { return m_errno; }
|
||||
const char* c_str() const { return std::strerror(m_errno); }
|
||||
|
||||
bool is_blocked_momentary() const { return m_errno == e_again || m_errno == e_intr; }
|
||||
bool is_blocked_prolonged() const { return m_errno == e_deadlk; }
|
||||
|
||||
bool is_closed() const { return m_errno == e_connreset || m_errno == e_connaborted; }
|
||||
|
||||
bool is_bad_path() const { return m_errno == e_noent || m_errno == e_notdir || m_errno == e_access; }
|
||||
|
||||
static error_number current() { return errno; }
|
||||
static void clear_global() { errno = 0; }
|
||||
static void set_global(error_number err) { errno = err.m_errno; }
|
||||
|
||||
bool operator == (const error_number& e) const { return m_errno == e.m_errno; }
|
||||
|
||||
private:
|
||||
int m_errno;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_FILE_STAT_H
|
||||
#define RAK_FILE_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class file_stat {
|
||||
public:
|
||||
// Consider storing rak::error_number.
|
||||
|
||||
bool update(int fd) { return fstat(fd, &m_stat) == 0; }
|
||||
bool update(const char* filename) { return stat(filename, &m_stat) == 0; }
|
||||
bool update(const std::string& filename) { return update(filename.c_str()); }
|
||||
|
||||
bool update_link(const char* filename) { return lstat(filename, &m_stat) == 0; }
|
||||
bool update_link(const std::string& filename) { return update_link(filename.c_str()); }
|
||||
|
||||
bool is_regular() const { return S_ISREG(m_stat.st_mode); }
|
||||
bool is_directory() const { return S_ISDIR(m_stat.st_mode); }
|
||||
bool is_character() const { return S_ISCHR(m_stat.st_mode); }
|
||||
bool is_block() const { return S_ISBLK(m_stat.st_mode); }
|
||||
bool is_fifo() const { return S_ISFIFO(m_stat.st_mode); }
|
||||
bool is_link() const { return S_ISLNK(m_stat.st_mode); }
|
||||
bool is_socket() const { return S_ISSOCK(m_stat.st_mode); }
|
||||
|
||||
off_t size() const { return m_stat.st_size; }
|
||||
|
||||
time_t access_time() const { return m_stat.st_atime; }
|
||||
time_t change_time() const { return m_stat.st_ctime; }
|
||||
time_t modified_time() const { return m_stat.st_mtime; }
|
||||
|
||||
private:
|
||||
struct stat m_stat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_FS_STAT_H
|
||||
#define RAK_FS_STAT_H
|
||||
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <rak/error_number.h>
|
||||
|
||||
#if HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
namespace rak {
|
||||
|
||||
class fs_stat {
|
||||
public:
|
||||
|
||||
typedef FS_STAT_SIZE_TYPE blocksize_type;
|
||||
typedef FS_STAT_COUNT_TYPE blockcount_type;
|
||||
typedef FS_STAT_STRUCT fs_stat_type;
|
||||
|
||||
bool update(int fd) { return FS_STAT_FD; }
|
||||
bool update(const char* fn) { return FS_STAT_FN; }
|
||||
bool update(const std::string& filename) { return update(filename.c_str()); }
|
||||
|
||||
blocksize_type blocksize() { return FS_STAT_BLOCK_SIZE; }
|
||||
blockcount_type blocks_avail() { return m_stat.f_bavail; }
|
||||
int64_t bytes_avail() { return (int64_t) blocksize() * m_stat.f_bavail; }
|
||||
|
||||
private:
|
||||
fs_stat_type m_stat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,683 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_FUNCTIONAL_H
|
||||
#define RAK_FUNCTIONAL_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <typename Type>
|
||||
struct reference_fix {
|
||||
typedef Type type;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct reference_fix<Type&> {
|
||||
typedef Type type;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct value_t {
|
||||
value_t(Type v) : m_v(v) {}
|
||||
|
||||
Type operator () () const { return m_v; }
|
||||
|
||||
Type m_v;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
inline value_t<Type>
|
||||
value(Type v) {
|
||||
return value_t<Type>(v);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct accumulate_t {
|
||||
accumulate_t(Type t, Ftor f) : result(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
void operator () (const Arg& a) { result += m_f(a); }
|
||||
|
||||
Type result;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline accumulate_t<Type, Ftor>
|
||||
accumulate(Type t, Ftor f) {
|
||||
return accumulate_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
// Operators:
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct equal_t {
|
||||
typedef bool result_type;
|
||||
|
||||
equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t == m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline equal_t<Type, Ftor>
|
||||
equal(Type t, Ftor f) {
|
||||
return equal_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct equal_ptr_t {
|
||||
typedef bool result_type;
|
||||
|
||||
equal_ptr_t(Type* t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (const Arg& a) {
|
||||
return *m_t == *m_f(a);
|
||||
}
|
||||
|
||||
Type* m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline equal_ptr_t<Type, Ftor>
|
||||
equal_ptr(Type* t, Ftor f) {
|
||||
return equal_ptr_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct not_equal_t {
|
||||
typedef bool result_type;
|
||||
|
||||
not_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t != m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline not_equal_t<Type, Ftor>
|
||||
not_equal(Type t, Ftor f) {
|
||||
return not_equal_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct less_t {
|
||||
typedef bool result_type;
|
||||
|
||||
less_t(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t < m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline less_t<Type, Ftor>
|
||||
less(Type t, Ftor f) {
|
||||
return less_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename FtorA, typename FtorB>
|
||||
struct less2_t : public std::binary_function<typename FtorA::argument_type, typename FtorB::argument_type, bool> {
|
||||
less2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {}
|
||||
|
||||
bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) {
|
||||
return m_f_a(a) < m_f_b(b);
|
||||
}
|
||||
|
||||
FtorA m_f_a;
|
||||
FtorB m_f_b;
|
||||
};
|
||||
|
||||
template <typename FtorA, typename FtorB>
|
||||
inline less2_t<FtorA, FtorB>
|
||||
less2(FtorA f_a, FtorB f_b) {
|
||||
return less2_t<FtorA,FtorB>(f_a,f_b);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct _greater {
|
||||
typedef bool result_type;
|
||||
|
||||
_greater(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t > m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline _greater<Type, Ftor>
|
||||
greater(Type t, Ftor f) {
|
||||
return _greater<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename FtorA, typename FtorB>
|
||||
struct greater2_t : public std::binary_function<typename FtorA::argument_type, typename FtorB::argument_type, bool> {
|
||||
greater2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {}
|
||||
|
||||
bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) {
|
||||
return m_f_a(a) > m_f_b(b);
|
||||
}
|
||||
|
||||
FtorA m_f_a;
|
||||
FtorB m_f_b;
|
||||
};
|
||||
|
||||
template <typename FtorA, typename FtorB>
|
||||
inline greater2_t<FtorA, FtorB>
|
||||
greater2(FtorA f_a, FtorB f_b) {
|
||||
return greater2_t<FtorA,FtorB>(f_a,f_b);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct less_equal_t {
|
||||
typedef bool result_type;
|
||||
|
||||
less_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t <= m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline less_equal_t<Type, Ftor>
|
||||
less_equal(Type t, Ftor f) {
|
||||
return less_equal_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
struct greater_equal_t {
|
||||
typedef bool result_type;
|
||||
|
||||
greater_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {}
|
||||
|
||||
template <typename Arg>
|
||||
bool operator () (Arg& a) {
|
||||
return m_t >= m_f(a);
|
||||
}
|
||||
|
||||
Type m_t;
|
||||
Ftor m_f;
|
||||
};
|
||||
|
||||
template <typename Type, typename Ftor>
|
||||
inline greater_equal_t<Type, Ftor>
|
||||
greater_equal(Type t, Ftor f) {
|
||||
return greater_equal_t<Type, Ftor>(t, f);
|
||||
}
|
||||
|
||||
template<typename Tp>
|
||||
struct invert : public std::unary_function<Tp, Tp> {
|
||||
Tp
|
||||
operator () (const Tp& x) const { return ~x; }
|
||||
};
|
||||
|
||||
template <typename Src, typename Dest>
|
||||
struct on_t : public std::unary_function<typename Src::argument_type, typename Dest::result_type> {
|
||||
typedef typename Dest::result_type result_type;
|
||||
|
||||
on_t(Src s, Dest d) : m_dest(d), m_src(s) {}
|
||||
|
||||
result_type operator () (typename reference_fix<typename Src::argument_type>::type arg) {
|
||||
return m_dest(m_src(arg));
|
||||
}
|
||||
|
||||
Dest m_dest;
|
||||
Src m_src;
|
||||
};
|
||||
|
||||
template <typename Src, typename Dest>
|
||||
inline on_t<Src, Dest>
|
||||
on(Src s, Dest d) {
|
||||
return on_t<Src, Dest>(s, d);
|
||||
}
|
||||
|
||||
template <typename Src, typename Dest>
|
||||
struct on2_t : public std::binary_function<typename Src::argument_type, typename Dest::second_argument_type, typename Dest::result_type> {
|
||||
typedef typename Dest::result_type result_type;
|
||||
|
||||
on2_t(Src s, Dest d) : m_dest(d), m_src(s) {}
|
||||
|
||||
result_type operator () (typename reference_fix<typename Src::argument_type>::type first, typename reference_fix<typename Dest::second_argument_type>::type second) {
|
||||
return m_dest(m_src(first), second);
|
||||
}
|
||||
|
||||
Dest m_dest;
|
||||
Src m_src;
|
||||
};
|
||||
|
||||
template <typename Src, typename Dest>
|
||||
inline on2_t<Src, Dest>
|
||||
on2(Src s, Dest d) {
|
||||
return on2_t<Src, Dest>(s, d);
|
||||
}
|
||||
|
||||
// Creates a functor for accessing a member.
|
||||
template <typename Class, typename Member>
|
||||
struct mem_ptr_t : public std::unary_function<Class*, Member&> {
|
||||
mem_ptr_t(Member Class::*m) : m_member(m) {}
|
||||
|
||||
Member& operator () (Class* c) {
|
||||
return c->*m_member;
|
||||
}
|
||||
|
||||
const Member& operator () (const Class* c) {
|
||||
return c->*m_member;
|
||||
}
|
||||
|
||||
Member Class::*m_member;
|
||||
};
|
||||
|
||||
template <typename Class, typename Member>
|
||||
inline mem_ptr_t<Class, Member>
|
||||
mem_ptr(Member Class::*m) {
|
||||
return mem_ptr_t<Class, Member>(m);
|
||||
}
|
||||
|
||||
template <typename Class, typename Member>
|
||||
struct mem_ref_t : public std::unary_function<Class&, Member&> {
|
||||
mem_ref_t(Member Class::*m) : m_member(m) {}
|
||||
|
||||
Member& operator () (Class& c) {
|
||||
return c.*m_member;
|
||||
}
|
||||
|
||||
Member Class::*m_member;
|
||||
};
|
||||
|
||||
template <typename Class, typename Member>
|
||||
struct const_mem_ref_t : public std::unary_function<const Class&, const Member&> {
|
||||
const_mem_ref_t(const Member Class::*m) : m_member(m) {}
|
||||
|
||||
const Member& operator () (const Class& c) {
|
||||
return c.*m_member;
|
||||
}
|
||||
|
||||
const Member Class::*m_member;
|
||||
};
|
||||
|
||||
template <typename Class, typename Member>
|
||||
inline mem_ref_t<Class, Member>
|
||||
mem_ref(Member Class::*m) {
|
||||
return mem_ref_t<Class, Member>(m);
|
||||
}
|
||||
|
||||
template <typename Class, typename Member>
|
||||
inline const_mem_ref_t<Class, Member>
|
||||
const_mem_ref(const Member Class::*m) {
|
||||
return const_mem_ref_t<Class, Member>(m);
|
||||
}
|
||||
|
||||
template <typename Cond, typename Then>
|
||||
struct if_then_t {
|
||||
if_then_t(Cond c, Then t) : m_cond(c), m_then(t) {}
|
||||
|
||||
template <typename Arg>
|
||||
void operator () (Arg& a) {
|
||||
if (m_cond(a))
|
||||
m_then(a);
|
||||
}
|
||||
|
||||
Cond m_cond;
|
||||
Then m_then;
|
||||
};
|
||||
|
||||
template <typename Cond, typename Then>
|
||||
inline if_then_t<Cond, Then>
|
||||
if_then(Cond c, Then t) {
|
||||
return if_then_t<Cond, Then>(c, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct call_delete : public std::unary_function<T*, void> {
|
||||
void operator () (T* t) {
|
||||
delete t;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
call_delete_func(T* t) {
|
||||
delete t;
|
||||
}
|
||||
|
||||
template <typename Operation>
|
||||
class bind1st_t : public std::unary_function<typename Operation::second_argument_type, typename Operation::result_type> {
|
||||
public:
|
||||
typedef typename reference_fix<typename Operation::first_argument_type>::type value_type;
|
||||
typedef typename reference_fix<typename Operation::second_argument_type>::type argument_type;
|
||||
|
||||
bind1st_t(const Operation& op, const value_type v) :
|
||||
m_op(op), m_value(v) {}
|
||||
|
||||
typename Operation::result_type
|
||||
operator () (const argument_type arg) {
|
||||
return m_op(m_value, arg);
|
||||
}
|
||||
|
||||
protected:
|
||||
Operation m_op;
|
||||
value_type m_value;
|
||||
};
|
||||
|
||||
template <typename Operation, typename Type>
|
||||
inline bind1st_t<Operation>
|
||||
bind1st(const Operation& op, const Type& val) {
|
||||
return bind1st_t<Operation>(op, val);
|
||||
}
|
||||
|
||||
template <typename Operation>
|
||||
class bind2nd_t : public std::unary_function<typename Operation::first_argument_type, typename Operation::result_type> {
|
||||
public:
|
||||
typedef typename reference_fix<typename Operation::first_argument_type>::type argument_type;
|
||||
typedef typename reference_fix<typename Operation::second_argument_type>::type value_type;
|
||||
|
||||
bind2nd_t(const Operation& op, const value_type v) :
|
||||
m_op(op), m_value(v) {}
|
||||
|
||||
typename Operation::result_type
|
||||
operator () (argument_type arg) {
|
||||
return m_op(arg, m_value);
|
||||
}
|
||||
|
||||
protected:
|
||||
Operation m_op;
|
||||
value_type m_value;
|
||||
};
|
||||
|
||||
template <typename Operation, typename Type>
|
||||
inline bind2nd_t<Operation>
|
||||
bind2nd(const Operation& op, const Type& val) {
|
||||
return bind2nd_t<Operation>(op, val);
|
||||
}
|
||||
|
||||
// Lightweight callback function including pointer to object. Should
|
||||
// be replaced by TR1 stuff later. Requires an object to bind, instead
|
||||
// of using a seperate functor for that.
|
||||
|
||||
template <typename Ret>
|
||||
class ptr_fun0 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (*Function)();
|
||||
|
||||
ptr_fun0() {}
|
||||
ptr_fun0(Function f) : m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_function; }
|
||||
|
||||
Ret operator () () { return m_function(); }
|
||||
|
||||
private:
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret>
|
||||
class mem_fun0 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)();
|
||||
|
||||
mem_fun0() : m_object(NULL) {}
|
||||
mem_fun0(Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
Ret operator () () { return (m_object->*m_function)(); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret>
|
||||
class const_mem_fun0 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)() const;
|
||||
|
||||
const_mem_fun0() : m_object(NULL) {}
|
||||
const_mem_fun0(const Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
Ret operator () () const { return (m_object->*m_function)(); }
|
||||
|
||||
private:
|
||||
const Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1>
|
||||
class mem_fun1 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)(Arg1);
|
||||
|
||||
mem_fun1() : m_object(NULL) {}
|
||||
mem_fun1(Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
Ret operator () (Arg1 a1) { return (m_object->*m_function)(a1); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1>
|
||||
class const_mem_fun1 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)(Arg1) const;
|
||||
|
||||
const_mem_fun1() : m_object(NULL) {}
|
||||
const_mem_fun1(const Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
Ret operator () (Arg1 a1) const { return (m_object->*m_function)(a1); }
|
||||
|
||||
private:
|
||||
const Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1, typename Arg2>
|
||||
class mem_fun2 : public std::binary_function<Arg1, Arg2, Ret> {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)(Arg1, Arg2);
|
||||
typedef Object object_type;
|
||||
|
||||
mem_fun2() : m_object(NULL) {}
|
||||
mem_fun2(Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
object_type* object() { return m_object; }
|
||||
const object_type* object() const { return m_object; }
|
||||
|
||||
Ret operator () (Arg1 a1, Arg2 a2) { return (m_object->*m_function)(a1, a2); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1, typename Arg2, typename Arg3>
|
||||
class mem_fun3 {
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
typedef Ret (Object::*Function)(Arg1, Arg2, Arg3);
|
||||
|
||||
mem_fun3() : m_object(NULL) {}
|
||||
mem_fun3(Object* o, Function f) : m_object(o), m_function(f) {}
|
||||
|
||||
bool is_valid() const { return m_object; }
|
||||
|
||||
Ret operator () (Arg1 a1, Arg2 a2, Arg3 a3) { return (m_object->*m_function)(a1, a2, a3); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Function m_function;
|
||||
};
|
||||
|
||||
template <typename Ret>
|
||||
inline ptr_fun0<Ret>
|
||||
ptr_fun(Ret (*f)()) { return ptr_fun0<Ret>(f); }
|
||||
|
||||
template <typename Object, typename Ret>
|
||||
inline mem_fun0<Object, Ret>
|
||||
make_mem_fun(Object* o, Ret (Object::*f)()) {
|
||||
return mem_fun0<Object, Ret>(o, f);
|
||||
}
|
||||
|
||||
template <typename Object, typename Ret>
|
||||
inline const_mem_fun0<Object, Ret>
|
||||
make_mem_fun(const Object* o, Ret (Object::*f)() const) {
|
||||
return const_mem_fun0<Object, Ret>(o, f);
|
||||
}
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1>
|
||||
inline mem_fun1<Object, Ret, Arg1>
|
||||
make_mem_fun(Object* o, Ret (Object::*f)(Arg1)) {
|
||||
return mem_fun1<Object, Ret, Arg1>(o, f);
|
||||
}
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1>
|
||||
inline const_mem_fun1<Object, Ret, Arg1>
|
||||
make_mem_fun(const Object* o, Ret (Object::*f)(Arg1) const) {
|
||||
return const_mem_fun1<Object, Ret, Arg1>(o, f);
|
||||
}
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1, typename Arg2>
|
||||
inline mem_fun2<Object, Ret, Arg1, Arg2>
|
||||
make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2)) {
|
||||
return mem_fun2<Object, Ret, Arg1, Arg2>(o, f);
|
||||
}
|
||||
|
||||
template <typename Object, typename Ret, typename Arg1, typename Arg2, typename Arg3>
|
||||
inline mem_fun3<Object, Ret, Arg1, Arg2, Arg3>
|
||||
make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2, Arg3)) {
|
||||
return mem_fun3<Object, Ret, Arg1, Arg2, Arg3>(o, f);
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline void
|
||||
slot_list_call(const Container& slot_list) {
|
||||
if (slot_list.empty())
|
||||
return;
|
||||
|
||||
typename Container::const_iterator first = slot_list.begin();
|
||||
typename Container::const_iterator next = slot_list.begin();
|
||||
|
||||
while (++next != slot_list.end()) {
|
||||
(*first)();
|
||||
first = next;
|
||||
}
|
||||
|
||||
(*first)();
|
||||
}
|
||||
|
||||
template <typename Container, typename Arg1>
|
||||
inline void
|
||||
slot_list_call(const Container& slot_list, Arg1 arg1) {
|
||||
if (slot_list.empty())
|
||||
return;
|
||||
|
||||
typename Container::const_iterator first = slot_list.begin();
|
||||
typename Container::const_iterator next = slot_list.begin();
|
||||
|
||||
while (++next != slot_list.end()) {
|
||||
(*first)(arg1);
|
||||
first = next;
|
||||
}
|
||||
|
||||
(*first)(arg1);
|
||||
}
|
||||
|
||||
template <typename Container, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void
|
||||
slot_list_call(const Container& slot_list, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
|
||||
if (slot_list.empty())
|
||||
return;
|
||||
|
||||
typename Container::const_iterator first = slot_list.begin();
|
||||
typename Container::const_iterator next = slot_list.begin();
|
||||
|
||||
while (++next != slot_list.end()) {
|
||||
(*first)(arg1, arg2, arg3, arg4);
|
||||
first = next;
|
||||
}
|
||||
|
||||
(*first)(arg1, arg2, arg3, arg4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,656 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// This file contains functors that wrap function pointers and member
|
||||
// function pointers.
|
||||
//
|
||||
// 'fn' functors are polymorphic and derives from 'rak::function' and
|
||||
// thus is less strict about types, this adds the cost of calling a
|
||||
// virtual function.
|
||||
//
|
||||
// 'fun' functors are non-polymorphic and thus cheaper, but requires
|
||||
// the target object's type in the functor's template arguments.
|
||||
//
|
||||
// This should be replaced with TR1 stuff when it becomes widely
|
||||
// available. At the moment it behaves like std::auto_ptr, so be
|
||||
// careful when copying.
|
||||
|
||||
#ifndef RAK_FUNCTIONAL_FUN_H
|
||||
#define RAK_FUNCTIONAL_FUN_H
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include lt_tr1_functional
|
||||
#include lt_tr1_memory
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <typename Result>
|
||||
class function_base0 {
|
||||
public:
|
||||
virtual ~function_base0() {}
|
||||
|
||||
virtual Result operator () () = 0;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1>
|
||||
class function_base1 : public std::unary_function<Arg1, Result> {
|
||||
public:
|
||||
virtual ~function_base1() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1) = 0;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2>
|
||||
class function_base2 : public std::binary_function<Arg1, Arg2, Result> {
|
||||
public:
|
||||
virtual ~function_base2() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2) = 0;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
|
||||
class function_base3 {
|
||||
public:
|
||||
virtual ~function_base3() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) = 0;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
class function0 {
|
||||
public:
|
||||
typedef Result result_type;
|
||||
typedef function_base0<Result> base_type;
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () () { return (*m_base)(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1>
|
||||
class function1 {
|
||||
public:
|
||||
typedef Result result_type;
|
||||
typedef function_base1<Result, Arg1> base_type;
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () (Arg1 arg1) { return (*m_base)(arg1); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2>
|
||||
class function2 {
|
||||
public:
|
||||
typedef Result result_type;
|
||||
typedef function_base2<Result, Arg1, Arg2> base_type;
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () (Arg1 arg1, Arg2 arg2) { return (*m_base)(arg1, arg2); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg2>
|
||||
class function2<Result, void, Arg2> {
|
||||
public:
|
||||
typedef Result result_type;
|
||||
typedef function_base1<Result, Arg2> base_type;
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () (Arg2 arg2) { return (*m_base)(arg2); }
|
||||
|
||||
template <typename Discard>
|
||||
Result operator () (Discard discard, Arg2 arg2) { return (*m_base)(arg2); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
|
||||
class function3 {
|
||||
public:
|
||||
typedef Result result_type;
|
||||
typedef function_base3<Result, Arg1, Arg2, Arg3> base_type;
|
||||
|
||||
bool is_valid() const { return m_base.get() != NULL; }
|
||||
|
||||
void set(base_type* base) { m_base = std::shared_ptr<base_type>(base); }
|
||||
base_type* release() { return m_base.release(); }
|
||||
|
||||
Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (*m_base)(arg1, arg2, arg3); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<base_type> m_base;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
class ptr_fn0_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef Result (*Func)();
|
||||
|
||||
ptr_fn0_t(Func func) : m_func(func) {}
|
||||
virtual ~ptr_fn0_t() {}
|
||||
|
||||
virtual Result operator () () { return m_func(); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1>
|
||||
class ptr_fn1_t : public function_base1<Result, Arg1> {
|
||||
public:
|
||||
typedef Result (*Func)(Arg1);
|
||||
|
||||
ptr_fn1_t(Func func) : m_func(func) {}
|
||||
virtual ~ptr_fn1_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1) { return m_func(arg1); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2>
|
||||
class ptr_fn2_t : public function_base2<Result, Arg1, Arg2> {
|
||||
public:
|
||||
typedef Result (*Func)(Arg1, Arg2);
|
||||
|
||||
ptr_fn2_t(Func func) : m_func(func) {}
|
||||
virtual ~ptr_fn2_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2) { return m_func(arg1, arg2); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result>
|
||||
class mem_fn0_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef Result (Object::*Func)();
|
||||
|
||||
mem_fn0_t(Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~mem_fn0_t() {}
|
||||
|
||||
virtual Result operator () () { return (m_object->*m_func)(); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1>
|
||||
class mem_fn1_t : public function_base1<Result, Arg1> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1);
|
||||
|
||||
mem_fn1_t(Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~mem_fn1_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1, typename Arg2, typename Arg3>
|
||||
class mem_fn3_t : public function_base3<Result, Arg1, Arg2, Arg3> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1, Arg2, Arg3);
|
||||
|
||||
mem_fn3_t(Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~mem_fn3_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (m_object->*m_func)(arg1, arg2, arg3); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1, typename Arg2>
|
||||
class mem_fn2_t : public function_base2<Result, Arg1, Arg2> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1, Arg2);
|
||||
|
||||
mem_fn2_t(Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~mem_fn2_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2) { return (m_object->*m_func)(arg1, arg2); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result>
|
||||
class const_mem_fn0_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef Result (Object::*Func)() const;
|
||||
|
||||
const_mem_fn0_t(const Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~const_mem_fn0_t() {}
|
||||
|
||||
virtual Result operator () () { return (m_object->*m_func)(); }
|
||||
|
||||
private:
|
||||
const Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1>
|
||||
class const_mem_fn1_t : public function_base1<Result, Arg1> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1) const;
|
||||
|
||||
const_mem_fn1_t(const Object* object, Func func) : m_object(object), m_func(func) {}
|
||||
virtual ~const_mem_fn1_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); }
|
||||
|
||||
private:
|
||||
const Object* m_object;
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
// Unary functor with a bound argument.
|
||||
template <typename Object, typename Result, typename Arg1>
|
||||
class mem_fn0_b1_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1);
|
||||
|
||||
mem_fn0_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {}
|
||||
virtual ~mem_fn0_b1_t() {}
|
||||
|
||||
virtual Result operator () () { return (m_object->*m_func)(m_arg1); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
const Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1, typename Arg2>
|
||||
class mem_fn1_b1_t : public function_base1<Result, Arg2> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1, Arg2);
|
||||
|
||||
mem_fn1_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {}
|
||||
virtual ~mem_fn1_b1_t() {}
|
||||
|
||||
virtual Result operator () (const Arg2 arg2) { return (m_object->*m_func)(m_arg1, arg2); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
const Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template <typename Object, typename Result, typename Arg1, typename Arg2>
|
||||
class mem_fn1_b2_t : public function_base1<Result, Arg1> {
|
||||
public:
|
||||
typedef Result (Object::*Func)(Arg1, Arg2);
|
||||
|
||||
mem_fn1_b2_t(Object* object, Func func, const Arg2 arg2) : m_object(object), m_func(func), m_arg2(arg2) {}
|
||||
virtual ~mem_fn1_b2_t() {}
|
||||
|
||||
virtual Result operator () (const Arg1 arg1) { return (m_object->*m_func)(arg1, m_arg2); }
|
||||
|
||||
private:
|
||||
Object* m_object;
|
||||
Func m_func;
|
||||
const Arg2 m_arg2;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1>
|
||||
class ptr_fn0_b1_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef Result (*Func)(Arg1);
|
||||
|
||||
ptr_fn0_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
|
||||
virtual ~ptr_fn0_b1_t() {}
|
||||
|
||||
virtual Result operator () () { return m_func(m_arg1); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2>
|
||||
class ptr_fn1_b1_t : public function_base1<Result, Arg2> {
|
||||
public:
|
||||
typedef Result (*Func)(Arg1, Arg2);
|
||||
|
||||
ptr_fn1_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
|
||||
virtual ~ptr_fn1_b1_t() {}
|
||||
|
||||
virtual Result operator () (Arg2 arg2) { return m_func(m_arg1, arg2); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename Arg3>
|
||||
class ptr_fn2_b1_t : public function_base2<Result, Arg2, Arg3> {
|
||||
public:
|
||||
typedef Result (*Func)(Arg1, Arg2, Arg3);
|
||||
|
||||
ptr_fn2_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {}
|
||||
virtual ~ptr_fn2_b1_t() {}
|
||||
|
||||
virtual Result operator () (Arg2 arg2, Arg3 arg3) { return m_func(m_arg1, arg2, arg3); }
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
Arg1 m_arg1;
|
||||
};
|
||||
|
||||
template <typename Ftor>
|
||||
class ftor_fn1_t : public function_base1<typename Ftor::result_type, typename Ftor::argument_type> {
|
||||
public:
|
||||
typedef typename Ftor::result_type result_type;
|
||||
typedef typename Ftor::argument_type argument_type;
|
||||
|
||||
ftor_fn1_t(Ftor ftor) : m_ftor(ftor) {}
|
||||
virtual ~ftor_fn1_t() {}
|
||||
|
||||
virtual result_type operator () (argument_type arg1) { return m_ftor(arg1); }
|
||||
|
||||
private:
|
||||
Ftor m_ftor;
|
||||
};
|
||||
|
||||
template <typename Ftor>
|
||||
class ftor_fn2_t : public function_base2<typename Ftor::result_type, typename Ftor::first_argument_type, typename Ftor::second_argument_type> {
|
||||
public:
|
||||
typedef typename Ftor::result_type result_type;
|
||||
typedef typename Ftor::first_argument_type first_argument_type;
|
||||
typedef typename Ftor::second_argument_type second_argument_type;
|
||||
|
||||
ftor_fn2_t(Ftor ftor) : m_ftor(ftor) {}
|
||||
virtual ~ftor_fn2_t() {}
|
||||
|
||||
virtual result_type operator () (first_argument_type arg1, second_argument_type arg2) { return m_ftor(arg1, arg2); }
|
||||
|
||||
private:
|
||||
Ftor m_ftor;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
class value_fn0_t : public function_base0<Result> {
|
||||
public:
|
||||
value_fn0_t(const Result& val) : m_value(val) {}
|
||||
|
||||
virtual Result operator () () { return m_value; }
|
||||
|
||||
private:
|
||||
Result m_value;
|
||||
};
|
||||
|
||||
template <typename Result, typename SrcResult>
|
||||
class convert_fn0_t : public function_base0<Result> {
|
||||
public:
|
||||
typedef function0<SrcResult> src_type;
|
||||
|
||||
convert_fn0_t(typename src_type::base_type* object) { m_object.set(object); }
|
||||
virtual ~convert_fn0_t() {}
|
||||
|
||||
virtual Result operator () () {
|
||||
return m_object();
|
||||
}
|
||||
|
||||
private:
|
||||
src_type m_object;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename SrcResult, typename SrcArg1>
|
||||
class convert_fn1_t : public function_base1<Result, Arg1> {
|
||||
public:
|
||||
typedef function1<SrcResult, SrcArg1> src_type;
|
||||
|
||||
convert_fn1_t(typename src_type::base_type* object) { m_object.set(object); }
|
||||
virtual ~convert_fn1_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1) {
|
||||
return m_object(arg1);
|
||||
}
|
||||
|
||||
private:
|
||||
src_type m_object;
|
||||
};
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename SrcResult, typename SrcArg1, typename SrcArg2>
|
||||
class convert_fn2_t : public function_base2<Result, Arg1, Arg2> {
|
||||
public:
|
||||
typedef function2<SrcResult, SrcArg1, SrcArg2> src_type;
|
||||
|
||||
convert_fn2_t(typename src_type::base_type* object) { m_object.set(object); }
|
||||
virtual ~convert_fn2_t() {}
|
||||
|
||||
virtual Result operator () (Arg1 arg1, Arg2 arg2) {
|
||||
return m_object(arg1, arg2);
|
||||
}
|
||||
|
||||
private:
|
||||
src_type m_object;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
inline function_base0<Result>*
|
||||
ptr_fn(Result (*func)()) {
|
||||
return new ptr_fn0_t<Result>(func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Result>
|
||||
inline function_base1<Result, Arg1>*
|
||||
ptr_fn(Result (*func)(Arg1)) {
|
||||
return new ptr_fn1_t<Result, Arg1>(func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Result>
|
||||
inline function_base2<Result, Arg1, Arg2>*
|
||||
ptr_fn(Result (*func)(Arg1, Arg2)) {
|
||||
return new ptr_fn2_t<Result, Arg1, Arg2>(func);
|
||||
}
|
||||
|
||||
template <typename Result, typename Object>
|
||||
inline function_base0<Result>*
|
||||
mem_fn(Object* object, Result (Object::*func)()) {
|
||||
return new mem_fn0_t<Object, Result>(object, func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Result, typename Object>
|
||||
inline function_base1<Result, Arg1>*
|
||||
mem_fn(Object* object, Result (Object::*func)(Arg1)) {
|
||||
return new mem_fn1_t<Object, Result, Arg1>(object, func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Result, typename Object>
|
||||
inline function_base2<Result, Arg1, Arg2>*
|
||||
mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2)) {
|
||||
return new mem_fn2_t<Object, Result, Arg1, Arg2>(object, func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Result, typename Object>
|
||||
inline function_base3<Result, Arg1, Arg2, Arg3>*
|
||||
mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2, Arg3)) {
|
||||
return new mem_fn3_t<Object, Result, Arg1, Arg2, Arg3>(object, func);
|
||||
}
|
||||
|
||||
template <typename Result, typename Object>
|
||||
inline function_base0<Result>*
|
||||
mem_fn(const Object* object, Result (Object::*func)() const) {
|
||||
return new const_mem_fn0_t<Object, Result>(object, func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Result, typename Object>
|
||||
inline function_base1<Result, Arg1>*
|
||||
mem_fn(const Object* object, Result (Object::*func)(Arg1) const) {
|
||||
return new const_mem_fn1_t<Object, Result, Arg1>(object, func);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Result, typename Object>
|
||||
inline function_base0<Result>*
|
||||
bind_mem_fn(Object* object, Result (Object::*func)(Arg1), const Arg1 arg1) {
|
||||
return new mem_fn0_b1_t<Object, Result, Arg1>(object, func, arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Result, typename Object>
|
||||
inline function_base1<Result, Arg2>*
|
||||
bind_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg1 arg1) {
|
||||
return new mem_fn1_b1_t<Object, Result, Arg1, Arg2>(object, func, arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Result, typename Object>
|
||||
inline function_base1<Result, Arg1>*
|
||||
bind2_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg2 arg2) {
|
||||
return new mem_fn1_b2_t<Object, Result, Arg1, Arg2>(object, func, arg2);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Result>
|
||||
inline function_base0<Result>*
|
||||
bind_ptr_fn(Result (*func)(Arg1), const Arg1 arg1) {
|
||||
return new ptr_fn0_b1_t<Result, Arg1>(func, arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Result>
|
||||
inline function_base1<Result, Arg2>*
|
||||
bind_ptr_fn(Result (*func)(Arg1, Arg2), const Arg1 arg1) {
|
||||
return new ptr_fn1_b1_t<Result, Arg1, Arg2>(func, arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Result>
|
||||
inline function_base2<Result, Arg2, Arg3>*
|
||||
bind_ptr_fn(Result (*func)(Arg1, Arg2, Arg3), const Arg1 arg1) {
|
||||
return new ptr_fn2_b1_t<Result, Arg1, Arg2, Arg3>(func, arg1);
|
||||
}
|
||||
|
||||
template <typename Ftor>
|
||||
inline function_base1<typename Ftor::result_type, typename Ftor::argument_type>*
|
||||
ftor_fn1(Ftor ftor) {
|
||||
return new ftor_fn1_t<Ftor>(ftor);
|
||||
}
|
||||
|
||||
template <typename Ftor>
|
||||
inline function_base2<typename Ftor::result_type, typename Ftor::first_argument_type, typename Ftor::second_argument_type>*
|
||||
ftor_fn2(Ftor ftor) {
|
||||
return new ftor_fn2_t<Ftor>(ftor);
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
inline function_base0<Result>*
|
||||
value_fn(const Result& val) {
|
||||
return new value_fn0_t<Result>(val);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
struct equal_types_t {
|
||||
typedef A first_type;
|
||||
typedef B second_type;
|
||||
|
||||
const static int result = 0;
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
struct equal_types_t<A, A> {
|
||||
typedef A first_type;
|
||||
typedef A second_type;
|
||||
|
||||
const static int result = 1;
|
||||
};
|
||||
|
||||
template <typename Result, typename SrcResult>
|
||||
inline function_base0<Result>*
|
||||
convert_fn(function_base0<SrcResult>* src) {
|
||||
if (equal_types_t<function_base0<Result>, function_base0<SrcResult> >::result)
|
||||
// The pointer cast never gets done if the types are different,
|
||||
// but needs to be here to pleasant the compiler.
|
||||
return reinterpret_cast<typename equal_types_t<function_base0<Result>, function_base0<SrcResult> >::first_type*>(src);
|
||||
else
|
||||
return new convert_fn0_t<Result, SrcResult>(src);
|
||||
}
|
||||
|
||||
template <typename Result, typename Arg1, typename SrcResult, typename SrcArg1>
|
||||
inline function_base1<Result, Arg1>*
|
||||
convert_fn(function_base1<SrcResult, SrcArg1>* src) {
|
||||
if (equal_types_t<function_base1<Result, Arg1>, function_base1<SrcResult, SrcArg1> >::result)
|
||||
// The pointer cast never gets done if the types are different,
|
||||
// but needs to be here to pleasant the compiler.
|
||||
return reinterpret_cast<typename equal_types_t<function_base1<Result, Arg1>, function_base1<SrcResult, SrcArg1> >::first_type*>(src);
|
||||
else
|
||||
return new convert_fn1_t<Result, Arg1, SrcResult, SrcArg1>(src);
|
||||
}
|
||||
|
||||
template <typename Result, typename Arg1, typename Arg2, typename SrcResult, typename SrcArg1, typename SrcArg2>
|
||||
inline function_base2<Result, Arg1, Arg2>*
|
||||
convert_fn(function_base2<SrcResult, SrcArg1, SrcArg2>* src) {
|
||||
if (equal_types_t<function_base2<Result, Arg1, Arg2>, function_base2<SrcResult, SrcArg1, SrcArg2> >::result)
|
||||
// The pointer cast never gets done if the types are different,
|
||||
// but needs to be here to pleasant the compiler.
|
||||
return reinterpret_cast<typename equal_types_t<function_base2<Result, Arg1, Arg2>, function_base2<SrcResult, SrcArg1, SrcArg2> >::first_type*>(src);
|
||||
else
|
||||
return new convert_fn2_t<Result, Arg1, Arg2, SrcResult, SrcArg1, SrcArg2>(src);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,198 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_PARTIAL_QUEUE_H
|
||||
#define RAK_PARTIAL_QUEUE_H
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
// First step, don't allow overflowing to the next layer. Only disable
|
||||
// the above layers for now.
|
||||
|
||||
// We also include 0 in a single layer as some chunk may be available
|
||||
// only through seeders.
|
||||
|
||||
class partial_queue {
|
||||
public:
|
||||
typedef uint8_t key_type;
|
||||
typedef uint32_t mapped_type;
|
||||
typedef uint16_t size_type;
|
||||
typedef std::pair<size_type, size_type> size_pair_type;
|
||||
|
||||
static const size_type num_layers = 8;
|
||||
|
||||
partial_queue() : m_data(NULL), m_maxLayerSize(0) {}
|
||||
~partial_queue() { disable(); }
|
||||
|
||||
bool is_full() const { return m_ceiling == 0; }
|
||||
bool is_layer_full(size_type l) const { return m_layers[l].second >= m_maxLayerSize; }
|
||||
|
||||
bool is_enabled() const { return m_data != NULL; }
|
||||
|
||||
// Add check to see if we can add more. Also make it possible to
|
||||
// check how full we are in the lower parts so the caller knows when
|
||||
// he can stop searching.
|
||||
//
|
||||
// Though propably not needed, as we must continue til the first
|
||||
// layer is full.
|
||||
|
||||
size_type max_size() const { return m_maxLayerSize * num_layers; }
|
||||
size_type max_layer_size() const { return m_maxLayerSize; }
|
||||
|
||||
// Must be less that or equal to (max size_type) / num_layers.
|
||||
void enable(size_type ls);
|
||||
void disable();
|
||||
|
||||
void clear();
|
||||
|
||||
// Safe to call while pop'ing and it will not reuse pop'ed indices
|
||||
// so it is guaranteed to reach max_size at some point. This will
|
||||
// ensure that the user needs to refill with new data at regular
|
||||
// intervals.
|
||||
bool insert(key_type key, mapped_type value);
|
||||
|
||||
// Only call this when pop'ing as it moves the index.
|
||||
bool prepare_pop();
|
||||
|
||||
mapped_type pop();
|
||||
|
||||
private:
|
||||
partial_queue(const partial_queue&);
|
||||
void operator = (const partial_queue&);
|
||||
|
||||
static size_type ceiling(size_type layer) { return (2 << layer) - 1; }
|
||||
|
||||
void find_non_empty();
|
||||
|
||||
mapped_type* m_data;
|
||||
size_type m_maxLayerSize;
|
||||
|
||||
size_type m_index;
|
||||
size_type m_ceiling;
|
||||
|
||||
size_pair_type m_layers[num_layers];
|
||||
};
|
||||
|
||||
inline void
|
||||
partial_queue::enable(size_type ls) {
|
||||
if (ls == 0)
|
||||
throw std::logic_error("partial_queue::enable(...) ls == 0.");
|
||||
|
||||
delete [] m_data;
|
||||
m_data = new mapped_type[ls * num_layers];
|
||||
|
||||
m_maxLayerSize = ls;
|
||||
}
|
||||
|
||||
inline void
|
||||
partial_queue::disable() {
|
||||
delete [] m_data;
|
||||
m_data = NULL;
|
||||
|
||||
m_maxLayerSize = 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
partial_queue::clear() {
|
||||
if (m_data == NULL)
|
||||
return;
|
||||
|
||||
m_index = 0;
|
||||
m_ceiling = ceiling(num_layers - 1);
|
||||
|
||||
std::memset(m_layers, 0, num_layers * sizeof(size_pair_type));
|
||||
}
|
||||
|
||||
inline bool
|
||||
partial_queue::insert(key_type key, mapped_type value) {
|
||||
if (key >= m_ceiling)
|
||||
return false;
|
||||
|
||||
size_type idx = 0;
|
||||
|
||||
// Hmm... since we already check the 'm_ceiling' above, we only need
|
||||
// to find the target layer. Could this be calculated directly?
|
||||
while (key >= ceiling(idx))
|
||||
++idx;
|
||||
|
||||
m_index = std::min(m_index, idx);
|
||||
|
||||
// Currently don't allow overflow.
|
||||
if (is_layer_full(idx))
|
||||
throw std::logic_error("partial_queue::insert(...) layer already full.");
|
||||
//return false;
|
||||
|
||||
m_data[m_maxLayerSize * idx + m_layers[idx].second] = value;
|
||||
m_layers[idx].second++;
|
||||
|
||||
if (is_layer_full(idx))
|
||||
// Set the ceiling to 0 when layer 0 is full so no more values can
|
||||
// be inserted.
|
||||
m_ceiling = idx > 0 ? ceiling(idx - 1) : 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// is_empty() will iterate to the first layer with un-popped elements
|
||||
// and return true, else return false when it reaches a overflowed or
|
||||
// the last layer.
|
||||
inline bool
|
||||
partial_queue::prepare_pop() {
|
||||
while (m_layers[m_index].first == m_layers[m_index].second) {
|
||||
if (is_layer_full(m_index) || m_index + 1 == num_layers)
|
||||
return false;
|
||||
|
||||
m_index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline partial_queue::mapped_type
|
||||
partial_queue::pop() {
|
||||
if (m_index >= num_layers || m_layers[m_index].first >= m_layers[m_index].second)
|
||||
throw std::logic_error("partial_queue::pop() bad state.");
|
||||
|
||||
return m_data[m_index * m_maxLayerSize + m_layers[m_index].first++];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// Various functions for manipulating file paths. Also consider making
|
||||
// a directory iterator.
|
||||
|
||||
#ifndef RAK_PATH_H
|
||||
#define RAK_PATH_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
namespace rak {
|
||||
|
||||
inline std::string
|
||||
path_expand(const std::string& path) {
|
||||
if (path.empty() || path[0] != '~')
|
||||
return path;
|
||||
|
||||
char* home = std::getenv("HOME");
|
||||
|
||||
if (home == NULL)
|
||||
return path;
|
||||
|
||||
return home + path.substr(1);
|
||||
}
|
||||
|
||||
// Don't inline this...
|
||||
//
|
||||
// Same strlcpy as found in *bsd.
|
||||
inline size_t
|
||||
strlcpy(char *dest, const char *src, size_t size) {
|
||||
size_t n = size;
|
||||
const char* first = src;
|
||||
|
||||
if (n != 0) {
|
||||
while (--n != 0)
|
||||
if ((*dest++ = *src++) == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
if (size != 0)
|
||||
*dest = '\0';
|
||||
|
||||
while (*src++)
|
||||
;
|
||||
}
|
||||
|
||||
return src - first - 1;
|
||||
}
|
||||
|
||||
inline char*
|
||||
path_expand(const char* src, char* first, char* last) {
|
||||
if (*src == '~') {
|
||||
char* home = std::getenv("HOME");
|
||||
|
||||
if (home == NULL)
|
||||
return first;
|
||||
|
||||
first += strlcpy(first, home, std::distance(first, last));
|
||||
|
||||
if (first > last)
|
||||
return last;
|
||||
|
||||
src++;
|
||||
}
|
||||
|
||||
return std::min(first + strlcpy(first, src, std::distance(first, last)), last);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// priority_queue is a priority queue implemented using a binary
|
||||
// heap. It can contain multiple instances of a value.
|
||||
|
||||
#ifndef RAK_PRIORITY_QUEUE_H
|
||||
#define RAK_PRIORITY_QUEUE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <typename Value, typename Compare, typename Equal, typename Alloc = std::allocator<Value> >
|
||||
class priority_queue : public std::vector<Value, Alloc> {
|
||||
public:
|
||||
typedef std::vector<Value, Alloc> base_type;
|
||||
typedef typename base_type::reference reference;
|
||||
typedef typename base_type::const_reference const_reference;
|
||||
typedef typename base_type::iterator iterator;
|
||||
typedef typename base_type::const_iterator const_iterator;
|
||||
typedef typename base_type::value_type value_type;
|
||||
|
||||
using base_type::begin;
|
||||
using base_type::end;
|
||||
using base_type::size;
|
||||
using base_type::empty;
|
||||
using base_type::clear;
|
||||
|
||||
priority_queue(Compare l = Compare(), Equal e = Equal())
|
||||
: m_compare(l), m_equal(e) {}
|
||||
|
||||
const_reference top() const {
|
||||
return base_type::front();
|
||||
}
|
||||
|
||||
void pop() {
|
||||
std::pop_heap(begin(), end(), m_compare);
|
||||
base_type::pop_back();
|
||||
}
|
||||
|
||||
void push(const value_type& value) {
|
||||
base_type::push_back(value);
|
||||
std::push_heap(begin(), end(), m_compare);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
iterator find(const Key& key) {
|
||||
return std::find_if(begin(), end(), std::bind2nd(m_equal, key));
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
bool erase(const Key& key) {
|
||||
iterator itr = find(key);
|
||||
|
||||
if (itr == end())
|
||||
return false;
|
||||
|
||||
erase(itr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes 'itr' from the queue. This assumes 'itr' has been
|
||||
// modified such that it has a higher priority than any other
|
||||
// element in the queue.
|
||||
void erase(iterator itr) {
|
||||
// std::push_heap(begin(), ++itr, m_compare);
|
||||
// pop();
|
||||
base_type::erase(itr);
|
||||
std::make_heap(begin(), end(), m_compare);
|
||||
}
|
||||
|
||||
private:
|
||||
Compare m_compare;
|
||||
Equal m_equal;
|
||||
};
|
||||
|
||||
// Iterate while the top node has higher priority, as 'Compare'
|
||||
// returns false.
|
||||
template <typename Queue, typename Compare>
|
||||
class queue_pop_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, void, void, void, void> {
|
||||
public:
|
||||
typedef Queue container_type;
|
||||
|
||||
queue_pop_iterator() : m_queue(NULL) {}
|
||||
queue_pop_iterator(Queue* q, Compare c) : m_queue(q), m_compare(c) {}
|
||||
|
||||
queue_pop_iterator& operator ++ () { m_queue->pop(); return *this; }
|
||||
queue_pop_iterator& operator ++ (int) { m_queue->pop(); return *this; }
|
||||
|
||||
typename container_type::const_reference operator * () { return m_queue->top(); }
|
||||
|
||||
bool operator != (const queue_pop_iterator& itr) { return !m_queue->empty() && !m_compare(m_queue->top()); }
|
||||
bool operator == (const queue_pop_iterator& itr) { return m_queue->empty() || m_compare(m_queue->top()); }
|
||||
|
||||
private:
|
||||
Queue* m_queue;
|
||||
Compare m_compare;
|
||||
};
|
||||
|
||||
template <typename Queue, typename Compare>
|
||||
inline queue_pop_iterator<Queue, Compare>
|
||||
queue_popper(Queue& queue, Compare comp) {
|
||||
return queue_pop_iterator<Queue, Compare>(&queue, comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,142 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
#define RAK_PRIORITY_QUEUE_DEFAULT_H
|
||||
|
||||
#include lt_tr1_functional
|
||||
#include <rak/allocators.h>
|
||||
#include <rak/priority_queue.h>
|
||||
#include <rak/timer.h>
|
||||
|
||||
#include "torrent/exceptions.h"
|
||||
|
||||
namespace rak {
|
||||
|
||||
class priority_item {
|
||||
public:
|
||||
typedef std::function<void (void)> slot_void;
|
||||
|
||||
priority_item() {}
|
||||
~priority_item() {
|
||||
if (is_queued())
|
||||
throw torrent::internal_error("priority_item::~priority_item() called on a queued item.");
|
||||
|
||||
m_time = timer();
|
||||
m_slot = slot_void();
|
||||
}
|
||||
|
||||
bool is_valid() const { return (bool)m_slot; }
|
||||
bool is_queued() const { return m_time != timer(); }
|
||||
|
||||
slot_void& slot() { return m_slot; }
|
||||
|
||||
const timer& time() const { return m_time; }
|
||||
void clear_time() { m_time = timer(); }
|
||||
void set_time(const timer& t) { m_time = t; }
|
||||
|
||||
bool compare(const timer& t) const { return m_time > t; }
|
||||
|
||||
private:
|
||||
priority_item(const priority_item&);
|
||||
void operator = (const priority_item&);
|
||||
|
||||
timer m_time;
|
||||
slot_void m_slot;
|
||||
};
|
||||
|
||||
struct priority_compare {
|
||||
bool operator () (const priority_item* const p1, const priority_item* const p2) const {
|
||||
return p1->time() > p2->time();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::equal_to<priority_item*> priority_equal;
|
||||
typedef priority_queue<priority_item*, priority_compare, priority_equal,
|
||||
cacheline_allocator<priority_item*> > priority_queue_default;
|
||||
|
||||
inline void
|
||||
priority_queue_perform(priority_queue_default* queue, timer t) {
|
||||
while (!queue->empty() && queue->top()->time() <= t) {
|
||||
priority_item* v = queue->top();
|
||||
queue->pop();
|
||||
|
||||
v->clear_time();
|
||||
v->slot()();
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) {
|
||||
if (t == timer())
|
||||
throw torrent::internal_error("priority_queue_insert(...) received a bad timer.");
|
||||
|
||||
if (!item->is_valid())
|
||||
throw torrent::internal_error("priority_queue_insert(...) called on an invalid item.");
|
||||
|
||||
if (item->is_queued())
|
||||
throw torrent::internal_error("priority_queue_insert(...) called on an already queued item.");
|
||||
|
||||
if (queue->find(item) != queue->end())
|
||||
throw torrent::internal_error("priority_queue_insert(...) item found in queue.");
|
||||
|
||||
item->set_time(t);
|
||||
queue->push(item);
|
||||
}
|
||||
|
||||
inline void
|
||||
priority_queue_erase(priority_queue_default* queue, priority_item* item) {
|
||||
if (!item->is_queued())
|
||||
return;
|
||||
|
||||
// Check is_valid() after is_queued() so that it is safe to call
|
||||
// erase on untouched instances.
|
||||
if (!item->is_valid())
|
||||
throw torrent::internal_error("priority_queue_erase(...) called on an invalid item.");
|
||||
|
||||
// Clear time before erasing to force it to the top.
|
||||
item->clear_time();
|
||||
|
||||
if (!queue->erase(item))
|
||||
throw torrent::internal_error("priority_queue_erase(...) could not find item in queue.");
|
||||
|
||||
if (queue->find(item) != queue->end())
|
||||
throw torrent::internal_error("priority_queue_erase(...) item still in queue.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// This is a hacked up whole string pattern matching. Replace with
|
||||
// TR1's regex when that becomes widely available. It is intended for
|
||||
// small strings.
|
||||
|
||||
#ifndef RAK_REGEX_H
|
||||
#define RAK_REGEX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class regex : public std::unary_function<std::string, bool> {
|
||||
public:
|
||||
regex() {}
|
||||
regex(const std::string& p) : m_pattern(p) {}
|
||||
|
||||
const std::string& pattern() const { return m_pattern; }
|
||||
|
||||
bool operator () (const std::string& p) const;
|
||||
|
||||
private:
|
||||
std::string m_pattern;
|
||||
};
|
||||
|
||||
// This isn't optimized, or very clean. A simple hack that should work.
|
||||
inline bool
|
||||
regex::operator () (const std::string& text) const {
|
||||
if (m_pattern.empty() ||
|
||||
text.empty() ||
|
||||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
|
||||
return false;
|
||||
|
||||
// Replace with unordered_vector?
|
||||
std::list<unsigned int> paths;
|
||||
paths.push_front(0);
|
||||
|
||||
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
|
||||
|
||||
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
|
||||
|
||||
unsigned int next = *itrPaths + 1;
|
||||
|
||||
if (m_pattern[*itrPaths] != '*')
|
||||
itrPaths = paths.erase(itrPaths);
|
||||
else
|
||||
itrPaths++;
|
||||
|
||||
// When we reach the end of 'm_pattern', we don't have a whole
|
||||
// match of 'text'.
|
||||
if (next == m_pattern.size())
|
||||
continue;
|
||||
|
||||
// Push to the back so that '*' will match zero length strings.
|
||||
if (m_pattern[next] == '*')
|
||||
paths.push_back(next);
|
||||
|
||||
if (m_pattern[next] == *itrText)
|
||||
paths.push_front(next);
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,490 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
// Wrappers for the various sockaddr types with focus on zero-copy
|
||||
// casting between the original type and the wrapper class.
|
||||
//
|
||||
// The default ctor does not initialize any data.
|
||||
//
|
||||
// _n suffixes indicate that the argument or return value is in
|
||||
// network byte order, _h that they are in hardware byte order.
|
||||
|
||||
// Add define for inet6 scope id?
|
||||
|
||||
#ifndef RAK_SOCKET_ADDRESS_H
|
||||
#define RAK_SOCKET_ADDRESS_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class socket_address_inet;
|
||||
class socket_address_inet6;
|
||||
|
||||
class socket_address {
|
||||
public:
|
||||
static const sa_family_t af_inet = AF_INET;
|
||||
static const int pf_inet = PF_INET;
|
||||
static const sa_family_t af_inet6 = AF_INET6;
|
||||
static const int pf_inet6 = PF_INET6;
|
||||
static const sa_family_t af_unspec = AF_UNSPEC;
|
||||
static const int pf_unspec = PF_UNSPEC;
|
||||
|
||||
#ifdef AF_LOCAL
|
||||
static const sa_family_t af_local = AF_LOCAL;
|
||||
static const int pf_local = PF_LOCAL;
|
||||
#else
|
||||
static const sa_family_t af_local = AF_UNIX;
|
||||
static const int pf_local = PF_UNIX;
|
||||
#endif
|
||||
|
||||
bool is_valid() const;
|
||||
bool is_bindable() const;
|
||||
bool is_address_any() const;
|
||||
|
||||
// Should we need to set AF_UNSPEC?
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); }
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sa_family; }
|
||||
void set_family() { m_sockaddr.sa_family = af_unspec; }
|
||||
|
||||
uint16_t port() const;
|
||||
void set_port(uint16_t p);
|
||||
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
// Attemts to set it as an inet, then an inet6 address. It will
|
||||
// never set anything but net addresses, no local/unix.
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
uint32_t length() const;
|
||||
|
||||
socket_address_inet* sa_inet() { return reinterpret_cast<socket_address_inet*>(this); }
|
||||
const socket_address_inet* sa_inet() const { return reinterpret_cast<const socket_address_inet*>(this); }
|
||||
|
||||
sockaddr* c_sockaddr() { return &m_sockaddr; }
|
||||
sockaddr_in* c_sockaddr_inet() { return &m_sockaddrInet; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
|
||||
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
|
||||
|
||||
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
|
||||
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
|
||||
|
||||
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
|
||||
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
|
||||
|
||||
// Copy a socket address which has the length 'length. Zero out any
|
||||
// extranous bytes and ensure it does not go beyond the size of this
|
||||
// struct.
|
||||
void copy(const socket_address& src, size_t length);
|
||||
|
||||
static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast<socket_address*>(sa); }
|
||||
static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast<const socket_address*>(sa); }
|
||||
|
||||
// The different families will be sorted according to the
|
||||
// sa_family_t's numeric value.
|
||||
bool operator == (const socket_address& rhs) const;
|
||||
bool operator < (const socket_address& rhs) const;
|
||||
|
||||
bool operator == (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
|
||||
bool operator == (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
|
||||
bool operator < (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
|
||||
bool operator < (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
|
||||
|
||||
private:
|
||||
union {
|
||||
sockaddr m_sockaddr;
|
||||
sockaddr_in m_sockaddrInet;
|
||||
sockaddr_in6 m_sockaddrInet6;
|
||||
};
|
||||
};
|
||||
|
||||
// Remember to set the AF_INET.
|
||||
|
||||
class socket_address_inet {
|
||||
public:
|
||||
bool is_any() const { return is_port_any() && is_address_any(); }
|
||||
bool is_valid() const { return !is_port_any() && !is_address_any(); }
|
||||
bool is_port_any() const { return port() == 0; }
|
||||
bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }
|
||||
|
||||
uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
|
||||
uint16_t port_n() const { return m_sockaddr.sin_port; }
|
||||
void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); }
|
||||
void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; }
|
||||
|
||||
// Should address() return the uint32_t?
|
||||
in_addr address() const { return m_sockaddr.sin_addr; }
|
||||
uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); }
|
||||
uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
|
||||
void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
|
||||
void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; }
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
void set_address_any() { set_port(0); set_address_h(INADDR_ANY); }
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sin_family; }
|
||||
void set_family() { m_sockaddr.sin_family = AF_INET; }
|
||||
|
||||
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
|
||||
sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
|
||||
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
|
||||
|
||||
socket_address_inet6 to_mapped_address() const;
|
||||
|
||||
bool operator == (const socket_address_inet& rhs) const;
|
||||
bool operator < (const socket_address_inet& rhs) const;
|
||||
|
||||
private:
|
||||
struct sockaddr_in m_sockaddr;
|
||||
};
|
||||
|
||||
class socket_address_inet6 {
|
||||
public:
|
||||
bool is_any() const { return is_port_any() && is_address_any(); }
|
||||
bool is_valid() const { return !is_port_any() && !is_address_any(); }
|
||||
bool is_port_any() const { return port() == 0; }
|
||||
bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
|
||||
|
||||
uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
|
||||
uint16_t port_n() const { return m_sockaddr.sin6_port; }
|
||||
void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
|
||||
void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
|
||||
|
||||
in6_addr address() const { return m_sockaddr.sin6_addr; }
|
||||
const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; }
|
||||
std::string address_str() const;
|
||||
bool address_c_str(char* buf, socklen_t size) const;
|
||||
|
||||
void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
|
||||
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
|
||||
bool set_address_c_str(const char* a);
|
||||
|
||||
void set_address_any() { set_port(0); set_address(in6addr_any); }
|
||||
|
||||
sa_family_t family() const { return m_sockaddr.sin6_family; }
|
||||
void set_family() { m_sockaddr.sin6_family = AF_INET6; }
|
||||
|
||||
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
|
||||
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
|
||||
|
||||
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
|
||||
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
|
||||
|
||||
socket_address normalize_address() const;
|
||||
|
||||
bool operator == (const socket_address_inet6& rhs) const;
|
||||
bool operator < (const socket_address_inet6& rhs) const;
|
||||
|
||||
private:
|
||||
struct sockaddr_in6 m_sockaddr;
|
||||
};
|
||||
|
||||
inline bool
|
||||
socket_address::is_valid() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->is_valid();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_valid();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::is_bindable() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return !sa_inet()->is_address_any();
|
||||
case af_inet6:
|
||||
return !sa_inet6()->is_address_any();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::is_address_any() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->is_address_any();
|
||||
case af_inet6:
|
||||
return sa_inet6()->is_address_any();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint16_t
|
||||
socket_address::port() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->port();
|
||||
case af_inet6:
|
||||
return sa_inet6()->port();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
socket_address::set_port(uint16_t p) {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->set_port(p);
|
||||
case af_inet6:
|
||||
return sa_inet6()->set_port(p);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address::address_str() const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->address_str();
|
||||
case af_inet6:
|
||||
return sa_inet6()->address_str();
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::address_c_str(char* buf, socklen_t size) const {
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return sa_inet()->address_c_str(buf, size);
|
||||
case af_inet6:
|
||||
return sa_inet6()->address_c_str(buf, size);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::set_address_c_str(const char* a) {
|
||||
if (sa_inet()->set_address_c_str(a)) {
|
||||
sa_inet()->set_family();
|
||||
return true;
|
||||
|
||||
} else if (sa_inet6()->set_address_c_str(a)) {
|
||||
sa_inet6()->set_family();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the zero length really needed, should we require some length?
|
||||
inline uint32_t
|
||||
socket_address::length() const {
|
||||
switch(family()) {
|
||||
case af_inet:
|
||||
return sizeof(sockaddr_in);
|
||||
case af_inet6:
|
||||
return sizeof(sockaddr_in6);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
socket_address::copy(const socket_address& src, size_t length) {
|
||||
length = std::min(length, sizeof(socket_address));
|
||||
|
||||
// Does this get properly optimized?
|
||||
std::memset(this, 0, sizeof(socket_address));
|
||||
std::memcpy(this, &src, length);
|
||||
}
|
||||
|
||||
// Should we be able to compare af_unspec?
|
||||
|
||||
inline bool
|
||||
socket_address::operator == (const socket_address& rhs) const {
|
||||
if (family() != rhs.family())
|
||||
return false;
|
||||
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() == *rhs.sa_inet();
|
||||
case af_inet6:
|
||||
return *sa_inet6() == *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address::operator < (const socket_address& rhs) const {
|
||||
if (family() != rhs.family())
|
||||
return family() < rhs.family();
|
||||
|
||||
switch (family()) {
|
||||
case af_inet:
|
||||
return *sa_inet() < *rhs.sa_inet();
|
||||
case af_inet6:
|
||||
return *sa_inet6() < *rhs.sa_inet6();
|
||||
default:
|
||||
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address_inet::address_str() const {
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
if (!address_c_str(buf, INET_ADDRSTRLEN))
|
||||
return std::string();
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::address_c_str(char* buf, socklen_t size) const {
|
||||
return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::set_address_c_str(const char* a) {
|
||||
return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
|
||||
}
|
||||
|
||||
inline socket_address_inet6
|
||||
socket_address_inet::to_mapped_address() const {
|
||||
uint32_t addr32[4];
|
||||
addr32[0] = 0;
|
||||
addr32[1] = 0;
|
||||
addr32[2] = htonl(0xffff);
|
||||
addr32[3] = m_sockaddr.sin_addr.s_addr;
|
||||
|
||||
socket_address_inet6 sa;
|
||||
sa.clear();
|
||||
sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
|
||||
sa.set_port_n(m_sockaddr.sin_port);
|
||||
return sa;
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::operator == (const socket_address_inet& rhs) const {
|
||||
return
|
||||
m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
|
||||
m_sockaddr.sin_port == rhs.m_sockaddr.sin_port;
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet::operator < (const socket_address_inet& rhs) const {
|
||||
return
|
||||
m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr ||
|
||||
(m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
|
||||
m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
socket_address_inet6::address_str() const {
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!address_c_str(buf, INET6_ADDRSTRLEN))
|
||||
return std::string();
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
|
||||
return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
|
||||
}
|
||||
|
||||
inline bool
|
||||
socket_address_inet6::set_address_c_str(const char* a) {
|
||||
return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
|
||||
}
|
||||
|
||||
inline 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
|
||||
@@ -0,0 +1,376 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_STRING_MANIP_H
|
||||
#define RAK_STRING_MANIP_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <locale>
|
||||
|
||||
namespace rak {
|
||||
|
||||
// Use these trim functions until n1872 is widely supported.
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_begin(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*seq.begin()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = 0;
|
||||
|
||||
while (pos != seq.length() && std::isspace(seq[pos]))
|
||||
pos++;
|
||||
|
||||
return seq.substr(pos, seq.length() - pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_end(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*(--seq.end())))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = seq.size();
|
||||
|
||||
while (pos != 0 && std::isspace(seq[pos - 1]))
|
||||
pos--;
|
||||
|
||||
return seq.substr(0, pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim(const Sequence& seq) {
|
||||
return trim_begin(trim_end(seq));
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_begin_classic(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*seq.begin(), std::locale::classic()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = 0;
|
||||
|
||||
while (pos != seq.length() && std::isspace(seq[pos], std::locale::classic()))
|
||||
pos++;
|
||||
|
||||
return seq.substr(pos, seq.length() - pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_end_classic(const Sequence& seq) {
|
||||
if (seq.empty() || !std::isspace(*(--seq.end()), std::locale::classic()))
|
||||
return seq;
|
||||
|
||||
typename Sequence::size_type pos = seq.size();
|
||||
|
||||
while (pos != 0 && std::isspace(seq[pos - 1], std::locale::classic()))
|
||||
pos--;
|
||||
|
||||
return seq.substr(0, pos);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence trim_classic(const Sequence& seq) {
|
||||
return trim_begin_classic(trim_end_classic(seq));
|
||||
}
|
||||
|
||||
// Consider rewritting such that m_seq is replaced by first/last.
|
||||
template <typename Sequence>
|
||||
class split_iterator_t {
|
||||
public:
|
||||
typedef typename Sequence::const_iterator const_iterator;
|
||||
typedef typename Sequence::value_type value_type;
|
||||
|
||||
split_iterator_t() {}
|
||||
|
||||
split_iterator_t(const Sequence& seq, value_type delim) :
|
||||
m_seq(&seq),
|
||||
m_delim(delim),
|
||||
m_pos(seq.begin()),
|
||||
m_next(std::find(seq.begin(), seq.end(), delim)) {
|
||||
}
|
||||
|
||||
Sequence operator * () { return Sequence(m_pos, m_next); }
|
||||
|
||||
split_iterator_t& operator ++ () {
|
||||
m_pos = m_next;
|
||||
|
||||
if (m_pos == m_seq->end())
|
||||
return *this;
|
||||
|
||||
m_pos++;
|
||||
m_next = std::find(m_pos, m_seq->end(), m_delim);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (__UNUSED const split_iterator_t& itr) const { return m_pos == m_seq->end(); }
|
||||
bool operator != (__UNUSED const split_iterator_t& itr) const { return m_pos != m_seq->end(); }
|
||||
|
||||
private:
|
||||
const Sequence* m_seq;
|
||||
value_type m_delim;
|
||||
const_iterator m_pos;
|
||||
const_iterator m_next;
|
||||
};
|
||||
|
||||
template <typename Sequence>
|
||||
inline split_iterator_t<Sequence>
|
||||
split_iterator(const Sequence& seq, typename Sequence::value_type delim) {
|
||||
return split_iterator_t<Sequence>(seq, delim);
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline split_iterator_t<Sequence>
|
||||
split_iterator(__UNUSED const Sequence& seq) {
|
||||
return split_iterator_t<Sequence>();
|
||||
}
|
||||
|
||||
// Could optimize this abit.
|
||||
inline char
|
||||
hexchar_to_value(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return 10 + c - 'A';
|
||||
|
||||
else
|
||||
return 10 + c - 'a';
|
||||
}
|
||||
|
||||
template <int pos, typename Value>
|
||||
inline char
|
||||
value_to_hexchar(Value v) {
|
||||
v >>= pos * 4;
|
||||
v &= 0xf;
|
||||
|
||||
if (v < 0xA)
|
||||
return '0' + v;
|
||||
else
|
||||
return 'A' + v - 0xA;
|
||||
}
|
||||
|
||||
template <typename InputIterator, typename OutputIterator>
|
||||
OutputIterator
|
||||
copy_escape_html(InputIterator first, InputIterator last, OutputIterator dest) {
|
||||
while (first != last) {
|
||||
if (std::isalpha(*first, std::locale::classic()) ||
|
||||
std::isdigit(*first, std::locale::classic()) ||
|
||||
*first == '-') {
|
||||
*(dest++) = *first;
|
||||
|
||||
} else {
|
||||
*(dest++) = '%';
|
||||
*(dest++) = value_to_hexchar<1>(*first);
|
||||
*(dest++) = value_to_hexchar<0>(*first);
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename InputIterator, typename OutputIterator>
|
||||
OutputIterator
|
||||
copy_escape_html(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) {
|
||||
while (first1 != last1) {
|
||||
if (std::isalpha(*first1, std::locale::classic()) ||
|
||||
std::isdigit(*first1, std::locale::classic()) ||
|
||||
*first1 == '-') {
|
||||
if (first2 == last2) break; else *(first2++) = *first1;
|
||||
|
||||
} else {
|
||||
if (first2 == last2) break; else *(first2++) = '%';
|
||||
if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1);
|
||||
if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1);
|
||||
}
|
||||
|
||||
++first1;
|
||||
}
|
||||
|
||||
return first2;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline std::string
|
||||
copy_escape_html(Iterator first, Iterator last) {
|
||||
std::string dest;
|
||||
copy_escape_html(first, last, std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline Sequence
|
||||
copy_escape_html(const Sequence& src) {
|
||||
Sequence dest;
|
||||
copy_escape_html(src.begin(), src.end(), std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline std::string
|
||||
copy_escape_html_str(const Sequence& src) {
|
||||
std::string dest;
|
||||
copy_escape_html(src.begin(), src.end(), std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Consider support for larger than char type.
|
||||
template <typename InputIterator, typename OutputIterator>
|
||||
OutputIterator
|
||||
transform_hex(InputIterator first, InputIterator last, OutputIterator dest) {
|
||||
while (first != last) {
|
||||
*(dest++) = value_to_hexchar<1>(*first);
|
||||
*(dest++) = value_to_hexchar<0>(*first);
|
||||
|
||||
++first;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename InputIterator, typename OutputIterator>
|
||||
OutputIterator
|
||||
transform_hex(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) {
|
||||
while (first1 != last1) {
|
||||
if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1);
|
||||
if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1);
|
||||
|
||||
++first1;
|
||||
}
|
||||
|
||||
return first2;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline Sequence
|
||||
transform_hex(const Sequence& src) {
|
||||
Sequence dest;
|
||||
transform_hex(src.begin(), src.end(), std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline std::string
|
||||
transform_hex(Iterator first, Iterator last) {
|
||||
std::string dest;
|
||||
transform_hex(first, last, std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline std::string
|
||||
transform_hex_str(const Sequence& seq) {
|
||||
std::string dest;
|
||||
transform_hex(seq.begin(), seq.end(), std::back_inserter(dest));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
Sequence
|
||||
generate_random(size_t length) {
|
||||
Sequence s;
|
||||
s.reserve(length);
|
||||
|
||||
std::generate_n(std::back_inserter(s), length, &::random);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_alpha(Iterator first, Iterator last) {
|
||||
while (first != last)
|
||||
if (!std::isalpha(*first++, std::locale::classic()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_alpha(const Sequence& src) {
|
||||
return is_all_alpha(src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_alnum(Iterator first, Iterator last) {
|
||||
while (first != last)
|
||||
if (!std::isalnum(*first++, std::locale::classic()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_alnum(const Sequence& src) {
|
||||
return is_all_alnum(src.begin(), src.end());
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline bool
|
||||
is_all_name(Iterator first, Iterator last) {
|
||||
while (first != last) {
|
||||
if (!std::isalnum(*first, std::locale::classic()) && *first != '_')
|
||||
return false;
|
||||
|
||||
first++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Sequence>
|
||||
inline bool
|
||||
is_all_name(const Sequence& src) {
|
||||
return is_all_name(src.begin(), src.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// libTorrent - BitTorrent library
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_TIMER_H
|
||||
#define RAK_TIMER_H
|
||||
|
||||
#include <limits>
|
||||
#include <inttypes.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
namespace rak {
|
||||
|
||||
// Don't convert negative Timer to timeval and then back to Timer, that will bork.
|
||||
class timer {
|
||||
public:
|
||||
timer(int64_t usec = 0) : m_time(usec) {}
|
||||
timer(timeval tv) : m_time((int64_t)(uint32_t)tv.tv_sec * 1000000 + (int64_t)(uint32_t)tv.tv_usec % 1000000) {}
|
||||
|
||||
bool is_zero() const { return m_time == 0; }
|
||||
bool is_not_zero() const { return m_time != 0; }
|
||||
|
||||
int32_t seconds() const { return m_time / 1000000; }
|
||||
int32_t seconds_ceiling() const { return (m_time + 1000000 - 1) / 1000000; }
|
||||
int64_t usec() const { return m_time; }
|
||||
|
||||
timer round_seconds() const { return (m_time / 1000000) * 1000000; }
|
||||
timer round_seconds_ceiling() const { return ((m_time + 1000000 - 1) / 1000000) * 1000000; }
|
||||
|
||||
timeval tval() const {
|
||||
timeval val;
|
||||
val.tv_sec = m_time / 1000000;
|
||||
val.tv_usec = m_time % 1000000;
|
||||
return val;
|
||||
}
|
||||
|
||||
static timer current();
|
||||
static int64_t current_seconds() { return current().seconds(); }
|
||||
static int64_t current_usec() { return current().usec(); }
|
||||
static timer from_minutes(uint32_t minutes) { return rak::timer((uint64_t)minutes * 60 * 1000000); }
|
||||
static timer from_seconds(uint32_t seconds) { return rak::timer((uint64_t)seconds * 1000000); }
|
||||
static timer from_milliseconds(uint32_t msec) { return rak::timer((uint64_t)msec * 1000); }
|
||||
|
||||
static timer max() { return std::numeric_limits<int64_t>::max(); }
|
||||
|
||||
bool operator < (const timer& t) const { return m_time < t.m_time; }
|
||||
bool operator > (const timer& t) const { return m_time > t.m_time; }
|
||||
bool operator <= (const timer& t) const { return m_time <= t.m_time; }
|
||||
bool operator >= (const timer& t) const { return m_time >= t.m_time; }
|
||||
bool operator == (const timer& t) const { return m_time == t.m_time; }
|
||||
bool operator != (const timer& t) const { return m_time != t.m_time; }
|
||||
|
||||
timer operator - (const timer& t) const { return timer(m_time - t.m_time); }
|
||||
timer operator + (const timer& t) const { return timer(m_time + t.m_time); }
|
||||
timer operator * (int64_t t) const { return timer(m_time * t); }
|
||||
timer operator / (int64_t t) const { return timer(m_time / t); }
|
||||
|
||||
timer operator -= (int64_t t) { m_time -= t; return *this; }
|
||||
timer operator -= (const timer& t) { m_time -= t.m_time; return *this; }
|
||||
|
||||
timer operator += (int64_t t) { m_time += t; return *this; }
|
||||
timer operator += (const timer& t) { m_time += t.m_time; return *this; }
|
||||
|
||||
private:
|
||||
int64_t m_time;
|
||||
};
|
||||
|
||||
inline timer
|
||||
timer::current() {
|
||||
timeval t;
|
||||
gettimeofday(&t, 0);
|
||||
|
||||
return timer(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RAK_UNORDERED_VECTOR_H
|
||||
#define RAK_UNORDERED_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace rak {
|
||||
|
||||
template <typename _Tp>
|
||||
class unordered_vector : private std::vector<_Tp> {
|
||||
public:
|
||||
typedef std::vector<_Tp> Base;
|
||||
|
||||
typedef typename Base::value_type value_type;
|
||||
typedef typename Base::pointer pointer;
|
||||
typedef typename Base::const_pointer const_pointer;
|
||||
typedef typename Base::reference reference;
|
||||
typedef typename Base::const_reference const_reference;
|
||||
typedef typename Base::size_type size_type;
|
||||
typedef typename Base::difference_type difference_type;
|
||||
typedef typename Base::allocator_type allocator_type;
|
||||
|
||||
typedef typename Base::iterator iterator;
|
||||
typedef typename Base::reverse_iterator reverse_iterator;
|
||||
typedef typename Base::const_iterator const_iterator;
|
||||
typedef typename Base::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
using Base::clear;
|
||||
using Base::empty;
|
||||
using Base::size;
|
||||
using Base::reserve;
|
||||
|
||||
using Base::front;
|
||||
using Base::back;
|
||||
using Base::begin;
|
||||
using Base::end;
|
||||
using Base::rbegin;
|
||||
using Base::rend;
|
||||
|
||||
using Base::push_back;
|
||||
using Base::pop_back;
|
||||
|
||||
// Use the range erase function, the single element erase gets
|
||||
// overloaded.
|
||||
using Base::erase;
|
||||
|
||||
iterator insert(iterator position, const value_type& x);
|
||||
iterator erase(iterator position);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
template <typename _Tp>
|
||||
typename unordered_vector<_Tp>::iterator
|
||||
unordered_vector<_Tp>::insert(iterator position, const value_type& x) {
|
||||
Base::push_back(x);
|
||||
|
||||
return --end();
|
||||
}
|
||||
|
||||
template <typename _Tp>
|
||||
typename unordered_vector<_Tp>::iterator
|
||||
unordered_vector<_Tp>::erase(iterator position) {
|
||||
// We don't need to check if position == end - 1 since we then copy
|
||||
// to the position we pop later.
|
||||
*position = Base::back();
|
||||
Base::pop_back();
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
# Functions to check for attributes support in compiler
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((constructor))],
|
||||
[cc_cv_attribute_constructor],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void ctor() __attribute__((constructor));
|
||||
void ctor() { };
|
||||
])],
|
||||
[cc_cv_attribute_constructor=yes],
|
||||
[cc_cv_attribute_constructor=no])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_constructor" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_CONSTRUCTOR], 1, [Define this if the compiler supports the constructor attribute])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((format(printf, n, n)))],
|
||||
[cc_cv_attribute_format],
|
||||
[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])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_format" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_FORMAT], 1, [Define this if the compiler supports the format attribute])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_INTERNAL], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((visibility("internal")))],
|
||||
[cc_cv_attribute_internal],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void __attribute__((visibility("internal"))) internal_function() { }
|
||||
])],
|
||||
[cc_cv_attribute_internal=yes],
|
||||
[cc_cv_attribute_internal=no])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_internal" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_INTERNAL], 1, [Define this if the compiler supports the internal visibility attribute])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
tmp_CXXFLAGS=$CXXFLAGS
|
||||
CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
|
||||
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((visibility("default")))],
|
||||
[cc_cv_attribute_visibility],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void __attribute__((visibility("default"))) visibility_function() { }
|
||||
])],
|
||||
[cc_cv_attribute_visibility=yes],
|
||||
[cc_cv_attribute_visibility=no])
|
||||
])
|
||||
|
||||
CXXFLAGS=$tmp_CXXFLAGS
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
if test "x$cc_cv_attribute_visibility" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_VISIBILITY], 1, [Define this if the compiler supports the visibility attributes.])
|
||||
CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((nonnull()))],
|
||||
[cc_cv_attribute_nonnull],
|
||||
[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])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_nonnull" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_NONNULL], 1, [Define this if the compiler supports the nonnull attribute])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
|
||||
AC_CACHE_CHECK([if compiler supports __attribute__((unused))],
|
||||
[cc_cv_attribute_unused],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
void some_function(void *foo, __attribute__((unused)) void *bar);
|
||||
])],
|
||||
[cc_cv_attribute_unused=yes],
|
||||
[cc_cv_attribute_unused=no])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_attribute_unused" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT_ATTRIBUTE_UNUSED], 1, [Define this if the compiler supports the unused attribute])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CC_FUNC_EXPECT], [
|
||||
AC_CACHE_CHECK([if compiler has __builtin_expect function],
|
||||
[cc_cv_func_expect],
|
||||
[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])
|
||||
])
|
||||
|
||||
if test "x$cc_cv_func_expect" = "xyes"; then
|
||||
AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, [Define this if the compiler supports __builtin_expect() function])
|
||||
$1
|
||||
else
|
||||
true
|
||||
$2
|
||||
fi
|
||||
])
|
||||
@@ -0,0 +1,142 @@
|
||||
# ===========================================================================
|
||||
# http://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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# 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 14
|
||||
|
||||
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_SAVE
|
||||
AC_LANG_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_RESTORE
|
||||
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
|
||||
])
|
||||
@@ -0,0 +1,106 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_0x.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_0X
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++0x
|
||||
# standard.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@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 7 (+1)
|
||||
|
||||
AU_ALIAS([AC_CXX_COMPILE_STDCXX_0X], [AX_CXX_COMPILE_STDCXX_0X])
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_0X], [
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features without additional flags,
|
||||
ax_cv_cxx_compile_cxx0x_native,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_native=yes, ax_cv_cxx_compile_cxx0x_native=no)
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=c++0x,
|
||||
ax_cv_cxx_compile_cxx0x_cxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=c++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_cxx=yes, ax_cv_cxx_compile_cxx0x_cxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=gnu++0x,
|
||||
ax_cv_cxx_compile_cxx0x_gxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_gxx=yes, ax_cv_cxx_compile_cxx0x_gxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
if test "$ax_cv_cxx_compile_cxx0x_cxx" = yes; then
|
||||
AC_DEFINE(HAVE_STDCXX_0X,, [Define if compiler supports C++0x features.])
|
||||
CXXFLAGS="$CXXFLAGS -std=c++0x"
|
||||
fi
|
||||
])
|
||||
@@ -0,0 +1,147 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++11
|
||||
# standard; if necessary, add switches to CXXFLAGS to enable support.
|
||||
#
|
||||
# The first 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 an extended mode.
|
||||
#
|
||||
# The second argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline C++11 support 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_CXX11 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 Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2014 Jari Sundell <sundell.software@gmail.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 5
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
struct Base {
|
||||
virtual void f() {}
|
||||
};
|
||||
struct Child : public Base {
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);
|
||||
|
||||
auto d = a;
|
||||
auto l = [](){};
|
||||
|
||||
void unused() {
|
||||
l();
|
||||
}
|
||||
]])
|
||||
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
|
||||
m4_if([$1], [], [],
|
||||
[$1], [ext], [],
|
||||
[$1], [noext], [],
|
||||
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
|
||||
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
|
||||
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
|
||||
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
|
||||
ax_cv_cxx_compile_cxx11,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[ax_cv_cxx_compile_cxx11=yes],
|
||||
[ax_cv_cxx_compile_cxx11=no])])
|
||||
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
|
||||
ac_success=yes
|
||||
fi
|
||||
|
||||
m4_if([$1], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for switch in -std=gnu++11 -std=gnu++0x; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$1], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for switch in -std=c++11 -std=c++0x; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx11_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
|
||||
fi
|
||||
else
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX11=0
|
||||
AC_MSG_NOTICE([No compiler with C++11 support was found])
|
||||
else
|
||||
HAVE_CXX11=1
|
||||
AC_DEFINE(HAVE_CXX11,1,
|
||||
[define if the compiler supports basic C++11 syntax])
|
||||
fi
|
||||
|
||||
AC_SUBST(HAVE_CXX11)
|
||||
fi
|
||||
])
|
||||
@@ -0,0 +1,309 @@
|
||||
# ===========================================================================
|
||||
# http://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 to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
# 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>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# 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 17
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
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 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, ax_pthread_ok=yes)
|
||||
AC_MSG_RESULT($ax_pthread_ok)
|
||||
if test x"$ax_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.
|
||||
|
||||
ax_pthread_flags="none pthreads -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# 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)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case "${host_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 -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
*-darwin*)
|
||||
ax_pthread_flags="none -pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# 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>
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT($ax_pthread_ok)
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT($attr_name)
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||||
*-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||||
*solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT(${flag})
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
ax_cv_PTHREAD_PRIO_INHERIT, [
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# More AIX lossage: must compile with xlc_r or cc_r
|
||||
if test x"$GCC" != xyes; then
|
||||
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
|
||||
else
|
||||
PTHREAD_CC=$CC
|
||||
fi
|
||||
else
|
||||
PTHREAD_CC="$CC"
|
||||
fi
|
||||
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_CC)
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_POP
|
||||
])dnl AX_PTHREAD
|
||||
@@ -0,0 +1,546 @@
|
||||
# ===========================================================================
|
||||
# http://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.
|
||||
#
|
||||
# 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 variable is defined by this macro; it is precious
|
||||
# and may be overridden on the ./configure command line:
|
||||
#
|
||||
# CURSES_LIB - library to add to xxx_LDADD
|
||||
#
|
||||
# The library listed in CURSES_LIB is NOT added to LIBS by default. You
|
||||
# need to add CURSES_LIB to the appropriate xxx_LDADD line in your
|
||||
# Makefile.am. For example:
|
||||
#
|
||||
# prog_LDADD = @CURSES_LIB@
|
||||
#
|
||||
# If CURSES_LIB is set on the configure command line (such as by running
|
||||
# "./configure CURSES_LIB=-lmycurses"), then the only header searched for
|
||||
# is <curses.h>. The user may use the CPPFLAGS precious variable to
|
||||
# override the standard #include search path. If the user needs to
|
||||
# specify an alternative path for a library (such as for a non-standard
|
||||
# NcurseW), the user should use the LDFLAGS variable.
|
||||
#
|
||||
# The following shell variables may be defined by this macro:
|
||||
#
|
||||
# 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
|
||||
# AX_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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# 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 13
|
||||
|
||||
AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES])
|
||||
AC_DEFUN([AX_WITH_CURSES], [
|
||||
AC_ARG_VAR([CURSES_LIB], [linker library for Curses, e.g. -lcurses])
|
||||
AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses],
|
||||
[force the use of Ncurses or NcursesW])],
|
||||
[], [with_ncurses=check])
|
||||
AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw],
|
||||
[do not use NcursesW (wide character support)])],
|
||||
[], [with_ncursesw=check])
|
||||
|
||||
ax_saved_LIBS=$LIBS
|
||||
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_LIB" = x && test "x$with_ncursesw" != xno], [
|
||||
LIBS="$ax_saved_LIBS -lncursesw"
|
||||
|
||||
AC_CACHE_CHECK([for NcursesW wide-character library], [ax_cv_ncursesw], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_ncursesw=yes], [ax_cv_ncursesw=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncursesw
|
||||
CURSES_LIB="-lncursesw"
|
||||
AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
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])
|
||||
])
|
||||
|
||||
dnl Test if we need to explicitly link against -ltinfow.
|
||||
AC_CACHE_CHECK([if curses tinfo library is linked properly], [ax_cv_ncurses_compiled], [
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIB"
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_ncurses_compiled=yes], [ax_cv_ncurses_compiled=no])
|
||||
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfo"
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfo_compiled=yes], [ax_cv_tinfo_compiled=no])
|
||||
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfow"
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfow_compiled=yes], [ax_cv_tinfow_compiled=no])
|
||||
|
||||
LIBS=$ax_saved_LIBS
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncurses_compiled" = xno], [
|
||||
AS_IF(
|
||||
[test "x$ax_cv_tinfo_compiled" = xyes], [
|
||||
AC_MSG_RESULT([adding libtinfo])
|
||||
CURSES_LIB="$CURSES_LIB -ltinfo"
|
||||
],
|
||||
[test "x$ax_cv_tinfow_compiled" = xyes], [
|
||||
AC_MSG_RESULT([adding libtinfow])
|
||||
CURSES_LIB="$CURSES_LIB -ltinfow"
|
||||
], [
|
||||
AC_MSG_ERROR([no])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
# Test for Ncurses
|
||||
|
||||
AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
LIBS="$ax_saved_LIBS -lncurses"
|
||||
|
||||
AC_CACHE_CHECK([for Ncurses library], [ax_cv_ncurses], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_ncurses=yes], [ax_cv_ncurses=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncurses" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncurses
|
||||
CURSES_LIB="-lncurses"
|
||||
AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
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])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
# Test for plain Curses (or if CURSES_LIB was set by user)
|
||||
|
||||
AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
AS_IF([test "x$CURSES_LIB" != x], [
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIB"
|
||||
], [
|
||||
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_LIB" = x], [
|
||||
CURSES_LIB="-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
|
||||
])dnl
|
||||
@@ -0,0 +1,494 @@
|
||||
AC_DEFUN([TORRENT_CHECK_XFS], [
|
||||
AC_MSG_CHECKING(for XFS support)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <xfs/libxfs.h>
|
||||
#include <sys/ioctl.h>
|
||||
int main() {
|
||||
struct xfs_flock64 l;
|
||||
ioctl(0, XFS_IOC_RESVSP64, &l);
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_XFS, 1, Use XFS filesystem stuff.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
AC_HELP_STRING([--without-xfs], [do not check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_XFS
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
AC_HELP_STRING([--with-xfs], [check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
AC_MSG_CHECKING(for epoll support)
|
||||
|
||||
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)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_EPOLL], [
|
||||
AC_ARG_WITH(epoll,
|
||||
AC_HELP_STRING([--without-epoll], [do not check for epoll support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_EPOLL
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_EPOLL
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_KQUEUE], [
|
||||
AC_MSG_CHECKING(for kqueue support)
|
||||
|
||||
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)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [
|
||||
AC_MSG_CHECKING(whether kqueue supports pipes and ptys)
|
||||
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
int main() {
|
||||
struct kevent ev@<:@2@:>@, ev_out@<:@2@:>@;
|
||||
struct timespec ts = { 0, 0 };
|
||||
int pfd@<:@2@:>@, pty@<:@2@:>@, kfd, n;
|
||||
char buffer@<:@9001@:>@;
|
||||
if (pipe(pfd) == -1) return 1;
|
||||
if (fcntl(pfd@<:@1@:>@, F_SETFL, O_NONBLOCK) == -1) return 2;
|
||||
while ((n = write(pfd@<:@1@:>@, buffer, sizeof(buffer))) == sizeof(buffer));
|
||||
if ((pty@<:@0@:>@=posix_openpt(O_RDWR | O_NOCTTY)) == -1) return 3;
|
||||
if ((pty@<:@1@:>@=grantpt(pty@<:@0@:>@)) == -1) return 4;
|
||||
EV_SET(ev+0, pfd@<:@1@:>@, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
|
||||
EV_SET(ev+1, pty@<:@1@:>@, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
|
||||
if ((kfd = kqueue()) == -1) return 5;
|
||||
if ((n = kevent(kfd, ev, 2, NULL, 0, NULL)) == -1) return 6;
|
||||
if (ev_out@<:@0@:>@.flags & EV_ERROR) return 7;
|
||||
if (ev_out@<:@1@:>@.flags & EV_ERROR) return 8;
|
||||
read(pfd@<:@0@:>@, buffer, sizeof(buffer));
|
||||
if ((n = kevent(kfd, NULL, 0, ev_out, 2, &ts)) < 1) return 9;
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_DEFINE(KQUEUE_SOCKET_ONLY, 1, kqueue only supports sockets.)
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_KQUEUE], [
|
||||
AC_ARG_WITH(kqueue,
|
||||
AC_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,
|
||||
AC_HELP_STRING([--without-kqueue], [do not check for kqueue support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_KQUEUE
|
||||
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_KQUEUE
|
||||
TORRENT_CHECK_KQUEUE_SOCKET_ONLY
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
|
||||
AC_ARG_WITH(variable-fdset,
|
||||
AC_HELP_STRING([--without-variable-fdset], [do not use non-portable variable sized fd_set's]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
|
||||
fi
|
||||
], [
|
||||
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for fallocate)
|
||||
|
||||
AC_TRY_LINK([#include <fcntl.h>
|
||||
#include <linux/falloc.h>
|
||||
],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
|
||||
],
|
||||
[
|
||||
AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for posix_fallocate)
|
||||
|
||||
AC_TRY_LINK([#include <fcntl.h>
|
||||
],[ posix_fallocate(0, 0, 0);
|
||||
],
|
||||
[
|
||||
AC_DEFINE(USE_POSIX_FALLOCATE, 1, posix_fallocate supported.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
|
||||
AC_ARG_WITH(posix-fallocate,
|
||||
AC_HELP_STRING([--with-posix-fallocate], [check for and use posix_fallocate to allocate files]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_POSIX_FALLOCATE
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_STATVFS], [
|
||||
AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h)
|
||||
|
||||
AC_MSG_CHECKING(for statvfs)
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#if HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
],[
|
||||
struct statvfs s; fsblkcnt_t c;
|
||||
statvfs("", &s);
|
||||
fstatvfs(0, &s);
|
||||
],
|
||||
[
|
||||
AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
|
||||
AC_MSG_RESULT(ok)
|
||||
have_stat_vfs=yes
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
have_stat_vfs=no
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_STATFS], [
|
||||
AC_CHECK_HEADERS(sys/statfs.h sys/param.h sys/mount.h)
|
||||
|
||||
AC_MSG_CHECKING(for statfs)
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#if HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
],[
|
||||
struct statfs s;
|
||||
statfs("", &s);
|
||||
fstatfs(0, &s);
|
||||
],
|
||||
[
|
||||
AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
|
||||
AC_MSG_RESULT(ok)
|
||||
have_stat_vfs=yes
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
have_stat_vfs=no
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLED_STATFS], [
|
||||
AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd)
|
||||
AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename)
|
||||
AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function)
|
||||
AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct)
|
||||
AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct)
|
||||
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size)
|
||||
AC_MSG_RESULT(No filesystem stats available)
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
|
||||
AC_ARG_WITH(statvfs,
|
||||
AC_HELP_STRING([--without-statvfs], [don't try to use statvfs to find free diskspace]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_STATVFS
|
||||
else
|
||||
have_stat_vfs=no
|
||||
fi
|
||||
],
|
||||
[
|
||||
TORRENT_CHECK_STATVFS
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_STATFS], [
|
||||
AC_ARG_WITH(statfs,
|
||||
AC_HELP_STRING([--without-statfs], [don't try to use statfs to find free diskspace]),
|
||||
[
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_STATFS
|
||||
else
|
||||
TORRENT_DISABLED_STATFS
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
TORRENT_CHECK_STATFS
|
||||
if test "$have_stat_vfs" = "no"; then
|
||||
TORRENT_DISABLED_STATFS
|
||||
fi
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_ARG_WITH(address-space,
|
||||
AC_HELP_STRING([--with-address-space=MB], [change the default address space size [[default=1024mb]]]),
|
||||
[
|
||||
if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
|
||||
else
|
||||
AC_MSG_ERROR(--with-address-space requires a parameter.)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_CHECK_SIZEOF(long)
|
||||
|
||||
if test $ac_cv_sizeof_long = 8; then
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 4096, Default address space size.)
|
||||
else
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 1024, Default address space size.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
AC_ARG_WITH(fastcgi,
|
||||
AC_HELP_STRING([--with-fastcgi=PATH], [enable FastCGI RPC support (DO NOT USE)]),
|
||||
[
|
||||
AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
|
||||
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
elif test "$withval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
LIBS="$LIBS -lfcgi"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <fcgiapp.h>
|
||||
],[ FCGX_Init(); ],
|
||||
[
|
||||
AC_MSG_RESULT(ok)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_ERROR(Could not compile FastCGI test.)
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
|
||||
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -I$withval/include"
|
||||
LIBS="$LIBS -lfcgi -L$withval/lib"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <fcgiapp.h>
|
||||
],[ FCGX_Init(); ],
|
||||
[
|
||||
AC_MSG_RESULT(ok)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_ERROR(Could not compile FastCGI test.)
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
|
||||
AC_MSG_CHECKING(for XMLRPC-C)
|
||||
|
||||
AC_ARG_WITH(xmlrpc-c,
|
||||
AC_HELP_STRING([--with-xmlrpc-c=PATH], [enable XMLRPC-C support]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
else
|
||||
if test "$withval" = "yes"; then
|
||||
xmlrpc_cc_prg="xmlrpc-c-config"
|
||||
else
|
||||
xmlrpc_cc_prg="$withval"
|
||||
fi
|
||||
|
||||
if eval $xmlrpc_cc_prg --version 2>/dev/null >/dev/null; then
|
||||
CXXFLAGS="$CXXFLAGS `$xmlrpc_cc_prg --cflags server-util`"
|
||||
LIBS="$LIBS `$xmlrpc_cc_prg server-util --libs`"
|
||||
|
||||
AC_TRY_LINK(
|
||||
[ #include <xmlrpc-c/server.h>
|
||||
],[ xmlrpc_registry_new(NULL); ],
|
||||
[
|
||||
AC_MSG_RESULT(ok)
|
||||
], [
|
||||
AC_MSG_RESULT(failed)
|
||||
AC_MSG_ERROR(Could not compile XMLRPC-C test.)
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_XMLRPC_C, 1, Support for XMLRPC-C.)
|
||||
|
||||
else
|
||||
AC_MSG_RESULT(failed)
|
||||
AC_MSG_ERROR(Could not compile XMLRPC-C test.)
|
||||
fi
|
||||
fi
|
||||
|
||||
],[
|
||||
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_TRY_LINK([
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
],[
|
||||
pthread_t t;
|
||||
pthread_setname_np(t, "foo");
|
||||
],[
|
||||
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_GENERIC, 1, The function to set pthread name has a pthread_t argumet.)
|
||||
AC_MSG_RESULT(generic)
|
||||
],[
|
||||
AC_TRY_LINK([
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
],[
|
||||
pthread_t t;
|
||||
pthread_setname_np("foo");
|
||||
],[
|
||||
AC_DEFINE(HAS_PTHREAD_SETNAME_NP_DARWIN, 1, The function to set pthread name has no pthread argument.)
|
||||
AC_MSG_RESULT(darwin)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,242 @@
|
||||
AC_DEFUN([TORRENT_WITH_SYSROOT], [
|
||||
AC_ARG_WITH(sysroot,
|
||||
AC_HELP_STRING([--with-sysroot=PATH], [compile and link with a specific sysroot]),
|
||||
[
|
||||
AC_MSG_CHECKING(for sysroot)
|
||||
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
elif test "$withval" = "yes"; then
|
||||
AC_MSG_RESULT(not a path)
|
||||
AC_MSG_ERROR(The sysroot option must point to a directory, like f.ex "/Developer/SDKs/MacOSX10.4u.sdk".)
|
||||
else
|
||||
AC_MSG_RESULT($withval)
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -isysroot $withval"
|
||||
LDFLAGS="$LDFLAGS -Wl,-syslibroot,$withval"
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ARCH], [
|
||||
AC_ARG_ENABLE(arch,
|
||||
AC_HELP_STRING([--enable-arch=ARCH], [comma seprated list of architectures to compile for]),
|
||||
[
|
||||
AC_MSG_CHECKING(for target architectures)
|
||||
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_MSG_ERROR(no arch supplied)
|
||||
|
||||
elif test "$enableval" = "no"; then
|
||||
AC_MSG_RESULT(using default)
|
||||
|
||||
else
|
||||
AC_MSG_RESULT($enableval)
|
||||
|
||||
for i in `IFS=,; echo $enableval`; do
|
||||
CFLAGS="$CFLAGS -march=$i"
|
||||
CXXFLAGS="$CXXFLAGS -march=$i"
|
||||
LDFLAGS="$LDFLAGS -march=$i"
|
||||
done
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(signedness of mincore parameter)
|
||||
|
||||
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([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)
|
||||
AC_MSG_RESULT(signed)
|
||||
],
|
||||
[
|
||||
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32.])
|
||||
])
|
||||
])
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_MINCORE], [
|
||||
AC_ARG_ENABLE(mincore,
|
||||
AC_HELP_STRING([--disable-mincore], [disable mincore check [[default=enable]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
TORRENT_MINCORE_SIGNEDNESS()
|
||||
else
|
||||
AC_MSG_CHECKING(for mincore)
|
||||
AC_MSG_RESULT(disabled)
|
||||
fi
|
||||
],[
|
||||
TORRENT_MINCORE_SIGNEDNESS()
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_MADVISE], [
|
||||
AC_MSG_CHECKING(for madvise)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
void f() { static char test@<:@1024@:>@; madvise((void *)test, sizeof(test), MADV_NORMAL); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_MADVISE, 1, Use madvise)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
|
||||
AC_MSG_CHECKING(for __builtin_popcount)
|
||||
|
||||
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.)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
|
||||
AC_MSG_CHECKING(for cacheline)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <stdlib.h>
|
||||
#include <linux/cache.h>
|
||||
void* vptr __cacheline_aligned;
|
||||
void f() { posix_memalign(&vptr, SMP_CACHE_BYTES, 42); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(found builtin)
|
||||
dnl AC_DEFINE(LT_SMP_CACHE_BYTES, SMP_CACHE_BYTES, Largest L1 cache size we know of, should work on all archs.)
|
||||
dnl AC_DEFINE(lt_cacheline_aligned, __cacheline_aligned, LibTorrent defined cacheline aligned.)
|
||||
|
||||
dnl Need to fix this so that it uses the stuff defined by the system.
|
||||
|
||||
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
|
||||
AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.)
|
||||
], [
|
||||
AC_MSG_RESULT(using default 128 bytes)
|
||||
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
|
||||
AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_EXECINFO], [
|
||||
AC_MSG_CHECKING(for execinfo.h)
|
||||
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
#include <execinfo.h>
|
||||
int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_EXECINFO, 1, Use execinfo.h)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_ALIGNED], [
|
||||
AC_MSG_CHECKING(the byte alignment)
|
||||
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
#include <inttypes.h>
|
||||
int main() {
|
||||
char buf@<:@8@:>@ = { 0, 0, 0, 0, 1, 0, 0, 0 };
|
||||
int i;
|
||||
for (i = 1; i < 4; ++i)
|
||||
if (*(uint32_t*)(buf + i) == 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(none needed)
|
||||
], [
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
AC_MSG_RESULT(required)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
|
||||
AC_ARG_ENABLE(aligned,
|
||||
AC_HELP_STRING([--enable-aligned], [enable alignment safe code [[default=check]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
fi
|
||||
],[
|
||||
TORRENT_CHECK_ALIGNED
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
|
||||
AC_MSG_CHECKING([if instrumentation should be included])
|
||||
|
||||
AC_ARG_ENABLE(instrumentation,
|
||||
AC_HELP_STRING([--disable-instrumentation], [disable instrumentation [[default=enabled]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
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,
|
||||
AC_HELP_STRING([--enable-interrupt-socket], [enable interrupt socket [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_INTERRUPT_SOCKET, 1, Use interrupt socket instead of pthread_kill)
|
||||
fi
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_IPV6], [
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--enable-ipv6], [enable ipv6 [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(RAK_USE_INET6, 1, enable ipv6 stuff)
|
||||
fi
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,272 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 2006, David Shaw <dshaw@jabberwocky.com>
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
# are also available at https://curl.haxx.se/docs/copyright.html.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the COPYING file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
###########################################################################
|
||||
# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
|
||||
# [ACTION-IF-YES], [ACTION-IF-NO])
|
||||
# ----------------------------------------------------------
|
||||
# David Shaw <dshaw@jabberwocky.com> May-09-2006
|
||||
#
|
||||
# Checks for libcurl. DEFAULT-ACTION is the string yes or no to
|
||||
# specify whether to default to --with-libcurl or --without-libcurl.
|
||||
# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the
|
||||
# minimum version of libcurl to accept. Pass the version as a regular
|
||||
# version number like 7.10.1. If not supplied, any version is
|
||||
# accepted. ACTION-IF-YES is a list of shell commands to run if
|
||||
# libcurl was successfully found and passed the various tests.
|
||||
# ACTION-IF-NO is a list of shell commands that are run otherwise.
|
||||
# Note that using --without-libcurl does run ACTION-IF-NO.
|
||||
#
|
||||
# This macro #defines HAVE_LIBCURL if a working libcurl setup is
|
||||
# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
|
||||
# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are
|
||||
# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
|
||||
# where yyy are the various protocols supported by libcurl. Both xxx
|
||||
# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of
|
||||
# the macro for the complete list of possible defines. Shell
|
||||
# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
|
||||
# defined to 'yes' for those features and protocols that were found.
|
||||
# Note that xxx and yyy keep the same capitalization as in the
|
||||
# curl-config list (e.g. it's "HTTP" and not "http").
|
||||
#
|
||||
# Users may override the detected values by doing something like:
|
||||
# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
|
||||
#
|
||||
# For the sake of sanity, this macro assumes that any libcurl that is
|
||||
# found is after version 7.7.2, the first version that included the
|
||||
# curl-config script. Note that it is very important for people
|
||||
# packaging binary versions of libcurl to include this script!
|
||||
# Without curl-config, we can only guess what protocols are available,
|
||||
# or use curl_version_info to figure it out at runtime.
|
||||
|
||||
AC_DEFUN([LIBCURL_CHECK_CONFIG],
|
||||
[
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
|
||||
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
|
||||
|
||||
AC_ARG_WITH(libcurl,
|
||||
AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
|
||||
[_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
|
||||
|
||||
if test "$_libcurl_with" != "no" ; then
|
||||
|
||||
AC_PROG_AWK
|
||||
|
||||
_libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
|
||||
|
||||
_libcurl_try_link=yes
|
||||
|
||||
if test -d "$_libcurl_with" ; then
|
||||
LIBCURL_CPPFLAGS="-I$withval/include"
|
||||
_libcurl_ldflags="-L$withval/lib"
|
||||
AC_PATH_PROG([_libcurl_config],[curl-config],[],
|
||||
["$withval/bin"])
|
||||
else
|
||||
AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
|
||||
fi
|
||||
|
||||
if test x$_libcurl_config != "x" ; then
|
||||
AC_CACHE_CHECK([for the version of libcurl],
|
||||
[libcurl_cv_lib_curl_version],
|
||||
[libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
|
||||
|
||||
_libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
|
||||
_libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
|
||||
|
||||
if test $_libcurl_wanted -gt 0 ; then
|
||||
AC_CACHE_CHECK([for libcurl >= version $2],
|
||||
[libcurl_cv_lib_version_ok],
|
||||
[
|
||||
if test $_libcurl_version -ge $_libcurl_wanted ; then
|
||||
libcurl_cv_lib_version_ok=yes
|
||||
else
|
||||
libcurl_cv_lib_version_ok=no
|
||||
fi
|
||||
])
|
||||
fi
|
||||
|
||||
if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
|
||||
if test x"$LIBCURL_CPPFLAGS" = "x" ; then
|
||||
LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
|
||||
fi
|
||||
if test x"$LIBCURL" = "x" ; then
|
||||
LIBCURL=`$_libcurl_config --libs`
|
||||
|
||||
# This is so silly, but Apple actually has a bug in their
|
||||
# curl-config script. Fixed in Tiger, but there are still
|
||||
# lots of Panther installs around.
|
||||
case "${host}" in
|
||||
powerpc-apple-darwin7*)
|
||||
LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# All curl-config scripts support --feature
|
||||
_libcurl_features=`$_libcurl_config --feature`
|
||||
|
||||
# Is it modern enough to have --protocols? (7.12.4)
|
||||
if test $_libcurl_version -ge 461828 ; then
|
||||
_libcurl_protocols=`$_libcurl_config --protocols`
|
||||
fi
|
||||
else
|
||||
_libcurl_try_link=no
|
||||
fi
|
||||
|
||||
unset _libcurl_wanted
|
||||
fi
|
||||
|
||||
if test $_libcurl_try_link = yes ; then
|
||||
|
||||
# we didn't find curl-config, so let's see if the user-supplied
|
||||
# link line (or failing that, "-lcurl") is enough.
|
||||
LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
|
||||
|
||||
AC_CACHE_CHECK([whether libcurl is usable],
|
||||
[libcurl_cv_lib_curl_usable],
|
||||
[
|
||||
_libcurl_save_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
|
||||
_libcurl_save_libs=$LIBS
|
||||
LIBS="$LIBCURL $LIBS"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
|
||||
/* Try and use a few common options to force a failure if we are
|
||||
missing symbols or can't link. */
|
||||
int x;
|
||||
curl_easy_setopt(NULL,CURLOPT_URL,NULL);
|
||||
x=CURL_ERROR_SIZE;
|
||||
x=CURLOPT_WRITEFUNCTION;
|
||||
x=CURLOPT_WRITEDATA;
|
||||
x=CURLOPT_ERRORBUFFER;
|
||||
x=CURLOPT_STDERR;
|
||||
x=CURLOPT_VERBOSE;
|
||||
if (x) {;}
|
||||
]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
|
||||
|
||||
CPPFLAGS=$_libcurl_save_cppflags
|
||||
LIBS=$_libcurl_save_libs
|
||||
unset _libcurl_save_cppflags
|
||||
unset _libcurl_save_libs
|
||||
])
|
||||
|
||||
if test $libcurl_cv_lib_curl_usable = yes ; then
|
||||
|
||||
# Does curl_free() exist in this version of libcurl?
|
||||
# If not, fake it with free()
|
||||
|
||||
_libcurl_save_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
|
||||
_libcurl_save_libs=$LIBS
|
||||
LIBS="$LIBS $LIBCURL"
|
||||
|
||||
AC_CHECK_FUNC(curl_free,,
|
||||
AC_DEFINE(curl_free,free,
|
||||
[Define curl_free() as free() if our version of curl lacks curl_free.]))
|
||||
|
||||
CPPFLAGS=$_libcurl_save_cppflags
|
||||
LIBS=$_libcurl_save_libs
|
||||
unset _libcurl_save_cppflags
|
||||
unset _libcurl_save_libs
|
||||
|
||||
AC_DEFINE(HAVE_LIBCURL,1,
|
||||
[Define to 1 if you have a functional curl library.])
|
||||
AC_SUBST(LIBCURL_CPPFLAGS)
|
||||
AC_SUBST(LIBCURL)
|
||||
|
||||
for _libcurl_feature in $_libcurl_features ; do
|
||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
|
||||
eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
|
||||
done
|
||||
|
||||
if test "x$_libcurl_protocols" = "x" ; then
|
||||
|
||||
# We don't have --protocols, so just assume that all
|
||||
# protocols are available
|
||||
_libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
|
||||
|
||||
if test x$libcurl_feature_SSL = xyes ; then
|
||||
_libcurl_protocols="$_libcurl_protocols HTTPS"
|
||||
|
||||
# FTPS wasn't standards-compliant until version
|
||||
# 7.11.0 (0x070b00 == 461568)
|
||||
if test $_libcurl_version -ge 461568; then
|
||||
_libcurl_protocols="$_libcurl_protocols FTPS"
|
||||
fi
|
||||
fi
|
||||
|
||||
# RTSP, IMAP, POP3 and SMTP were added in
|
||||
# 7.20.0 (0x071400 == 463872)
|
||||
if test $_libcurl_version -ge 463872; then
|
||||
_libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
|
||||
fi
|
||||
fi
|
||||
|
||||
for _libcurl_protocol in $_libcurl_protocols ; do
|
||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
|
||||
eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
|
||||
done
|
||||
else
|
||||
unset LIBCURL
|
||||
unset LIBCURL_CPPFLAGS
|
||||
fi
|
||||
fi
|
||||
|
||||
unset _libcurl_try_link
|
||||
unset _libcurl_version_parse
|
||||
unset _libcurl_config
|
||||
unset _libcurl_feature
|
||||
unset _libcurl_features
|
||||
unset _libcurl_protocol
|
||||
unset _libcurl_protocols
|
||||
unset _libcurl_version
|
||||
unset _libcurl_ldflags
|
||||
fi
|
||||
|
||||
if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
|
||||
# This is the IF-NO path
|
||||
ifelse([$4],,:,[$4])
|
||||
else
|
||||
# This is the IF-YES path
|
||||
ifelse([$3],,:,[$3])
|
||||
fi
|
||||
|
||||
unset _libcurl_with
|
||||
])dnl
|
||||
@@ -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,
|
||||
AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -DNDEBUG"
|
||||
fi
|
||||
],[
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_ENABLE_WERROR], [
|
||||
AC_ARG_ENABLE(werror,
|
||||
AC_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,
|
||||
AC_HELP_STRING([--enable-extra-debug], [enable extra debugging checks [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,61 @@
|
||||
AC_DEFUN([RAK_CHECK_CXX11], [
|
||||
AC_ARG_ENABLE([c++0x],
|
||||
AC_HELP_STRING([--enable-c++0x], [compile with C++0x (unsupported)]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AX_CXX_COMPILE_STDCXX_0X
|
||||
else
|
||||
AX_CXX_COMPILE_STDCXX_11(noext)
|
||||
fi
|
||||
],[
|
||||
AX_CXX_COMPILE_STDCXX_11(noext)
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
AC_DEFUN([RAK_CHECK_TR1_LIB], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(should use TR1 headers)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <unordered_map>
|
||||
class Foo; typedef std::unordered_map<Foo*, int> Bar;
|
||||
Bar b1;
|
||||
])
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
AC_DEFINE(USE_TR1_LIB, 0, Define to 1 if you need to use TR1 containers.)
|
||||
|
||||
AC_DEFINE([lt_tr1_array], [<array>], [TR1 array])
|
||||
AC_DEFINE([lt_tr1_functional], [<functional>], [TR1 functional])
|
||||
AC_DEFINE([lt_tr1_memory], [<memory>], [TR1 memory])
|
||||
AC_DEFINE([lt_tr1_unordered_map], [<unordered_map>], [TR1 unordered_map])
|
||||
|
||||
], [
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <tr1/unordered_map>
|
||||
class Foo; typedef std::tr1::unordered_map<Foo*, int> Bar;
|
||||
Bar b1;
|
||||
])
|
||||
], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(USE_TR1_LIB, 1, Define to 1 if you need to use TR1 containers.)
|
||||
|
||||
AC_DEFINE([lt_tr1_array], [<tr1/array>], [TR1 array])
|
||||
AC_DEFINE([lt_tr1_functional], [<tr1/functional>], [TR1 functional])
|
||||
AC_DEFINE([lt_tr1_memory], [<tr1/memory>], [TR1 memory])
|
||||
AC_DEFINE([lt_tr1_unordered_map], [<tr1/unordered_map>], [TR1 unordered_map])
|
||||
|
||||
], [
|
||||
AC_MSG_ERROR([No support for C++11 standard library nor TR1 extensions found.])
|
||||
])
|
||||
])
|
||||
|
||||
AH_VERBATIM(lt_tr1_zzz, [
|
||||
#if USE_TR1_LIB == 1
|
||||
namespace std { namespace tr1 {} using namespace tr1; }
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
])
|
||||
@@ -0,0 +1,56 @@
|
||||
SUBDIRS = \
|
||||
core \
|
||||
display \
|
||||
input \
|
||||
rpc \
|
||||
ui \
|
||||
utils
|
||||
|
||||
noinst_LIBRARIES = libsub_root.a
|
||||
|
||||
libsub_root_a_SOURCES = \
|
||||
command_download.cc \
|
||||
command_dynamic.cc \
|
||||
command_events.cc \
|
||||
command_file.cc \
|
||||
command_ip.cc \
|
||||
command_helpers.cc \
|
||||
command_helpers.h \
|
||||
command_groups.cc \
|
||||
command_local.cc \
|
||||
command_logging.cc \
|
||||
command_network.cc \
|
||||
command_peer.cc \
|
||||
command_throttle.cc \
|
||||
command_tracker.cc \
|
||||
command_scheduler.cc \
|
||||
command_ui.cc \
|
||||
control.cc \
|
||||
control.h \
|
||||
globals.cc \
|
||||
globals.h \
|
||||
option_parser.cc \
|
||||
option_parser.h \
|
||||
signal_handler.cc \
|
||||
signal_handler.h \
|
||||
thread_base.cc \
|
||||
thread_base.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 \
|
||||
@PTHREAD_LIBS@
|
||||
|
||||
rtorrent_SOURCES = \
|
||||
main.cc
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
|
||||
@@ -0,0 +1,875 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/socket_address.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <rak/regex.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/tracker.h>
|
||||
#include <torrent/tracker_controller.h>
|
||||
#include <torrent/tracker_list.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/data/download_data.h>
|
||||
#include <torrent/data/file.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/peer/connection_list.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/download_store.h"
|
||||
#include "core/manager.h"
|
||||
#include "rpc/parse.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
std::string
|
||||
retrieve_d_base_path(core::Download* download) {
|
||||
if (download->file_list()->is_multi_file())
|
||||
return download->file_list()->frozen_root_dir();
|
||||
else
|
||||
return download->file_list()->empty() ? std::string() : download->file_list()->at(0)->frozen_path();
|
||||
}
|
||||
|
||||
std::string
|
||||
retrieve_d_base_filename(core::Download* download) {
|
||||
const std::string* base;
|
||||
|
||||
if (download->file_list()->is_multi_file())
|
||||
base = &download->file_list()->frozen_root_dir();
|
||||
else
|
||||
base = &download->file_list()->at(0)->frozen_path();
|
||||
|
||||
std::string::size_type split = base->rfind('/');
|
||||
|
||||
if (split == std::string::npos)
|
||||
return *base;
|
||||
else
|
||||
return base->substr(split + 1);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_d_change_link(core::Download* download, const torrent::Object::list_type& args, int changeType) {
|
||||
if (args.size() != 3)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
|
||||
const std::string& type = (itr++)->as_string();
|
||||
const std::string& prefix = (itr++)->as_string();
|
||||
const std::string& postfix = (itr++)->as_string();
|
||||
|
||||
if (type.empty())
|
||||
throw torrent::input_error("Invalid arguments.");
|
||||
|
||||
std::string target;
|
||||
std::string link;
|
||||
|
||||
if (type == "base_path") {
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
|
||||
} else if (type == "base_filename") {
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
link = rak::path_expand(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix);
|
||||
|
||||
// } else if (type == "directory_path") {
|
||||
// target = rpc::call_command_string("d.directory", rpc::make_target(download));
|
||||
// link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
|
||||
|
||||
} else if (type == "tied") {
|
||||
link = rak::path_expand(rpc::call_command_string("d.tied_to_file", rpc::make_target(download)));
|
||||
|
||||
if (link.empty())
|
||||
return torrent::Object();
|
||||
|
||||
link = rak::path_expand(prefix + link + postfix);
|
||||
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
|
||||
|
||||
} else {
|
||||
throw torrent::input_error("Unknown type argument.");
|
||||
}
|
||||
|
||||
switch (changeType) {
|
||||
case 0:
|
||||
if (symlink(target.c_str(), link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
rak::file_stat fileStat;
|
||||
rak::error_number::clear_global();
|
||||
|
||||
if (!fileStat.update_link(link) || !fileStat.is_link() ||
|
||||
unlink(link.c_str()) == -1){
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s",
|
||||
rak::error_number::current().c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_d_delete_tied(core::Download* download) {
|
||||
const std::string& tie = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
|
||||
|
||||
if (tie.empty())
|
||||
return torrent::Object();
|
||||
|
||||
if (::unlink(rak::path_expand(tie).c_str()) == -1)
|
||||
control->core()->push_log_std("Could not unlink tied file: " + std::string(rak::error_number::current().c_str()));
|
||||
|
||||
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(download));
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
apply_d_directory(core::Download* download, const std::string& name) {
|
||||
if (!download->file_list()->is_multi_file())
|
||||
download->set_root_directory(name);
|
||||
else if (name.empty() || *name.rbegin() == '/')
|
||||
download->set_root_directory(name + download->info()->name());
|
||||
else
|
||||
download->set_root_directory(name + "/" + download->info()->name());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_d_connection_type(core::Download* download, const std::string& name) {
|
||||
torrent::Download::ConnectionType t =
|
||||
(torrent::Download::ConnectionType)torrent::option_find_string(torrent::OPTION_CONNECTION_TYPE, name.c_str());
|
||||
|
||||
download->download()->set_connection_type(t);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_d_choke_heuristics(core::Download* download, const std::string& name, bool is_down) {
|
||||
torrent::Download::HeuristicType t =
|
||||
(torrent::Download::HeuristicType)torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str());
|
||||
|
||||
if (is_down)
|
||||
download->download()->set_download_choke_heuristic(t);
|
||||
else
|
||||
download->download()->set_upload_choke_heuristic(t);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
const char*
|
||||
retrieve_d_priority_str(core::Download* download) {
|
||||
switch (download->priority()) {
|
||||
case 0:
|
||||
return "off";
|
||||
case 1:
|
||||
return "low";
|
||||
case 2:
|
||||
return "normal";
|
||||
case 3:
|
||||
return "high";
|
||||
default:
|
||||
throw torrent::input_error("Priority out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_ratio(core::Download* download) {
|
||||
if (download->is_hash_checking())
|
||||
return int64_t();
|
||||
|
||||
int64_t bytesDone = download->download()->bytes_done();
|
||||
int64_t upTotal = download->info()->up_rate()->total();
|
||||
|
||||
return bytesDone > 0 ? (1000 * upTotal) / bytesDone : 0;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_d_custom(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("Missing key argument.");
|
||||
|
||||
const std::string& key = itr->as_string();
|
||||
|
||||
if (++itr == args.end())
|
||||
throw torrent::bencode_error("Missing value argument.");
|
||||
|
||||
download->bencode()->get_key("rtorrent").
|
||||
insert_preserve_copy("custom", torrent::Object::create_map()).first->second.
|
||||
insert_key(key, itr->as_string());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom(core::Download* download, const std::string& key) {
|
||||
try {
|
||||
return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
|
||||
|
||||
} catch (torrent::bencode_error& e) {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom_throw(core::Download* download, const std::string& key) {
|
||||
try {
|
||||
return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
|
||||
|
||||
} catch (torrent::bencode_error& e) {
|
||||
throw torrent::input_error("No such custom value.");
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_bitfield(core::Download* download) {
|
||||
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
|
||||
|
||||
if (bitField->empty())
|
||||
return torrent::Object("");
|
||||
|
||||
return torrent::Object(rak::transform_hex(bitField->begin(), bitField->end()));
|
||||
}
|
||||
|
||||
struct call_add_d_peer_t {
|
||||
call_add_d_peer_t(core::Download* d, int port) : m_download(d), m_port(port) { }
|
||||
|
||||
void operator() (const sockaddr* sa, int err) {
|
||||
if (sa == NULL) {
|
||||
lt_log_print(torrent::LOG_CONNECTION_WARN, "Could not resolve hostname for added peer.");
|
||||
} else {
|
||||
m_download->download()->add_peer(sa, m_port);
|
||||
}
|
||||
}
|
||||
|
||||
core::Download* m_download;
|
||||
int m_port;
|
||||
};
|
||||
|
||||
void
|
||||
apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
int port, ret;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
|
||||
if (download->download()->info()->is_private())
|
||||
throw torrent::input_error("Download is private.");
|
||||
|
||||
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;
|
||||
else if (ret != 2)
|
||||
throw torrent::input_error("Could not parse host.");
|
||||
|
||||
if (port < 1 || port > 65535)
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_unspec, SOCK_STREAM, call_add_d_peer_t(download, port));
|
||||
}
|
||||
|
||||
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
|
||||
f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
// We ignore the first arg for now, but it will be used for
|
||||
// selecting what files to include.
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
std::vector<rak::regex> regex_list;
|
||||
|
||||
bool use_regex = true;
|
||||
|
||||
if (args.front().is_list())
|
||||
std::transform(args.front().as_list().begin(), args.front().as_list().end(),
|
||||
std::back_inserter(regex_list),
|
||||
std::bind(&torrent::Object::as_string_c, std::placeholders::_1));
|
||||
else if (args.front().is_string() && !args.front().as_string().empty())
|
||||
regex_list.push_back(args.front().as_string());
|
||||
else
|
||||
use_regex = false;
|
||||
|
||||
for (torrent::FileList::const_iterator itr = download->file_list()->begin(), last = download->file_list()->end(); itr != last; itr++) {
|
||||
if (use_regex &&
|
||||
std::find_if(regex_list.begin(), regex_list.end(),
|
||||
std::bind(&rak::regex::operator(), std::placeholders::_1, (*itr)->path()->as_string())) == regex_list.end())
|
||||
continue;
|
||||
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
t_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
// We ignore the first arg for now, but it will be used for
|
||||
// selecting what files to include.
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (int itr = 0, last = download->tracker_list()->size(); itr != last; itr++) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
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);
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(t), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
p_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
// We ignore the first arg for now, but it will be used for
|
||||
// selecting what files to include.
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end();
|
||||
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(); 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);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
p_call_target(const torrent::Object::list_type& args) {
|
||||
if (args.empty() || args.begin() + 1 == args.end() || args.begin() + 2 == args.end())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
// We ignore the first arg for now, but it will be used for
|
||||
// selecting what files to include.
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
|
||||
core::Download* download = control->core()->download_list()->find_hex_ptr(itr++->as_string().c_str());
|
||||
const std::string& peer_id = itr++->as_string();
|
||||
const std::string& command_key = itr++->as_string();
|
||||
|
||||
torrent::HashString hash;
|
||||
|
||||
if (peer_id.size() != 40 ||
|
||||
torrent::hash_string_from_hex_c_str(peer_id.c_str(), hash) == peer_id.c_str())
|
||||
throw torrent::input_error("Not a hash string.");
|
||||
|
||||
torrent::ConnectionList::iterator peerItr = download->connection_list()->find(hash.c_str());
|
||||
|
||||
if (peerItr == download->connection_list()->end())
|
||||
throw torrent::input_error("Could not find peer.");
|
||||
|
||||
if (itr == args.end())
|
||||
return rpc::commands.call(command_key.c_str());
|
||||
|
||||
if (itr + 1 == args.end())
|
||||
return rpc::commands.call(command_key.c_str(), *itr);
|
||||
|
||||
return rpc::commands.call(command_key.c_str(), torrent::Object::create_list_range(itr, args.end()));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_tracker_insert(core::Download* download, const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
int64_t group;
|
||||
|
||||
if (args.front().is_string())
|
||||
rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group);
|
||||
else
|
||||
group = args.front().as_value();
|
||||
|
||||
if (group < 0 || group > 32)
|
||||
throw torrent::input_error("Tracker group number invalid.");
|
||||
|
||||
download->download()->tracker_list()->insert_url(group, args.back().as_string(), true);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
//
|
||||
// New download commands and macros:
|
||||
//
|
||||
|
||||
torrent::Object&
|
||||
download_get_variable(core::Download* download, const char* first_key, const char* second_key = NULL) {
|
||||
if (second_key == NULL)
|
||||
return download->bencode()->get_key(first_key);
|
||||
|
||||
return download->bencode()->get_key(first_key).get_key(second_key);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_set_variable(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key = NULL) {
|
||||
if (second_key == NULL)
|
||||
return download->bencode()->get_key(first_key) = torrent::object_create_normal(rawArgs);
|
||||
|
||||
return download->bencode()->get_key(first_key).get_key(second_key) = torrent::object_create_normal(rawArgs);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_set_variable_value(core::Download* download, const torrent::Object::value_type& args,
|
||||
const char* first_key, const char* second_key = NULL) {
|
||||
if (second_key == NULL)
|
||||
return download->bencode()->get_key(first_key) = args;
|
||||
|
||||
return download->bencode()->get_key(first_key).get_key(second_key) = args;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_set_variable_value_ifz(core::Download* download, const torrent::Object::value_type& args,
|
||||
const char* first_key, const char* second_key = NULL) {
|
||||
torrent::Object& object = second_key == NULL ?
|
||||
download->bencode()->get_key(first_key) :
|
||||
download->bencode()->get_key(first_key).get_key(second_key);
|
||||
|
||||
if (object.as_value() == 0)
|
||||
object = args;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
download_set_variable_string(core::Download* download, const torrent::Object::string_type& args,
|
||||
const char* first_key, const char* second_key = NULL) {
|
||||
if (second_key == NULL)
|
||||
return download->bencode()->get_key(first_key) = args;
|
||||
|
||||
return download->bencode()->get_key(first_key).get_key(second_key) = args;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
download_get_variable(download, first_key, second_key).as_list().push_back(rawArgs);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back_unique(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
if (std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) == list.end())
|
||||
list.push_back(rawArgs);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_has(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
return (int64_t)(std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) != list.end());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_remove(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
|
||||
|
||||
list.erase(std::remove_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)), list.end());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
#define CMD2_ON_INFO(func) std::bind(&torrent::DownloadInfo::func, std::bind(&core::Download::info, std::placeholders::_1))
|
||||
#define CMD2_ON_DATA(func) std::bind(&torrent::download_data::func, std::bind(&core::Download::data, std::placeholders::_1))
|
||||
#define CMD2_ON_DL(func) std::bind(&torrent::Download::func, std::bind(&core::Download::download, std::placeholders::_1))
|
||||
#define CMD2_ON_FL(func) std::bind(&torrent::FileList::func, std::bind(&core::Download::file_list, std::placeholders::_1))
|
||||
|
||||
#define CMD2_BIND_DL std::bind(&core::Download::download, std::placeholders::_1)
|
||||
#define CMD2_BIND_CL std::bind(&core::Download::connection_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_FL std::bind(&core::Download::file_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_PL std::bind(&core::Download::c_peer_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_TL std::bind(&core::Download::tracker_list, std::placeholders::_1)
|
||||
#define CMD2_BIND_TC std::bind(&core::Download::tracker_controller, std::placeholders::_1)
|
||||
|
||||
#define CMD2_BIND_INFO std::bind(&core::Download::info, std::placeholders::_1)
|
||||
#define CMD2_BIND_DATA std::bind(&core::Download::data, std::placeholders::_1)
|
||||
|
||||
#define CMD2_DL_VAR_VALUE(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key));
|
||||
|
||||
#define CMD2_DL_VAR_VALUE_PUBLIC(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_VALUE(key ".set", std::bind(&download_set_variable_value, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key));
|
||||
|
||||
#define CMD2_DL_TIMESTAMP(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key)); \
|
||||
CMD2_DL_VALUE_P(key ".set_if_z", std::bind(&download_set_variable_value_ifz, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key)); \
|
||||
|
||||
#define CMD2_DL_VAR_STRING(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_STRING_P(key ".set", std::bind(&download_set_variable_string, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key));
|
||||
|
||||
#define CMD2_DL_VAR_STRING_PUBLIC(key, first_key, second_key) \
|
||||
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
|
||||
CMD2_DL_STRING(key ".set", std::bind(&download_set_variable_string, \
|
||||
std::placeholders::_1, std::placeholders::_2, \
|
||||
first_key, second_key));
|
||||
|
||||
int64_t cg_d_group(core::Download* download);
|
||||
const std::string& cg_d_group_name(core::Download* download);
|
||||
void cg_d_group_set(core::Download* download, const torrent::Object& arg);
|
||||
|
||||
void
|
||||
initialize_command_download() {
|
||||
CMD2_DL("d.hash", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(hash)));
|
||||
CMD2_DL("d.local_id", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
|
||||
CMD2_DL("d.local_id_html", std::bind(&rak::copy_escape_html_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
|
||||
CMD2_DL("d.bitfield", std::bind(&retrieve_d_bitfield, std::placeholders::_1));
|
||||
CMD2_DL("d.base_path", std::bind(&retrieve_d_base_path, std::placeholders::_1));
|
||||
CMD2_DL("d.base_filename", std::bind(&retrieve_d_base_filename, std::placeholders::_1));
|
||||
|
||||
CMD2_DL("d.name", CMD2_ON_INFO(name));
|
||||
CMD2_DL("d.creation_date", CMD2_ON_INFO(creation_date));
|
||||
CMD2_DL("d.load_date", CMD2_ON_INFO(load_date));
|
||||
|
||||
//
|
||||
// Network related:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.up.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.up.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.down.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.down.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.skip.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(skip_rate)));
|
||||
CMD2_DL ("d.skip.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(skip_rate)));
|
||||
|
||||
CMD2_DL ("d.peer_exchange", CMD2_ON_INFO(is_pex_enabled));
|
||||
CMD2_DL_VALUE_V ("d.peer_exchange.set", std::bind(&torrent::Download::set_pex_enabled, CMD2_BIND_DL, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_LIST ("d.create_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_DL_LIST ("d.delete_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 1));
|
||||
CMD2_DL ("d.delete_tied", std::bind(&apply_d_delete_tied, std::placeholders::_1));
|
||||
|
||||
CMD2_FUNC_SINGLE("d.start", "d.hashing_failed.set=0 ;view.set_visible=started");
|
||||
CMD2_FUNC_SINGLE("d.stop", "view.set_visible=stopped");
|
||||
CMD2_FUNC_SINGLE("d.try_start", "branch=\"or={d.hashing_failed=,d.ignore_commands=}\",{},{view.set_visible=started}");
|
||||
CMD2_FUNC_SINGLE("d.try_stop", "branch=d.ignore_commands=, {}, {view.set_visible=stopped}");
|
||||
CMD2_FUNC_SINGLE("d.try_close", "branch=d.ignore_commands=, {}, {view.set_visible=stopped, d.close=}");
|
||||
|
||||
//
|
||||
// Control functinos:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.is_open", CMD2_ON_INFO(is_open));
|
||||
CMD2_DL ("d.is_active", CMD2_ON_INFO(is_active));
|
||||
CMD2_DL ("d.is_hash_checked", std::bind(&torrent::Download::is_hash_checked, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_hash_checking", std::bind(&torrent::Download::is_hash_checking, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_multi_file", std::bind(&torrent::FileList::is_multi_file, CMD2_BIND_FL));
|
||||
CMD2_DL ("d.is_private", CMD2_ON_INFO(is_private));
|
||||
CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active));
|
||||
CMD2_DL ("d.is_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));
|
||||
CMD2_DL_V ("d.open", std::bind(&core::DownloadList::open_throw, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.close", std::bind(&core::DownloadList::close_throw, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.close.directly", std::bind(&core::DownloadList::close_directly, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.erase", std::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.check_hash", std::bind(&core::DownloadList::check_hash, control->core()->download_list(), std::placeholders::_1));
|
||||
|
||||
CMD2_DL ("d.save_resume", std::bind(&core::DownloadStore::save_resume, control->core()->download_store(), std::placeholders::_1));
|
||||
CMD2_DL ("d.save_full_session", std::bind(&core::DownloadStore::save_full, control->core()->download_store(), std::placeholders::_1));
|
||||
|
||||
CMD2_DL_V ("d.update_priorities", CMD2_ON_DL(update_priorities));
|
||||
|
||||
CMD2_DL_STRING_V("add_peer", std::bind(&apply_d_add_peer, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
//
|
||||
// Custom settings:
|
||||
//
|
||||
|
||||
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_VAR_STRING_PUBLIC("d.custom1", "rtorrent", "custom1");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom2", "rtorrent", "custom2");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom3", "rtorrent", "custom3");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom4", "rtorrent", "custom4");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom5", "rtorrent", "custom5");
|
||||
|
||||
// 0 - stopped
|
||||
// 1 - started
|
||||
CMD2_DL_VAR_VALUE("d.state", "rtorrent", "state");
|
||||
CMD2_DL_VAR_VALUE("d.complete", "rtorrent", "complete");
|
||||
|
||||
CMD2_FUNC_SINGLE ("d.incomplete", "not=(d.complete)");
|
||||
|
||||
// 0 off
|
||||
// 1 scheduled, being controlled by a download scheduler. Includes a priority.
|
||||
// 3 forced off
|
||||
// 2 forced on
|
||||
CMD2_DL_VAR_VALUE("d.mode", "rtorrent", "mode");
|
||||
|
||||
// 0 - Not hashing
|
||||
// 1 - Normal hashing
|
||||
// 2 - Download finished, hashing
|
||||
// 3 - Rehashing
|
||||
CMD2_DL_VAR_VALUE("d.hashing", "rtorrent", "hashing");
|
||||
|
||||
// 'tied_to_file' is the file the download is associated with, and
|
||||
// can be changed by the user.
|
||||
//
|
||||
// 'loaded_file' is the file this instance of the torrent was loaded
|
||||
// from, and should not be changed.
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.tied_to_file", "rtorrent", "tied_to_file");
|
||||
CMD2_DL_VAR_STRING("d.loaded_file", "rtorrent", "loaded_file");
|
||||
|
||||
// The "state_changed" variable is required to be a valid unix time
|
||||
// value, it indicates the last time the torrent changed its state,
|
||||
// resume/pause.
|
||||
CMD2_DL_VAR_VALUE("d.state_changed", "rtorrent", "state_changed");
|
||||
CMD2_DL_VAR_VALUE("d.state_counter", "rtorrent", "state_counter");
|
||||
CMD2_DL_VAR_VALUE_PUBLIC("d.ignore_commands", "rtorrent", "ignore_commands");
|
||||
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.started", "rtorrent", "timestamp.started");
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.finished", "rtorrent", "timestamp.finished");
|
||||
|
||||
CMD2_DL ("d.connection_current", std::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type)));
|
||||
CMD2_DL_STRING("d.connection_current.set", std::bind(&apply_d_connection_type, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_VAR_STRING("d.connection_leech", "rtorrent", "connection_leech");
|
||||
CMD2_DL_VAR_STRING("d.connection_seed", "rtorrent", "connection_seed");
|
||||
|
||||
CMD2_DL ("d.up.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(upload_choke_heuristic)));
|
||||
CMD2_DL_STRING("d.up.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, false));
|
||||
CMD2_DL ("d.down.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(download_choke_heuristic)));
|
||||
CMD2_DL_STRING("d.down.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, true));
|
||||
|
||||
CMD2_DL_VAR_STRING("d.up.choke_heuristics.leech", "rtorrent", "choke_heuristics.up.leech");
|
||||
CMD2_DL_VAR_STRING("d.up.choke_heuristics.seed", "rtorrent", "choke_heuristics.up.seed");
|
||||
CMD2_DL_VAR_STRING("d.down.choke_heuristics.leech", "rtorrent", "choke_heuristics.down.leech");
|
||||
CMD2_DL_VAR_STRING("d.down.choke_heuristics.seed", "rtorrent", "choke_heuristics.down.seed");
|
||||
|
||||
CMD2_DL ("d.hashing_failed", std::bind(&core::Download::is_hash_failed, std::placeholders::_1));
|
||||
CMD2_DL_VALUE_V ("d.hashing_failed.set", std::bind(&core::Download::set_hash_failed, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.views", std::bind(&download_get_variable, std::placeholders::_1, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.has", std::bind(&d_list_has, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.remove", std::bind(&d_list_remove, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.push_back", std::bind(&d_list_push_back, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
CMD2_DL ("d.views.push_back_unique", std::bind(&d_list_push_back_unique, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
|
||||
|
||||
// This command really needs to be improved, so we have proper
|
||||
// logging support.
|
||||
CMD2_DL ("d.message", std::bind(&core::Download::message, std::placeholders::_1));
|
||||
CMD2_DL_STRING_V("d.message.set", std::bind(&core::Download::set_message, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.max_file_size", CMD2_ON_FL(max_file_size));
|
||||
CMD2_DL_VALUE_V ("d.max_file_size.set", std::bind(&torrent::FileList::set_max_file_size, CMD2_BIND_FL, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.peers_min", std::bind(&torrent::ConnectionList::min_size, CMD2_BIND_CL));
|
||||
CMD2_DL_VALUE_V ("d.peers_min.set", std::bind(&torrent::ConnectionList::set_min_size, CMD2_BIND_CL, std::placeholders::_2));
|
||||
CMD2_DL ("d.peers_max", std::bind(&torrent::ConnectionList::max_size, CMD2_BIND_CL));
|
||||
CMD2_DL_VALUE_V ("d.peers_max.set", std::bind(&torrent::ConnectionList::set_max_size, CMD2_BIND_CL, std::placeholders::_2));
|
||||
CMD2_DL ("d.uploads_max", std::bind(&torrent::Download::uploads_max, CMD2_BIND_DL));
|
||||
CMD2_DL_VALUE_V ("d.uploads_max.set", std::bind(&torrent::Download::set_uploads_max, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.uploads_min", std::bind(&torrent::Download::uploads_min, CMD2_BIND_DL));
|
||||
CMD2_DL_VALUE_V ("d.uploads_min.set", std::bind(&torrent::Download::set_uploads_min, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.downloads_max", std::bind(&torrent::Download::downloads_max, CMD2_BIND_DL));
|
||||
CMD2_DL_VALUE_V ("d.downloads_max.set", std::bind(&torrent::Download::set_downloads_max, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.downloads_min", std::bind(&torrent::Download::downloads_min, CMD2_BIND_DL));
|
||||
CMD2_DL_VALUE_V ("d.downloads_min.set", std::bind(&torrent::Download::set_downloads_min, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.peers_connected", std::bind(&torrent::ConnectionList::size, CMD2_BIND_CL));
|
||||
CMD2_DL ("d.peers_not_connected", std::bind(&torrent::PeerList::available_list_size, CMD2_BIND_PL));
|
||||
|
||||
CMD2_DL ("d.peers_complete", CMD2_ON_DL(peers_complete));
|
||||
CMD2_DL ("d.peers_accounted", CMD2_ON_DL(peers_accounted));
|
||||
|
||||
CMD2_DL_V ("d.disconnect.seeders", std::bind(&torrent::ConnectionList::erase_seeders, CMD2_BIND_CL));
|
||||
|
||||
CMD2_DL ("d.accepting_seeders", CMD2_ON_INFO(is_accepting_seeders));
|
||||
CMD2_DL_V ("d.accepting_seeders.enable", std::bind(&torrent::DownloadInfo::public_set_flags, CMD2_BIND_INFO, torrent::DownloadInfo::flag_accepting_seeders));
|
||||
CMD2_DL_V ("d.accepting_seeders.disable", std::bind(&torrent::DownloadInfo::public_unset_flags, CMD2_BIND_INFO, torrent::DownloadInfo::flag_accepting_seeders));
|
||||
|
||||
CMD2_DL ("d.throttle_name", std::bind(&download_get_variable, std::placeholders::_1, "rtorrent", "throttle_name"));
|
||||
CMD2_DL_STRING_V("d.throttle_name.set", std::bind(&core::Download::set_throttle_name, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.bytes_done", CMD2_ON_DL(bytes_done));
|
||||
CMD2_DL ("d.ratio", std::bind(&retrieve_d_ratio, std::placeholders::_1));
|
||||
CMD2_DL ("d.chunks_hashed", CMD2_ON_DL(chunks_hashed));
|
||||
CMD2_DL ("d.free_diskspace", CMD2_ON_FL(free_diskspace));
|
||||
|
||||
CMD2_DL ("d.size_files", CMD2_ON_FL(size_files));
|
||||
CMD2_DL ("d.size_bytes", CMD2_ON_FL(size_bytes));
|
||||
CMD2_DL ("d.size_chunks", CMD2_ON_FL(size_chunks));
|
||||
CMD2_DL ("d.chunk_size", CMD2_ON_FL(chunk_size));
|
||||
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));
|
||||
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'.
|
||||
CMD2_DL ("d.tracker_focus", std::bind(&core::Download::tracker_list_size, std::placeholders::_1));
|
||||
CMD2_DL ("d.tracker_size", std::bind(&core::Download::tracker_list_size, std::placeholders::_1));
|
||||
|
||||
CMD2_DL_LIST ("d.tracker.insert", std::bind(&download_tracker_insert, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_VALUE_V ("d.tracker.send_scrape", std::bind(&torrent::TrackerController::scrape_request, CMD2_BIND_TC, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.directory", CMD2_ON_FL(root_dir));
|
||||
CMD2_DL_STRING_V("d.directory.set", std::bind(&apply_d_directory, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL ("d.directory_base", CMD2_ON_FL(root_dir));
|
||||
CMD2_DL_STRING_V("d.directory_base.set", std::bind(&core::Download::set_root_directory, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL ("d.priority", std::bind(&core::Download::priority, std::placeholders::_1));
|
||||
CMD2_DL ("d.priority_str", std::bind(&retrieve_d_priority_str, std::placeholders::_1));
|
||||
CMD2_DL_VALUE_V ("d.priority.set", std::bind(&core::Download::set_priority, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
// CMD2_DL ("d.group", std::bind(&torrent::resource_manager_entry::group,
|
||||
// std::bind(&torrent::ResourceManager::entry_at, torrent::resource_manager(),
|
||||
// std::bind(&core::Download::main, std::placeholders::_1))));
|
||||
|
||||
// CMD2_DL_V ("d.group.set", std::bind(&torrent::ResourceManager::set_group,
|
||||
// torrent::resource_manager(),
|
||||
// std::bind(&torrent::ResourceManager::find_throw, torrent::resource_manager(),
|
||||
// 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_V ("d.group.set", std::bind(&cg_d_group_set, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_LIST ("f.multicall", std::bind(&f_multicall, std::placeholders::_1, std::placeholders::_2));
|
||||
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));
|
||||
|
||||
CMD2_ANY_LIST ("p.call_target", std::bind(&p_call_target, std::placeholders::_2));
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/parse.h"
|
||||
|
||||
std::string
|
||||
system_method_generate_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
|
||||
std::string command;
|
||||
|
||||
while (first != last) {
|
||||
if (!command.empty())
|
||||
command += " ;";
|
||||
|
||||
command += (first++)->as_string();
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
void
|
||||
system_method_generate_command2(torrent::Object* object, torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) {
|
||||
if (first == last) {
|
||||
// TODO: Use empty object.
|
||||
*object = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (first->is_string()) {
|
||||
std::string command;
|
||||
|
||||
while (first != last) {
|
||||
if (!command.empty())
|
||||
command += " ;";
|
||||
|
||||
command += (first++)->as_string();
|
||||
}
|
||||
|
||||
*object = command;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (first + 1 == last) {
|
||||
if (!first->is_dict_key())
|
||||
throw torrent::input_error("New command of wrong type.");
|
||||
|
||||
*object = *first;
|
||||
|
||||
uint32_t flags = object->flags() & torrent::Object::mask_function;
|
||||
object->unset_flags(torrent::Object::mask_function);
|
||||
object->set_flags((flags >> 1) & torrent::Object::mask_function);
|
||||
|
||||
} else {
|
||||
*object = torrent::Object::create_list();
|
||||
|
||||
while (first != last) {
|
||||
if (!first->is_dict_key())
|
||||
throw torrent::input_error("New command of wrong type.");
|
||||
|
||||
object->as_list().push_back(*first++);
|
||||
|
||||
uint32_t flags = object->as_list().back().flags() & torrent::Object::mask_function;
|
||||
object->as_list().back().unset_flags(torrent::Object::mask_function);
|
||||
object->as_list().back().set_flags((flags >> 1) & torrent::Object::mask_function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// torrent::Object
|
||||
// system_method_insert_function(const torrent::Object::list_type& args, int flags) {
|
||||
|
||||
// }
|
||||
|
||||
torrent::Object
|
||||
system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
torrent::Object::list_const_iterator itrArgs = args.begin();
|
||||
const std::string& rawKey = (itrArgs++)->as_string();
|
||||
|
||||
if (rawKey.empty() ||
|
||||
control->object_storage()->find_local(torrent::raw_string::from_string(rawKey)) != control->object_storage()->end(0) ||
|
||||
rpc::commands.has(rawKey) || rpc::commands.has(rawKey + ".set"))
|
||||
throw torrent::input_error("Invalid key.");
|
||||
|
||||
torrent::Object value;
|
||||
|
||||
switch (flags & rpc::object_storage::mask_type) {
|
||||
case rpc::object_storage::flag_bool_type:
|
||||
case rpc::object_storage::flag_value_type:
|
||||
value = itrArgs != args.end() ? rpc::convert_to_value(*itrArgs) : int64_t();
|
||||
break;
|
||||
case rpc::object_storage::flag_string_type:
|
||||
value = itrArgs != args.end() ? rpc::convert_to_string(*itrArgs) : "";
|
||||
break;
|
||||
case rpc::object_storage::flag_function_type:
|
||||
system_method_generate_command2(&value, itrArgs, args.end());
|
||||
break;
|
||||
case rpc::object_storage::flag_multi_type:
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Invalid type.");
|
||||
}
|
||||
|
||||
int cmd_flags = 0;
|
||||
|
||||
if (!(flags & rpc::object_storage::flag_static))
|
||||
cmd_flags |= rpc::CommandMap::flag_modifiable;
|
||||
if (!(flags & rpc::object_storage::flag_private))
|
||||
cmd_flags |= rpc::CommandMap::flag_public_xmlrpc;
|
||||
|
||||
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(rawKey),
|
||||
std::bind(&rpc::object_storage::call_function_str, control->object_storage(),
|
||||
rawKey, std::placeholders::_1, std::placeholders::_2),
|
||||
&rpc::command_base_call<rpc::target_type>,
|
||||
cmd_flags, NULL, NULL);
|
||||
|
||||
} else {
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call<rpc::target_type> >::type>
|
||||
(create_new_key(rawKey),
|
||||
std::bind(&rpc::object_storage::get_str, control->object_storage(), rawKey),
|
||||
&rpc::command_base_call<rpc::target_type>,
|
||||
cmd_flags, NULL, NULL);
|
||||
}
|
||||
|
||||
// Not the right argument.
|
||||
// if (flags & rpc::object_storage::flag_rlookup) {
|
||||
// rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_string<rpc::target_type> >::type>
|
||||
// (create_new_key<9>(rawKey, ".rlookup"),
|
||||
// std::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), rawKey),
|
||||
// &rpc::command_base_call_string<rpc::target_type>,
|
||||
// cmd_flags, NULL, NULL);
|
||||
// }
|
||||
|
||||
// TODO: Next... Make test class for this.
|
||||
|
||||
// // Ehm... no proper handling if these throw.
|
||||
|
||||
if (!(flags & rpc::object_storage::flag_constant)) {
|
||||
switch (flags & rpc::object_storage::mask_type) {
|
||||
case rpc::object_storage::flag_bool_type:
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type> >::type>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_bool, control->object_storage(), rawKey, std::placeholders::_2),
|
||||
&rpc::command_base_call_value<rpc::target_type>,
|
||||
cmd_flags, NULL, NULL);
|
||||
break;
|
||||
case rpc::object_storage::flag_value_type:
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_value<rpc::target_type> >::type>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_value, control->object_storage(), rawKey, std::placeholders::_2),
|
||||
&rpc::command_base_call_value<rpc::target_type>,
|
||||
cmd_flags, NULL, NULL);
|
||||
break;
|
||||
case rpc::object_storage::flag_string_type:
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::command_base_call_string<rpc::target_type> >::type>
|
||||
(create_new_key<5>(rawKey, ".set"),
|
||||
std::bind(&rpc::object_storage::set_str_string, control->object_storage(), rawKey, std::placeholders::_2),
|
||||
&rpc::command_base_call_string<rpc::target_type>,
|
||||
cmd_flags, NULL, NULL);
|
||||
break;
|
||||
case rpc::object_storage::flag_function_type:
|
||||
case rpc::object_storage::flag_multi_type:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// method.insert <generic> {name, "simple|private|const", ...}
|
||||
// method.insert <generic> {name, "multi|private|const"}
|
||||
// method.insert <generic> {name, "value|private|const"}
|
||||
// method.insert <generic> {name, "value|private|const", value}
|
||||
// method.insert <generic> {name, "bool|private|const"}
|
||||
// method.insert <generic> {name, "bool|private|const", bool}
|
||||
// method.insert <generic> {name, "string|private|const"}
|
||||
// method.insert <generic> {name, "string|private|const", string}
|
||||
//
|
||||
// Add a new user-defined method called 'name' and any number of
|
||||
// lines.
|
||||
//
|
||||
// TODO: Make a static version of this that doesn't need to be called
|
||||
// as a command, and which takes advantage of static const char
|
||||
// strings, etc.
|
||||
torrent::Object
|
||||
system_method_insert(const torrent::Object::list_type& args) {
|
||||
if (args.empty() || ++args.begin() == args.end())
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
torrent::Object::list_const_iterator itrArgs = args.begin();
|
||||
const std::string& rawKey = (itrArgs++)->as_string();
|
||||
|
||||
if (rawKey.empty() || rpc::commands.has(rawKey))
|
||||
throw torrent::input_error("Invalid key.");
|
||||
|
||||
int flags = rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc;
|
||||
|
||||
const std::string& options = itrArgs->as_string();
|
||||
|
||||
// TODO: Replace find with a method that does '|' separated search
|
||||
// for all valid options, and then cross-checks that unmixable ones
|
||||
// aren't in there. Use a bitfield.
|
||||
|
||||
if (options.find("private") != std::string::npos)
|
||||
flags &= ~rpc::CommandMap::flag_public_xmlrpc;
|
||||
if (options.find("const") != std::string::npos)
|
||||
flags &= ~rpc::CommandMap::flag_modifiable;
|
||||
|
||||
if (options.find("multi") != std::string::npos) {
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
new_args.push_back(system_method_generate_command(++itrArgs, args.end()));
|
||||
|
||||
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) {
|
||||
torrent::Object::list_type new_args;
|
||||
new_args.push_back(rawKey);
|
||||
|
||||
if (++itrArgs != args.end())
|
||||
new_args.insert(new_args.end(), itrArgs, args.end());
|
||||
|
||||
int new_flags;
|
||||
|
||||
if (options.find("value") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_value_type;
|
||||
else if (options.find("bool") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_bool_type;
|
||||
else if (options.find("string") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_string_type;
|
||||
else if (options.find("list") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_list_type;
|
||||
else if (options.find("simple") != std::string::npos)
|
||||
new_flags = rpc::object_storage::flag_function_type;
|
||||
else
|
||||
throw torrent::input_error("No support for 'list' variable type.");
|
||||
|
||||
if (options.find("static") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_static;
|
||||
if (options.find("private") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_private;
|
||||
if (options.find("const") != std::string::npos)
|
||||
new_flags |= rpc::object_storage::flag_constant;
|
||||
|
||||
return system_method_insert_object(new_args, new_flags);
|
||||
|
||||
} else {
|
||||
// THROW.
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// method.erase <> {name}
|
||||
//
|
||||
// Erase a modifiable method called 'name. Trying to remove methods
|
||||
// that aren't modifiable, e.g. defined by rtorrent or set to
|
||||
// read-only by the user, will result in an error.
|
||||
torrent::Object
|
||||
system_method_erase(const torrent::Object::string_type& args) {
|
||||
rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str());
|
||||
|
||||
if (itr == rpc::commands.end())
|
||||
return torrent::Object();
|
||||
|
||||
if (!rpc::commands.is_modifiable(itr))
|
||||
throw torrent::input_error("Command not modifiable.");
|
||||
|
||||
rpc::commands.erase(itr);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_method_redirect(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
std::string new_key = torrent::object_create_string(args.front());
|
||||
std::string dest_key = torrent::object_create_string(args.back());
|
||||
|
||||
rpc::commands.create_redirect(create_new_key(new_key), create_new_key(dest_key),
|
||||
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
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()));
|
||||
|
||||
if (itr == control->object_storage()->end(0) || itr->second.flags & rpc::object_storage::flag_constant)
|
||||
throw torrent::input_error("Command is not modifiable.");
|
||||
|
||||
return control->object_storage()->set_str_function(args.front().as_string(),
|
||||
system_method_generate_command(++args.begin(), args.end()));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_method_has_key(const torrent::Object::list_type& args) {
|
||||
if (args.empty() || ++args.begin() == args.end())
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
torrent::Object::list_const_iterator itrArgs = args.begin();
|
||||
const std::string& key = (itrArgs++)->as_string();
|
||||
const std::string& cmd_key = (itrArgs++)->as_string();
|
||||
|
||||
return control->object_storage()->has_str_multi_key(key, cmd_key);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_method_set_key(const torrent::Object::list_type& args) {
|
||||
if (args.empty() || ++args.begin() == args.end())
|
||||
throw torrent::input_error("Invalid argument count.");
|
||||
|
||||
torrent::Object::list_const_iterator itrArgs = args.begin();
|
||||
const std::string& key = (itrArgs++)->as_string();
|
||||
const std::string& cmd_key = (itrArgs++)->as_string();
|
||||
|
||||
if (itrArgs == args.end()) {
|
||||
control->object_storage()->erase_str_multi_key(key, cmd_key);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
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()));
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_method_list_keys(const torrent::Object::string_type& args) {
|
||||
const torrent::Object::map_type& multi_cmd = control->object_storage()->get_str(args).as_map();
|
||||
|
||||
torrent::Object rawResult = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = rawResult.as_list();
|
||||
|
||||
for (torrent::Object::map_const_iterator itr = multi_cmd.begin(), last = multi_cmd.end(); itr != last; itr++)
|
||||
result.push_back(itr->first);
|
||||
|
||||
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));
|
||||
|
||||
void
|
||||
initialize_command_dynamic() {
|
||||
CMD2_VAR_BOOL ("method.use_deprecated", false);
|
||||
CMD2_VAR_VALUE ("method.use_intermediate", 1);
|
||||
|
||||
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_METHOD_INSERT("method.insert.simple", rpc::object_storage::flag_function_type);
|
||||
CMD2_METHOD_INSERT("method.insert.c_simple", rpc::object_storage::flag_constant | rpc::object_storage::flag_function_type);
|
||||
CMD2_METHOD_INSERT("method.insert.s_c_simple", rpc::object_storage::flag_static |
|
||||
rpc::object_storage::flag_constant |rpc::object_storage::flag_function_type);
|
||||
|
||||
CMD2_ANY_STRING ("method.erase", std::bind(&system_method_erase, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("method.redirect", std::bind(&system_method_redirect, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("method.get", std::bind(&rpc::object_storage::get_str, control->object_storage(),
|
||||
std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("method.set", std::bind(&system_method_set_function, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("method.const", std::bind(&rpc::object_storage::has_flag_str, control->object_storage(),
|
||||
std::placeholders::_2, rpc::object_storage::flag_constant));
|
||||
CMD2_ANY_STRING_V("method.const.enable", std::bind(&rpc::object_storage::enable_flag_str, control->object_storage(),
|
||||
std::placeholders::_2, rpc::object_storage::flag_constant));
|
||||
|
||||
CMD2_ANY_LIST ("method.has_key", std::bind(&system_method_has_key, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("method.set_key", std::bind(&system_method_set_key, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("method.list_keys", std::bind(&system_method_list_keys, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_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));
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <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"
|
||||
#include "core/manager.h"
|
||||
#include "core/view_manager.h"
|
||||
#include "rpc/command_scheduler.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
#include "thread_worker.h"
|
||||
|
||||
torrent::Object
|
||||
apply_on_ratio(const torrent::Object& rawArgs) {
|
||||
const std::string& groupName = rawArgs.as_string();
|
||||
|
||||
char buffer[32 + groupName.size()];
|
||||
sprintf(buffer, "group2.%s.view", groupName.c_str());
|
||||
|
||||
core::ViewManager::iterator viewItr = control->view_manager()->find(rpc::commands.call(buffer, rpc::make_target()).as_string());
|
||||
|
||||
if (viewItr == control->view_manager()->end())
|
||||
throw torrent::input_error("Could not find view.");
|
||||
|
||||
char* bufferStart = buffer + sprintf(buffer, "group2.%s.ratio.", groupName.c_str());
|
||||
|
||||
// first argument: minimum ratio to reach
|
||||
// second argument: minimum upload amount to reach [optional]
|
||||
// third argument: maximum ratio to reach [optional]
|
||||
std::strcpy(bufferStart, "min");
|
||||
int64_t minRatio = rpc::commands.call(buffer, rpc::make_target()).as_value();
|
||||
std::strcpy(bufferStart, "max");
|
||||
int64_t maxRatio = rpc::commands.call(buffer, rpc::make_target()).as_value();
|
||||
std::strcpy(bufferStart, "upload");
|
||||
int64_t minUpload = rpc::commands.call(buffer, rpc::make_target()).as_value();
|
||||
|
||||
std::vector<core::Download*> downloads;
|
||||
|
||||
for (core::View::iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
|
||||
if (!(*itr)->is_seeding() || rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) != 0)
|
||||
continue;
|
||||
|
||||
// rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
|
||||
|
||||
int64_t totalDone = (*itr)->download()->bytes_done();
|
||||
int64_t totalUpload = (*itr)->info()->up_rate()->total();
|
||||
|
||||
if (!(totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) &&
|
||||
!(maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio))
|
||||
continue;
|
||||
|
||||
downloads.push_back(*itr);
|
||||
}
|
||||
|
||||
sprintf(buffer, "group.%s.ratio.command", groupName.c_str());
|
||||
|
||||
for (std::vector<core::Download*>::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) {
|
||||
// rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
|
||||
rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: ");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_start_tied() {
|
||||
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
|
||||
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 1)
|
||||
continue;
|
||||
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
|
||||
if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile)))
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "d.try_start=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_stop_untied() {
|
||||
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
|
||||
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 0)
|
||||
continue;
|
||||
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
|
||||
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)))
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_close_untied() {
|
||||
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
|
||||
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)))
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "d.try_close=");
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_remove_untied() {
|
||||
for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) {
|
||||
rak::file_stat fs;
|
||||
const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
|
||||
|
||||
if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) {
|
||||
// Need to clear tied_to_file so it doesn't try to delete it.
|
||||
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(*itr));
|
||||
|
||||
itr = control->core()->download_list()->erase(itr);
|
||||
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_schedule(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 4)
|
||||
throw torrent::input_error("Wrong number of arguments.");
|
||||
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
|
||||
const std::string& arg1 = (itr++)->as_string();
|
||||
const std::string& arg2 = (itr++)->as_string();
|
||||
const std::string& arg3 = (itr++)->as_string();
|
||||
|
||||
control->command_scheduler()->parse(arg1, arg2, arg3, *itr);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_load(const torrent::Object::list_type& args, int flags) {
|
||||
torrent::Object::list_const_iterator argsItr = args.begin();
|
||||
|
||||
if (argsItr == args.end())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
const std::string& filename = argsItr->as_string();
|
||||
core::Manager::command_list_type commands;
|
||||
|
||||
while (++argsItr != args.end())
|
||||
commands.push_back(argsItr->as_string());
|
||||
|
||||
control->core()->try_create_download_expand(filename, flags, commands);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void apply_import(const std::string& path) { if (!rpc::parse_command_file(path)) throw torrent::input_error("Could not open option file: " + path); }
|
||||
void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); }
|
||||
|
||||
torrent::Object
|
||||
apply_close_low_diskspace(int64_t arg) {
|
||||
core::DownloadList* downloadList = control->core()->download_list();
|
||||
|
||||
bool closed = false;
|
||||
core::Manager::DListItr itr = downloadList->begin();
|
||||
|
||||
while ((itr = std::find_if(itr, downloadList->end(), std::mem_fun(&core::Download::is_downloading)))
|
||||
!= downloadList->end()) {
|
||||
if ((*itr)->file_list()->free_diskspace() < (uint64_t)arg) {
|
||||
downloadList->close(*itr);
|
||||
|
||||
(*itr)->set_hash_failed(true);
|
||||
(*itr)->set_message(std::string("Low diskspace."));
|
||||
|
||||
closed = true;
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
if (closed)
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Closed torrents due to low diskspace.");
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_download_list(const torrent::Object::list_type& args) {
|
||||
torrent::Object::list_const_iterator argsItr = args.begin();
|
||||
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator viewItr;
|
||||
|
||||
if (argsItr != args.end() && !argsItr->as_string().empty())
|
||||
viewItr = viewManager->find((argsItr++)->as_string());
|
||||
else
|
||||
viewItr = viewManager->find("default");
|
||||
|
||||
if (viewItr == viewManager->end())
|
||||
throw torrent::input_error("Could not find view.");
|
||||
|
||||
torrent::Object result = torrent::Object::create_list();
|
||||
torrent::Object::list_type& resultList = result.as_list();
|
||||
|
||||
for (core::View::const_iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) {
|
||||
const torrent::HashString* hashString = &(*itr)->info()->hash();
|
||||
|
||||
resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_multicall(const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator viewItr;
|
||||
|
||||
if (!args.front().as_string().empty())
|
||||
viewItr = viewManager->find(args.front().as_string());
|
||||
else
|
||||
viewItr = viewManager->find("default");
|
||||
|
||||
if (viewItr == viewManager->end())
|
||||
throw torrent::input_error("Could not find view.");
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
unsigned int dlist_size = (*viewItr)->size_visible();
|
||||
core::Download* dlist[dlist_size];
|
||||
|
||||
std::copy((*viewItr)->begin_visible(), (*viewItr)->end_visible(), dlist);
|
||||
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
row.push_back(rpc::parse_command(rpc::make_target(*vItr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
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_STRING ("on_ratio", std::bind(&apply_on_ratio, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("start_tied", std::bind(&apply_start_tied));
|
||||
CMD2_ANY ("stop_untied", std::bind(&apply_stop_untied));
|
||||
CMD2_ANY ("close_untied", std::bind(&apply_close_untied));
|
||||
CMD2_ANY ("remove_untied", std::bind(&apply_remove_untied));
|
||||
|
||||
CMD2_ANY_LIST ("schedule2", std::bind(&apply_schedule, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("schedule_remove2", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING_V("import", std::bind(&apply_import, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("try_import", std::bind(&apply_try_import, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("load.normal", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.raw", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_start | core::Manager::create_raw_data));
|
||||
|
||||
CMD2_ANY_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 ("directory.watch.added", std::bind(&directory_watch_added, std::placeholders::_2));
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/data/file.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
#include <torrent/data/file_list_iterator.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
void
|
||||
apply_f_set_priority(torrent::File* file, uint32_t value) {
|
||||
if (value > torrent::PRIORITY_HIGH)
|
||||
throw torrent::input_error("Invalid value.");
|
||||
|
||||
file->set_priority((torrent::priority_t)value);
|
||||
}
|
||||
|
||||
// TODO: Redundant.
|
||||
torrent::Object
|
||||
apply_f_path(torrent::File* file) {
|
||||
if (file->path()->empty())
|
||||
return std::string();
|
||||
|
||||
torrent::Object resultRaw(*file->path()->begin());
|
||||
torrent::Object::string_type& result = resultRaw.as_string();
|
||||
|
||||
for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++)
|
||||
result += '/' + *itr;
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_f_path_components(torrent::File* file) {
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
|
||||
for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++)
|
||||
result.push_back(*itr);
|
||||
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_f_path_depth(torrent::File* file) {
|
||||
return (int64_t)file->path()->size();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_fi_filename_last(torrent::FileListIterator* itr) {
|
||||
if (itr->file()->path()->empty())
|
||||
return "EMPTY";
|
||||
|
||||
if (itr->depth() >= itr->file()->path()->size())
|
||||
return "ERROR";
|
||||
|
||||
return itr->file()->path()->at(itr->depth());
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_file() {
|
||||
CMD2_FILE("f.is_created", std::bind(&torrent::File::is_created, std::placeholders::_1));
|
||||
CMD2_FILE("f.is_open", std::bind(&torrent::File::is_open, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE("f.is_create_queued", std::bind(&torrent::File::is_create_queued, std::placeholders::_1));
|
||||
CMD2_FILE("f.is_resize_queued", std::bind(&torrent::File::is_resize_queued, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE_VALUE_V("f.set_create_queued", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_create_queued));
|
||||
CMD2_FILE_VALUE_V("f.set_resize_queued", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_resize_queued));
|
||||
CMD2_FILE_VALUE_V("f.unset_create_queued", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_create_queued));
|
||||
CMD2_FILE_VALUE_V("f.unset_resize_queued", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_resize_queued));
|
||||
|
||||
CMD2_FILE ("f.prioritize_first", std::bind(&torrent::File::has_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
|
||||
CMD2_FILE_V("f.prioritize_first.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
|
||||
CMD2_FILE_V("f.prioritize_first.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_first));
|
||||
CMD2_FILE ("f.prioritize_last", std::bind(&torrent::File::has_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
CMD2_FILE_V("f.prioritize_last.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
CMD2_FILE_V("f.prioritize_last.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
|
||||
CMD2_FILE("f.size_bytes", std::bind(&torrent::File::size_bytes, std::placeholders::_1));
|
||||
CMD2_FILE("f.size_chunks", std::bind(&torrent::File::size_chunks, std::placeholders::_1));
|
||||
CMD2_FILE("f.completed_chunks", std::bind(&torrent::File::completed_chunks, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE("f.offset", std::bind(&torrent::File::offset, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_first", std::bind(&torrent::File::range_first, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_second", std::bind(&torrent::File::range_second, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE("f.priority", std::bind(&torrent::File::priority, std::placeholders::_1));
|
||||
CMD2_FILE_VALUE_V("f.priority.set", std::bind(&apply_f_set_priority, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_FILE("f.path", std::bind(&apply_f_path, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_components", std::bind(&apply_f_path_components, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_depth", std::bind(&apply_f_path_depth, std::placeholders::_1));
|
||||
CMD2_FILE("f.frozen_path", std::bind(&torrent::File::frozen_path, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE("f.match_depth_prev", std::bind(&torrent::File::match_depth_prev, std::placeholders::_1));
|
||||
CMD2_FILE("f.match_depth_next", std::bind(&torrent::File::match_depth_next, std::placeholders::_1));
|
||||
|
||||
CMD2_FILE("f.last_touched", std::bind(&torrent::File::last_touched, std::placeholders::_1));
|
||||
|
||||
CMD2_FILEITR("fi.filename_last", std::bind(&apply_fi_filename_last, std::placeholders::_1));
|
||||
CMD2_FILEITR("fi.is_file", std::bind(&torrent::FileListIterator::is_file, std::placeholders::_1));
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
// 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/option_strings.h>
|
||||
|
||||
#include "ui/root.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
// For cg_d_group.
|
||||
#include "core/download.h"
|
||||
|
||||
// A hack to allow testing of the new choke_group API without the
|
||||
// working parts present.
|
||||
#define USE_CHOKE_GROUP 0
|
||||
|
||||
#if USE_CHOKE_GROUP
|
||||
|
||||
int64_t
|
||||
cg_get_index(const torrent::Object& raw_args) {
|
||||
const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args;
|
||||
|
||||
int64_t index = 0;
|
||||
|
||||
if (arg.is_string()) {
|
||||
if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index))
|
||||
return torrent::resource_manager()->group_index_of(arg.as_string());
|
||||
|
||||
} else {
|
||||
index = arg.as_value();
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
index = (int64_t)torrent::resource_manager()->group_size() + index;
|
||||
|
||||
return std::min<uint64_t>(index, torrent::resource_manager()->group_size());
|
||||
}
|
||||
|
||||
torrent::choke_group*
|
||||
cg_get_group(const torrent::Object& raw_args) {
|
||||
return torrent::resource_manager()->group_at(cg_get_index(raw_args));
|
||||
}
|
||||
|
||||
int64_t
|
||||
cg_d_group(core::Download* download) {
|
||||
return torrent::resource_manager()->entry_at(download->main()).group();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
cg_d_group_name(core::Download* download) {
|
||||
return torrent::resource_manager()->group_at(torrent::resource_manager()->entry_at(download->main()).group())->name();
|
||||
}
|
||||
|
||||
void
|
||||
cg_d_group_set(core::Download* download, const torrent::Object& arg) {
|
||||
torrent::resource_manager()->set_group(torrent::resource_manager()->find_throw(download->main()), cg_get_index(arg));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_list() {
|
||||
torrent::Object::list_type result;
|
||||
|
||||
for (torrent::ResourceManager::group_iterator
|
||||
itr = torrent::resource_manager()->group_begin(),
|
||||
last = torrent::resource_manager()->group_end(); itr != last; itr++)
|
||||
result.push_back((*itr)->name());
|
||||
|
||||
return torrent::Object::from_list(result);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_insert(const std::string& arg) {
|
||||
int64_t dummy;
|
||||
|
||||
if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))
|
||||
throw torrent::input_error("Cannot use a value string as choke group name.");
|
||||
|
||||
torrent::resource_manager()->push_group(arg);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
//
|
||||
// The hacked version:
|
||||
//
|
||||
#else
|
||||
|
||||
std::vector<torrent::choke_group*> cg_list_hack;
|
||||
|
||||
int64_t
|
||||
cg_get_index(const torrent::Object& raw_args) {
|
||||
const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args;
|
||||
|
||||
int64_t index = 0;
|
||||
|
||||
if (arg.is_string()) {
|
||||
if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) {
|
||||
std::vector<torrent::choke_group*>::iterator itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(),
|
||||
rak::equal(arg.as_string(), std::mem_fun(&torrent::choke_group::name)));
|
||||
|
||||
if (itr == cg_list_hack.end())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
|
||||
return std::distance(cg_list_hack.begin(), itr);
|
||||
}
|
||||
|
||||
} else {
|
||||
index = arg.as_value();
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
index = (int64_t)cg_list_hack.size() + index;
|
||||
|
||||
if ((size_t)index >= cg_list_hack.size())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
torrent::choke_group*
|
||||
cg_get_group(const torrent::Object& raw_args) {
|
||||
int64_t index = cg_get_index(raw_args);
|
||||
|
||||
if ((size_t)index >= cg_list_hack.size())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
|
||||
return cg_list_hack.at(index);
|
||||
}
|
||||
|
||||
int64_t cg_d_group(core::Download* download) { return download->group(); }
|
||||
void cg_d_group_set(core::Download* download, const torrent::Object& arg) { download->set_group(cg_get_index(arg)); }
|
||||
|
||||
torrent::Object
|
||||
apply_cg_list() {
|
||||
torrent::Object::list_type result;
|
||||
|
||||
for (std::vector<torrent::choke_group*>::iterator itr = cg_list_hack.begin(), last = cg_list_hack.end(); itr != last; itr++)
|
||||
result.push_back((*itr)->name());
|
||||
|
||||
return torrent::Object::from_list(result);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_insert(const std::string& arg) {
|
||||
int64_t dummy;
|
||||
|
||||
if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))
|
||||
throw torrent::input_error("Cannot use a value string as choke group name.");
|
||||
|
||||
if (arg.empty() ||
|
||||
std::find_if(cg_list_hack.begin(), cg_list_hack.end(),
|
||||
rak::equal(arg, std::mem_fun(&torrent::choke_group::name))) != cg_list_hack.end())
|
||||
throw torrent::input_error("Duplicate name for choke group.");
|
||||
|
||||
cg_list_hack.push_back(new torrent::choke_group());
|
||||
cg_list_hack.back()->set_name(arg);
|
||||
|
||||
cg_list_hack.back()->up_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_UPLOAD_LEECH);
|
||||
cg_list_hack.back()->down_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_DOWNLOAD_LEECH);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_index_of(const std::string& arg) {
|
||||
std::vector<torrent::choke_group*>::iterator itr =
|
||||
std::find_if(cg_list_hack.begin(), cg_list_hack.end(), rak::equal(arg, std::mem_fun(&torrent::choke_group::name)));
|
||||
|
||||
if (itr == cg_list_hack.end())
|
||||
throw torrent::input_error("Choke group not found.");
|
||||
|
||||
return std::distance(cg_list_hack.begin(), itr);
|
||||
}
|
||||
|
||||
//
|
||||
// End of choke group hack.
|
||||
//
|
||||
#endif
|
||||
|
||||
|
||||
torrent::Object
|
||||
apply_cg_max_set(const torrent::Object::list_type& args, bool is_up) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
int64_t second_arg = 0;
|
||||
rpc::parse_whole_value(args.back().as_string().c_str(), &second_arg);
|
||||
|
||||
if (is_up)
|
||||
cg_get_group(args.front())->up_queue()->set_max_unchoked(second_arg);
|
||||
else
|
||||
cg_get_group(args.front())->down_queue()->set_max_unchoked(second_arg);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_heuristics_set(const torrent::Object::list_type& args, bool is_up) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
int t = torrent::option_find_string(is_up ? torrent::OPTION_CHOKE_HEURISTICS_UPLOAD : torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD,
|
||||
args.back().as_string().c_str());
|
||||
|
||||
if (is_up)
|
||||
cg_get_group(args.front())->up_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t);
|
||||
else
|
||||
cg_get_group(args.front())->down_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cg_tracker_mode_set(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
int t = torrent::option_find_string(torrent::OPTION_TRACKER_MODE, args.back().as_string().c_str());
|
||||
|
||||
cg_get_group(args.front())->set_tracker_mode((torrent::choke_group::tracker_mode_enum)t);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
#define CG_GROUP_AT() std::bind(&cg_get_group, std::placeholders::_2)
|
||||
#define CHOKE_GROUP(direction) std::bind(direction, CG_GROUP_AT())
|
||||
|
||||
/*
|
||||
|
||||
<cg_index> -> '0'..'(choke_group.size)'
|
||||
-> '-1'..'-(choke_group.size)'
|
||||
-> '<group_name>'
|
||||
|
||||
(choke_group.list) -> List of group names.
|
||||
(choke_group.size) -> Number of groups.
|
||||
|
||||
(choke_group.insert,"group_name")
|
||||
|
||||
Adds a new group with default settings, use index '-1' to accessing it
|
||||
immediately afterwards.
|
||||
|
||||
(choke_group.index_of,"group_name") -> <group_index>
|
||||
|
||||
Throws if the group name was not found.
|
||||
|
||||
(choke_group.general.size,<cg_index>) -> <size>
|
||||
|
||||
Number of torrents in this group.
|
||||
|
||||
(choke_group.tracker.mode,<cg_index>) -> "tracker_mode"
|
||||
(choke_group.tracker.mode.set,<cg_index>,"tracker_mode")
|
||||
|
||||
Decide on how aggressive a tracker should be, see
|
||||
'strings.tracker_mode' for list of available options
|
||||
|
||||
(choke_group.up.rate,<cg_index>) -> <bytes/second>
|
||||
(choke_group.down.rate,<cg_index>) -> <bytes/second>
|
||||
|
||||
Upload / download rate for the aggregate of all torrents in this
|
||||
particular group.
|
||||
|
||||
(choke_group.up.max,<cg_index>) -> <max_upload_slots>
|
||||
(choke_group.up.max.unlimited,<cg_index>) -> <max_upload_slots>
|
||||
(choke_group.up.max.set,<cg_index>, <max_upload_slots>)
|
||||
(choke_group.down.max,<cg_index>) -> <max_download_slots>
|
||||
(choke_group.down.max.unlimited,<cg_index>) -> <max_download_slots>
|
||||
(choke_group.down.max.set,<cg_index>, <max_download_slots)
|
||||
|
||||
Number of unchoked upload / download peers regulated on a group basis.
|
||||
|
||||
(choke_group.up.total,<cg_index>) -> <number of queued and unchoked interested peers>
|
||||
(choke_group.up.queued,<cg_index>) -> <number of queued interested peers>
|
||||
(choke_group.up.unchoked,<cg_index>) -> <number of unchoked uploads>
|
||||
(choke_group.down.total,<cg_index>) -> <number of queued and unchoked interested peers>
|
||||
(choke_group.down.queued,<cg_index>) -> <number of queued interested peers>
|
||||
(choke_group.down.unchoked,<cg_index>) -> <number of unchoked uploads>
|
||||
|
||||
(choke_group.up.heuristics,<cg_index>) -> "heuristics"
|
||||
(choke_group.up.heuristics.set,<cg_index>,"heuristics")
|
||||
(choke_group.down.heuristics,<cg_index>) -> "heuristics"
|
||||
(choke_group.down.heuristics.set,<cg_index>,"heuristics")
|
||||
|
||||
Heuristics are used for deciding what peers to choke and unchoke, see
|
||||
'strings.choke_heuristics{,_download,_upload}' for a list of available
|
||||
options.
|
||||
|
||||
(d.group) -> <choke_group_index>
|
||||
(d.group.name) -> "choke_group_name"
|
||||
(d.group.set,<cg_index>)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
initialize_command_groups() {
|
||||
CMD2_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD2_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
|
||||
#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));
|
||||
#else
|
||||
apply_cg_insert("default");
|
||||
|
||||
CMD2_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
#endif
|
||||
|
||||
// Commands specific for a group. Supports as the first argument the
|
||||
// name, the index or a negative index.
|
||||
CMD2_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.tracker.mode", std::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE,
|
||||
std::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT())));
|
||||
CMD2_ANY_LIST ("choke_group.tracker.mode.set", std::bind(&apply_cg_tracker_mode_set, std::placeholders::_2));
|
||||
|
||||
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()));
|
||||
|
||||
CMD2_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
|
||||
CMD2_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.up.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, true));
|
||||
|
||||
CMD2_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
|
||||
CMD2_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
void initialize_command_dynamic();
|
||||
void initialize_command_download();
|
||||
void initialize_command_events();
|
||||
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();
|
||||
void initialize_command_tracker();
|
||||
void initialize_command_scheduler();
|
||||
void initialize_command_ui();
|
||||
|
||||
void
|
||||
initialize_commands() {
|
||||
initialize_command_dynamic();
|
||||
initialize_command_events();
|
||||
initialize_command_network();
|
||||
initialize_command_groups();
|
||||
initialize_command_local();
|
||||
initialize_command_logging();
|
||||
initialize_command_ui();
|
||||
initialize_command_download();
|
||||
initialize_command_file();
|
||||
initialize_command_ip();
|
||||
initialize_command_peer();
|
||||
initialize_command_throttle();
|
||||
initialize_command_tracker();
|
||||
initialize_command_scheduler();
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
#define RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
|
||||
#include "rpc/command.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/object_storage.h"
|
||||
|
||||
void initialize_commands();
|
||||
|
||||
//
|
||||
// New std::function based command_base helper functions:
|
||||
//
|
||||
|
||||
#define CMD2_A_FUNCTION(key, function, slot, parm, doc) \
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
|
||||
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL);
|
||||
|
||||
#define CMD2_A_FUNCTION_PRIVATE(key, function, slot, parm, doc) \
|
||||
rpc::commands.insert_slot<rpc::command_base_is_type<rpc::function>::type>(key, slot, &rpc::function, \
|
||||
rpc::CommandMap::flag_dont_delete, NULL, NULL);
|
||||
|
||||
#define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call<rpc::target_type>, slot, "i:", "")
|
||||
|
||||
#define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call<rpc::target_type>, slot, "i:", "")
|
||||
#define CMD2_ANY_VOID(key, slot) CMD2_A_FUNCTION(key, command_base_call<rpc::target_type>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, slot, "A:", "")
|
||||
|
||||
#define CMD2_ANY_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<rpc::target_type>, slot, "i:i", "")
|
||||
#define CMD2_ANY_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<rpc::target_type>, object_convert_void(slot), "i:i", "")
|
||||
#define CMD2_ANY_VALUE_KB(key, slot) CMD2_A_FUNCTION(key, command_base_call_value_kb<rpc::target_type>, object_convert_void(slot), "i:i", "")
|
||||
|
||||
#define CMD2_ANY_STRING(key, slot) CMD2_A_FUNCTION(key, command_base_call_string<rpc::target_type>, slot, "i:s", "")
|
||||
#define CMD2_ANY_STRING_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_string<rpc::target_type>, object_convert_void(slot), "i:s", "")
|
||||
|
||||
#define CMD2_ANY_LIST(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<rpc::target_type>, slot, "i:", "")
|
||||
|
||||
#define CMD2_DL(key, slot) CMD2_A_FUNCTION(key, command_base_call<core::Download*>, slot, "i:", "")
|
||||
#define CMD2_DL_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<core::Download*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_DL_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<core::Download*>, slot, "i:", "")
|
||||
#define CMD2_DL_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<core::Download*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_DL_STRING(key, slot) CMD2_A_FUNCTION(key, command_base_call_string<core::Download*>, slot, "i:", "")
|
||||
#define CMD2_DL_STRING_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_string<core::Download*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_DL_LIST(key, slot) CMD2_A_FUNCTION(key, command_base_call_list<core::Download*>, slot, "i:", "")
|
||||
|
||||
#define CMD2_DL_VALUE_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call_value<core::Download*>, slot, "i:", "")
|
||||
#define CMD2_DL_STRING_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call_string<core::Download*>, slot, "i:", "")
|
||||
|
||||
#define CMD2_FILE(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::File*>, slot, "i:", "")
|
||||
#define CMD2_FILE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::File*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_FILE_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::File*>, object_convert_void(slot), "i:i", "")
|
||||
|
||||
#define CMD2_FILEITR(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::FileListIterator*>, slot, "i:", "")
|
||||
|
||||
#define CMD2_PEER(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Peer*>, slot, "i:", "")
|
||||
#define CMD2_PEER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Peer*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_PEER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::Peer*>, object_convert_void(slot), "i:i", "")
|
||||
|
||||
#define CMD2_TRACKER(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Tracker*>, slot, "i:", "")
|
||||
#define CMD2_TRACKER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call<torrent::Tracker*>, object_convert_void(slot), "i:", "")
|
||||
#define CMD2_TRACKER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value<torrent::Tracker*>, object_convert_void(slot), "i:i", "")
|
||||
|
||||
#define CMD2_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(), \
|
||||
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(), \
|
||||
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(), \
|
||||
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));
|
||||
|
||||
|
||||
#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(), \
|
||||
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(), \
|
||||
torrent::raw_string::from_c_str(key))); \
|
||||
CMD2_ANY_LIST(key ".set", std::bind(&rpc::object_storage::set_list, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2)); \
|
||||
CMD2_ANY_VOID(key ".push_back", std::bind(&rpc::object_storage::list_push_back, control->object_storage(), \
|
||||
torrent::raw_string::from_c_str(key), std::placeholders::_2));
|
||||
|
||||
#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) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_dont_delete);
|
||||
#define CMD2_REDIRECT_GENERIC(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
|
||||
#define CMD2_REDIRECT_GENERIC_NO_EXPORT(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
|
||||
#define CMD2_REDIRECT_FILE(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
|
||||
#define CMD2_REDIRECT_TRACKER(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
|
||||
|
||||
#define CMD2_REDIRECT_GENERIC_STR(from_key, to_key) \
|
||||
rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \
|
||||
rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key);
|
||||
|
||||
#define CMD2_REDIRECT_GENERIC_STR_NO_EXPORT(from_key, to_key) \
|
||||
rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \
|
||||
rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key);
|
||||
|
||||
//
|
||||
// Conversion of return types:
|
||||
//
|
||||
|
||||
template <typename Functor, typename Result>
|
||||
struct object_convert_type;
|
||||
|
||||
template <typename Functor>
|
||||
struct object_convert_type<Functor, void> {
|
||||
|
||||
template <typename Signature> struct result {
|
||||
typedef torrent::Object type;
|
||||
};
|
||||
|
||||
object_convert_type(Functor s) : m_slot(s) {}
|
||||
|
||||
torrent::Object operator () () { m_slot(); return torrent::Object(); }
|
||||
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;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
object_convert_type<T, void>
|
||||
object_convert_void(T f) { return f; }
|
||||
|
||||
//
|
||||
// Key creation:
|
||||
//
|
||||
|
||||
template <int postfix_size>
|
||||
inline const char*
|
||||
create_new_key(const std::string& key, const char postfix[postfix_size]) {
|
||||
char *buffer = new char[key.size() + std::max(postfix_size, 1)];
|
||||
std::memcpy(buffer, key.c_str(), key.size() + 1);
|
||||
std::memcpy(buffer + key.size(), postfix, postfix_size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
create_new_key(const std::string& key) {
|
||||
char *buffer = new char[key.size() + 1];
|
||||
std::memcpy(buffer, key.c_str(), key.size() + 1);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,411 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
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) {
|
||||
if (ip_tables.find(args) != ip_tables.end())
|
||||
throw torrent::input_error("IP table already exists.");
|
||||
|
||||
ip_tables.insert(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)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
torrent::Object::list_const_iterator args_itr = args.begin();
|
||||
|
||||
const std::string& name = (args_itr++)->as_string();
|
||||
const std::string& address = (args_itr++)->as_string();
|
||||
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.");
|
||||
|
||||
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
|
||||
apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 3)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
torrent::Object::list_const_iterator args_itr = args.begin();
|
||||
|
||||
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();
|
||||
|
||||
int value;
|
||||
|
||||
if (value_str == "block")
|
||||
value = 1;
|
||||
else
|
||||
throw torrent::input_error("Invalid value.");
|
||||
|
||||
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.");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
//
|
||||
// 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_DEBUG, "Adding ip filter for %s-%s.", start_str, end_str);
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_size_data() {
|
||||
return torrent::PeerList::ipv4_filter()->sizeof_data();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_get(const std::string& args) {
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
|
||||
throw torrent::input_error("No value defined for specified IP(s).");
|
||||
|
||||
return torrent::PeerList::ipv4_filter()->at(address_start, address_end);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_add_address(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
ipv4_filter_parse(args.front().as_string().c_str(),
|
||||
torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str()));
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
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(filename).c_str(), std::ios::in);
|
||||
|
||||
if (!file.is_open())
|
||||
throw torrent::input_error("Could not open ip filter file: " + filename);
|
||||
|
||||
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.");
|
||||
|
||||
lineNumber++;
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == '#')
|
||||
continue;
|
||||
|
||||
ipv4_filter_parse(buffer, value);
|
||||
}
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
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'.",
|
||||
lineNumber,
|
||||
value_name.c_str(),
|
||||
torrent::PeerList::ipv4_filter()->sizeof_data() / 1024,
|
||||
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_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));
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/chunk_manager.h>
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/download_store.h"
|
||||
#include "core/manager.h"
|
||||
#include "rak/string_manip.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/scgi.h"
|
||||
#include "utils/file_status_cache.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
typedef torrent::ChunkManager CM_t;
|
||||
typedef torrent::FileManager FM_t;
|
||||
|
||||
torrent::Object
|
||||
apply_pieces_stats_total_size() {
|
||||
uint64_t size = 0;
|
||||
core::DownloadList* d_list = control->core()->download_list();
|
||||
|
||||
for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++)
|
||||
if ((*itr)->is_active())
|
||||
size += (*itr)->file_list()->size_bytes();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_env(const torrent::Object::string_type& arg) {
|
||||
if (arg.empty())
|
||||
throw torrent::input_error("system.env: Missing variable name.");
|
||||
|
||||
char* val = getenv(arg.c_str());
|
||||
return std::string(val ? val : "");
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_hostname() {
|
||||
char buffer[1024];
|
||||
|
||||
if (gethostname(buffer, 1023) == -1)
|
||||
throw torrent::input_error("Unable to read hostname.");
|
||||
|
||||
// if (shorten)
|
||||
// *std::find(buffer, buffer + 1023, '.') = '\0';
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_get_cwd() {
|
||||
char* buffer = getcwd(NULL, 0);
|
||||
|
||||
if (buffer == NULL)
|
||||
throw torrent::input_error("Unable to read cwd.");
|
||||
|
||||
torrent::Object result = torrent::Object(std::string(buffer));
|
||||
free(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
system_set_cwd(const torrent::Object::string_type& rawArgs) {
|
||||
if (::chdir(rawArgs.c_str()) != 0)
|
||||
throw torrent::input_error("Could not change current working directory.");
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
inline torrent::Object::list_const_iterator
|
||||
post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object::list_const_iterator& last) {
|
||||
if (itr == last)
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
return itr++;
|
||||
}
|
||||
|
||||
inline const std::string&
|
||||
check_name(const std::string& str) {
|
||||
if (!rak::is_all_name(str))
|
||||
throw torrent::input_error("Non-alphanumeric characters found.");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
group_insert(const torrent::Object::list_type& args) {
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
torrent::Object::list_const_iterator last = args.end();
|
||||
|
||||
const std::string& name = check_name(post_increment(itr, last)->as_string());
|
||||
const std::string& view = check_name(post_increment(itr, last)->as_string());
|
||||
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.enable", "simple",
|
||||
"schedule2=group." + name + ".ratio,5,60,on_ratio=" + name));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple",
|
||||
"schedule_remove2=group." + name + ".ratio"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
|
||||
"d.try_close= ;d.ignore_commands.set=1"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".view", "string", view));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.min", "value", (int64_t)200));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.max", "value", (int64_t)300));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.upload", "value", (int64_t)20 << 20));
|
||||
|
||||
if (rpc::call_command_value("method.use_intermediate") == 1) {
|
||||
// Deprecated in 0.7.0:
|
||||
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view", "group2." + name + ".view");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view.set", "group2." + name + ".view.set");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
|
||||
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
|
||||
|
||||
} if (rpc::call_command_value("method.use_intermediate") == 2) {
|
||||
// Deprecated in 0.7.0:
|
||||
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view", "group2." + name + ".view");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view.set", "group2." + name + ".view.set");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
|
||||
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static const int file_print_use_space = 0x1;
|
||||
static const int file_print_delim_space = 0x2;
|
||||
|
||||
void
|
||||
file_print_list(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last, FILE* output, int flags) {
|
||||
while (first != last) {
|
||||
switch (first->type()) {
|
||||
case torrent::Object::TYPE_STRING:
|
||||
fprintf(output, (const char*)" %s" + !(flags & file_print_use_space), first->as_string().c_str());
|
||||
break;
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
fprintf(output, (const char*)" %lli" + !(flags & file_print_use_space), first->as_value());
|
||||
break;
|
||||
case torrent::Object::TYPE_LIST:
|
||||
file_print_list(first->as_list().begin(), first->as_list().end(), output, 0);
|
||||
break;
|
||||
case torrent::Object::TYPE_NONE:
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Invalid type.");
|
||||
}
|
||||
|
||||
flags |= (flags & file_print_delim_space) >> 1;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
|
||||
|
||||
fprintf(output, "\n");
|
||||
fclose(output);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_local() {
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
core::DownloadStore* dStore = control->core()->download_store();
|
||||
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
|
||||
CMD2_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD2_ANY ("system.pid", std::bind(&getpid));
|
||||
|
||||
CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
|
||||
CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
|
||||
CMD2_VAR_C_STRING("system.library_version", torrent::version());
|
||||
CMD2_VAR_VALUE ("system.file.allocate", 0);
|
||||
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
|
||||
CMD2_VAR_VALUE ("system.file.split_size", -1);
|
||||
CMD2_VAR_STRING ("system.file.split_suffix", ".part");
|
||||
|
||||
CMD2_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
|
||||
CMD2_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
|
||||
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.last");
|
||||
|
||||
CMD2_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
|
||||
CMD2_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
|
||||
CMD2_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
|
||||
|
||||
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));
|
||||
|
||||
CMD2_ANY ("pieces.sync.always_safe", std::bind(&CM_t::safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", std::bind(&CM_t::set_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.safe_free_diskspace", std::bind(&CM_t::safe_free_diskspace, chunkManager));
|
||||
CMD2_ANY ("pieces.sync.timeout", std::bind(&CM_t::timeout_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", std::bind(&CM_t::set_timeout_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.timeout_safe", std::bind(&CM_t::timeout_safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", std::bind(&CM_t::set_timeout_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.queue_size", std::bind(&CM_t::sync_queue_size, chunkManager));
|
||||
|
||||
CMD2_ANY ("pieces.preload.type", std::bind(&CM_t::preload_type, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.type.set", std::bind(&CM_t::set_preload_type, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_size", std::bind(&CM_t::preload_min_size, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", std::bind(&CM_t::set_preload_min_size, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_rate", std::bind(&CM_t::preload_required_rate, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", std::bind(&CM_t::set_preload_required_rate, chunkManager, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("pieces.memory.current", std::bind(&CM_t::memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.sync_queue", std::bind(&CM_t::sync_queue_memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.block_count", std::bind(&CM_t::memory_block_count, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.max", std::bind(&CM_t::max_memory_usage, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.memory.max.set", std::bind(&CM_t::set_max_memory_usage, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.stats_preloaded", std::bind(&CM_t::stats_preloaded, chunkManager));
|
||||
CMD2_ANY ("pieces.stats_not_preloaded", std::bind(&CM_t::stats_not_preloaded, chunkManager));
|
||||
|
||||
CMD2_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
|
||||
CMD2_ANY ("pieces.hash.queue_size", std::bind(&torrent::hash_queue_size));
|
||||
CMD2_VAR_BOOL ("pieces.hash.on_completion", true);
|
||||
|
||||
CMD2_VAR_STRING ("directory.default", "./");
|
||||
|
||||
CMD2_VAR_STRING ("session.name", "");
|
||||
CMD2_VAR_BOOL ("session.use_lock", true);
|
||||
CMD2_VAR_BOOL ("session.on_completion", true);
|
||||
|
||||
CMD2_ANY ("session.path", std::bind(&core::DownloadStore::path, dStore));
|
||||
CMD2_ANY_STRING_V("session.path.set", std::bind(&core::DownloadStore::set_path, dStore, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_V ("session.save", std::bind(&core::DownloadList::session_save, dList));
|
||||
|
||||
#define CMD2_EXECUTE(key, flags) \
|
||||
CMD2_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
|
||||
CMD2_EXECUTE ("execute2", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
|
||||
CMD2_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow", 0);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD2_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
|
||||
CMD2_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
|
||||
// TODO: Convert to new command types:
|
||||
*rpc::command_base::argument(0) = "placeholder.0";
|
||||
*rpc::command_base::argument(1) = "placeholder.1";
|
||||
*rpc::command_base::argument(2) = "placeholder.2";
|
||||
*rpc::command_base::argument(3) = "placeholder.3";
|
||||
CMD2_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD2_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD2_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD2_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
|
||||
CMD2_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((output_flags & log_flag_use_gz))
|
||||
torrent::log_open_gz_file_output(output_id.c_str(), file_name.c_str());
|
||||
else
|
||||
torrent::log_open_file_output(output_id.c_str(), file_name.c_str());
|
||||
|
||||
while (itr != args.end())
|
||||
log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str());
|
||||
|
||||
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.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));
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <rak/address_info.h>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/tracker.h>
|
||||
#include <torrent/tracker_list.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/manager.h"
|
||||
#include "rpc/scgi.h"
|
||||
#include "ui/root.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
torrent::Object
|
||||
apply_encryption(const torrent::Object::list_type& args) {
|
||||
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, itr->as_string().c_str());
|
||||
|
||||
if (opt == torrent::ConnectionManager::encryption_none)
|
||||
options_mask = torrent::ConnectionManager::encryption_none;
|
||||
else
|
||||
options_mask |= opt;
|
||||
}
|
||||
|
||||
torrent::connection_manager()->set_encryption_options(options_mask);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_tos(const torrent::Object::string_type& arg) {
|
||||
rpc::command_base::value_type value;
|
||||
|
||||
if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1))
|
||||
value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str());
|
||||
|
||||
torrent::connection_manager()->set_priority(value);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); }
|
||||
|
||||
torrent::File*
|
||||
xmlrpc_find_file(core::Download* download, uint32_t index) {
|
||||
if (index >= download->file_list()->size_files())
|
||||
return NULL;
|
||||
|
||||
return (*download->file_list())[index];
|
||||
}
|
||||
|
||||
// Ergh... time to update the Tracker API to allow proper ptrs.
|
||||
torrent::Tracker*
|
||||
xmlrpc_find_tracker(core::Download* download, uint32_t index) {
|
||||
if (index >= download->tracker_list()->size())
|
||||
return NULL;
|
||||
|
||||
return download->tracker_list()->at(index);
|
||||
}
|
||||
|
||||
torrent::Peer*
|
||||
xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) {
|
||||
torrent::ConnectionList::iterator itr = download->connection_list()->find(hash.c_str());
|
||||
|
||||
if (itr == download->connection_list()->end())
|
||||
return NULL;
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
void
|
||||
initialize_xmlrpc() {
|
||||
rpc::xmlrpc.initialize();
|
||||
rpc::xmlrpc.slot_find_download() = std::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), std::placeholders::_1);
|
||||
rpc::xmlrpc.slot_find_file() = std::bind(&xmlrpc_find_file, std::placeholders::_1, std::placeholders::_2);
|
||||
rpc::xmlrpc.slot_find_tracker() = std::bind(&xmlrpc_find_tracker, std::placeholders::_1, std::placeholders::_2);
|
||||
rpc::xmlrpc.slot_find_peer() = std::bind(&xmlrpc_find_peer, std::placeholders::_1, std::placeholders::_2);
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++, count++) {
|
||||
if (!(itr->second.m_flags & rpc::CommandMap::flag_public_xmlrpc))
|
||||
continue;
|
||||
|
||||
rpc::xmlrpc.insert_command(itr->first, itr->second.m_parm, itr->second.m_doc);
|
||||
}
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "XMLRPC initialized with %u functions.", count);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_scgi(const std::string& arg, int type) {
|
||||
if (worker_thread->scgi() != NULL)
|
||||
throw torrent::input_error("SCGI already enabled.");
|
||||
|
||||
if (!rpc::xmlrpc.is_valid())
|
||||
initialize_xmlrpc();
|
||||
|
||||
rpc::SCgi* scgi = new rpc::SCgi;
|
||||
|
||||
rak::address_info* ai = NULL;
|
||||
rak::socket_address sa;
|
||||
rak::socket_address* saPtr;
|
||||
|
||||
try {
|
||||
int port, err;
|
||||
char dummy;
|
||||
char address[1024];
|
||||
std::string path;
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) {
|
||||
sa.sa_inet()->clear();
|
||||
saPtr = &sa;
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS,
|
||||
"The SCGI socket has not been bound to any address and likely poses a security risk.");
|
||||
|
||||
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
|
||||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
|
||||
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_EVENTS,
|
||||
"The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'.");
|
||||
|
||||
} else {
|
||||
throw torrent::input_error("Could not parse address.");
|
||||
}
|
||||
|
||||
if (port <= 0 || port >= (1 << 16))
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
saPtr->set_port(port);
|
||||
scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route"));
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
default:
|
||||
path = rak::path_expand(arg);
|
||||
|
||||
unlink(path.c_str());
|
||||
scgi->open_named(path);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ai != NULL) rak::address_info::free_address_info(ai);
|
||||
|
||||
} catch (torrent::local_error& e) {
|
||||
if (ai != NULL) rak::address_info::free_address_info(ai);
|
||||
|
||||
delete scgi;
|
||||
throw torrent::input_error(e.what());
|
||||
}
|
||||
|
||||
worker_thread->set_scgi(scgi);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_xmlrpc_dialect(const std::string& arg) {
|
||||
int value;
|
||||
|
||||
if (arg == "i8")
|
||||
value = rpc::XmlRpc::dialect_i8;
|
||||
else if (arg == "apache")
|
||||
value = rpc::XmlRpc::dialect_apache;
|
||||
else if (arg == "generic")
|
||||
value = rpc::XmlRpc::dialect_generic;
|
||||
else
|
||||
value = -1;
|
||||
|
||||
rpc::xmlrpc.set_dialect(value);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_network() {
|
||||
torrent::ConnectionManager* cm = torrent::connection_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
core::CurlStack* httpStack = control->core()->http_stack();
|
||||
|
||||
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
|
||||
|
||||
// Isn't port_open used?
|
||||
CMD2_VAR_BOOL ("network.port_open", true);
|
||||
CMD2_VAR_BOOL ("network.port_random", true);
|
||||
CMD2_VAR_STRING ("network.port_range", "6881-6999");
|
||||
|
||||
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));
|
||||
|
||||
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
|
||||
CMD2_ANY ("network.http.cacert", std::bind(&core::CurlStack::http_cacert, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.cacert.set", std::bind(&core::CurlStack::set_http_cacert, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.capath", std::bind(&core::CurlStack::http_capath, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack));
|
||||
CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack));
|
||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", std::bind(&core::CurlStack::set_http_proxy, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_host", std::bind(&core::CurlStack::ssl_verify_host, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", std::bind(&core::CurlStack::set_ssl_verify_host, httpStack, std::placeholders::_2));
|
||||
CMD2_ANY ("network.http.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack));
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.send_buffer.size", std::bind(&torrent::ConnectionManager::send_buffer_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", std::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY ("network.receive_buffer.size", std::bind(&torrent::ConnectionManager::receive_buffer_size, cm));
|
||||
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", std::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("network.tos.set", std::bind(&apply_tos, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("network.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_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));
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <rak/error_number.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/socket_address.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <torrent/bitfield.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/peer/connection_list.h>
|
||||
#include <torrent/peer/peer.h>
|
||||
#include <torrent/peer/peer_info.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "display/utils.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_id(torrent::Peer* peer) {
|
||||
const torrent::HashString* hashString = &peer->id();
|
||||
|
||||
return rak::transform_hex(hashString->begin(), hashString->end());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_id_html(torrent::Peer* peer) {
|
||||
const torrent::HashString* hashString = &peer->id();
|
||||
|
||||
return rak::copy_escape_html(hashString->begin(), hashString->end());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_address(torrent::Peer* peer) {
|
||||
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
|
||||
|
||||
if (addr->family() == rak::socket_address::af_inet6)
|
||||
return "[" + addr->address_str() + "]";
|
||||
else
|
||||
return addr->address_str();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_port(torrent::Peer* peer) {
|
||||
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_client_version(torrent::Peer* peer) {
|
||||
char buf[128];
|
||||
display::print_client_version(buf, buf + 128, peer->peer_info()->client_info());
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_options_str(torrent::Peer* peer) {
|
||||
return rak::transform_hex(peer->peer_info()->options(), peer->peer_info()->options() + 8);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_p_completed_percent(torrent::Peer* peer) {
|
||||
return (100 * peer->bitfield()->size_set()) / peer->bitfield()->size_bits();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_peer() {
|
||||
CMD2_PEER("p.id", std::bind(&retrieve_p_id, std::placeholders::_1));
|
||||
CMD2_PEER("p.id_html", std::bind(&retrieve_p_id_html, std::placeholders::_1));
|
||||
CMD2_PEER("p.client_version", std::bind(&retrieve_p_client_version, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.options_str", std::bind(&retrieve_p_options_str, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.is_encrypted", std::bind(&torrent::Peer::is_encrypted, std::placeholders::_1));
|
||||
CMD2_PEER("p.is_incoming", std::bind(&torrent::Peer::is_incoming, std::placeholders::_1));
|
||||
CMD2_PEER("p.is_obfuscated", std::bind(&torrent::Peer::is_obfuscated, std::placeholders::_1));
|
||||
CMD2_PEER("p.is_snubbed", std::bind(&torrent::Peer::is_snubbed, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.is_unwanted", std::bind(&torrent::PeerInfo::is_unwanted, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
|
||||
CMD2_PEER("p.is_preferred", std::bind(&torrent::PeerInfo::is_preferred, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
|
||||
|
||||
CMD2_PEER("p.address", std::bind(&retrieve_p_address, std::placeholders::_1));
|
||||
CMD2_PEER("p.port", std::bind(&retrieve_p_port, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.completed_percent", std::bind(&retrieve_p_completed_percent, std::placeholders::_1));
|
||||
|
||||
CMD2_PEER("p.up_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::up_rate, std::placeholders::_1)));
|
||||
CMD2_PEER("p.up_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::up_rate, std::placeholders::_1)));
|
||||
CMD2_PEER("p.down_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::down_rate, std::placeholders::_1)));
|
||||
CMD2_PEER("p.down_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::down_rate, std::placeholders::_1)));
|
||||
CMD2_PEER("p.peer_rate", std::bind(&torrent::Rate::rate, std::bind(&torrent::Peer::peer_rate, std::placeholders::_1)));
|
||||
CMD2_PEER("p.peer_total", std::bind(&torrent::Rate::total, std::bind(&torrent::Peer::peer_rate, std::placeholders::_1)));
|
||||
|
||||
CMD2_PEER ("p.snubbed", std::bind(&torrent::Peer::is_snubbed, std::placeholders::_1));
|
||||
CMD2_PEER_VALUE_V("p.snubbed.set", std::bind(&torrent::Peer::set_snubbed, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_PEER ("p.banned", std::bind(&torrent::Peer::is_banned, std::placeholders::_1));
|
||||
CMD2_PEER_VALUE_V("p.banned.set", std::bind(&torrent::Peer::set_banned, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_PEER_V("p.disconnect", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, 0));
|
||||
CMD2_PEER_V("p.disconnect_delayed", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, torrent::ConnectionList::disconnect_delayed));
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/view.h"
|
||||
#include "core/view_manager.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
torrent::Object
|
||||
cmd_scheduler_simple_added(core::Download* download) {
|
||||
unsigned int numActive = (*control->view_manager()->find("active"))->size_visible();
|
||||
int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
|
||||
|
||||
if (numActive < (uint64_t)maxActive)
|
||||
control->core()->download_list()->resume(download);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_scheduler_simple_removed(core::Download* download) {
|
||||
control->core()->download_list()->pause(download);
|
||||
|
||||
core::View* viewActive = *control->view_manager()->find("active");
|
||||
int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
|
||||
|
||||
if ((int64_t)viewActive->size_visible() >= maxActive)
|
||||
return torrent::Object();
|
||||
|
||||
// The 'started' view contains all the views we may choose amongst.
|
||||
core::View* viewStarted = *control->view_manager()->find("started");
|
||||
|
||||
for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) {
|
||||
if ((*itr)->is_active())
|
||||
continue;
|
||||
|
||||
control->core()->download_list()->resume(*itr);
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_scheduler_simple_update(core::Download* download) {
|
||||
core::View* viewActive = *control->view_manager()->find("active");
|
||||
core::View* viewStarted = *control->view_manager()->find("started");
|
||||
|
||||
unsigned int numActive = viewActive->size_visible();
|
||||
uint64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
|
||||
|
||||
if (viewActive->size_visible() < maxActive) {
|
||||
|
||||
for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) {
|
||||
if ((*itr)->is_active())
|
||||
continue;
|
||||
|
||||
control->core()->download_list()->resume(*itr);
|
||||
|
||||
if (++numActive >= maxActive)
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (viewActive->size_visible() > maxActive) {
|
||||
|
||||
while (viewActive->size_visible() > maxActive)
|
||||
control->core()->download_list()->pause(*viewActive->begin_visible());
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_scheduler() {
|
||||
CMD2_VAR_VALUE("scheduler.max_active", int64_t(-1));
|
||||
|
||||
CMD2_DL("scheduler.simple.added", std::bind(&cmd_scheduler_simple_added, std::placeholders::_1));
|
||||
CMD2_DL("scheduler.simple.removed", std::bind(&cmd_scheduler_simple_removed, std::placeholders::_1));
|
||||
CMD2_DL("scheduler.simple.update", std::bind(&cmd_scheduler_simple_update, std::placeholders::_1));
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <rak/address_info.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "ui/root.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
std::pair<uint32_t, uint32_t>
|
||||
parse_address_range(const torrent::Object::list_type& args, torrent::Object::list_type::const_iterator itr) {
|
||||
unsigned int prefixWidth, ret;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
rak::address_info* ai;
|
||||
|
||||
ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy);
|
||||
if (ret < 1 || rak::address_info::get_address_info(host, PF_INET, SOCK_STREAM, &ai) != 0)
|
||||
throw torrent::input_error("Could not resolve host.");
|
||||
|
||||
uint32_t begin, end;
|
||||
rak::socket_address sa;
|
||||
sa.copy(*ai->address(), ai->length());
|
||||
begin = end = sa.sa_inet()->address_h();
|
||||
rak::address_info::free_address_info(ai);
|
||||
|
||||
if (ret == 2) {
|
||||
if (++itr != args.end())
|
||||
throw torrent::input_error("Cannot specify both network and range end.");
|
||||
|
||||
uint32_t netmask = std::numeric_limits<uint32_t>::max() << (32 - prefixWidth);
|
||||
if (prefixWidth >= 32 || sa.sa_inet()->address_h() & ~netmask)
|
||||
throw torrent::input_error("Invalid address/prefix.");
|
||||
|
||||
end = sa.sa_inet()->address_h() | ~netmask;
|
||||
|
||||
} else if (++itr != args.end()) {
|
||||
if (rak::address_info::get_address_info(itr->as_string().c_str(), PF_INET, SOCK_STREAM, &ai) != 0)
|
||||
throw torrent::input_error("Could not resolve host.");
|
||||
|
||||
sa.copy(*ai->address(), ai->length());
|
||||
rak::address_info::free_address_info(ai);
|
||||
end = sa.sa_inet()->address_h();
|
||||
}
|
||||
|
||||
// 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)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 '" + name + "'.");
|
||||
|
||||
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);
|
||||
|
||||
if (rate < 0)
|
||||
throw torrent::input_error("Throttle rate must be non-negative.");
|
||||
|
||||
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
|
||||
if (itr == control->core()->throttles().end())
|
||||
itr = control->core()->throttles().insert(std::make_pair(name, torrent::ThrottlePair(NULL, NULL))).first;
|
||||
|
||||
torrent::Throttle*& throttle = up ? itr->second.first : itr->second.second;
|
||||
if (rate != 0 && throttle == NULL)
|
||||
throttle = (up ? torrent::up_throttle_global() : torrent::down_throttle_global())->create_slave();
|
||||
|
||||
if (throttle != NULL)
|
||||
throttle->set_max_rate(rate * 1024);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
static const int throttle_info_up = (1 << 0);
|
||||
static const int throttle_info_down = (1 << 1);
|
||||
static const int throttle_info_max = (1 << 2);
|
||||
static const int throttle_info_rate = (1 << 3);
|
||||
|
||||
torrent::Object
|
||||
retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
|
||||
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
|
||||
torrent::ThrottlePair throttles = itr == control->core()->throttles().end() ? torrent::ThrottlePair(NULL, NULL) : itr->second;
|
||||
torrent::Throttle* throttle = flags & throttle_info_down ? throttles.second : throttles.first;
|
||||
torrent::Throttle* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global();
|
||||
|
||||
if (throttle == NULL && name.empty())
|
||||
throttle = global;
|
||||
|
||||
if (throttle == NULL)
|
||||
return flags & throttle_info_rate ? (int64_t)0 : (int64_t)-1;
|
||||
else if (!throttle->is_throttled() || !global->is_throttled())
|
||||
return (int64_t)0;
|
||||
else if (flags & throttle_info_rate)
|
||||
return (int64_t)throttle->rate()->rate();
|
||||
else
|
||||
return (int64_t)throttle->max_rate();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_address_throttle(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2 || args.size() > 3)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
std::pair<uint32_t, uint32_t> range = parse_address_range(args, ++args.begin());
|
||||
core::ThrottleMap::iterator throttleItr = control->core()->throttles().find(args.begin()->as_string().c_str());
|
||||
if (throttleItr == control->core()->throttles().end())
|
||||
throw torrent::input_error("Throttle not found.");
|
||||
|
||||
control->core()->set_address_throttle(range.first, range.second, throttleItr->second);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
throttle_update(const char* variable, int64_t value) {
|
||||
rpc::commands.call_command(variable, value);
|
||||
|
||||
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_VAR_VALUE ("throttle.min_peers.normal", 100);
|
||||
CMD2_VAR_VALUE ("throttle.max_peers.normal", 200);
|
||||
CMD2_VAR_VALUE ("throttle.min_peers.seed", -1);
|
||||
CMD2_VAR_VALUE ("throttle.max_peers.seed", -1);
|
||||
|
||||
CMD2_VAR_VALUE ("throttle.min_uploads", 0);
|
||||
CMD2_VAR_VALUE ("throttle.max_uploads", 50);
|
||||
CMD2_VAR_VALUE ("throttle.min_downloads", 0);
|
||||
CMD2_VAR_VALUE ("throttle.max_downloads", 50);
|
||||
|
||||
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()));
|
||||
CMD2_ANY ("throttle.global_up.total", std::bind(&torrent::Rate::total, torrent::up_rate()));
|
||||
CMD2_ANY ("throttle.global_up.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::up_throttle_global()));
|
||||
CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY ("throttle.global_down.rate", std::bind(&torrent::Rate::rate, torrent::down_rate()));
|
||||
CMD2_ANY ("throttle.global_down.total", std::bind(&torrent::Rate::total, torrent::down_rate()));
|
||||
CMD2_ANY ("throttle.global_down.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::down_throttle_global()));
|
||||
CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
|
||||
|
||||
// Temporary names, need to change this to accept real rates rather
|
||||
// than kB.
|
||||
CMD2_ANY_LIST ("throttle.up", std::bind(&apply_throttle, std::placeholders::_2, true));
|
||||
CMD2_ANY_LIST ("throttle.down", std::bind(&apply_throttle, std::placeholders::_2, false));
|
||||
CMD2_ANY_LIST ("throttle.ip", std::bind(&apply_address_throttle, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("throttle.up.max", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_max));
|
||||
CMD2_ANY_STRING ("throttle.up.rate", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_rate));
|
||||
CMD2_ANY_STRING ("throttle.down.max", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_down | throttle_info_max));
|
||||
CMD2_ANY_STRING ("throttle.down.rate", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_down | throttle_info_rate));
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <rak/address_info.h>
|
||||
#include <rak/error_number.h>
|
||||
#include <torrent/dht_manager.h>
|
||||
#include <torrent/tracker.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
#include "core/download.h"
|
||||
#include "core/manager.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "core/dht_manager.h"
|
||||
|
||||
void
|
||||
tracker_set_enabled(torrent::Tracker* tracker, bool state) {
|
||||
if (state)
|
||||
tracker->enable();
|
||||
else
|
||||
tracker->disable();
|
||||
}
|
||||
|
||||
struct call_add_node_t {
|
||||
call_add_node_t(int port) : m_port(port) { }
|
||||
|
||||
void operator() (const sockaddr* sa, int err) {
|
||||
if (sa == NULL) {
|
||||
lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host.");
|
||||
} else {
|
||||
torrent::dht_manager()->add_node(sa, m_port);
|
||||
}
|
||||
}
|
||||
|
||||
int m_port;
|
||||
};
|
||||
|
||||
torrent::Object
|
||||
apply_dht_add_node(const std::string& arg) {
|
||||
if (!torrent::dht_manager()->is_valid())
|
||||
throw torrent::input_error("DHT not enabled.");
|
||||
|
||||
int port, ret;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
|
||||
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
|
||||
|
||||
if (ret == 1)
|
||||
port = 6881;
|
||||
else if (ret != 2)
|
||||
throw torrent::input_error("Could not parse host.");
|
||||
|
||||
if (port < 1 || port > 65535)
|
||||
throw torrent::input_error("Invalid port number.");
|
||||
|
||||
torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port));
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_enable_trackers(int64_t arg) {
|
||||
for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) {
|
||||
std::for_each((*itr)->tracker_list()->begin(), (*itr)->tracker_list()->end(),
|
||||
arg ? std::mem_fun(&torrent::Tracker::enable) : std::mem_fun(&torrent::Tracker::disable));
|
||||
|
||||
if (arg && !rpc::call_command_value("trackers.use_udp"))
|
||||
(*itr)->enable_udp_trackers(false);
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_tracker() {
|
||||
CMD2_TRACKER ("t.is_open", std::bind(&torrent::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_enabled", std::bind(&torrent::Tracker::is_enabled, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_usable", std::bind(&torrent::Tracker::is_usable, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_busy", std::bind(&torrent::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_extra_tracker", std::bind(&torrent::Tracker::is_extra_tracker, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.can_scrape", std::bind(&torrent::Tracker::can_scrape, std::placeholders::_1));
|
||||
|
||||
CMD2_TRACKER_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));
|
||||
CMD2_TRACKER ("t.id", std::bind(&torrent::Tracker::tracker_id, std::placeholders::_1));
|
||||
|
||||
CMD2_TRACKER ("t.latest_event", std::bind(&torrent::Tracker::latest_event, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.latest_new_peers", std::bind(&torrent::Tracker::latest_new_peers, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.latest_sum_peers", std::bind(&torrent::Tracker::latest_sum_peers, std::placeholders::_1));
|
||||
|
||||
// Time since last connection, connection attempt.
|
||||
|
||||
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));
|
||||
|
||||
CMD2_TRACKER ("t.scrape_time_last", std::bind(&torrent::Tracker::scrape_time_last, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_counter", std::bind(&torrent::Tracker::scrape_counter, std::placeholders::_1));
|
||||
|
||||
CMD2_TRACKER ("t.scrape_complete", std::bind(&torrent::Tracker::scrape_complete, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_incomplete", std::bind(&torrent::Tracker::scrape_incomplete, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.scrape_downloaded", std::bind(&torrent::Tracker::scrape_downloaded, std::placeholders::_1));
|
||||
|
||||
CMD2_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_VALUE ("trackers.numwant", -1);
|
||||
CMD2_VAR_BOOL ("trackers.use_udp", true);
|
||||
|
||||
CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2));
|
||||
CMD2_VAR_VALUE ("dht.port", int64_t(6881));
|
||||
CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2));
|
||||
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, control->dht_manager()));
|
||||
CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, control->dht_manager()));
|
||||
CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), std::placeholders::_2));
|
||||
}
|
||||
@@ -0,0 +1,590 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "core/view_manager.h"
|
||||
#include "ui/root.h"
|
||||
#include "ui/download_list.h"
|
||||
#include "rpc/parse.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
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) {
|
||||
if (args.size() < 1)
|
||||
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.");
|
||||
|
||||
core::ViewManager::filter_args filterArgs;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = ++args.begin(), last = args.end(); itr != last; itr++)
|
||||
filterArgs.push_back(itr->as_string());
|
||||
|
||||
control->view_manager()->set_filter_on(name, filterArgs);
|
||||
|
||||
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("Wrong argument count.");
|
||||
|
||||
(control->view_manager()->*viewFilterSlot)(args.front().as_string(), args.back());
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_sort(const torrent::Object::list_type& args) {
|
||||
if (args.size() <= 0 || args.size() > 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
const std::string& name = args.front().as_string();
|
||||
|
||||
if (name.empty())
|
||||
throw torrent::input_error("First argument must be a string.");
|
||||
|
||||
int32_t value = 0;
|
||||
|
||||
if (args.size() == 2)
|
||||
value = rpc::convert_to_value(args.back());
|
||||
|
||||
control->view_manager()->sort(name, value);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_list() {
|
||||
torrent::Object rawResult = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = rawResult.as_list();
|
||||
|
||||
for (core::ViewManager::const_iterator itr = control->view_manager()->begin(), last = control->view_manager()->end(); itr != last; itr++)
|
||||
result.push_back((*itr)->name());
|
||||
|
||||
return rawResult;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_set(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
core::ViewManager::iterator itr = control->view_manager()->find(args.back().as_string());
|
||||
|
||||
if (itr == control->view_manager()->end())
|
||||
throw torrent::input_error("Could not find view \"" + args.back().as_string() + "\".");
|
||||
|
||||
// if (args.front().as_string() == "main")
|
||||
// control->ui()->download_list()->set_view(*itr);
|
||||
// else
|
||||
throw torrent::input_error("No such target.");
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_print(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
char buffer[1024];
|
||||
rpc::print_object(buffer, buffer + 1024, &rawArgs, 0);
|
||||
|
||||
control->core()->push_log(buffer);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
std::string result;
|
||||
|
||||
rpc::print_object_std(&result, &rawArgs, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Move these boolean operators to a new file.
|
||||
|
||||
inline bool
|
||||
as_boolean(const torrent::Object& rawArgs) {
|
||||
switch (rawArgs.type()) {
|
||||
case torrent::Object::TYPE_VALUE: return rawArgs.as_value();
|
||||
case torrent::Object::TYPE_STRING: return !rawArgs.as_string().empty();
|
||||
|
||||
// We need to properly handle argument lists that are single-object
|
||||
// at a higher level.
|
||||
case torrent::Object::TYPE_LIST: return !rawArgs.as_list().empty() && as_boolean(rawArgs.as_list().front());
|
||||
// case torrent::Object::TYPE_MAP: return !rawArgs.as_map().empty();
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_not(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
bool result;
|
||||
|
||||
if (rawArgs.is_dict_key())
|
||||
result = as_boolean(rpc::commands.call_command(rawArgs.as_dict_key().c_str(), rawArgs.as_dict_obj(),
|
||||
target));
|
||||
// TODO: Thus we should clean this up...
|
||||
else if (rawArgs.is_list() && !rawArgs.as_list().empty())
|
||||
return apply_not(target, rawArgs.as_list().front());
|
||||
|
||||
else
|
||||
result = as_boolean(rawArgs);
|
||||
|
||||
return (int64_t)!result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_false(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
return (int64_t)0;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_and(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST)
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
|
||||
if (itr->is_dict_key()) {
|
||||
if (!as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
|
||||
return (int64_t)false;
|
||||
|
||||
} else if (itr->is_value()) {
|
||||
if (!itr->as_value())
|
||||
return (int64_t)false;
|
||||
|
||||
} else {
|
||||
// TODO: Switch to new versions that only accept the new command syntax.
|
||||
if (!as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)false;
|
||||
}
|
||||
|
||||
return (int64_t)true;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_or(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST)
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
|
||||
if (itr->is_dict_key()) {
|
||||
if (as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
|
||||
return (int64_t)true;
|
||||
|
||||
} else if (itr->is_value()) {
|
||||
if (itr->as_value())
|
||||
return (int64_t)true;
|
||||
|
||||
} else {
|
||||
if (as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)true;
|
||||
}
|
||||
|
||||
return (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_cmp(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
// We only need to check if empty() since if size() == 1 it calls
|
||||
// the same command for both, or if size() == 2 then each side of
|
||||
// the comparison has different commands.
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
// 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 = rpc::parse_command_single(target2, args.back().as_string());
|
||||
|
||||
if (result1.type() != result2.type())
|
||||
throw torrent::input_error("Type mismatch.");
|
||||
|
||||
switch (result1.type()) {
|
||||
case torrent::Object::TYPE_VALUE: return result1.as_value() - result2.as_value();
|
||||
case torrent::Object::TYPE_STRING: return result1.as_string().compare(result2.as_string());
|
||||
default: return torrent::Object();
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object apply_less(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
torrent::Object result = apply_cmp(target, args);
|
||||
return result.is_value() ? result.as_value() < 0 : (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object apply_greater(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
torrent::Object result = apply_cmp(target, args);
|
||||
return result.is_value() ? result.as_value() > 0 : (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object apply_equal(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
torrent::Object result = apply_cmp(target, args);
|
||||
return result.is_value() ? result.as_value() == 0 : (int64_t)false;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_time(const torrent::Object& rawArgs, int flags) {
|
||||
std::tm *u;
|
||||
time_t t = (uint64_t)rawArgs.as_value();
|
||||
|
||||
if (flags & 0x1)
|
||||
u = std::localtime(&t);
|
||||
else
|
||||
u = std::gmtime(&t);
|
||||
|
||||
if (u == NULL)
|
||||
return torrent::Object();
|
||||
|
||||
char buffer[11];
|
||||
|
||||
if (flags & 0x2)
|
||||
snprintf(buffer, 11, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year));
|
||||
else
|
||||
snprintf(buffer, 9, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec);
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_elapsed_time(const torrent::Object& rawArgs) {
|
||||
uint64_t arg = cachedTime.seconds() - rawArgs.as_value();
|
||||
|
||||
char buffer[48];
|
||||
snprintf(buffer, 48, "%2d:%02d:%02d", (int)(arg / 3600), (int)((arg / 60) % 60), (int)(arg % 60));
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_kb(const torrent::Object& rawArgs) {
|
||||
char buffer[32];
|
||||
snprintf(buffer, 32, "%5.1f", (double)rawArgs.as_value() / (1 << 10));
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_mb(const torrent::Object& rawArgs) {
|
||||
char buffer[32];
|
||||
snprintf(buffer, 32, "%8.1f", (double)rawArgs.as_value() / (1 << 20));
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_xb(const torrent::Object& rawArgs) {
|
||||
char buffer[48];
|
||||
int64_t arg = rawArgs.as_value();
|
||||
|
||||
if (arg < (int64_t(1000) << 10))
|
||||
snprintf(buffer, 48, "%5.1f KB", (double)arg / (int64_t(1) << 10));
|
||||
else if (arg < (int64_t(1000) << 20))
|
||||
snprintf(buffer, 48, "%5.1f MB", (double)arg / (int64_t(1) << 20));
|
||||
else if (arg < (int64_t(1000) << 30))
|
||||
snprintf(buffer, 48, "%5.1f GB", (double)arg / (int64_t(1) << 30));
|
||||
else
|
||||
snprintf(buffer, 48, "%5.1f TB", (double)arg / (int64_t(1) << 40));
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_to_throttle(const torrent::Object& rawArgs) {
|
||||
int64_t arg = rawArgs.as_value();
|
||||
if (arg < 0)
|
||||
return "---";
|
||||
else if (arg == 0)
|
||||
return "off";
|
||||
|
||||
char buffer[32];
|
||||
snprintf(buffer, 32, "%3d", (int)(arg / (1 << 10)));
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
// A series of if/else statements. Every even arguments are
|
||||
// conditionals and odd arguments are branches to be executed, except
|
||||
// the last one which is always a branch.
|
||||
//
|
||||
// if (cond1) { branch1 }
|
||||
// <cond1>,<branch1>
|
||||
//
|
||||
// if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 }
|
||||
// <cond1>,<branch1>,<cond2>,<branch2>,<branch3>
|
||||
torrent::Object
|
||||
apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
const torrent::Object::list_type& args = rawArgs.as_list();
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
|
||||
while (itr != args.end() && itr != --args.end()) {
|
||||
torrent::Object tmp;
|
||||
const torrent::Object* conditional;
|
||||
|
||||
if (flags & 0x1 && itr->is_string())
|
||||
conditional = &(tmp = rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first);
|
||||
else if (flags & 0x1 && itr->is_dict_key())
|
||||
conditional = &(tmp = rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target));
|
||||
else
|
||||
conditional = &*itr;
|
||||
|
||||
bool result;
|
||||
|
||||
switch (conditional->type()) {
|
||||
case torrent::Object::TYPE_STRING:
|
||||
result = !conditional->as_string().empty();
|
||||
break;
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
result = conditional->as_value();
|
||||
break;
|
||||
case torrent::Object::TYPE_NONE:
|
||||
result = false;
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Type not supported by 'if'.");
|
||||
};
|
||||
|
||||
itr++;
|
||||
|
||||
if (result)
|
||||
break;
|
||||
|
||||
itr++;
|
||||
}
|
||||
|
||||
if (itr == args.end())
|
||||
return torrent::Object();
|
||||
|
||||
if (flags & 0x1 && itr->is_string()) {
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
|
||||
} else if (flags & 0x1 && itr->is_dict_key()) {
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
|
||||
} else if (flags & 0x1 && itr->is_list()) {
|
||||
// Move this into a special function or something. Also, might be
|
||||
// nice to have a parse_command function that takes list
|
||||
// iterator...
|
||||
|
||||
for (torrent::Object::list_type::const_iterator cmdItr = itr->as_list().begin(), last = itr->as_list().end(); cmdItr != last; cmdItr++)
|
||||
if (cmdItr->is_string())
|
||||
rpc::parse_command(target, cmdItr->as_string().c_str(), cmdItr->as_string().c_str() + cmdItr->as_string().size());
|
||||
|
||||
return torrent::Object();
|
||||
|
||||
} else {
|
||||
return *itr;
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_size(const torrent::Object::string_type& args) {
|
||||
return (*control->view_manager()->find_throw(args))->size_visible();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_size_not_visible(const torrent::Object::string_type& args) {
|
||||
return (*control->view_manager()->find_throw(args))->size_not_visible();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_persistent(const torrent::Object::string_type& args) {
|
||||
core::View* view = *control->view_manager()->find_throw(args);
|
||||
|
||||
if (!view->get_filter().is_empty() || !view->event_added().is_empty() || !view->event_removed().is_empty())
|
||||
throw torrent::input_error("Cannot set modified views as persitent.");
|
||||
|
||||
view->set_filter("d.views.has=" + args);
|
||||
view->set_event_added("d.views.push_back_unique=" + args);
|
||||
view->set_event_removed("d.views.remove=" + args);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// TODO: These don't need wrapper functions anymore...
|
||||
torrent::Object
|
||||
cmd_ui_set_view(const torrent::Object::string_type& args) {
|
||||
control->ui()->download_list()->set_current_view(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);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_filter_download(core::Download* download, const torrent::Object::string_type& args) {
|
||||
(*control->view_manager()->find_throw(args))->filter_download(download);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_set_visible(core::Download* download, const torrent::Object::string_type& args) {
|
||||
(*control->view_manager()->find_throw(args))->set_visible(download);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_set_not_visible(core::Download* download, const torrent::Object::string_type& args) {
|
||||
(*control->view_manager()->find_throw(args))->set_not_visible(download);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_elapsed_less(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
int64_t start_time = rpc::convert_to_value(args.front());
|
||||
|
||||
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time < rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_elapsed_greater(const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Wrong argument count.");
|
||||
|
||||
int64_t start_time = rpc::convert_to_value(args.front());
|
||||
|
||||
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_ui() {
|
||||
CMD2_VAR_STRING("keys.layout", "qwerty");
|
||||
|
||||
CMD2_ANY_STRING("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2)));
|
||||
|
||||
CMD2_ANY_L ("view.list", std::bind(&apply_view_list));
|
||||
CMD2_ANY_LIST("view.set", std::bind(&apply_view_set, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_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.sort", std::bind(&apply_view_sort, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_current", std::bind(&apply_view_event, &core::ViewManager::set_sort_current, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST("view.event_added", std::bind(&apply_view_event, &core::ViewManager::set_event_added, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.event_removed", std::bind(&apply_view_event, &core::ViewManager::set_event_removed, std::placeholders::_2));
|
||||
|
||||
// Cleanup and add . to view.
|
||||
|
||||
CMD2_ANY_STRING("view.size", std::bind(&cmd_view_size, std::placeholders::_2));
|
||||
CMD2_ANY_STRING("view.size_not_visible", std::bind(&cmd_view_size_not_visible, std::placeholders::_2));
|
||||
CMD2_ANY_STRING("view.persistent", std::bind(&cmd_view_persistent, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING_V("view.filter_all", std::bind(&core::View::filter, std::bind(&core::ViewManager::find_ptr_throw, control->view_manager(), std::placeholders::_2)));
|
||||
|
||||
CMD2_DL_STRING ("view.filter_download", std::bind(&cmd_view_filter_download, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_visible", std::bind(&cmd_view_set_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_not_visible", std::bind(&cmd_view_set_not_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
// 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));
|
||||
|
||||
// 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("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_ANY("not", &apply_not);
|
||||
CMD2_ANY("false", &apply_false);
|
||||
CMD2_ANY("and", &apply_and);
|
||||
CMD2_ANY("or", &apply_or);
|
||||
|
||||
// A temporary command for handling stuff until we get proper
|
||||
// support for seperation of commands and literals.
|
||||
CMD2_ANY("branch", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 1));
|
||||
|
||||
CMD2_ANY_LIST("less", &apply_less);
|
||||
CMD2_ANY_LIST("greater", &apply_greater);
|
||||
CMD2_ANY_LIST("equal", &apply_equal);
|
||||
|
||||
CMD2_ANY_VALUE("convert.gm_time", std::bind(&apply_to_time, std::placeholders::_2, 0));
|
||||
CMD2_ANY_VALUE("convert.gm_date", std::bind(&apply_to_time, std::placeholders::_2, 0x2));
|
||||
CMD2_ANY_VALUE("convert.time", std::bind(&apply_to_time, std::placeholders::_2, 0x1));
|
||||
CMD2_ANY_VALUE("convert.date", std::bind(&apply_to_time, std::placeholders::_2, 0x1 | 0x2));
|
||||
CMD2_ANY_VALUE("convert.elapsed_time", std::bind(&apply_to_elapsed_time, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.kb", std::bind(&apply_to_kb, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.mb", std::bind(&apply_to_mb, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2));
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/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"
|
||||
#include "display/manager.h"
|
||||
#include "input/manager.h"
|
||||
#include "input/input_event.h"
|
||||
#include "rpc/command_scheduler.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/scgi.h"
|
||||
#include "rpc/object_storage.h"
|
||||
#include "ui/root.h"
|
||||
|
||||
#include "control.h"
|
||||
|
||||
Control::Control() :
|
||||
m_ui(new ui::Root()),
|
||||
m_display(new display::Manager()),
|
||||
m_input(new input::Manager()),
|
||||
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
|
||||
|
||||
m_commandScheduler(new rpc::CommandScheduler()),
|
||||
m_objectStorage(new rpc::object_storage()),
|
||||
m_directory_events(new torrent::directory_events()),
|
||||
|
||||
m_tick(0),
|
||||
m_shutdownReceived(false),
|
||||
m_shutdownQuick(false) {
|
||||
|
||||
m_core = new core::Manager();
|
||||
m_viewManager = new core::ViewManager();
|
||||
m_dhtManager = new core::DhtManager();
|
||||
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input, std::placeholders::_1));
|
||||
|
||||
m_taskShutdown.slot() = std::bind(&Control::handle_shutdown, this);
|
||||
|
||||
m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log_std));
|
||||
}
|
||||
|
||||
Control::~Control() {
|
||||
delete m_inputStdin;
|
||||
delete m_input;
|
||||
|
||||
delete m_viewManager;
|
||||
|
||||
delete m_ui;
|
||||
delete m_display;
|
||||
delete m_core;
|
||||
delete m_dhtManager;
|
||||
|
||||
delete m_directory_events;
|
||||
delete m_commandScheduler;
|
||||
delete m_objectStorage;
|
||||
}
|
||||
|
||||
void
|
||||
Control::initialize() {
|
||||
display::Canvas::initialize();
|
||||
display::Window::slot_schedule(rak::make_mem_fun(m_display, &display::Manager::schedule));
|
||||
display::Window::slot_unschedule(rak::make_mem_fun(m_display, &display::Manager::unschedule));
|
||||
display::Window::slot_adjust(rak::make_mem_fun(m_display, &display::Manager::adjust_layout));
|
||||
|
||||
m_core->http_stack()->set_user_agent(USER_AGENT);
|
||||
|
||||
m_core->initialize_second();
|
||||
m_core->listen_open();
|
||||
m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
|
||||
|
||||
m_core->set_hashing_view(*m_viewManager->find_throw("hashing"));
|
||||
|
||||
m_ui->init(this);
|
||||
|
||||
if(!display::Canvas::daemon()) {
|
||||
m_inputStdin->insert(torrent::main_thread()->poll());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Control::cleanup() {
|
||||
// delete m_scgi; m_scgi = NULL;
|
||||
rpc::xmlrpc.cleanup();
|
||||
|
||||
priority_queue_erase(&taskScheduler, &m_taskShutdown);
|
||||
|
||||
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();
|
||||
display::Canvas::cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
Control::cleanup_exception() {
|
||||
// delete m_scgi; m_scgi = NULL;
|
||||
|
||||
display::Canvas::cleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
Control::is_shutdown_completed() {
|
||||
if (!m_shutdownQuick || worker_thread->is_active())
|
||||
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() {
|
||||
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())
|
||||
priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + rak::timer::from_seconds(5));
|
||||
|
||||
} else {
|
||||
// Temporary hack:
|
||||
if (worker_thread->is_active())
|
||||
worker_thread->queue_item(&ThreadBase::stop_thread);
|
||||
|
||||
m_core->shutdown(true);
|
||||
}
|
||||
|
||||
m_shutdownQuick = true;
|
||||
m_shutdownReceived = false;
|
||||
}
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CONTROL_H
|
||||
#define RTORRENT_CONTROL_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <rak/timer.h>
|
||||
#include <rak/priority_queue_default.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
namespace ui {
|
||||
class Root;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
class Manager;
|
||||
class ViewManager;
|
||||
class DhtManager;
|
||||
}
|
||||
|
||||
namespace display {
|
||||
class Manager;
|
||||
}
|
||||
|
||||
namespace input {
|
||||
class InputEvent;
|
||||
class Manager;
|
||||
}
|
||||
|
||||
namespace rpc {
|
||||
class CommandScheduler;
|
||||
class XmlRpc;
|
||||
class object_storage;
|
||||
}
|
||||
|
||||
namespace torrent {
|
||||
class directory_events;
|
||||
}
|
||||
|
||||
class Control {
|
||||
public:
|
||||
Control();
|
||||
~Control();
|
||||
|
||||
bool is_shutdown_completed();
|
||||
bool is_shutdown_received() { return m_shutdownReceived; }
|
||||
bool is_shutdown_started() { return m_shutdownQuick; }
|
||||
|
||||
void initialize();
|
||||
void cleanup();
|
||||
void cleanup_exception();
|
||||
|
||||
void handle_shutdown();
|
||||
|
||||
void receive_normal_shutdown() { m_shutdownReceived = true; __sync_synchronize(); }
|
||||
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; __sync_synchronize(); }
|
||||
|
||||
core::Manager* core() { return m_core; }
|
||||
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; }
|
||||
input::InputEvent* input_stdin() { return m_inputStdin; }
|
||||
|
||||
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++; }
|
||||
|
||||
const std::string& working_directory() const { return m_workingDirectory; }
|
||||
void set_working_directory(const std::string& dir);
|
||||
|
||||
private:
|
||||
Control(const Control&);
|
||||
void operator = (const Control&);
|
||||
|
||||
core::Manager* m_core;
|
||||
core::ViewManager* m_viewManager;
|
||||
core::DhtManager* m_dhtManager;
|
||||
|
||||
ui::Root* m_ui;
|
||||
display::Manager* m_display;
|
||||
input::Manager* m_input;
|
||||
input::InputEvent* m_inputStdin;
|
||||
|
||||
rpc::CommandScheduler* m_commandScheduler;
|
||||
rpc::object_storage* m_objectStorage;
|
||||
torrent::directory_events* m_directory_events;
|
||||
|
||||
uint64_t m_tick;
|
||||
|
||||
mode_t m_umask;
|
||||
std::string m_workingDirectory;
|
||||
|
||||
rak::priority_item m_taskShutdown;
|
||||
|
||||
bool m_shutdownReceived lt_cacheline_aligned;
|
||||
bool m_shutdownQuick lt_cacheline_aligned;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
noinst_LIBRARIES = libsub_core.a
|
||||
|
||||
libsub_core_a_SOURCES = \
|
||||
curl_get.cc \
|
||||
curl_get.h \
|
||||
curl_socket.cc \
|
||||
curl_socket.h \
|
||||
curl_stack.cc \
|
||||
curl_stack.h \
|
||||
dht_manager.cc \
|
||||
dht_manager.h \
|
||||
download.cc \
|
||||
download.h \
|
||||
download_factory.cc \
|
||||
download_factory.h \
|
||||
download_list.cc \
|
||||
download_list.h \
|
||||
download_slot_map.h \
|
||||
download_store.cc \
|
||||
download_store.h \
|
||||
http_queue.cc \
|
||||
http_queue.h \
|
||||
manager.cc \
|
||||
manager.h \
|
||||
poll_manager.cc \
|
||||
poll_manager.h \
|
||||
range_map.h \
|
||||
view.cc \
|
||||
view.h \
|
||||
view_manager.cc \
|
||||
view_manager.h
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
|
||||
@@ -0,0 +1,149 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "curl_get.h"
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
size_t
|
||||
curl_get_receive_write(void* data, size_t size, size_t nmemb, void* handle) {
|
||||
if (!((CurlGet*)handle)->stream()->write((const char*)data, size * nmemb).fail())
|
||||
return size * nmemb;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CurlGet::~CurlGet() {
|
||||
close();
|
||||
}
|
||||
|
||||
void
|
||||
CurlGet::start() {
|
||||
if (is_busy())
|
||||
throw torrent::internal_error("Tried to call CurlGet::start on a busy object.");
|
||||
|
||||
if (m_stream == NULL)
|
||||
throw torrent::internal_error("Tried to call CurlGet::start without a valid output stream.");
|
||||
|
||||
m_handle = curl_easy_init();
|
||||
|
||||
if (m_handle == NULL)
|
||||
throw torrent::internal_error("Call to curl_easy_init() failed.");
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &curl_get_receive_write);
|
||||
curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
|
||||
|
||||
if (m_timeout != 0) {
|
||||
curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, (long)60);
|
||||
curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, (long)m_timeout);
|
||||
|
||||
// Normally libcurl should handle the timeout. But sometimes that doesn't
|
||||
// work right so we do a fallback timeout that just aborts the transfer.
|
||||
m_taskTimeout.slot() = std::bind(&CurlGet::receive_timeout, this);
|
||||
priority_queue_erase(&taskScheduler, &m_taskTimeout);
|
||||
priority_queue_insert(&taskScheduler, &m_taskTimeout, cachedTime + rak::timer::from_seconds(m_timeout + 5));
|
||||
}
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_FORBID_REUSE, (long)1);
|
||||
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
|
||||
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
|
||||
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
|
||||
|
||||
m_ipv6 = false;
|
||||
|
||||
m_stack->add_get(this);
|
||||
}
|
||||
|
||||
void
|
||||
CurlGet::close() {
|
||||
priority_queue_erase(&taskScheduler, &m_taskTimeout);
|
||||
if (!is_busy())
|
||||
return;
|
||||
|
||||
m_stack->remove_get(this);
|
||||
|
||||
curl_easy_cleanup(m_handle);
|
||||
|
||||
m_handle = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CurlGet::retry_ipv6() {
|
||||
CURL* nhandle = curl_easy_duphandle(m_handle);
|
||||
|
||||
curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
|
||||
curl_easy_cleanup(m_handle);
|
||||
|
||||
m_handle = nhandle;
|
||||
m_ipv6 = true;
|
||||
}
|
||||
|
||||
void
|
||||
CurlGet::receive_timeout() {
|
||||
return m_stack->transfer_done(m_handle, "Timed out");
|
||||
}
|
||||
|
||||
double
|
||||
CurlGet::size_done() {
|
||||
double d = 0.0;
|
||||
curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD, &d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
double
|
||||
CurlGet::size_total() {
|
||||
double d = 0.0;
|
||||
curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CORE_CURL_GET_H
|
||||
#define RTORRENT_CORE_CURL_GET_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
#include <torrent/http.h>
|
||||
|
||||
#include "rak/priority_queue_default.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class CurlStack;
|
||||
|
||||
class CurlGet : public torrent::Http {
|
||||
public:
|
||||
friend class CurlStack;
|
||||
|
||||
CurlGet(CurlStack* s) : m_active(false), m_handle(NULL), m_stack(s) {}
|
||||
virtual ~CurlGet();
|
||||
|
||||
void start();
|
||||
void close();
|
||||
|
||||
bool is_using_ipv6() { return m_ipv6; }
|
||||
void retry_ipv6();
|
||||
|
||||
bool is_busy() const { return m_handle; }
|
||||
bool is_active() const { return m_active; }
|
||||
|
||||
void set_active(bool a) { m_active = a; }
|
||||
|
||||
double size_done();
|
||||
double size_total();
|
||||
|
||||
CURL* handle() { return m_handle; }
|
||||
|
||||
private:
|
||||
CurlGet(const CurlGet&);
|
||||
void operator = (const CurlGet&);
|
||||
|
||||
void receive_timeout();
|
||||
|
||||
bool m_active;
|
||||
bool m_ipv6;
|
||||
|
||||
rak::priority_item m_taskTimeout;
|
||||
|
||||
CURL* m_handle;
|
||||
CurlStack* m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2008, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/multi.h>
|
||||
|
||||
#include <torrent/poll.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/utils/thread_base.h>
|
||||
|
||||
#include "control.h"
|
||||
|
||||
#include "curl_socket.h"
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
int
|
||||
CurlSocket::receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp) {
|
||||
CurlStack* stack = (CurlStack*)userp;
|
||||
CurlSocket* socket = (CurlSocket*)socketp;
|
||||
|
||||
if (what == CURL_POLL_REMOVE) {
|
||||
// We also probably need the special code here as we're not
|
||||
// guaranteed that the fd will be closed, afaik.
|
||||
if (socket != NULL)
|
||||
socket->close();
|
||||
|
||||
// TODO: Consider the possibility that we'll need to set the
|
||||
// fd-associated pointer curl holds to NULL.
|
||||
|
||||
delete socket;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (socket == NULL) {
|
||||
socket = stack->new_socket(fd);
|
||||
torrent::main_thread()->poll()->open(socket);
|
||||
|
||||
// No interface for libcurl to signal when it's interested in error events.
|
||||
// Assume that hence it must always be interested in them.
|
||||
torrent::main_thread()->poll()->insert_error(socket);
|
||||
}
|
||||
|
||||
if (what == CURL_POLL_NONE || what == CURL_POLL_OUT)
|
||||
torrent::main_thread()->poll()->remove_read(socket);
|
||||
else
|
||||
torrent::main_thread()->poll()->insert_read(socket);
|
||||
|
||||
if (what == CURL_POLL_NONE || what == CURL_POLL_IN)
|
||||
torrent::main_thread()->poll()->remove_write(socket);
|
||||
else
|
||||
torrent::main_thread()->poll()->insert_write(socket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CurlSocket::~CurlSocket() {
|
||||
if (m_fileDesc != -1)
|
||||
throw torrent::internal_error("CurlSocket::~CurlSocket() m_fileDesc != -1.");
|
||||
}
|
||||
|
||||
void
|
||||
CurlSocket::close() {
|
||||
if (m_fileDesc == -1)
|
||||
throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1.");
|
||||
|
||||
torrent::main_thread()->poll()->closed(this);
|
||||
m_fileDesc = -1;
|
||||
}
|
||||
|
||||
void
|
||||
CurlSocket::event_read() {
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071003)
|
||||
return m_stack->receive_action(this, CURL_CSELECT_IN);
|
||||
#else
|
||||
return m_stack->receive_action(this, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CurlSocket::event_write() {
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071003)
|
||||
return m_stack->receive_action(this, CURL_CSELECT_OUT);
|
||||
#else
|
||||
return m_stack->receive_action(this, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CurlSocket::event_error() {
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071003)
|
||||
return m_stack->receive_action(this, CURL_CSELECT_ERR);
|
||||
#else
|
||||
return m_stack->receive_action(this, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2008, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_CORE_CURL_SOCKET_H
|
||||
#define RTORRENT_CORE_CURL_SOCKET_H
|
||||
|
||||
#include <torrent/event.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class CurlStack;
|
||||
|
||||
class CurlSocket : public torrent::Event {
|
||||
public:
|
||||
CurlSocket(int fd, CurlStack* stack) : m_stack(stack) { m_fileDesc = fd; }
|
||||
~CurlSocket();
|
||||
|
||||
const char* type_name() const { return "curl"; }
|
||||
|
||||
void close();
|
||||
|
||||
static int receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp);
|
||||
|
||||
private:
|
||||
CurlSocket(const CurlSocket&);
|
||||
void operator = (const CurlSocket&);
|
||||
|
||||
virtual void event_read();
|
||||
virtual void event_write();
|
||||
virtual void event_error();
|
||||
|
||||
CurlStack* m_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,271 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <curl/multi.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rak/functional.h"
|
||||
#include "curl_get.h"
|
||||
#include "curl_socket.h"
|
||||
#include "curl_stack.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
CurlStack::CurlStack() :
|
||||
m_handle((void*)curl_multi_init()),
|
||||
m_active(0),
|
||||
m_maxActive(32),
|
||||
m_ssl_verify_host(true),
|
||||
m_ssl_verify_peer(true),
|
||||
m_dns_timeout(60) {
|
||||
|
||||
m_taskTimeout.slot() = std::bind(&CurlStack::receive_timeout, this);
|
||||
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071000)
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
|
||||
#endif
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
|
||||
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
|
||||
}
|
||||
|
||||
CurlStack::~CurlStack() {
|
||||
while (!empty())
|
||||
front()->close();
|
||||
|
||||
curl_multi_cleanup((CURLM*)m_handle);
|
||||
priority_queue_erase(&taskScheduler, &m_taskTimeout);
|
||||
}
|
||||
|
||||
CurlGet*
|
||||
CurlStack::new_object() {
|
||||
return new CurlGet(this);
|
||||
}
|
||||
|
||||
CurlSocket*
|
||||
CurlStack::new_socket(int fd) {
|
||||
CurlSocket* socket = new CurlSocket(fd, this);
|
||||
curl_multi_assign((CURLM*)m_handle, fd, socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::receive_action(CurlSocket* socket, int events) {
|
||||
CURLMcode code;
|
||||
|
||||
do {
|
||||
int count;
|
||||
#if (LIBCURL_VERSION_NUM >= 0x071003)
|
||||
code = curl_multi_socket_action((CURLM*)m_handle,
|
||||
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
|
||||
events,
|
||||
&count);
|
||||
#else
|
||||
code = curl_multi_socket((CURLM*)m_handle,
|
||||
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
|
||||
&count);
|
||||
#endif
|
||||
|
||||
if (code > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_socket_action.");
|
||||
|
||||
// Socket might be removed when cleaning handles below, future
|
||||
// calls should not use it.
|
||||
socket = NULL;
|
||||
events = 0;
|
||||
|
||||
if ((unsigned int)count != size()) {
|
||||
while (process_done_handle())
|
||||
; // Do nothing.
|
||||
|
||||
if (empty())
|
||||
priority_queue_erase(&taskScheduler, &m_taskTimeout);
|
||||
}
|
||||
|
||||
} while (code == CURLM_CALL_MULTI_PERFORM);
|
||||
}
|
||||
|
||||
bool
|
||||
CurlStack::process_done_handle() {
|
||||
int remaining_msgs = 0;
|
||||
CURLMsg* msg = curl_multi_info_read((CURLM*)m_handle, &remaining_msgs);
|
||||
|
||||
if (msg == NULL)
|
||||
return false;
|
||||
|
||||
if (msg->msg != CURLMSG_DONE)
|
||||
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
|
||||
|
||||
if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
|
||||
iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
|
||||
|
||||
if (itr == end())
|
||||
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
|
||||
|
||||
if (!(*itr)->is_using_ipv6()) {
|
||||
(*itr)->retry_ipv6();
|
||||
|
||||
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_add_handle.");
|
||||
}
|
||||
|
||||
} else {
|
||||
transfer_done(msg->easy_handle,
|
||||
msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
|
||||
}
|
||||
|
||||
return remaining_msgs != 0;
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::transfer_done(void* handle, const char* msg) {
|
||||
iterator itr = std::find_if(begin(), end(), rak::equal(handle, std::mem_fun(&CurlGet::handle)));
|
||||
|
||||
if (itr == end())
|
||||
throw torrent::internal_error("Could not find CurlGet with the right easy_handle.");
|
||||
|
||||
if (msg == NULL)
|
||||
(*itr)->trigger_done();
|
||||
else
|
||||
(*itr)->trigger_failed(msg);
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::receive_timeout() {
|
||||
receive_action(NULL, 0);
|
||||
|
||||
// Sometimes libcurl forgets to reset the timeout. Try to poll the value in that case, or use 10 seconds.
|
||||
if (!empty() && !m_taskTimeout.is_queued()) {
|
||||
long timeout;
|
||||
curl_multi_timeout((CURLM*)m_handle, &timeout);
|
||||
priority_queue_insert(&taskScheduler, &m_taskTimeout,
|
||||
cachedTime + rak::timer::from_milliseconds(std::max<unsigned long>(timeout, 10000)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::add_get(CurlGet* get) {
|
||||
if (!m_userAgent.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_USERAGENT, m_userAgent.c_str());
|
||||
|
||||
if (!m_httpProxy.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_PROXY, m_httpProxy.c_str());
|
||||
|
||||
if (!m_bindAddress.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bindAddress.c_str());
|
||||
|
||||
if (!m_httpCaPath.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_httpCaPath.c_str());
|
||||
|
||||
if (!m_httpCaCert.empty())
|
||||
curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_httpCaCert.c_str());
|
||||
|
||||
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYHOST, (long)(m_ssl_verify_host ? 2 : 0));
|
||||
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)(m_ssl_verify_peer ? 1 : 0));
|
||||
curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout);
|
||||
|
||||
base_type::push_back(get);
|
||||
|
||||
if (m_active >= m_maxActive)
|
||||
return;
|
||||
|
||||
m_active++;
|
||||
get->set_active(true);
|
||||
|
||||
if (curl_multi_add_handle((CURLM*)m_handle, get->handle()) > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_add_handle.");
|
||||
|
||||
#if (LIBCURL_VERSION_NUM < 0x071000)
|
||||
receive_timeout();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::remove_get(CurlGet* get) {
|
||||
iterator itr = std::find(begin(), end(), get);
|
||||
|
||||
if (itr == end())
|
||||
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::remove.");
|
||||
|
||||
base_type::erase(itr);
|
||||
|
||||
// The CurlGet object was never activated, so we just skip this one.
|
||||
if (!get->is_active())
|
||||
return;
|
||||
|
||||
get->set_active(false);
|
||||
|
||||
if (curl_multi_remove_handle((CURLM*)m_handle, get->handle()) > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_remove_handle.");
|
||||
|
||||
if (m_active == m_maxActive &&
|
||||
(itr = std::find_if(begin(), end(), std::not1(std::mem_fun(&CurlGet::is_active)))) != end()) {
|
||||
(*itr)->set_active(true);
|
||||
|
||||
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
|
||||
throw torrent::internal_error("Error calling curl_multi_add_handle.");
|
||||
|
||||
} else {
|
||||
m_active--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::global_init() {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
}
|
||||
|
||||
void
|
||||
CurlStack::global_cleanup() {
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
// TODO: Is this function supposed to set a per-handle timeout, or is
|
||||
// it the shortest timeout amongst all handles?
|
||||
int
|
||||
CurlStack::set_timeout(void* handle, long timeout_ms, void* userp) {
|
||||
CurlStack* stack = (CurlStack*)userp;
|
||||
|
||||
priority_queue_erase(&taskScheduler, &stack->m_taskTimeout);
|
||||
priority_queue_insert(&taskScheduler, &stack->m_taskTimeout, cachedTime + rak::timer::from_milliseconds(timeout_ms));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user