Compare commits

...
254 Commits
Author SHA1 Message Date
Adrien Béraud 1751cb02cb dhtnode: print metrics 2020-03-30 14:18:41 -04:00
Adrien Béraud c8cc0e9750 add req count debug 2020-03-30 14:18:41 -04:00
Adrien Béraud 6f05112970 dht: add node metrics
Provides info about internal dht structures
2020-03-30 14:18:41 -04:00
Adrien Béraud a1d62fd062 stats: add search, cached node count 2020-03-30 14:18:23 -04:00
Adrien Béraud 69f8969883 utils: fix build in 32 bit 2020-03-25 23:39:54 -04:00
Adrien Béraud bc200cd76d utils: fix indentation 2020-03-25 23:08:39 -04:00
Adrien Béraud 187c7dbce3 http: preserve headers during redirect 2020-03-25 23:00:16 -04:00
Adrien Béraud 81131f1c4e utils: check time bounds 2020-03-25 23:00:16 -04:00
Adrien Béraud ce9445a93f pseudo-rng: improve fallback seed 2020-03-25 23:00:16 -04:00
Adrien Béraud 16372cba0c Update README.md 2020-03-21 12:45:11 -04:00
Adrien Béraud a2cbef315a dht: avoid crash in persistent put when logging 2020-02-22 19:59:36 -05:00
Adrien Béraud bc7c43dfd1 value: cleanup 2020-02-22 19:59:36 -05:00
Adrien Béraud 771b300622 durl: cleanup, fix on macOS 2020-02-22 19:59:36 -05:00
Adrien Béraud 5ffb5c628d dht: avoid use-after-free when sending probe query 2020-02-14 13:52:55 -05:00
Adrien Béraud cfa4ce61b4 cmake: add option to build http without proxy 2020-02-13 16:55:59 -05:00
Adrien Béraud 5f15043f03 tools: add durl for http client testing 2020-02-12 16:46:06 -05:00
Adrien Béraud f445b2536d http: handle redirects 2020-02-12 16:45:25 -05:00
Adrien Béraud 6c2f791c4d network utils: don't block on mutex in rx thread (2) 2020-02-11 17:07:53 -05:00
Adrien Béraud 780726c66d network utils: don't block on mutex in rx thread 2020-02-11 16:20:30 -05:00
Adrien Béraud 8703cfdaee dht: erase announce form search nodes on cancelPut 2020-02-09 15:15:47 -05:00
Adrien Béraud 1c536cbf5e permanent put: set clientId 2020-02-09 10:34:42 -05:00
Adrien Béraud a39e2443a0 dht: reuse probe query, avoid leak 2020-02-09 00:51:58 -05:00
Adrien Béraud 57528e7aab scheduler: don't sync time on run 2020-02-08 22:04:50 -05:00
Adrien Béraud e9d70f204a tools: add perftest 2020-02-08 22:04:41 -05:00
Adrien Béraud ceb35c05c1 securedht: add option to disable cache 2020-02-08 20:27:44 -05:00
Adrien Béraud 55ccec5871 securedht: putEncrypted, putSigned fail if no key 2020-02-07 00:54:18 -05:00
Adrien Béraud 95028e3770 dht: always use pseudo-RNG for non-critical random numbers 2020-02-07 00:36:42 -05:00
Adrien Béraud abede1e72a pingpong: print execution time 2020-02-07 00:21:13 -05:00
Adrien Béraud 859d8dc9cf proxy server: check clientId for merging put 2020-02-07 00:21:13 -05:00
Sébastien Blin 1a67140463 proxyserver: enable keep alive packets 2020-02-06 14:15:47 -05:00
Adrien Béraud 9ae3d3c4d4 proxy: move info if possible 2020-02-05 14:25:03 -05:00
Adrien Béraud d3508c80f5 dhtrunner: take bound address by reference 2020-02-04 16:21:24 -05:00
Adrien Béraud 6c43efa4da http: use proper target in requests 2020-02-04 16:21:24 -05:00
Sébastien Blin c5c4c217dd tools: add script for following dhtproxy's stats 2020-01-28 16:27:20 -05:00
Sébastien Blin 5cfcf4861d proxyserver: set permanent put pushToken 2020-01-28 16:27:20 -05:00
Adrien Béraud 8597267c63 dht: add 'public stable' node configuration 2020-01-27 16:27:21 -05:00
Adrien Béraud 1b81d707f3 value: fix potential crash in contentEquals 2020-01-27 12:13:17 -05:00
Adrien Béraud 7791163d49 proxy: receive values in blocks 2020-01-22 16:02:26 -05:00
Adrien Béraud 56db1bba19 proxy server: merge identical put requests 2020-01-22 15:56:48 -05:00
Adrien Béraud a7092c2dc7 dhtnode: show value id in put response 2020-01-22 13:15:37 -05:00
Adrien Béraud fc95c85983 proxy server: send values in batches 2020-01-22 13:15:37 -05:00
Adrien Béraud 3490b19fe3 proxy client: cleanup 2020-01-22 13:15:37 -05:00
Adrien Béraud 4a20814d59 proxy client: let the server choose the value id 2020-01-22 13:15:37 -05:00
Adrien Béraud 707fb39975 net: fix sending query in sendGetValues 2020-01-20 12:15:33 -05:00
Adrien Béraud cbb2406a12 utils: improve duration display 2020-01-19 17:47:54 -05:00
Adrien Béraud 7764620460 proxy client: fix warning 2020-01-19 14:32:57 -05:00
Adrien Béraud 5af0f0c3d0 proxy server: flush response after all values are sent 2020-01-19 14:32:57 -05:00
Adrien Béraud ec8beec427 proxy server: update stats on startup 2020-01-19 14:32:57 -05:00
Adrien Béraud 7b8ebbc54d proxy server: catch more exceptions, cleanup 2020-01-19 14:32:57 -05:00
Adrien Béraud dc46c2274c net: exponential backoff, randomize packet expiration time 2020-01-19 14:32:57 -05:00
Adrien Béraud 052ed1f58c proxy server: handlePrintStats on startup 2020-01-18 22:20:01 -05:00
Adrien Béraud 9096f650f5 dht: increase default max request rate to 8k req/s 2020-01-18 19:54:54 -05:00
Adrien Béraud 900655b11f dht: give current time through periodic 2020-01-18 13:58:22 -05:00
Adrien Béraud 2900b1d17f net: limit recycled packet queue max size 2020-01-18 13:56:50 -05:00
Adrien Béraud 69e71dbeaa SecureDht: cleanup 2020-01-17 15:58:22 -05:00
Adrien Béraud 3793423b2f dht: log cleanup 2020-01-17 15:57:32 -05:00
Adrien Béraud b012878488 dhtrunner: set logger in setLogger 2020-01-17 15:57:32 -05:00
Adrien Béraud c1005fa334 request: free message memory on clear 2020-01-17 15:17:35 -05:00
Adrien Béraud 0f9f623b31 dht: use unique_ptr for SearchNode 2020-01-17 12:47:14 -05:00
Adrien Béraud 2cfebdf9fa net: use packet lists and recycle old packet structures 2020-01-17 12:26:03 -05:00
Adrien Béraud 481b1cb3b4 dht: use pseudo-random generator for value ids 2020-01-16 13:51:51 -05:00
Adrien Béraud 7f1d960a56 dhtrunner: add async/non-blocking version of getNodeInfo 2020-01-16 13:24:37 -05:00
Adrien Béraud 91e1e942ab Update peer_discovery.cpp 2020-01-15 23:16:36 -05:00
Adrien Béraud ae89365f23 Update peer_discovery.cpp 2020-01-15 23:16:36 -05:00
Adrien Béraud 93cd8d541c Update peer_discovery.cpp 2020-01-15 23:16:36 -05:00
Paymon 9487bc5e42 implement connectivity change in peer discovery
this makes peer discovery pub/sub on connectivity change, it aims to
make peer discovery more energy efficient.

also, stop echo'ing.

TODO:
in its current implementation however, peer_discovery operates in the
dark; it doesn't know routes available to it (v4 vs v6); nor does it
know of the state of the link(s) (UP vs. DOWN) and therefore it merely
tries to, on connectivity change, (re)pub/sub on previous ip version
routes.

IDEA:
open an interface to kernel so that peer discovery, and perhaps others,
can learn about the routes available to them.

don't leave

add query() and direct publish(endpoint)

check if peer discovery was request (run and compile time)

add try/catch routine to DomainPeerDiscovery's constructor
2020-01-15 23:16:36 -05:00
Adrien Béraud 10d48137a9 proxy server: update stats on node info 2020-01-15 17:04:12 -05:00
Adrien Béraud 5b15fdeeef proxy server: use shared_ptr for stats, remove statsMutex_ 2020-01-15 13:54:24 -05:00
Adrien Béraud 3ba43c80a2 http: add weak_ptr to Request in Response 2020-01-15 11:45:26 -05:00
Adrien Béraud 16333f4224 http: add mutex to Request, Connection 2020-01-15 11:45:03 -05:00
Adrien Béraud 0864ac9a39 proxy server: handle put session id provided after first request 2020-01-10 12:26:57 -05:00
Adrien Béraud 616d6fe4b8 update copyright date 2020-01-03 15:14:32 -05:00
Adrien Béraud dea4b202bf proxy server: make json type explicit 2020-01-03 15:10:22 -05:00
Adrien Béraud dc2f354652 proxy: use timestamps to handle reordered notifications 2020-01-03 14:47:22 -05:00
Sébastien Blin 87041e301f proxyclient: refresh put on restartListeners
There is no need to check if the put is ok or not before refreshing it. Indeed,
the first successful put will make the ok flag to true. But, if an expiration
is missed (when not connected for example), the put will not be refreshed when
the connectivity will change (moreover, server and client can have different
timeouts).
2020-01-03 11:39:05 -05:00
Sébastien Blin 189f94442e dhtproxyclient: setPushNotification before first permanent put
When SecureDHT is initialized, a permanent put is done to announce the node
and then the push token is set. This means the the first permanent put will not
get expirations notification because it's considered as a non push device's put.
We should inject the push token as soon as possible.
2020-01-03 11:39:05 -05:00
Adrien Béraud c5c3695612 logger: use shared_ptr 2019-12-19 15:12:23 -05:00
Adrien Béraud 6a7ad871e2 value: toString prints raw data if text/plain 2019-12-19 15:12:23 -05:00
Adrien Béraud 99890fca64 proxy server: update sessionId when necessary 2019-12-19 14:20:03 -05:00
Adrien Béraud 2dbf57d36b Update README.md 2019-12-16 23:42:31 -05:00
Adrien Béraud 5438d50578 proxy: add session token 2019-12-16 16:37:07 -05:00
Adrien Béraud 548255073f docker: build c bindings, use asio 1.12 2019-12-16 12:22:05 -05:00
Adrien Béraud abaf091772 c binding: fix build 2019-12-16 11:41:49 -05:00
Adrien Béraud 7094b79714 crypto: add PublicKey::pack(uint8_t* out, size_t* out_len) 2019-12-14 15:29:42 -05:00
Adrien Béraud 1f672773ba proxy server: respect value priority for push notifications 2019-12-14 13:02:07 -05:00
Adrien Béraud 374fdd6cc9 proxy: send normal priority push message for value expiration 2019-12-14 13:02:07 -05:00
Adrien Béraud 54b1314ab8 value: optimize json parsing 2019-12-14 13:02:07 -05:00
Adrien Béraud 51c35d8b54 value: add priority 2019-12-14 13:02:07 -05:00
Adrien Béraud fea736428e msgpack: take const reference in unpack 2019-12-14 13:01:24 -05:00
Adrien Béraud 2d358adf0e utils: add findMapValue(string) 2019-12-14 13:00:13 -05:00
Adrien Béraud 26c2e16a42 value: optimize json parsing 2019-12-14 00:41:41 -05:00
Adrien Béraud e8b385c220 utils: optimize findMapValue 2019-12-13 23:57:22 -05:00
Adrien Béraud c1e2a368a8 docker: add ssl, install http-parser to /usr 2019-12-13 16:24:46 -05:00
Adrien Béraud c62f27c929 tools: add missing include 2019-12-12 17:00:35 -05:00
Adrien Béraud ec0c3d4d25 docker: build asio without tests and examples 2019-12-12 15:04:45 -05:00
Adrien Béraud 17a1178054 tools: add missing includes for indexation support 2019-12-12 15:00:17 -05:00
Adrien Béraud 6256c576c9 configure: cleanup 2019-12-12 14:51:59 -05:00
Adrien Béraud 9565adf693 proxy server: always depend on jsoncpp 2019-12-12 14:51:59 -05:00
Adrien Béraud c10aa32596 cpp: include config.h when necessary 2019-12-12 14:51:59 -05:00
Adrien Béraud 21c294f352 docker: update asio 2019-12-12 14:51:59 -05:00
Adrien Béraud 4654f78e08 autotools: allow to build without peer discovery 2019-12-12 14:51:59 -05:00
Adrien Béraud 38644fc934 includes: don't include proxy server, pht by default 2019-12-12 14:44:53 -05:00
Adrien Béraud fa8dc4c835 callbacks: add missing header 2019-12-12 14:33:00 -05:00
Adrien Béraud 6dab10cac2 github: disable tests and examples when building asio 2019-12-12 12:24:56 -05:00
Adrien Béraud 77a1c27f2b github: build asio 2019-12-12 11:52:43 -05:00
Adrien Béraud e8577bfd05 dhtrunner: fix build without peer discovery 2019-12-12 11:42:06 -05:00
Adrien Béraud c0327a9881 dhtrunner: fix build without peer discovery 2019-12-11 11:43:20 -05:00
Adrien Béraud 2a1eacc949 tests: only link with ssl if required 2019-12-09 16:23:15 -05:00
Adrien Béraud e705bebc25 github: don't build proxy 2019-12-09 16:06:39 -05:00
Adrien Béraud a330762f40 build: always use standalone asio 2019-12-09 15:40:48 -05:00
Adrien Béraud e7972ae897 dockerfiles: update 2019-12-09 15:34:26 -05:00
Adrien Béraud 8d2d40cb7f peer discovery: simplify includes 2019-12-09 14:53:27 -05:00
Adrien Béraud aceb548c26 cmake: make peer discovery build optional 2019-12-09 14:43:04 -05:00
Adrien Béraud afce4639e1 tests/peerdiscover: add missing includes 2019-12-09 14:07:42 -05:00
Adrien Béraud e5d248bcd0 peer discovery: use asio 2019-12-09 03:28:45 -05:00
Adrien Béraud 0fbebf8e03 http: cleanup, fix handling error when no logger is set 2019-12-08 10:48:34 -05:00
Adrien Béraud 24efa37846 http: cleanup 2019-12-08 00:25:21 -05:00
Linas Vepstas c0f14ca59d Fix duplicated, non-functional log message.
Inside the if-statement, the log message will always print zero.
Confusingly, its the same message as the one in the loop above it.
Make the message distinct.
2019-12-07 22:28:35 -05:00
Adrien Béraud 05a66cc1f1 proxy client: use common jsonReader 2019-12-07 22:22:37 -05:00
Adrien Béraud ed6df8869c proxy: don't use keep-alive by default 2019-12-07 22:22:37 -05:00
Adrien Béraud b7d410e1aa tests: add http tester 2019-12-07 16:23:08 -05:00
Adrien Béraud 77a377a406 http: add OnDone callback 2019-12-07 16:23:08 -05:00
Adrien Béraud e0b6f152f1 proxy client: add LineSplitter 2019-12-07 16:23:08 -05:00
Adrien Béraud dd3c789916 proxy server: 0-initialize fields 2019-12-07 16:23:08 -05:00
Adrien Béraud 333087bcba dhtrunner: fix getNodeInfo using proxy client 2019-12-07 16:23:08 -05:00
Adrien Béraud 5b87090cab http: use http_parser parsing logic 2019-12-07 16:23:08 -05:00
Adrien Béraud fffee634f1 proxy client: avoid destroying twice 2019-12-05 18:39:39 -05:00
Adrien Béraud c4aa272dbb http/request: add constructor 2019-12-05 18:39:39 -05:00
Adrien Béraud 4ce78bdb4d c wrapper: link statically when required 2019-12-05 18:35:43 -05:00
Adrien Béraud f331f39c77 c wrapper: add dht_privatekey_export 2019-12-05 18:35:43 -05:00
Adrien Béraud 17fb92654e http: check parser before use 2019-12-03 16:45:19 -05:00
Adrien Béraud 294034f00f proxy client: don't report connectivity failure for aborted requests 2019-12-03 16:21:33 -05:00
Adrien Béraud 36857c1f3d http/request: add aborted flag and actual status code 2019-12-03 16:21:04 -05:00
Adrien Béraud 7e9f5303bd github: don't run distcheck 2019-12-02 01:30:56 -05:00
Adrien Béraud c2780b1ca9 build/autoconf: always build python Makefile 2019-12-02 01:15:38 -05:00
Adrien Béraud 16b798324d github: disable python 2019-12-02 00:53:27 -05:00
Adrien Béraud bc850bf00c build/autotools: use proper path for tools build include 2019-12-02 00:30:37 -05:00
Adrien Béraud 0d8d302128 update argon2 2019-12-02 00:11:08 -05:00
Adrien Béraud 97013badfa github: install argon2 before configure 2019-12-02 00:06:49 -05:00
Adrien Béraud 31185c24f0 build/autoconf: always build doc Makefile 2019-12-01 23:49:04 -05:00
Adrien Béraud 2f6f8e2ac1 cmake/tools: link with readline dependenciess 2019-12-01 22:46:41 -05:00
zhengfish 8f141951ce fixed a compiling error in openwrt-18.04.5
Signed-off-by: zhengfish <zhengfish@gmail.com>
2019-12-01 22:41:29 -05:00
zhengfish 43d111b7dc fixed a linking error in openwrt-18.06: undefined reference to 'tgetnum'
Signed-off-by: zhengfish <zhengfish@gmail.com>
2019-12-01 22:41:29 -05:00
Adrien Béraud 620ba2a89b proxy server: fix warning 2019-12-01 21:01:42 -05:00
Adrien Béraud d1598380db proxy server: fix build without push notifications 2019-12-01 21:00:27 -05:00
Adrien Béraud 69fe399db0 proxy server: cancelListen on destroy 2019-12-01 20:54:48 -05:00
Adrien Béraud a60dde2e13 tests: use shutdown 2019-12-01 19:41:02 -05:00
Adrien Béraud 201982b1a9 dhtrunner: don't count cancel as ops 2019-12-01 19:40:44 -05:00
Adrien Béraud 83f2b272a7 dhtrunner: add ongoing op count to node info 2019-12-01 15:07:35 -05:00
Adrien Béraud 7e47d0458a tests/proxy: cleanup 2019-12-01 14:53:50 -05:00
Adrien Béraud f6d26757fa dhtrunner: wait for current ops to complete on shutdown 2019-12-01 14:53:36 -05:00
Adrien Béraud 476d0bca4f proxy client: lock while canceling requests 2019-12-01 14:52:42 -05:00
Adrien Béraud 259986e786 network engine: don't throw in case of unknown transaction 2019-12-01 14:52:21 -05:00
Adrien Béraud 8ff0c979d4 proxy server: cleanup 2019-11-30 20:36:20 -05:00
Adrien Béraud 913cb543c8 crypto: improve exception types 2019-11-30 19:42:02 -05:00
Adrien Béraud b380c9ffba http: cleanup 2019-11-30 18:47:29 -05:00
Adrien Béraud 8c717085b4 cmake: cleanup 2019-11-30 18:11:00 -05:00
Adrien Béraud 48742a1058 tests: fix catching exception 2019-11-30 18:11:00 -05:00
Adrien Béraud fe11285a03 http: close on request end with Connection: close, cleanup 2019-11-30 18:11:00 -05:00
Adrien Béraud fb34770a54 http: reuse connection istream, cleanup 2019-11-30 17:21:52 -05:00
Adrien Béraud 4a909419e9 http: handle Request lifetime when sharing resolver/connection 2019-11-30 17:21:52 -05:00
Adrien Béraud dab7099369 proxy server: cleanup 2019-11-28 22:16:22 -05:00
Adrien Béraud 9c84e59bbf autotools: update to C++14 2019-11-27 12:12:29 -05:00
Adrien Béraud eae383b3ed autotools: remove unneeded macros 2019-11-26 12:46:26 -05:00
Adrien Béraud 28bf78408d network utils: fix some race conditions 2019-11-26 12:24:37 -05:00
Adrien Béraud 7ed6f74e6b proxy_server: add mutex to protect requests 2019-11-26 12:24:28 -05:00
Adrien Béraud cf6d9fd8c2 proxy client: add lock for requests 2019-11-25 15:43:23 -05:00
Adrien Béraud 5df34bb752 http: use atomic ids 2019-11-25 15:42:45 -05:00
Adrien Béraud bebb66490d tests: fix proxy tester 2019-11-25 13:44:55 -05:00
Adrien Béraud 5f361748eb Update ccpp.yml 2019-11-19 13:59:55 -05:00
Adrien Béraud 984745624c Update ccpp.yml 2019-11-19 13:58:46 -05:00
Adrien Béraud f9e860fdc8 docker/github: use deps base image 2019-11-19 13:52:40 -05:00
Adrien Béraud 06ea3d23e5 docker: add dockerfiles for Ubuntu 18.04 (Bionic) 2019-11-19 13:44:45 -05:00
Adrien Béraud f0857a5925 Update ccpp.yml 2019-11-19 11:05:00 -05:00
Adrien Béraud 5a993fb902 Create ccpp.yml 2019-11-19 11:02:54 -05:00
Adrien Béraud 8a18c591e9 http: initialize connection type, cleanup 2019-11-12 16:45:00 -05:00
Adrien Béraud 9daa7ec283 dhtrunner: default peer request rate to global/8 2019-11-11 12:58:11 -05:00
Adrien Béraud 01f2ad9ea4 tools: show connectivity change in log 2019-11-11 11:54:44 -05:00
Adrien Béraud 2dd4cde035 tools: factorize print_node_info 2019-11-08 16:52:27 -05:00
Adrien Béraud cb0005d0eb tools: factor configuration parsing 2019-11-08 16:12:04 -05:00
Adrien Béraud eca340b785 tools: add argument to disable rate limiting 2019-11-08 15:29:53 -05:00
Adrien Béraud cdd035b801 rate limiter: cleanup 2019-11-07 19:17:27 -05:00
Adrien Béraud cb7d7f6614 dht: allow to configure rate limiter 2019-11-07 16:43:04 -05:00
Adrien Béraud f5a6801ab9 value: cleanup 2019-11-07 11:52:27 -05:00
Adrien Béraud 0049ba92e6 thread pool: retransmit exception through future 2019-11-07 11:51:44 -05:00
Adrien Béraud 7838e7de0b docker: add python3-setuptools 2019-11-06 12:51:18 -05:00
Adrien Béraud e2d7dbc293 proxy client: declare mutex before protected objects 2019-11-05 16:39:03 -05:00
Adrien Béraud 090da49fed http/Request: cleanup 2019-11-04 15:50:55 -05:00
Adrien Béraud 22594396d2 http/Request: check conn_ on cancel 2019-11-04 15:49:05 -05:00
Adrien Béraud 0c8d0e2e0d http/Request: atomically exchange terminate 2019-11-04 15:48:39 -05:00
Adrien Béraud 18793cee3b proxy server: close listener on connection close only 2019-11-01 10:37:19 -04:00
Adrien Béraud 0bde82a218 tests/proxy: cleanup 2019-11-01 10:24:17 -04:00
Adrien Béraud bc84655f42 proxy server: update for Restinio v.0.6.0.1 2019-10-31 16:00:51 -04:00
Adrien Béraud ed642b0337 proxy: check that callback is not null 2019-10-31 14:36:34 -04:00
Adrien Béraud f710df9675 proxy: cleanup 2019-10-31 13:44:05 -04:00
Sébastien Blin 42398a541d rust: infohash support == operator and from hex 2019-10-31 10:56:52 -04:00
Sébastien Blin 429a5ad1d4 dhtrunner: fix put_encrypted API 2019-10-31 10:56:52 -04:00
Sébastien Blin 01bc43af35 rust: fix import for PrivateKey 2019-10-31 10:56:52 -04:00
Sébastien Blin 555487012b rust: remove T for no. Anyway we must at least add None 2019-10-31 10:56:52 -04:00
Sébastien Blin 697d554edb dhtrunner: change put methods 2019-10-31 10:56:52 -04:00
Sébastien Blin 8edd67834c rust: add some wrappers for value 2019-10-31 10:56:52 -04:00
Adrien Béraud 80f04430c3 proxy client: build resolver if none available 2019-10-30 14:53:07 -04:00
Adrien Béraud e4853bd29c proxy: use common Json builder 2019-10-30 14:17:42 -04:00
Adrien Béraud 6863800cfb dhtrunner: allow to cancelPut with value 2019-10-30 11:33:33 -04:00
Adrien Béraud 1f387a0e95 proxy client: resolve again on connectivity change 2019-10-30 11:33:16 -04:00
Adrien Béraud 142aee12a7 c wrapper: add support for putEncrypted 2019-10-28 17:43:00 -04:00
Adrien Béraud 95a65ce565 c wrapper: add support for putSigned 2019-10-28 17:35:41 -04:00
Adrien Béraud 144fa7ddc8 dhtrunner: allow permanent put for signed/encrypted values 2019-10-28 17:35:19 -04:00
Adrien Béraud b77fd2336f c wrapper: return null if no signer 2019-10-28 17:34:03 -04:00
Adrien Béraud c0e117871e c wrapper: allow retrieving value owner and recipient 2019-10-28 15:25:31 -04:00
Sébastien Blin 3c88eaa602 rust: add from_slice 2019-10-25 15:29:38 -04:00
Sébastien Blin 8d131449a8 rust: load identity from bytes 2019-10-25 15:29:38 -04:00
Sébastien Blin fee7e5dd30 rust: fix callback result and add DhtIdentity::new() 2019-10-25 15:29:38 -04:00
Sébastien Blin 4c2a974433 rust: link to certificate C-bindings 2019-10-25 15:29:38 -04:00
Sébastien Blin a483205976 infohash: add from_bytes 2019-10-25 15:29:38 -04:00
Adrien Béraud 96df1d4339 c wrapper: update callback return types 2019-10-25 11:05:35 -04:00
Seva 432f387423 http: ensure conn callbacks are always invoked 2019-10-24 16:03:07 -04:00
Seva 3abb9114ba http: ensure sockets exists before invocations 2019-10-24 16:03:07 -04:00
Adrien Béraud 727c5f0e8c c wrapper: add wrappers for dht::crypto::Certificate 2019-10-24 13:29:50 -04:00
Adrien Béraud f86abfaf22 crypto: add tests for corrupted data 2019-10-22 13:59:36 -04:00
Adrien Béraud f84131c820 crypto: improve authenticated encryption performance 2019-10-22 13:59:36 -04:00
Adrien Béraud 28de983166 update to version 2.0.0 2019-10-22 10:52:49 -04:00
Adrien Béraud 4b28278cb1 Update README.md 2019-10-22 10:48:50 -04:00
Sébastien Blin 653a4309bd rust: value to bytes 2019-10-22 10:47:43 -04:00
Sébastien Blin 48b763f11b rust: add from_bytes for value 2019-10-22 10:47:43 -04:00
Sébastien Blin cbfa12a921 rust: add permanent put, get_id(), get_node_id(), get_public_addresses() 2019-10-22 10:47:43 -04:00
Sébastien Blin 3e0d4cd703 rust: link DhtRunnerConfig 2019-10-22 10:47:43 -04:00
Sébastien Blin 4bff6d392a rust: clean warnings 2019-10-22 10:47:43 -04:00
Sébastien Blin 712b7218a9 rust: clean listen API 2019-10-22 10:47:43 -04:00
Sébastien Blin 5a8e252e32 rust: get2 -> get 2019-10-22 10:47:43 -04:00
Sébastien Blin b5be4549dc rust: clean dhtnode.rs 2019-10-22 10:47:43 -04:00
Sébastien Blin bf8fb6f321 rust: clean listen API 2019-10-22 10:47:43 -04:00
Sébastien Blin 08cf212c53 rust: split in files 2019-10-22 10:47:43 -04:00
Sébastien Blin fc2a597bb2 rust: update bootstrap api 2019-10-22 10:47:43 -04:00
Sébastien Blin 7212b7a28b rust: change put api 2019-10-22 10:47:43 -04:00
Sébastien Blin 5c610895fe rust: add support for all functions available in the C wrapper 2019-10-22 10:47:43 -04:00
Sébastien Blin a567ca1dc1 rust: add support for listen/cancel_listen 2019-10-22 10:47:43 -04:00
Sébastien Blin 97b20705a1 rust: add put bindings 2019-10-22 10:47:43 -04:00
Sébastien Blin 431da16ba6 dhtnode: add example with get 2019-10-22 10:47:43 -04:00
Sébastien Blin 09818d779e rust: start dhtnode example 2019-10-22 10:47:43 -04:00
Sébastien Blin 934e36ba13 rust: ffi POC 2019-10-22 10:47:43 -04:00
Adrien Béraud 2e47b9bab5 c wrapper: add dht_runner_get_public_address to dhtcnode 2019-10-21 15:56:35 -04:00
Adrien Béraud f938d486d5 c wrapper: add listen context to dhtcnode 2019-10-21 15:09:56 -04:00
Adrien Béraud 76b4da089e c wrapper: add dht_runner_get_public_address 2019-10-21 14:33:37 -04:00
Adrien Béraud 2a72277194 c wrapper: add dht_runner_get_id, get_node_id 2019-10-21 14:19:29 -04:00
Adrien Béraud e8d96d3b42 c wrapper: add support for permanent put 2019-10-21 14:04:12 -04:00
Adrien Béraud c92d236c1b c wrapper: handle null string in config 2019-10-21 12:37:36 -04:00
Adrien Béraud b680407e9a c wrapper: add callback to free listen context data 2019-10-21 11:08:42 -04:00
Seva 6caf4b0d0b http: ensure no data is lost in read_bytes 2019-10-18 15:44:26 -04:00
Seva 7f65fdc7f9 http: try to read full content-length after headers 2019-10-18 10:45:34 -04:00
Adrien Béraud b00dfdf572 c wrapper: reverse is_zero value 2019-10-17 10:29:37 -04:00
Adrien Béraud 2b1d2fc3f6 c wrapper: use shared_ptr for dht_privatekey 2019-10-16 17:23:04 -04:00
Adrien Béraud a0566cf695 dhtchat: cancel listen on channel disconnect 2019-10-16 16:18:38 -04:00
Adrien Béraud a3f2b055a1 c wrapper: don't build by default 2019-10-16 16:17:09 -04:00
127 changed files with 6227 additions and 3272 deletions

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: deps
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev
- name: autogen
run: ./autogen.sh
- name: argon2
run: |
cd argon2 && make && sudo make install && cd ..
- name: asio
run: |
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& sudo make install \
&& cd ../../ && rm -rf asio*
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
+60 -35
View File
@@ -1,7 +1,10 @@
cmake_minimum_required (VERSION 3.1)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
project (opendht)
set (opendht_VERSION_MAJOR 1)
set (opendht_VERSION_MINOR 10.1)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 0.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -22,9 +25,11 @@ option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" O
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS "Add unit tests executable" OFF)
option (OPENDHT_C "Build C bindings" ON)
option (OPENDHT_C "Build C bindings" OFF)
find_package(Doxygen)
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
@@ -60,10 +65,9 @@ if (Jsoncpp_FOUND)
)
endif()
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_HTTP)
find_package(Restinio REQUIRED)
if (Restinio_FOUND)
add_definitions(-DASIO_STANDALONE)
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
find_library(HTTP_PARSER_LIBRARY http_parser)
@@ -85,6 +89,11 @@ if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
endif()
else()
set(OPENDHT_PROXY_OPENSSL OFF)
endif()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
endif()
# Build flags
@@ -95,6 +104,7 @@ if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
@@ -176,7 +186,6 @@ list (APPEND opendht_SOURCES
src/securedht.cpp
src/dhtrunner.cpp
src/log.cpp
src/peer_discovery.cpp
src/network_utils.cpp
src/thread_pool.cpp
)
@@ -202,12 +211,17 @@ list (APPEND opendht_HEADERS
include/opendht/securedht.h
include/opendht/log.h
include/opendht/log_enable.h
include/opendht/peer_discovery.h
include/opendht/thread_pool.h
include/opendht/network_utils.h
include/opendht.h
)
if (OPENDHT_PEER_DISCOVERY)
list (APPEND opendht_SOURCES src/peer_discovery.cpp)
list (APPEND opendht_HEADERS include/opendht/peer_discovery.h)
add_definitions(-DOPENDHT_PEER_DISCOVERY)
endif()
if (OPENDHT_PYTHON)
message("Indexation enabled since it is required for Python support")
set(OPENDHT_INDEX ON)
@@ -241,7 +255,7 @@ if (OPENDHT_PROXY_CLIENT)
)
endif ()
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_HTTP)
if (OPENDHT_PUSH_NOTIFICATIONS)
message("Using push notification")
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
@@ -321,7 +335,12 @@ if (OPENDHT_C)
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
target_link_libraries(opendht-c opendht)
if (OPENDHT_SHARED)
target_link_libraries(opendht-c opendht)
else ()
target_link_libraries(opendht-c opendht-static)
endif ()
# PkgConfig module
configure_file (
opendht-c.pc.in
@@ -342,7 +361,6 @@ if (OPENDHT_PYTHON)
endif ()
# CMake module
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
VERSION ${opendht_VERSION}
COMPATIBILITY AnyNewerVersion
@@ -362,46 +380,53 @@ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATIO
# Unit tests
if (OPENDHT_TESTS)
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
list (APPEND test_FILES
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
)
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
if (OPENDHT_PEER_DISCOVERY)
list (APPEND test_FILES
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
)
endif()
add_executable(opendht_unit_tests
tests/tests_runner.cpp
${test_FILES}
tests/tests_runner.cpp
${test_FILES}
)
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${CPPUNIT_INCLUDE_DIRS})
if (OPENDHT_SHARED)
target_link_libraries(opendht_unit_tests opendht)
target_link_libraries(opendht_unit_tests opendht)
else ()
target_link_libraries(opendht_unit_tests opendht-static)
target_link_libraries(opendht_unit_tests opendht-static)
endif ()
target_link_libraries(opendht_unit_tests
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
ssl crypto jsoncpp
${Jsoncpp_LIBRARIES}
)
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht_unit_tests ${OPENSSL_LIBRARIES})
endif()
enable_testing()
add_test(TEST opendht_unit_tests)
endif()
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
-2
View File
@@ -16,9 +16,7 @@ if ENABLE_TESTS
SUBDIRS += tests
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
+5 -5
View File
@@ -14,9 +14,9 @@ Values are distributed over the network, with redundancy.
* High resilience to network disruption
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
* IPv4 and IPv6 support
* Clean and powerful C++14 map API
* Python 3 bindings
* REST API
* Clean and powerful **C++14** map API
* Bindings for **C, Rust & Python 3**
* REST API with optional HTTP client+server with push notification support
## Documentation
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
@@ -99,14 +99,14 @@ for r in results:
- (optional) restinio used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 5.2+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2015
- Build tested with Microsoft Visual Studio 2015, 2017, 2019
## Contact
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## License
Copyright (C) 2014-2019 Savoir-faire Linux Inc.
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
OpenDHT 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.
+1 -1
Submodule argon2 updated: 670229c849...62358ba212.
+284 -75
View File
@@ -2,14 +2,29 @@
#include "opendht.h"
using ValueSp = std::shared_ptr<dht::Value>;
using PrivkeySp = std::shared_ptr<dht::crypto::PrivateKey>;
using PubkeySp = std::shared_ptr<const dht::crypto::PublicKey>;
using CertSp = std::shared_ptr<dht::crypto::Certificate>;
#ifdef __cplusplus
extern "C" {
#endif
// dht::InfoHash
const char* dht_infohash_print(const dht_infohash* h)
{
inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) {
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = h;
return ret;
}
inline dht_pkid dht_pkid_to_c(const dht::PkId& h) {
dht_pkid ret;
*reinterpret_cast<dht::PkId*>(&ret) = h;
return ret;
}
const char* dht_infohash_print(const dht_infohash* h) {
return reinterpret_cast<const dht::InfoHash*>(h)->to_c_str();
}
@@ -17,33 +32,36 @@ void dht_infohash_zero(dht_infohash* h) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash{};
}
void dht_infohash_random(dht_infohash* h)
{
void dht_infohash_random(dht_infohash* h) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::getRandom();
}
void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size)
{
void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get(dat, dat_size);
}
bool dht_infohash_is_zero(const dht_infohash* h) {
return static_cast<bool>(*reinterpret_cast<const dht::InfoHash*>(h));
void dht_infohash_get_from_string(dht_infohash* h, const char* dat) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get((const uint8_t*)dat, (size_t)strlen(dat));
}
const char* dht_pkid_print(const dht_pkid* h)
{
bool dht_infohash_is_zero(const dht_infohash* h) {
return !static_cast<bool>(*reinterpret_cast<const dht::InfoHash*>(h));
}
void dht_infohash_from_hex(dht_infohash* h, const char* dat) {
*h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2)));
}
const char* dht_pkid_print(const dht_pkid* h) {
return reinterpret_cast<const dht::PkId*>(h)->to_c_str();
}
// dht::Blob
void dht_blob_delete(dht_blob* data)
{
void dht_blob_delete(dht_blob* data) {
delete reinterpret_cast<dht::Blob*>(data);
}
dht_data_view dht_blob_get_data(const dht_blob* data)
{
dht_data_view dht_blob_get_data(const dht_blob* data) {
dht_data_view view;
view.data = reinterpret_cast<const dht::Blob*>(data)->data();
view.size = reinterpret_cast<const dht::Blob*>(data)->size();
@@ -51,8 +69,7 @@ dht_data_view dht_blob_get_data(const dht_blob* data)
}
// dht::Value
dht_data_view dht_value_get_data(const dht_value* data)
{
dht_data_view dht_value_get_data(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
dht_data_view view;
view.data = vsp->data.data();
@@ -60,6 +77,26 @@ dht_data_view dht_value_get_data(const dht_value* data)
return view;
}
dht_value_id dht_value_get_id(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->id;
}
dht_publickey* dht_value_get_owner(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->owner ? reinterpret_cast<dht_publickey*>(new PubkeySp(vsp->owner)) : nullptr;
}
dht_infohash dht_value_get_recipient(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return dht_infohash_to_c(vsp->recipient);
}
const char* dht_value_get_user_type(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->user_type.c_str();
}
dht_value* dht_value_new(const uint8_t* data, size_t size) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
}
@@ -73,69 +110,140 @@ void dht_value_unref(dht_value* v) {
}
// dht::crypto::PublicKey
dht_publickey* dht_publickey_new() {
return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey);
}
void dht_publickey_delete(dht_publickey* pk) {
delete reinterpret_cast<dht::crypto::PublicKey*>(pk);
}
int dht_publickey_unpack(dht_publickey* pk, const uint8_t* dat, size_t dat_size) {
dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size) {
try {
reinterpret_cast<dht::crypto::PublicKey*>(pk)->unpack(dat, dat_size);
} catch (const dht::crypto::CryptoException& e) {
return -1;
}
return 0;
}
int dht_publickey_pack(dht_publickey* pk, char* out, size_t* outlen) {
return gnutls_pubkey_export(reinterpret_cast<dht::crypto::PublicKey*>(pk)->pk, GNUTLS_X509_FMT_DER, out, outlen);
}
dht_infohash dht_publickey_get_id(const dht_publickey* pk) {
dht_infohash h;
*reinterpret_cast<dht::InfoHash*>(&h) = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->getId();
return h;
}
dht_pkid dht_publickey_get_long_id(const dht_publickey* pk) {
dht_pkid h;
*reinterpret_cast<dht::PkId*>(&h) = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->getLongId();
return h;
}
bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size) {
return reinterpret_cast<const dht::crypto::PublicKey*>(pk)->checkSignature((const uint8_t*)data, data_size, (const uint8_t*)signature, signature_size);
}
dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) {
auto rdata = new dht::Blob;
*rdata = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->encrypt((const uint8_t*)data, data_size);
return (dht_blob*)rdata;
}
dht_privatekey* dht_privatekey_generate(unsigned key_length_bits) {
if (key_length_bits == 0)
key_length_bits = 4096;
return reinterpret_cast<dht_privatekey*>(new dht::crypto::PrivateKey(dht::crypto::PrivateKey::generate(key_length_bits)));
}
dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password) {
try {
return reinterpret_cast<dht_privatekey*>(new dht::crypto::PrivateKey(dat, dat_size, password));
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<const dht::crypto::PublicKey>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* key) {
return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey(reinterpret_cast<const dht::crypto::PrivateKey*>(key)->getPublicKey()));
void dht_publickey_delete(dht_publickey* pk) {
delete reinterpret_cast<PubkeySp*>(pk);
}
int dht_publickey_export(const dht_publickey* pk, char* out, size_t* outlen) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->pack((uint8_t*)out, outlen);
}
dht_infohash dht_publickey_get_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_infohash_to_c(pkey->getId());
}
dht_pkid dht_publickey_get_long_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_pkid_to_c(pkey->getLongId());
}
bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->checkSignature((const uint8_t*)data, data_size, (const uint8_t*)signature, signature_size);
}
dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
auto rdata = new dht::Blob;
*rdata = pkey->encrypt((const uint8_t*)data, data_size);
return (dht_blob*)rdata;
}
// dht::crypto::PrivateKey
dht_privatekey* dht_privatekey_generate(unsigned key_length_bits) {
if (key_length_bits == 0)
key_length_bits = 4096;
return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dht::crypto::PrivateKey::generate(key_length_bits))));
}
dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password) {
try {
return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dat, dat_size, password)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, const char* password) {
if (!out or !out_size or !*out_size)
return -1;
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return key->serialize((uint8_t*)out, out_size, password);
}
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(key->getPublicKey())));
}
void dht_privatekey_delete(dht_privatekey* pk) {
delete reinterpret_cast<dht::crypto::PrivateKey*>(pk);
delete reinterpret_cast<PrivkeySp*>(pk);
}
// dht::crypto::Certificate
dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size) {
try {
return reinterpret_cast<dht_certificate*>(new CertSp(std::make_shared<dht::crypto::Certificate>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
void dht_certificate_delete(dht_certificate* c) {
delete reinterpret_cast<CertSp*>(c);
}
dht_infohash dht_certificate_get_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_infohash_to_c(cert->getId());
}
dht_pkid dht_certificate_get_long_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_pkid_to_c(cert->getLongId());
}
dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey())));
}
// dht::crypto::Identity
inline dht::crypto::Identity dht_identity_from_c(const dht_identity* cid) {
dht::crypto::Identity id {};
if (cid and cid->privatekey)
id.first = *reinterpret_cast<const PrivkeySp*>(cid->privatekey);
if (cid and cid->certificate)
id.second = *reinterpret_cast<const CertSp*>(cid->certificate);
return id;
}
inline dht_identity dht_identity_to_c(const dht::crypto::Identity& id) {
dht_identity cid {};
cid.privatekey = id.first ? reinterpret_cast<dht_privatekey*>(new PrivkeySp(id.first)) : NULL;
cid.certificate = id.second ? reinterpret_cast<dht_certificate*>(new CertSp(id.second)) : NULL;
return cid;
}
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca) {
return dht_identity_to_c(dht::crypto::generateIdentity(common_name, dht_identity_from_c(ca)));
}
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity* id) {
if (id->certificate) {
dht_certificate_delete(id->certificate);
id->certificate = NULL;
}
if (id->privatekey) {
dht_privatekey_delete(id->privatekey);
id->privatekey = NULL;
}
}
// config
void dht_runner_config_default(dht_runner_config* config) {
bzero(config, sizeof(dht_runner_config));
config->threaded = true;
}
// dht::DhtRunner
@@ -152,6 +260,31 @@ void dht_runner_run(dht_runner* r, in_port_t port) {
runner->run(port, {}, true);
}
void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
dht::DhtRunner::Config config;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.maintain_storage = conf->dht_config.node_config.maintain_storage;
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path) : std::string{};
if (conf->dht_config.id.privatekey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privatekey);
if (conf->dht_config.id.certificate)
config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
config.threaded = conf->threaded;
config.proxy_server = conf->proxy_server ? std::string(conf->proxy_server) : std::string{};
config.push_node_id = conf->push_node_id ? std::string(conf->push_node_id) : std::string{};
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
runner->run(port, config);
}
void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
runner->bootstrap(dht::SockAddr(addr, addr_len));
@@ -159,7 +292,10 @@ void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) {
void dht_runner_bootstrap(dht_runner* r, const char* host, const char* service) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
runner->bootstrap(host, service);
if (service)
runner->bootstrap(host, service);
else
runner->bootstrap(host);
}
void dht_runner_get(dht_runner* r, const dht_infohash* h, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data) {
@@ -173,11 +309,25 @@ void dht_runner_get(dht_runner* r, const dht_infohash* h, dht_get_cb cb, dht_don
});
}
dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_cb cb, void* cb_user_data) {
struct ScopeGuardCb {
ScopeGuardCb(dht_shutdown_cb cb, void* data)
: onDestroy(cb), userData(data) {}
~ScopeGuardCb() {
if (onDestroy)
onDestroy((void*)userData);
}
private:
const dht_shutdown_cb onDestroy;
void const* userData;
};
dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto fret = new std::future<size_t>;
*fret = runner->listen(*hash, [cb,cb_user_data](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
auto guard = done_cb ? std::make_shared<ScopeGuardCb>(done_cb, cb_user_data) : std::shared_ptr<ScopeGuardCb>{};
*fret = runner->listen(*hash, [cb,cb_user_data, guard](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
for (const auto& value : values) {
if (not cb(reinterpret_cast<const dht_value*>(&value), expired, cb_user_data))
return false;
@@ -198,14 +348,41 @@ void dht_op_token_delete(dht_op_token* token) {
delete reinterpret_cast<std::future<size_t>*>(token);
}
void dht_runner_put(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data) {
void dht_runner_put(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->put(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
});
}, dht::time_point::max(), permanent);
}
void dht_runner_put_signed(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putSigned(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}
void dht_runner_put_encrypted(dht_runner* r, const dht_infohash* h, const dht_infohash* to, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto toHash = reinterpret_cast<const dht::InfoHash*>(to);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putEncrypted(*hash, *toHash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}
void dht_runner_cancel_put(dht_runner* r, const dht_infohash* h, dht_value_id value_id) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
runner->cancelPut(*hash, value_id);
}
void dht_runner_shutdown(dht_runner* r, dht_shutdown_cb done_cb, void* cb_user_data) {
@@ -216,6 +393,38 @@ void dht_runner_shutdown(dht_runner* r, dht_shutdown_cb done_cb, void* cb_user_d
});
}
dht_infohash dht_runner_get_node_id(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = runner->getNodeId();
return ret;
}
dht_infohash dht_runner_get_id(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = runner->getId();
return ret;
}
struct sockaddr** dht_runner_get_public_address(const dht_runner* r) {
auto runner = reinterpret_cast<const dht::DhtRunner*>(r);
auto addrs = const_cast<dht::DhtRunner*>(runner)->getPublicAddress();
if (addrs.empty())
return nullptr;
auto ret = (struct sockaddr**)malloc(sizeof(struct sockaddr*) * (addrs.size() + 1));
for (size_t i=0; i<addrs.size(); i++) {
if (auto len = addrs[i].getLength()) {
ret[i] = (struct sockaddr*)malloc(len);
memcpy((struct sockaddr*)ret[i], addrs[i].get(), len);
} else {
ret[i] = nullptr;
}
}
ret[addrs.size()] = nullptr;
return ret;
}
#ifdef __cplusplus
}
#endif
+72 -15
View File
@@ -18,14 +18,6 @@ struct OPENDHT_C_PUBLIC dht_data_view {
};
typedef struct dht_data_view dht_data_view;
// dht::Value
struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data);
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
// dht::Blob
struct OPENDHT_C_PUBLIC dht_blob;
typedef struct dht_blob dht_blob;
@@ -37,7 +29,9 @@ struct OPENDHT_C_PUBLIC dht_infohash { uint8_t d[HASH_LEN]; };
typedef struct dht_infohash dht_infohash;
OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat);
OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str);
OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h);
OPENDHT_C_PUBLIC bool dht_infohash_is_zero(const dht_infohash* h);
@@ -49,10 +43,9 @@ OPENDHT_C_PUBLIC const char* dht_pkid_print(const dht_pkid* h);
// dht::crypto::PublicKey
struct OPENDHT_C_PUBLIC dht_publickey;
typedef struct dht_publickey dht_publickey;
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_new();
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_publickey_delete(dht_publickey* pk);
OPENDHT_C_PUBLIC int dht_publickey_unpack(dht_publickey* pk, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC int dht_publickey_pack(dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC int dht_publickey_export(const dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC dht_infohash dht_publickey_get_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC dht_pkid dht_publickey_get_long_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size);
@@ -63,36 +56,100 @@ struct OPENDHT_C_PUBLIC dht_privatekey;
typedef struct dht_privatekey dht_privatekey;
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bits);
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password);
OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password);
OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*);
OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*);
// dht::crypto::Certificate
struct OPENDHT_C_PUBLIC dht_certificate;
typedef struct dht_certificate dht_certificate;
OPENDHT_C_PUBLIC dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC dht_infohash dht_certificate_get_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_pkid dht_certificate_get_long_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_publickey* dht_certificate_get_publickey(const dht_certificate*);
OPENDHT_C_PUBLIC void dht_certificate_delete(dht_certificate*);
struct OPENDHT_PUBLIC dht_identity {
dht_privatekey* privatekey;
dht_certificate* certificate;
};
typedef struct dht_identity dht_identity;
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca);
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity*);
// dht::Value
struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data);
OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data);
OPENDHT_C_PUBLIC dht_publickey* dht_value_get_owner(const dht_value* data);
OPENDHT_C_PUBLIC dht_infohash dht_value_get_recipient(const dht_value* data);
OPENDHT_C_PUBLIC const char* dht_value_get_user_type(const dht_value* data);
// callbacks
typedef bool (*dht_get_cb)(const dht_value* value, void* user_data);
typedef bool (*dht_value_cb)(const dht_value* value, bool expired, void* user_data);
typedef bool (*dht_done_cb)(bool ok, void* user_data);
typedef bool (*dht_shutdown_cb)(void* user_data);
typedef void (*dht_done_cb)(bool ok, void* user_data);
typedef void (*dht_shutdown_cb)(void* user_data);
struct OPENDHT_C_PUBLIC dht_op_token;
typedef struct dht_op_token dht_op_token;
OPENDHT_C_PUBLIC void dht_op_token_delete(dht_op_token* token);
// config
struct OPENDHT_PUBLIC dht_node_config {
dht_infohash node_id;
uint32_t network;
bool is_bootstrap;
bool maintain_storage;
const char* persist_path;
};
typedef struct dht_node_config dht_node_config;
struct OPENDHT_PUBLIC dht_secure_config {
dht_node_config node_config;
dht_identity id;
};
typedef struct dht_secure_config dht_secure_config;
struct OPENDHT_PUBLIC dht_runner_config {
dht_secure_config dht_config;
bool threaded;
const char* proxy_server;
const char* push_node_id;
const char* push_token;
bool peer_discovery;
bool peer_publish;
dht_certificate* server_ca;
dht_identity client_identity;
};
typedef struct dht_runner_config dht_runner_config;
OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config);
// dht::DhtRunner
struct OPENDHT_C_PUBLIC dht_runner;
typedef struct dht_runner dht_runner;
OPENDHT_C_PUBLIC dht_runner* dht_runner_new();
OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner);
OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port);
OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config);
OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len);
OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host, const char* service);
OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_cancel_listen(dht_runner* runner, const dht_infohash* hash, dht_op_token* token);
OPENDHT_C_PUBLIC void dht_runner_put(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_put(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_signed(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_encrypted(dht_runner* runner, const dht_infohash* hash, const dht_infohash* to, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_cancel_put(dht_runner* runner, const dht_infohash* hash, dht_value_id value_id);
OPENDHT_C_PUBLIC void dht_runner_shutdown(dht_runner* runner, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_infohash dht_runner_get_node_id(const dht_runner* runner);
OPENDHT_C_PUBLIC dht_infohash dht_runner_get_id(const dht_runner* runner);
OPENDHT_C_PUBLIC struct sockaddr** dht_runner_get_public_address(const dht_runner* runner);
#ifdef __cplusplus
}
+22 -21
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 1)
m4_define([opendht_minor_version], 10)
m4_define([opendht_patch_version], 1)
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 0)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -35,10 +35,14 @@ AS_IF([test "x$enable_logs" != "xno"], [
dnl Check for indexation
AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])])
AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno")
AS_IF([test "x$enable_indexation" != "xno"], [
AC_DEFINE([OPENDHT_INDEXATION], [1], [Define if DHT indexation is enabled])
AM_COND_IF(ENABLE_INDEXATION, [
AC_DEFINE([OPENDHT_INDEXATION], [], [Define if DHT indexation is enabled])
])
AC_ARG_ENABLE([peer-discovery], [AS_HELP_STRING([--disable-peer-discovery], [Disable peer-discovery])])
AM_CONDITIONAL(ENABLE_PEER_DISCOVERY, test x$enable_peer_discovery != "xno")
AM_COND_IF(ENABLE_PEER_DISCOVERY, [AC_DEFINE([OPENDHT_PEER_DISCOVERY], [], [Define if peer discovery is enabled])])
dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
@@ -98,7 +102,7 @@ AS_IF([test "x$SYS" = "xandroid"],
LT_INIT()
LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
@@ -135,7 +139,7 @@ AS_IF([test "x$with_jsoncpp" != "xno"],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS+=" -DOPENDHT_JSONCPP=1"
CPPFLAGS+=" -DOPENDHT_JSONCPP"
], [
AC_MSG_NOTICE([Not using JsonCpp])
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
@@ -154,7 +158,7 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
CPPFLAGS+=" -DOPENDHT_PROXY_HTTP_PARSER_FORK"
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
@@ -205,27 +209,24 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT"], [])
AM_COND_IF(ENABLE_PROXY_SERVER, AC_DEFINE([OPENDHT_PROXY_SERVER], [], [Building with proxy server]))
AM_COND_IF(ENABLE_PROXY_CLIENT, AC_DEFINE([OPENDHT_PROXY_CLIENT], [], [Building with proxy client]))
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF([HAVE_DOXYGEN], [
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
])
dnl Configure setup.py if we build the python module
AM_COND_IF([USE_CYTHON], [
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([python/Makefile python/setup.py])
])
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([Makefile
src/Makefile
tools/Makefile
python/Makefile
python/setup.py
tests/Makefile
doc/Makefile
doc/Doxyfile
opendht.pc])
AC_OUTPUT
+4 -1
View File
@@ -1,7 +1,10 @@
dist_man1_MANS = dhtnode.1
noinst_HEADERS = \
Doxyfile
if HAVE_DOXYGEN
doxyfile.stamp:
doxyfile.stamp: Doxyfile
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
+13
View File
@@ -0,0 +1,13 @@
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.0.0
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_C=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_LTO=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+10 -13
View File
@@ -2,14 +2,14 @@ FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update && apt-get install -y \
build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libasio-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libssl-dev \
&& apt-get clean
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -17,25 +17,22 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 && make install \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/archive/v.0.5.1.2.tar.gz \
&& ls -l && tar -xzf v.0.5.1.2.tar.gz \
&& cd restinio-v.0.5.1.2/dev \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+28
View File
@@ -0,0 +1,28 @@
FROM ubuntu:18.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
RUN apt-get update && apt-get install -y \
apt-transport-https build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \
&& apt-get clean
# libasio-dev (1.10) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
+10 -10
View File
@@ -2,9 +2,9 @@ FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update \
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev libasio-dev cython3 python3-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip \
autotools-dev autoconf libasio-dev \
autotools-dev autoconf libssl-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
@@ -13,7 +13,7 @@ ENV CXX c++
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -21,14 +21,14 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 && make install \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
@@ -37,9 +37,9 @@ RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade c
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/archive/v.0.5.1.2.tar.gz \
&& ls -l && tar -xzf v.0.5.1.2.tar.gz \
&& cd restinio-v.0.5.1.2/dev \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+1 -1
View File
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
+1 -1
View File
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_TESTS=ON .. \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
+1 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,4 @@
#pragma once
#include "opendht/dhtrunner.h"
#ifdef OPENDHT_PROXY_SERVER
#include "opendht/dht_proxy_server.h"
#endif
#include "opendht/default_types.h"
#ifdef OPENDHT_INDEXATION
#include "opendht/indexation/pht.h"
#endif
+53 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -26,6 +26,7 @@
#include <vector>
#include <memory>
#include <functional>
#include <string>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
@@ -44,12 +45,21 @@ enum class NodeStatus {
Connected // 1+ good nodes
};
inline constexpr const char*
statusToStr(NodeStatus status) {
return status == NodeStatus::Connected ? "connected" : (
status == NodeStatus::Connecting ? "connecting" :
"disconnected");
}
struct OPENDHT_PUBLIC NodeStats {
unsigned good_nodes {0},
dubious_nodes {0},
cached_nodes {0},
incoming_nodes {0};
unsigned table_depth {0};
unsigned cachedNodes {0};
unsigned searches {0};
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
std::string toString() const;
@@ -63,14 +73,34 @@ struct OPENDHT_PUBLIC NodeStats {
explicit NodeStats(const Json::Value& v);
#endif
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth)
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth, searches)
};
struct OPENDHT_PUBLIC NodeMetrics {
size_t scheduler_size {0};
size_t node_cache_size {0};
size_t request_count {0};
size_t rate_limiter_size {0};
size_t reported_addr_num {0};
size_t store_size {0};
size_t store_values {0};
size_t store_quota_size {0};
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
#endif
};
struct OPENDHT_PUBLIC NodeInfo {
InfoHash id;
InfoHash node_id;
NodeStats ipv4;
NodeStats ipv6;
NodeStats ipv4 {};
NodeStats ipv6 {};
size_t ongoing_ops {0};
NodeMetrics metrics {};
#ifdef OPENDHT_JSONCPP
/**
@@ -106,6 +136,19 @@ struct OPENDHT_PUBLIC Config {
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
std::string persist_path {};
/** If non-0, overrides the default global rate-limit.-1 means no limit. */
ssize_t max_req_per_sec {0};
/** If non-0, overrides the default per-IP address rate-limit. -1 means no limit. */
ssize_t max_peer_req_per_sec {0};
/**
* Use appropriate bahavior for a public IP, stable node:
* - No connectivity change triggered when a search fails
* - Larger listen refresh time
*/
bool public_stable {false};
};
/**
@@ -115,6 +158,12 @@ struct OPENDHT_PUBLIC SecureDhtConfig
{
Config node_config {};
crypto::Identity id {};
/**
* Cache all encountered public keys and certificates,
* for use by the certificate store, putEncrypted and putSigned
*/
bool cert_cache_all {false};
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
+18 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -43,16 +43,22 @@ namespace dht {
namespace crypto {
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
public:
CryptoException(const std::string& str) : std::runtime_error(str) {};
public:
explicit CryptoException(const std::string& str) : std::runtime_error(str) {};
explicit CryptoException(const char* str) : std::runtime_error(str) {};
CryptoException(const CryptoException& e) noexcept = default;
CryptoException& operator=(const CryptoException&) noexcept = default;
};
/**
* Exception thrown when a decryption error happened.
*/
class OPENDHT_PUBLIC DecryptError : public CryptoException {
public:
DecryptError(const std::string& str = "") : CryptoException(str) {};
public:
explicit DecryptError(const std::string& str) : CryptoException(str) {};
explicit DecryptError(const char* str) : CryptoException(str) {};
DecryptError(const DecryptError& e) noexcept = default;
DecryptError& operator=(const DecryptError&) noexcept = default;
};
struct PrivateKey;
@@ -72,7 +78,8 @@ struct OPENDHT_PUBLIC PublicKey
* Takes ownership of an existing gnutls_pubkey.
*/
PublicKey(gnutls_pubkey_t k) : pk(k) {}
PublicKey(const Blob& pk);
PublicKey(const uint8_t* dat, size_t dat_size);
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
~PublicKey();
@@ -107,6 +114,7 @@ struct OPENDHT_PUBLIC PublicKey
}
void pack(Blob& b) const;
int pack(uint8_t* out, size_t* out_len) const;
void unpack(const uint8_t* dat, size_t dat_size);
std::string toString() const;
@@ -120,7 +128,7 @@ struct OPENDHT_PUBLIC PublicKey
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
gnutls_digest_algorithm_t getPreferredDigest() const;
@@ -153,6 +161,7 @@ struct OPENDHT_PUBLIC PrivateKey
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
/**
@@ -217,7 +226,7 @@ public:
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
void revoke(const Certificate& crt, time_point t = time_point::min());
@@ -415,7 +424,7 @@ struct OPENDHT_PUBLIC Certificate {
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
explicit operator bool() const { return cert; }
PublicKey getPublicKey() const;
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -189,7 +189,7 @@ public:
#endif
}
virtual void msgpack_unpack(msgpack::object o)
virtual void msgpack_unpack(const msgpack::object& o)
{
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size < 2) throw msgpack::type_error();
@@ -229,7 +229,7 @@ public:
pk.pack_bin_body((const char*)addr.get(), addr.getLength());
}
virtual void msgpack_unpack(msgpack::object o)
virtual void msgpack_unpack(const msgpack::object& o)
{
if (o.type == msgpack::type::BIN)
addr = {(sockaddr*)o.via.bin.ptr, (socklen_t)o.via.bin.size};
+20 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -68,7 +68,11 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {})
: Dht(std::move(sock), config, std::make_shared<Logger>(l)) {}
virtual ~Dht();
/**
@@ -119,9 +123,9 @@ public:
void pingNode(SockAddr, DoneCallbackSimple&& cb={}) override;
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) override;
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return periodic(buf, buflen, SockAddr(from, fromlen));
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
}
/**
@@ -269,6 +273,7 @@ public:
void loadState(const std::string& path);
NodeStats getNodesStats(sa_family_t af) const override;
NodeMetrics getNodeMetrics() const override;
std::string getStorageLog() const override;
std::string getStorageLog(const InfoHash&) const override;
@@ -337,9 +342,10 @@ private:
static constexpr std::chrono::minutes SEARCH_EXPIRE_TIME {62};
/* Timeout for listen */
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
static constexpr duration LISTEN_EXPIRE_TIME {std::chrono::seconds(30)};
static constexpr duration LISTEN_EXPIRE_TIME_PUBLIC {std::chrono::minutes(5)};
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
static constexpr size_t TOKEN_SIZE {32};
@@ -381,6 +387,8 @@ private:
std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
size_t listener_token {1};
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
// timing
Scheduler scheduler;
Sp<Scheduler::Job> nextNodesConfirmation {};
@@ -393,8 +401,6 @@ private:
using ReportedAddr = std::pair<unsigned, SockAddr>;
std::vector<ReportedAddr> reported_addr;
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
std::string persistPath;
// are we a bootstrap node ?
@@ -403,6 +409,11 @@ private:
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
const bool public_stable {false};
inline const duration& getListenExpiration() const {
return public_stable ? LISTEN_EXPIRE_TIME_PUBLIC : LISTEN_EXPIRE_TIME;
}
void rotateSecrets();
+23 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,8 @@ namespace net {
class OPENDHT_PUBLIC DhtInterface {
public:
DhtInterface() = default;
DhtInterface(const Logger& l) : DHT_LOG(l) {};
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {};
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {};
virtual ~DhtInterface() = default;
// [[deprecated]]
@@ -78,8 +79,8 @@ public:
virtual void pingNode(SockAddr, DoneCallbackSimple&& cb={}) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) = 0;
/**
* Get a value by searching on all available protocols (IPv4, IPv6),
@@ -193,6 +194,7 @@ public:
virtual void importValues(const std::vector<ValuesExport>&) = 0;
virtual NodeStats getNodesStats(sa_family_t af) const = 0;
virtual NodeMetrics getNodeMetrics() const { return {}; }
virtual std::string getStorageLog() const = 0;
virtual std::string getStorageLog(const InfoHash&) const = 0;
@@ -221,15 +223,23 @@ public:
* Enable or disable logging of DHT internal messages
*/
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
DHT_LOG.DBG = debug;
DHT_LOG.WARN = warn;
DHT_LOG.ERR = error;
if (logger_) {
logger_->DBG = std::move(debug);
logger_->WARN = std::move(warn);
logger_->ERR = std::move(error);
} else
logger_= std::make_shared<Logger>(std::move(error), std::move(warn), std::move(debug));
}
virtual void setLogger(const Logger& l) {
DHT_LOG.DBG = l.DBG;
DHT_LOG.WARN = l.WARN;
DHT_LOG.ERR = l.ERR;
if (logger_)
*logger_ = l;
else
logger_= std::make_shared<Logger>(l);
}
virtual void setLogger(const std::shared_ptr<Logger>& l) {
logger_ = l;
}
/**
@@ -237,7 +247,8 @@ public:
*/
virtual void setLogFilter(const InfoHash& f)
{
DHT_LOG.setFilter(f);
if (logger_)
logger_->setFilter(f);
}
virtual void setPushNotificationToken(const std::string&) {};
@@ -249,7 +260,7 @@ public:
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
Logger DHT_LOG;
std::shared_ptr<Logger> logger_ {};
};
} // namespace dht
+36 -36
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -53,9 +53,9 @@ public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<dht::Logger> logger = {});
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
void setHeaderFields(http::Request& request);
@@ -197,9 +197,9 @@ public:
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
time_point periodic(const uint8_t*, size_t, SockAddr) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return periodic(buf, buflen, SockAddr(from, fromlen));
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
}
/**
@@ -285,9 +285,7 @@ private:
*/
struct InfoState;
void getProxyInfos();
void handleProxyStatus(const asio::error_code &ec, std::shared_ptr<InfoState> infoState);
void queryProxyInfo(std::shared_ptr<InfoState> infoState, const sa_family_t family,
std::vector<asio::ip::tcp::endpoint>&& endpoints);
void queryProxyInfo(const std::shared_ptr<InfoState>& infoState, const std::shared_ptr<http::Resolver>& resolver, sa_family_t family);
void onProxyInfos(const Json::Value& val, const sa_family_t family);
SockAddr parsePublicAddress(const Json::Value& val);
@@ -302,17 +300,18 @@ private:
SUBSCRIBE,
RESUBSCRIBE,
};
using CacheValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired, system_clock::time_point)>;
/**
* Send Listen with httpClient_
*/
void sendListen(const restinio::http_request_header_t header, const ValueCallback& cb,
void sendListen(const restinio::http_request_header_t& header, const CacheValueCallback& cb,
const Sp<OperationState>& opstate, Listener& listener, ListenMethod method = ListenMethod::LISTEN);
void handleResubscribe(const asio::error_code& ec, const InfoHash& key,
const size_t token, std::shared_ptr<OperationState> opstate);
void doPut(const InfoHash&, Sp<Value>, DoneCallback, time_point created, bool permanent);
void handleRefreshPut(const asio::error_code& ec, const InfoHash& key, const Value::Id id,
std::shared_ptr<std::atomic_bool> ok);
void doPut(const InfoHash&, Sp<Value>, DoneCallbackSimple, time_point created, bool permanent);
void handleRefreshPut(const asio::error_code& ec, InfoHash key, Value::Id id);
/**
* Initialize statusIpvX_
@@ -322,27 +321,15 @@ private:
* cancel all Listeners
*/
void cancelAllListeners();
/**
* cancel all Operations
*/
void cancelAllOperations();
std::atomic_bool isDestroying_ {false};
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
std::pair<std::string, std::string> serverHostService_;
//std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
std::string pushSessionId_;
mutable std::mutex lockCurrentProxyInfos_;
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
@@ -357,24 +344,36 @@ private:
// registred types
TypeStore types;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
mutable std::mutex requestLock_;
std::map<unsigned, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
/**
* Store listen requests.
*/
struct ProxySearch;
mutable std::mutex searchLock_;
size_t listenerToken_ {0};
std::map<InfoHash, ProxySearch> searches_;
mutable std::mutex searchLock_;
/**
* Callbacks should be executed in the main thread.
*/
std::vector<std::function<void()>> callbacks_;
std::mutex lockCallbacks_;
std::vector<std::function<void()>> callbacks_;
Sp<InfoState> infoState_;
Sp<asio::steady_timer> statusTimer_;
mutable std::mutex statusLock_;
/**
* Retrieve if we can connect to the proxy (update statusIpvX_)
@@ -407,9 +406,10 @@ private:
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
std::atomic_bool isDestroying_ {false};
Json::StreamWriterBuilder jsonBuilder_;
std::unique_ptr<Json::CharReader> jsonReader_;
std::shared_ptr<dht::Logger> logger_;
std::shared_ptr<http::Request> buildRequest(const std::string& target = {});
};
}
+39 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -31,10 +31,7 @@
#include <restinio/all.hpp>
#include <restinio/tls.hpp>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
#include <memory>
#include <mutex>
@@ -54,8 +51,6 @@ class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
using RequestStatus = restinio::request_handling_status_t;
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
/**
* Describes the REST API
@@ -87,33 +82,31 @@ public:
struct ServerStats {
/** Current number of listen operations */
size_t listenCount;
size_t listenCount {0};
/** Current number of permanent put operations */
size_t putCount;
size_t putCount {0};
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount;
size_t pushListenersCount {0};
/** Average requests per second */
double requestRate;
double requestRate {0};
/** Node Info **/
NodeInfo nodeInfo;
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
auto& ni = nodeInfo;
auto& ipv4 = ni.ipv4;
if (ipv4.table_depth > 1) {
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
}
auto& ipv6 = ni.ipv6;
if (ipv6.table_depth > 1) {
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
}
return ss.str();
}
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
@@ -123,15 +116,15 @@ public:
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["requestRate"] = requestRate;
result["nodeInfo"] = nodeInfo.toJson();
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
return result;
}
#endif
};
ServerStats stats() const { return stats_; }
std::shared_ptr<ServerStats> stats() const { return stats_; }
void updateStats() const;
std::shared_ptr<ServerStats> updateStats(std::shared_ptr<NodeInfo> info) const;
std::shared_ptr<DhtRunner> getNode() const { return dht_; }
@@ -141,7 +134,8 @@ private:
struct RestRouterTraits;
template <typename HttpResponse>
HttpResponse initHttpResponse(HttpResponse response) const;
static HttpResponse initHttpResponse(HttpResponse response);
static restinio::request_handling_status_t serverError(restinio::request_t& request);
template< typename ServerSettings >
void addServerSettings(ServerSettings& serverSettings,
@@ -149,6 +143,8 @@ private:
std::unique_ptr<RestRouter> createRestRouter();
void onConnectionClosed(restinio::connection_id_t);
/**
* Return the PublicKey id, the node id and node stats
* Method: GET "/"
@@ -286,7 +282,7 @@ private:
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid);
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid, bool highPriority);
/**
* Send push notification with an expire timeout.
@@ -296,7 +292,7 @@ private:
* @param isAndroid
*/
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
Json::Value json, const bool isAndroid);
std::function<Json::Value()> json, const bool isAndroid);
/**
* Remove a push listener between a client and a hash
@@ -311,12 +307,15 @@ private:
#endif //OPENDHT_PUSH_NOTIFICATIONS
void handlePrintStats(const asio::error_code &ec);
void updateStats();
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
std::shared_ptr<asio::io_context> ioContext_;
std::shared_ptr<DhtRunner> dht_;
Json::StreamWriterBuilder jsonBuilder_;
Json::CharReaderBuilder jsonReaderBuilder_;
// http server
std::thread serverThread_;
@@ -325,29 +324,35 @@ private:
// http client
std::pair<std::string, std::string> pushHostPort_;
mutable std::mutex requestLock_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
std::shared_ptr<dht::Logger> logger_;
mutable std::mutex statsMutex_;
mutable ServerStats stats_;
mutable NodeInfo nodeInfo_ {};
std::shared_ptr<ServerStats> stats_;
std::shared_ptr<NodeInfo> nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
// Thread-safe access to listeners map.
std::shared_ptr<std::mutex> lockListener_;
std::mutex lockListener_;
// Shared with connection listener.
std::shared_ptr<std::map<restinio::connection_id_t,
http::ListenerSession>> listeners_;
std::map<restinio::connection_id_t, http::ListenerSession> listeners_;
// Connection Listener observing conn state changes.
std::shared_ptr<ConnectionListener> connListener_;
struct PushSessionContext {
std::mutex lock;
std::string sessionId;
};
struct PermanentPut {
time_point expiration;
std::string pushToken;
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
Sp<Value> value;
};
struct SearchPuts {
std::map<dht::Value::Id, PermanentPut> puts;
@@ -363,6 +368,7 @@ private:
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener {
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::future<size_t> internalToken;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
+42 -25
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -230,29 +230,30 @@ public:
}
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, time_point created=time_point::max(), bool permanent = false);
void cancelPut(const InfoHash& h, const Value::Id& id);
void cancelPut(const InfoHash& h, Value::Id id);
void cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={});
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putSigned(hash, value, bindDoneCb(cb));
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, value, bindDoneCb(cb), permanent);
}
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={});
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb));
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={});
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putEncrypted(hash, to, value, bindDoneCb(cb));
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
}
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb));
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
/**
* Insert known nodes to the routing table, without necessarly ping them.
@@ -316,9 +317,7 @@ public:
* Returns the currently bound port, in host byte order.
* @param f: address family of the bound port to retreive.
*/
in_port_t getBoundPort(sa_family_t f = AF_INET) const {
return getBound(f).getPort();
}
in_port_t getBoundPort(sa_family_t f = AF_INET) const;
std::pair<size_t, size_t> getStoreSize() const;
@@ -328,7 +327,10 @@ public:
std::vector<ValuesExport> exportValues() const;
void setLogger(const Logger& logger = {});
void setLogger(const Sp<Logger>& logger = {});
void setLogger(const Logger& logger) {
setLogger(std::make_shared<Logger>(logger));
}
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
/**
@@ -341,12 +343,13 @@ public:
void importValues(const std::vector<ValuesExport>& values);
bool isRunning() const {
return running;
return running != State::Idle;
}
NodeStats getNodesStats(sa_family_t af) const;
unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
NodeInfo getNodeInfo() const;
void getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)>);
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
std::string getStorageLog() const;
@@ -359,7 +362,7 @@ public:
// securedht methods
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)>);
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
@@ -412,7 +415,7 @@ public:
/**
* Gracefuly disconnect from network.
*/
void shutdown(ShutdownCallback cb);
void shutdown(ShutdownCallback cb = {});
/**
* Quit and wait for all threads to terminate.
@@ -450,6 +453,12 @@ public:
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
enum class State {
Idle,
Running,
Stopping
};
/**
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
* thread and then queue ping requests. This list should contain reliable
@@ -464,6 +473,11 @@ private:
return std::max(status4, status6);
}
bool checkShutdown();
void opEnded();
DoneCallback bindOpDoneCallback(DoneCallback&& cb);
DoneCallbackSimple bindOpDoneCallback(DoneCallbackSimple&& cb);
/** Local DHT instance */
std::unique_ptr<SecureDht> dht_;
@@ -496,7 +510,8 @@ private:
std::thread dht_thread {};
std::condition_variable cv {};
std::mutex sock_mtx {};
std::queue<std::unique_ptr<net::ReceivedPacket>> rcv {};
net::PacketList rcv {};
decltype(rcv) rcv_free {};
/** true if currently actively boostraping */
std::atomic_bool bootstraping {false};
@@ -511,7 +526,9 @@ private:
std::queue<std::function<void(SecureDht&)>> pending_ops {};
std::mutex storage_mtx {};
std::atomic_bool running {false};
std::atomic<State> running {State::Idle};
std::atomic_size_t ongoing_ops {0};
std::vector<ShutdownCallback> shutdownCallbacks_;
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
+70 -40
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
#include <memory>
#include <queue>
#include <mutex>
namespace Json {
class Value;
@@ -61,7 +62,7 @@ struct Certificate;
namespace http {
using HandlerCb = std::function<void(const asio::error_code& ec)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, const size_t bytes)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, size_t bytes)>;
using ConnectHandlerCb = std::function<void(const asio::error_code& ec,
const asio::ip::tcp::endpoint& endpoint)>;
@@ -82,7 +83,7 @@ public:
std::string fragment;
};
class OPENDHT_PUBLIC Connection
class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection>
{
public:
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<dht::Logger> l = {});
@@ -90,30 +91,42 @@ public:
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l = {});
~Connection();
unsigned int id();
bool is_open();
bool is_ssl();
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
void set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode);
asio::streambuf& input();
asio::streambuf& data();
std::istream& data() { return istream_; }
std::string read_bytes(const size_t bytes);
std::string read_bytes(size_t bytes = 0);
std::string read_until(const char delim);
void async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb);
void async_handshake(HandlerCb cb);
void async_write(BytesHandlerCb cb);
void async_read_until(const char* delim, BytesHandlerCb cb);
void async_read(const size_t bytes, BytesHandlerCb cb);
void async_read_until(char delim, BytesHandlerCb cb);
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
void close();
private:
template<typename T>
T wrapCallabck(T cb) const {
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
cb(params...);
};
}
mutable std::mutex mutex_;
unsigned int id_;
static unsigned int ids_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
std::unique_ptr<socket_t> socket_;
@@ -124,6 +137,7 @@ private:
asio::streambuf write_buf_;
asio::streambuf read_buf_;
std::istream istream_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
@@ -147,7 +161,7 @@ class OPENDHT_PUBLIC Resolver
{
public:
using ResolverCb = std::function<void(const asio::error_code& ec,
std::vector<asio::ip::tcp::endpoint> endpoints)>;
const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service,
@@ -156,19 +170,25 @@ public:
// use already resolved endpoints with classes using this resolver
Resolver(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint> endpoints,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& url, std::vector<asio::ip::tcp::endpoint> endpoints,
std::shared_ptr<dht::Logger> logger = {});
~Resolver();
inline const Url& get_url() const {
return url_;
};
}
void add_callback(ResolverCb cb);
void add_callback(ResolverCb cb, sa_family_t family = AF_UNSPEC);
std::shared_ptr<Logger> getLogger() const {
return logger_;
}
private:
void resolve(const std::string& host, const std::string& service);
std::mutex mutex_;
mutable std::mutex mutex_;
Url url_;
asio::error_code ec_;
@@ -182,14 +202,18 @@ private:
std::shared_ptr<dht::Logger> logger_;
};
class Request;
struct Response
{
unsigned int status_code;
unsigned status_code {0};
std::map<std::string, std::string> headers;
std::string body;
bool aborted {false};
std::weak_ptr<Request> request;
};
class OPENDHT_PUBLIC Request
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
{
public:
enum class State {
@@ -199,10 +223,11 @@ public:
RECEIVING,
DONE
};
using OnStatusCb = std::function<void(unsigned int status_code)>;
using OnStatusCb = std::function<void(unsigned status_code)>;
using OnDataCb = std::function<void(const char* at, size_t length)>;
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned int status_code)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned status_code)>;
using OnDoneCb = std::function<void(const Response& response)>;
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
@@ -210,9 +235,11 @@ public:
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger = {});
// user defined resolver
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, const std::string& target, sa_family_t family = AF_UNSPEC);
// user defined resolved endpoints
Request(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint>&& endpoints,
@@ -220,12 +247,18 @@ public:
~Request();
unsigned int id() const;
inline unsigned int id() const { return id_; };
void set_connection(std::shared_ptr<Connection> connection);
std::shared_ptr<Connection> get_connection() const;
inline const Url& get_url() const {
return resolver_->get_url();
};
/** The previous request in case of redirect following */
std::shared_ptr<Request> getPrevious() const {
return prev_.lock();
}
inline std::string& to_string() {
return request_;
}
@@ -248,6 +281,7 @@ public:
void add_on_status_callback(OnStatusCb cb);
void add_on_body_callback(OnDataCb cb);
void add_on_state_change_callback(OnStateChangeCb cb);
void add_on_done_callback(OnDoneCb cb);
void send();
@@ -260,19 +294,14 @@ private:
using OnCompleteCb = std::function<void()>;
struct Callbacks {
Callbacks(){}
OnStatusCb on_status;
OnDataCb on_header_field;
OnDataCb on_header_value;
OnDataCb on_body;
OnCompleteCb on_headers_complete;
OnCompleteCb on_message_complete;
OnStateChangeCb on_state_change;
};
void notify_state_change(const State state);
void notify_state_change(State state);
void build();
@@ -289,25 +318,22 @@ private:
void post();
void handle_request(const asio::error_code& ec);
void handle_response(const asio::error_code& ec, size_t bytes);
void handle_response_header(const asio::error_code& ec);
void onHeadersComplete();
void onBody(const char* at, size_t length);
void onComplete();
void handle_response_body(const asio::error_code& ec, const size_t bytes);
mutable std::mutex mutex_;
/**
* Parse the request with http_parser.
* Return how many bytes were parsed.
* Note: we pass requerst.size()==0 to signal that EOF has been received.
*/
size_t parse_request(const std::string& request);
std::shared_ptr<dht::Logger> logger_;
restinio::http_request_header_t header_;
std::map<restinio::http_field_t, std::string> headers_;
restinio::http_connection_header_t connection_type_;
restinio::http_connection_header_t connection_type_ {restinio::http_connection_header_t::close};
std::string body_;
std::mutex cbs_mutex_;
std::unique_ptr<Callbacks> cbs_;
Callbacks cbs_;
State state_;
dht::crypto::Identity client_identity_;
@@ -316,19 +342,23 @@ private:
std::string host_;
unsigned int id_;
static unsigned int ids_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
sa_family_t family_ = AF_UNSPEC;
std::shared_ptr<Connection> conn_;
std::shared_ptr<Resolver> resolver_;
Response response_ {};
std::string request_;
std::atomic<bool> message_complete_ {false};
std::atomic<bool> finishing_ {false};
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
std::shared_ptr<dht::Logger> logger_;
// Next request in case of redirect following
std::shared_ptr<Request> next_;
std::weak_ptr<Request> prev_;
unsigned num_redirect {0};
bool follow_redirect {true};
};
} // namespace http
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -71,13 +71,13 @@ OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getStdLogger();
std::shared_ptr<Logger> getStdLogger();
OPENDHT_PUBLIC
std::unique_ptr<Logger> getFileLogger(const std::string &path);
std::shared_ptr<Logger> getFileLogger(const std::string &path);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getSyslogLogger(const char* name);
std::shared_ptr<Logger> getSyslogLogger(const char* name);
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -64,7 +64,7 @@ struct LogMethod {
func(format, args);
va_end(args);
}
void log(char const* format, va_list args) const {
inline void log(char const* format, va_list args) const {
func(format, args);
}
explicit operator bool() const {
+46 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -48,6 +48,12 @@ struct TransId;
#define MSG_CONFIRM 0
#endif
struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
};
class DhtProtocolException : public DhtException {
public:
// sent to another peer (http-like).
@@ -206,8 +212,14 @@ public:
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(
InfoHash& myid,
NetworkConfig config,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
std::mt19937_64& rd,
Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
@@ -263,7 +275,8 @@ public:
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
/**
* Send a "ping" request to a given node.
*
@@ -275,11 +288,12 @@ public:
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa)),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa), rd),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
/**
* Send a "find node" request to a given node.
*
@@ -418,6 +432,21 @@ public:
return cache.getCachedNodes(id, sa_f, count);
}
size_t getNodeCacheSize() const {
return cache.size();
}
size_t getNodeCacheSize(sa_family_t af) const {
return cache.size(af);
}
size_t getRateLimiterSize() const {
return address_rate_limiter.size();
}
size_t getPartialCount() const {
return partial_messages.size();
}
private:
struct PartialMessage;
@@ -425,7 +454,6 @@ private:
/***************
* Constants *
***************/
static constexpr size_t MAX_REQUESTS_PER_SEC {1600};
/* the length of a node info buffer in ipv4 format */
static const constexpr size_t NODE4_INFO_BUF_LEN {HASH_LEN + sizeof(in_addr) + sizeof(in_port_t)};
/* the length of a node info buffer in ipv6 format */
@@ -513,18 +541,19 @@ private:
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const NetworkConfig config {};
const std::unique_ptr<DatagramSocket> dht_socket;
const Logger& DHT_LOG;
Sp<Logger> logger_;
std::mt19937_64& rd;
NodeCache cache {};
NodeCache cache;
// global limiting should be triggered by at least 8 different IPs
using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>;
using IpLimiter = RateLimiter;
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
IpLimiterMap address_rate_limiter {};
RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {};
size_t limiter_maintenance {0};
IpLimiterMap address_rate_limiter;
RateLimiter rate_limiter;
ssize_t limiter_maintenance {0};
// requests handling
std::map<Tid, Sp<Request>> requests {};
+51 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -35,12 +35,15 @@
#include <functional>
#include <thread>
#include <atomic>
#include <iostream>
#include <mutex>
#include <list>
namespace dht {
namespace net {
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650);
int bindSocket(const SockAddr& addr, SockAddr& bound);
@@ -54,55 +57,88 @@ struct ReceivedPacket {
SockAddr from;
time_point received;
};
using PacketList = std::list<ReceivedPacket>;
class OPENDHT_PUBLIC DatagramSocket {
public:
using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>;
using OnReceive = std::function<PacketList(PacketList&& packets)>;
virtual ~DatagramSocket() {};
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
inline void setOnReceive(OnReceive&& cb) {
std::lock_guard<std::mutex> lk(lock);
rx_callback = std::move(cb);
}
virtual const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const = 0;
virtual bool hasIPv4() const = 0;
virtual bool hasIPv6() const = 0;
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
return getBound(family).getPort();
SockAddr getBound(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family);
}
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family).getPort();
}
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
virtual void stop() = 0;
protected:
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
if (rx_callback)
rx_callback(std::move(packet));
PacketList getNewPacket() {
PacketList pkts;
if (toRecycle_.empty()) {
pkts.emplace_back();
} else {
auto begIt = toRecycle_.begin();
auto begItNext = std::next(begIt);
pkts.splice(pkts.end(), toRecycle_, begIt, begItNext);
}
return pkts;
}
inline void onReceived(PacketList&& packets) {
std::lock_guard<std::mutex> lk(lock);
if (rx_callback) {
auto r = rx_callback(std::move(packets));
if (not r.empty() and toRecycle_.size() < RX_QUEUE_MAX_SIZE)
toRecycle_.splice(toRecycle_.end(), std::move(r));
}
}
protected:
mutable std::mutex lock;
private:
OnReceive rx_callback;
PacketList toRecycle_;
};
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
public:
UdpSocket(in_port_t port, const Logger& l = {});
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l = {});
UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l = {});
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l = {});
~UdpSocket();
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const override {
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override {
return (family == AF_INET6) ? bound6 : bound4;
}
bool hasIPv4() const override { return s4 != -1; }
bool hasIPv6() const override { return s6 != -1; }
bool hasIPv4() const override {
std::lock_guard<std::mutex> lk(lock);
return s4 != -1;
}
bool hasIPv6() const override {
std::lock_guard<std::mutex> lk(lock);
return s6 != -1;
}
void stop() override;
private:
Logger logger;
std::shared_ptr<Logger> logger;
int s4 {-1};
int s6 {-1};
int stopfd {-1};
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -47,10 +47,10 @@ struct Socket {
struct Node {
const InfoHash id;
Node(const InfoHash& id, const SockAddr& addr, bool client=false);
Node(const InfoHash& id, SockAddr&& addr, bool client=false);
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
: Node(id, SockAddr(sa, salen)) {}
Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
: Node(id, SockAddr(sa, salen), rd) {}
InfoHash getId() const {
return id;
+12 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,13 @@
namespace dht {
struct NodeCache {
size_t size(sa_family_t family) const {
return cache(family).count();
}
size_t size() const {
return size(AF_INET) + size(AF_INET6);
}
Sp<Node> getNode(const InfoHash& id, sa_family_t family);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client=false);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const;
@@ -37,17 +44,19 @@ struct NodeCache {
*/
void clearBadNodes(sa_family_t family = 0);
NodeCache(std::mt19937_64& r) : rd(r) {};
~NodeCache();
private:
class NodeMap : private std::map<InfoHash, std::weak_ptr<Node>> {
public:
Sp<Node> getNode(const InfoHash& id);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client, std::mt19937_64& rd);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, size_t count) const;
void clearBadNodes();
void setExpired();
void cleanup();
size_t count() const { return size(); }
private:
size_t cleanup_counter {0};
};
@@ -56,6 +65,7 @@ private:
NodeMap& cache(sa_family_t af) { return af == AF_INET ? cache_4 : cache_6; }
NodeMap cache_4;
NodeMap cache_6;
std::mt19937_64& rd;
};
}
+11 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -22,10 +22,13 @@
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "log_enable.h"
#include <thread>
#include <mutex>
#include <condition_variable>
namespace asio {
class io_context;
}
namespace dht {
@@ -35,7 +38,7 @@ public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT);
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
@@ -51,7 +54,7 @@ public:
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
* startPublish - Keeping sending data until node is joinned or stop is called
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
@@ -79,20 +82,14 @@ public:
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join();
void connectivityChanged();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
std::shared_ptr<asio::io_context> ioContext_;
std::thread ioRunnner_;
};
}
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,8 @@
namespace dht {
namespace proxy {
constexpr const std::chrono::seconds OP_TIMEOUT {1 * 60 * 60}; // one hour
constexpr const std::chrono::seconds OP_MARGIN {5 * 60}; // 5 minutes
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
+10 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -23,19 +23,23 @@
namespace dht {
template<size_t Quota, unsigned long Period=1>
class RateLimiter {
public:
RateLimiter(size_t quota, const duration& period = std::chrono::seconds(1))
: quota_(quota), period_(period) {}
/** Clear outdated records and return current quota usage */
size_t maintain(const time_point& now) {
auto limit = now - std::chrono::seconds(Period);
auto limit = now - period_;
while (not records.empty() and records.front() < limit)
records.pop();
return records.size();
}
/** Return false if quota is reached, insert record and return true otherwise. */
bool limit(const time_point& now) {
if (maintain(now) >= Quota)
if (quota_ == std::numeric_limits<size_t>::max())
return true;
if (maintain(now) >= quota_)
return false;
records.emplace(now);
return true;
@@ -44,6 +48,8 @@ public:
return records.empty();
}
private:
const size_t quota_;
const duration period_;
std::queue<time_point> records {};
};
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -39,7 +39,7 @@ struct Bucket {
Sp<Node> cached; /* the address of a likely candidate */
/** Return a random node in a bucket. */
Sp<Node> randomNode();
Sp<Node> randomNode(std::mt19937_64& rd);
void sendCachedPing(net::NetworkEngine& ne);
void connectivityChanged() {
@@ -89,7 +89,7 @@ public:
/**
* Return a random id in the bucket's range.
*/
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
InfoHash randomId(const RoutingTable::const_iterator& bucket, std::mt19937_64& rd) const;
unsigned depth(const RoutingTable::const_iterator& bucket) const;
+4 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -84,7 +84,6 @@ public:
* @return The time for the next job to run.
*/
time_point run() {
syncTime();
while (not timers.empty()) {
auto timer = timers.begin();
/*
@@ -114,6 +113,9 @@ public:
*/
inline const time_point& time() const { return now; }
inline time_point syncTime() { return (now = clock::now()); }
inline void syncTime(const time_point& n) { now = n; }
inline size_t size() const { return timers.size(); }
private:
time_point now {clock::now()};
+15 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -180,6 +180,9 @@ public:
NodeStats getNodesStats(sa_family_t af) const override {
return dht_->getNodesStats(af);
}
NodeMetrics getNodeMetrics() const override {
return dht_->getNodeMetrics();
}
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
return dht_->getNodeMessageStats(in);
}
@@ -195,11 +198,11 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
return dht_->getPublicAddress(family);
}
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa) override {
return dht_->periodic(buf, buflen, std::move(sa));
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa, const time_point& now) override {
return dht_->periodic(buf, buflen, std::move(sa), now);
}
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return dht_->periodic(buf, buflen, from, fromlen);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return dht_->periodic(buf, buflen, from, fromlen, now);
}
NodeStatus getStatus(sa_family_t af) const override {
return dht_->getStatus(af);
@@ -316,11 +319,16 @@ public:
dht_->setLogger(logger);
}
void setLogger(const std::shared_ptr<Logger>& logger) override {
DhtInterface::setLogger(logger);
dht_->setLogger(logger);
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f) override {
DHT_LOG.setFilter(f);
DhtInterface::setLogFilter(f);
dht_->setLogFilter(f);
}
@@ -345,6 +353,7 @@ private:
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
};
const ValueType CERTIFICATE_TYPE = {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+10 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -43,9 +43,15 @@ public:
template<class T>
std::future<T> get(std::function<T()>&& cb) {
auto ret = std::make_shared<std::promise<T>>();
run(std::bind([=](std::function<T()>& mcb) mutable {
ret->set_value(mcb());
}, std::move(cb)));
run([cb = std::move(cb), ret]() mutable {
try {
ret->set_value(cb());
} catch (...) {
try {
ret->set_exception(std::current_exception());
} catch(...) {}
}
});
return ret->get_future();
}
template<class T>
+28 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -77,12 +77,20 @@ public:
// Time related definitions and utility functions
using clock = std::chrono::steady_clock;
using system_clock = std::chrono::system_clock;
using time_point = clock::time_point;
using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
@@ -99,14 +107,27 @@ print_duration(DT d) {
return "-" + print_duration(-d);
}
if (d < std::chrono::milliseconds(1)) {
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
} else if (d < std::chrono::seconds(1)) {
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else if (d < std::chrono::minutes(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
} else if (d < std::chrono::hours(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
} else {
return std::to_string(print_dt(d)) + " s";
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
}
}
template <class TimePoint>
static std::string
print_time_relative(TimePoint now, TimePoint d) {
if (d == TimePoint::min()) return "never";
if (d == now) return "now";
return (d > now) ? std::string("in ") + print_duration(d - now)
: print_duration(now - d) + std::string(" ago");
}
template <typename Duration = duration>
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
using Base = std::uniform_int_distribution<typename Duration::rep>;
@@ -133,7 +154,7 @@ using Blob = std::vector<uint8_t>;
/**
* Provides backward compatibility with msgpack 1.0
*/
OPENDHT_PUBLIC Blob unpackBlob(msgpack::object& o);
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object& o);
template <typename Type>
Blob
@@ -153,6 +174,7 @@ unpackMsg(Blob b) {
msgpack::unpacked unpackMsg(Blob b);
msgpack::object* findMapValue(msgpack::object& map, const std::string& key);
msgpack::object* findMapValue(const msgpack::object& map, const char* key);
msgpack::object* findMapValue(const msgpack::object& map, const std::string& key);
} // namespace dht
+62 -25
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -43,6 +43,19 @@
namespace dht {
static const std::string VALUE_KEY_ID("id");
static const std::string VALUE_KEY_DAT("dat");
static const std::string VALUE_KEY_PRIO("p");
static const std::string VALUE_KEY_SIGNATURE("sig");
static const std::string VALUE_KEY_SEQ("seq");
static const std::string VALUE_KEY_DATA("data");
static const std::string VALUE_KEY_OWNER("owner");
static const std::string VALUE_KEY_TYPE("type");
static const std::string VALUE_KEY_TO("to");
static const std::string VALUE_KEY_BODY("body");
static const std::string VALUE_KEY_USERTYPE("utype");
struct Value;
struct Query;
@@ -167,7 +180,7 @@ struct OPENDHT_PUBLIC Value
static Filter chain(Filter&& f1, Filter&& f2) {
if (not f1) return std::move(f2);
if (not f2) return std::move(f1);
return [f1,f2](const Value& v) {
return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
return f1(v) and f2(v);
};
}
@@ -180,12 +193,12 @@ struct OPENDHT_PUBLIC Value
}
static Filter chainAll(std::vector<Filter>&& set) {
if (set.empty()) return {};
return std::bind([](const Value& v, std::vector<Filter>& s) {
for (const auto& f : s)
return [set = std::move(set)](const Value& v) {
for (const auto& f : set)
if (f and not f(v))
return false;
return true;
}, std::placeholders::_1, std::move(set));
};
}
static Filter chain(std::initializer_list<Filter> l) {
return chainAll(std::vector<Filter>(l.begin(), l.end()));
@@ -390,7 +403,7 @@ struct OPENDHT_PUBLIC Value
* Build a value from a json object
* @param json
*/
Value(Json::Value& json);
Value(const Json::Value& json);
#endif
template <typename Type>
@@ -408,7 +421,9 @@ struct OPENDHT_PUBLIC Value
Value(Value&& o) noexcept
: id(o.id), owner(std::move(o.owner)), recipient(o.recipient),
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq), signature(std::move(o.signature)), cypher(std::move(o.cypher)) {}
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq)
, signature(std::move(o.signature)), cypher(std::move(o.cypher))
, priority(o.priority) {}
template <typename Type>
Value(const Type& vs)
@@ -421,10 +436,20 @@ struct OPENDHT_PUBLIC Value
msgpack_unpack(o);
}
/**
* Returns true if value contents are equals (not considering the value ID)
*/
inline bool contentEquals(const Value& o) {
return isEncrypted() ? cypher == o.cypher :
((owner == o.owner || (owner and o.owner and *owner == *o.owner))
&& type == o.type
&& data == o.data
&& user_type == o.user_type
&& signature == o.signature);
}
inline bool operator== (const Value& o) {
return id == o.id &&
(isEncrypted() ? cypher == o.cypher :
((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
return id == o.id and contentEquals(o);
}
void setRecipient(const InfoHash& r) {
@@ -485,17 +510,17 @@ struct OPENDHT_PUBLIC Value
bool has_owner = owner && *owner;
pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient ? 5 : 4):2));
if (has_owner) { // isSigned
pk.pack(std::string("seq")); pk.pack(seq);
pk.pack(std::string("owner")); owner->msgpack_pack(pk);
pk.pack(VALUE_KEY_SEQ); pk.pack(seq);
pk.pack(VALUE_KEY_OWNER); owner->msgpack_pack(pk);
if (recipient) {
pk.pack(std::string("to")); pk.pack(recipient);
pk.pack(VALUE_KEY_TO); pk.pack(recipient);
}
}
pk.pack(std::string("type")); pk.pack(type);
pk.pack(std::string("data")); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
pk.pack(VALUE_KEY_TYPE); pk.pack(type);
pk.pack(VALUE_KEY_DATA); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
if (not user_type.empty()) {
pk.pack(std::string("utype")); pk.pack(user_type);
pk.pack(VALUE_KEY_USERTYPE); pk.pack(user_type);
}
}
@@ -507,10 +532,10 @@ struct OPENDHT_PUBLIC Value
pk.pack_bin_body((const char*)cypher.data(), cypher.size());
} else {
pk.pack_map(isSigned() ? 2 : 1);
pk.pack(std::string("body")); msgpack_pack_to_sign(pk);
pk.pack(VALUE_KEY_BODY); msgpack_pack_to_sign(pk);
if (isSigned()) {
pk.pack(std::string("sig")); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
pk.pack(VALUE_KEY_SIGNATURE); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
}
}
}
@@ -518,9 +543,12 @@ struct OPENDHT_PUBLIC Value
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(id);
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
pk.pack_map(2 + (priority?1:0));
pk.pack(VALUE_KEY_ID); pk.pack(id);
pk.pack(VALUE_KEY_DAT); msgpack_pack_to_encrypt(pk);
if (priority) {
pk.pack(VALUE_KEY_PRIO); pk.pack(priority);
}
}
template <typename Packer>
@@ -551,7 +579,7 @@ struct OPENDHT_PUBLIC Value
}
}
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack_body(const msgpack::object& o);
Blob getPacked() const {
msgpack::sbuffer buffer;
@@ -602,6 +630,13 @@ struct OPENDHT_PUBLIC Value
*/
Blob cypher {};
/**
* Priority of this value (used for push notifications)
* 0 = high priority
* 1 = normal priority
*/
unsigned priority {0};
private:
friend class SecureDht;
/* Cache for crypto ops */
@@ -658,7 +693,7 @@ struct OPENDHT_PUBLIC FieldValue
}
}
void msgpack_unpack(msgpack::object msg) {
void msgpack_unpack(const msgpack::object& msg) {
hashValue = {};
blobValue.clear();
@@ -745,6 +780,8 @@ struct OPENDHT_PUBLIC Select
return ss.str();
}
bool empty() const { return fieldSelection_.empty(); }
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
private:
std::vector<Value::Field> fieldSelection_ {};
+419 -30
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
@@ -33,21 +33,23 @@
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# 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 4
#serial 11
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
@@ -59,18 +61,11 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++$1 -std=gnu++0x; do
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
@@ -96,22 +91,27 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
ac_success=yes
done
if test x$ac_success = xyes; then
break
fi
done
@@ -148,6 +148,11 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
@@ -185,11 +190,13 @@ namespace cxx11
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
@@ -518,7 +525,7 @@ namespace cxx14
}
namespace test_digit_seperators
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
@@ -560,3 +567,385 @@ namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])
+3
View File
@@ -458,6 +458,9 @@ cdef class DhtConfig(object):
self._config.dht_config.node_config.network = netid
def setMaintainStorage(self, bool maintain_storage):
self._config.dht_config.node_config.maintain_storage = maintain_storage
def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec):
self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec
self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec
cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
+3
View File
@@ -211,6 +211,9 @@ cdef extern from "opendht/callbacks.h" namespace "dht":
uint32_t network
bool is_bootstrap
bool maintain_storage
string persist_path
size_t max_req_per_sec
size_t max_peer_req_per_sec
cppclass SecureDhtConfig:
Config node_config
Identity id
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+22 -5
View File
@@ -19,30 +19,40 @@ import opendht as dht
import time
import asyncio
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
ping_node = dht.DhtRunner()
ping_node.run()
ping_node.run(config=config)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run()
pong_node.run(config=config)
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
net = []
for i in range(1,10):
node = dht.DhtRunner()
node.run(config=config)
node.ping(ping_node.getBound())
net.append(node)
i = 0
MAX = 2048
loop = asyncio.get_event_loop()
def done(h, ok):
print(h, "over", ok)
pass
#print(h, "over", ok)
def ping(node, h):
global i
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
@@ -50,13 +60,20 @@ def ping(node, h):
loop.stop()
def pong(node, h):
print(node.getNodeId().decode(), "got ping", h, i)
#print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h)
return True
t1 = time.time()
ping_node.listen(loc_ping, lambda v, e: pong(pong_node, loc_pong) if not e else True)
pong_node.listen(loc_pong, lambda v, e: pong(ping_node, loc_ping) if not e else True)
ping(pong_node, loc_ping)
loop.run_forever()
t2 = time.time()
print(MAX, "ping-pong done, took", t2 - t1, "s")
print(1000 * (t2 - t1)/MAX, "ms per rt", MAX/(t2 - t1), "rt per s")
+2
View File
@@ -0,0 +1,2 @@
*.lock
target
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "opendht"
version = "0.1.0"
authors = ["Sébastien Blin <sebastien.blin@savoirfairelinux.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc="0.2.0"
os_socketaddr="0.1.0"
+21
View File
@@ -0,0 +1,21 @@
# Rust bindings for opendht
## Build
Install rust on your system (https://rustup.rs/ is the recommanded way). Once done:
```
cargo build
```
## Run tests
```
cargo test
```
## Run dht node
```
cargo run --example dhtnode
```
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
extern crate opendht;
use std::{ thread, time };
use opendht::{ InfoHash, DhtRunner, DhtRunnerConfig, Value };
// use opendht::crypto::*;
fn main() {
println!("{}", InfoHash::random());
println!("{}", InfoHash::new());
println!("{}", InfoHash::new().is_zero());
println!("{}", InfoHash::get("alice"));
println!("{}", InfoHash::get("alice").is_zero());
let mut dht = DhtRunner::new();
let /*mut*/ config = DhtRunnerConfig::new();
//// If you want to inject a certificate, uncomment the following lines and previous mut.
//// Note: you can generate a certificate with
//// openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj /CN=example.com
//let cert = DhtCertificate::import("example.crt").ok().expect("Invalid cert file");
//let pk = PrivateKey::import("example.key", "");
//config.set_identity(cert, pk);
dht.run_config(1412, config);
dht.bootstrap("bootstrap.jami.net", 4222);
println!("Current node id: {}", dht.node_id());
let /* mut */ data = 42;
let mut get_cb = |v: Box<Value>| {
//data += 1;
println!("GET: VALUE CB - data: {} - v: {}", data, v);
true
};
let mut done_cb = |ok: bool| {
println!("GET: DONE CB - data: {} - ok: {}", data, ok);
};
dht.get(&InfoHash::get("alice"), &mut get_cb, &mut done_cb);
let mut put_done_cb = |ok: bool| {
println!("PUT: DONE CB - data: {} - ok: {}", data, ok);
};
dht.put(&InfoHash::get("bob"), Value::new("hi!"), &mut put_done_cb, false);
println!("Start listening /foo");
let mut value_cb = |v, expired| {
println!("LISTEN: DONE CB - data: {} - v: {} - expired: {}", data, v, expired);
true
};
let token = dht.listen(&InfoHash::get("foo"), &mut value_cb);
let one_min = time::Duration::from_secs(10);
thread::sleep(one_min);
dht.cancel_listen(&InfoHash::get("foo"), token);
println!("Public ips: {:#?}", dht.public_addresses());
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::ffi::*;
pub use crate::ffi::Blob;
impl Blob {
pub fn data(&self) -> DataView {
unsafe {
dht_blob_get_data(self)
}
}
}
impl Drop for Blob {
fn drop(&mut self) {
unsafe {
dht_blob_delete(&mut *self)
}
}
}
+194
View File
@@ -0,0 +1,194 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
pub use crate::ffi::*;
use std::ffi::CString;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::ptr;
impl PublicKey {
pub fn new(data: &str) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_publickey_import(data.as_ptr(), data.len()))
}
}
pub fn unpack(&mut self, data: Vec<u8>) -> i32 {
unsafe {
dht_publickey_unpack(&mut *self, data.as_ptr(), data.len())
}
}
pub fn pack(&mut self, data: &str) -> i32 {
let data = CString::new(data).unwrap();
unsafe {
dht_publickey_pack(&mut *self,
data.as_ptr(),
data.as_bytes().len())
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_publickey_get_id(self)
}
}
pub fn long_id(&self) -> PkId {
unsafe {
dht_publickey_get_long_id(self)
}
}
pub fn check_signature(&self, data: &str, signature: &str) -> bool {
let data = CString::new(data).unwrap();
let signature = CString::new(signature).unwrap();
unsafe {
dht_publickey_check_signature(self,
data.as_ptr(), data.as_bytes().len(),
signature.as_ptr(), signature.as_bytes().len())
}
}
pub fn encrypt(&self, data: &str) -> Box<Blob> {
let data = CString::new(data).unwrap();
unsafe {
Box::from_raw(dht_publickey_encrypt(self,
data.as_ptr(), data.as_bytes().len()))
}
}
}
impl Drop for PublicKey {
fn drop(&mut self) {
unsafe {
dht_publickey_delete(&mut *self)
}
}
}
impl PrivateKey {
pub fn new(key_length_bits: u32) -> Box<PrivateKey> {
unsafe {
Box::from_raw(dht_privatekey_generate(key_length_bits))
}
}
pub fn import(file: &str, password: &str) -> io::Result<Box<PrivateKey>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(PrivateKey::from_bytes(&buffer, password))
}
pub fn from_bytes(buffer: &Vec<u8>, password: &str) -> Box<PrivateKey> {
unsafe {
Box::from_raw(dht_privatekey_import((&*buffer).as_ptr(), buffer.len(),
password.as_ptr() as *const i8))
}
}
pub fn public_key(&self) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_privatekey_get_publickey(self))
}
}
}
impl Drop for PrivateKey {
fn drop(&mut self) {
unsafe {
dht_privatekey_delete(&mut *self)
}
}
}
impl DhtCertificate {
pub fn import(file: &str) -> io::Result<Box<DhtCertificate>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(DhtCertificate::from_bytes(&buffer))
}
pub fn from_bytes(buffer: &Vec<u8>) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn from_slice(buffer: &str) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_certificate_get_id(&*self)
}
}
pub fn long_id(&self) -> PkId {
unsafe {
dht_certificate_get_long_id(&*self)
}
}
pub fn publickey(&self) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_certificate_get_publickey(&*self))
}
}
}
impl Drop for DhtCertificate {
fn drop(&mut self) {
unsafe {
dht_certificate_delete(&mut *self)
}
}
}
impl DhtIdentity {
pub fn new(common_name: &str) -> DhtIdentity {
unsafe {
DhtIdentity::generate(common_name, Box::from_raw(ptr::null_mut()))
}
}
pub fn generate(common_name: &str, ca: Box<DhtIdentity>) -> DhtIdentity {
let common_name = CString::new(common_name).unwrap();
unsafe {
dht_identity_generate(common_name.as_ptr(), &*ca)
}
}
}
impl Drop for DhtIdentity {
fn drop(&mut self) {
unsafe {
dht_identity_delete(&mut *self)
}
}
}
+315
View File
@@ -0,0 +1,315 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use libc::c_void;
use std::ffi::CString;
use std::ptr;
pub use crate::ffi::*;
use std::net::SocketAddr;
use os_socketaddr::OsSocketAddr;
impl DhtRunnerConfig {
pub fn new() -> Box<DhtRunnerConfig> {
let mut config: Box<DhtRunnerConfig> = Box::new(DhtRunnerConfig {
dht_config: DhtSecureConfig {
node_config: DhtNodeConfig {
node_id: InfoHash::new(),
network: 0,
is_bootstrap: false,
maintain_storage: false,
persist_path: ptr::null(),
},
id: DhtIdentity {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
},
threaded: false,
proxy_server: ptr::null(),
push_node_id: ptr::null(),
push_token: ptr::null(),
peer_discovery: false,
peer_publish: false,
server_ca: ptr::null_mut(),
client_identity: DhtIdentity {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
});
unsafe {
dht_runner_config_default(&mut *config);
}
config
}
pub fn set_proxy_server(&mut self, proxy_server: &str) {
self.proxy_server = CString::new(proxy_server).unwrap().as_ptr();
}
pub fn set_push_node_id(&mut self, push_node_id: &str) {
self.push_node_id = CString::new(push_node_id).unwrap().as_ptr();
}
pub fn set_push_token(&mut self, push_token: &str) {
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
self.dht_config.id.privatekey = Box::into_raw(privatekey);
self.dht_config.id.certificate = Box::into_raw(certificate);
}
}
impl DhtNodeConfig
{
pub fn set_persist_path(&mut self, persist_path: &str) {
self.persist_path = CString::new(persist_path).unwrap().as_ptr();
}
}
struct GetHandler<'a>
{
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
done_cb: &'a mut(dyn FnMut(bool))
}
impl<'a> GetHandler<'a>
{
fn get_cb(&mut self, v: Box<Value>) -> bool{
(self.get_cb)(v)
}
fn done_cb(&mut self, ok: bool) {
(self.done_cb)(ok)
}
}
extern fn get_handler_cb(v: *mut Value, ptr: *mut c_void) -> bool {
if ptr.is_null() {
return true;
}
unsafe {
let handler = ptr as *mut GetHandler;
(*handler).get_cb((*v).boxed())
}
}
extern fn done_handler_cb(ok: bool, ptr: *mut c_void) {
unsafe {
let handler = Box::from_raw(ptr as *mut GetHandler);
(*handler.done_cb)(ok)
}
}
struct PutHandler<'a>
{
done_cb: &'a mut(dyn FnMut(bool))
}
impl<'a> PutHandler<'a>
{
fn done_cb(&mut self, ok: bool) {
(self.done_cb)(ok)
}
}
extern fn put_handler_done(ok: bool, ptr: *mut c_void) {
unsafe {
let handler = Box::from_raw(ptr as *mut PutHandler);
(*handler.done_cb)(ok)
}
}
struct ListenHandler<'a>
{
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)
}
impl<'a> ListenHandler<'a>
{
fn cb(&mut self, v: Box<Value>, expired: bool) -> bool {
(self.cb)(v, expired)
}
}
extern fn listen_handler(v: *mut Value, expired: bool, ptr: *mut c_void) -> bool {
unsafe {
let handler = ptr as *mut ListenHandler;
(*handler).cb((*v).boxed(), expired)
}
}
extern fn listen_handler_done(ptr: *mut c_void) {
unsafe {
Box::from_raw(ptr as *mut ListenHandler);
}
}
impl DhtRunner {
pub fn new() -> Box<DhtRunner> {
unsafe {
Box::from_raw(dht_runner_new())
}
}
pub fn run(&mut self, port: u16) {
unsafe {
dht_runner_run(&mut *self, port)
}
}
pub fn run_config(&mut self, port: u16, config: Box<DhtRunnerConfig>) {
unsafe {
dht_runner_run_config(&mut *self, port, &*config)
}
}
pub fn bootstrap(&mut self, host: &str, service: u16) {
unsafe {
dht_runner_bootstrap(&mut *self,
CString::new(host).unwrap().as_ptr(),
CString::new(service.to_string()).unwrap().as_ptr())
}
}
pub fn node_id(&self) -> InfoHash {
unsafe {
dht_runner_get_node_id(&*self)
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_runner_get_id(&*self)
}
}
pub fn get<'a>(&mut self, h: &InfoHash,
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
done_cb: &'a mut(dyn FnMut(bool))) {
let handler = Box::new(GetHandler {
get_cb,
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_get(&mut *self, h, get_handler_cb, done_handler_cb, handler)
}
}
pub fn put<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put(&mut *self, h, &*v, put_handler_done, handler, permanent)
}
}
pub fn put_signed<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_signed(&mut *self, h, &*v, put_handler_done, handler, permanent)
}
}
pub fn put_encrypted<'a>(&mut self, h: &InfoHash, to: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_encrypted(&mut *self, h, to, &*v, put_handler_done, handler, permanent)
}
}
pub fn cancel_put<'a>(&mut self, h: &InfoHash, vid: u64) {
unsafe {
dht_runner_cancel_put(&mut *self, h, vid)
}
}
pub fn listen<'a>(&mut self, h: &InfoHash,
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)) -> Box<OpToken> {
let handler = Box::new(ListenHandler {
cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
Box::from_raw(dht_runner_listen(&mut *self, h, listen_handler, listen_handler_done, handler))
}
}
pub fn cancel_listen(&mut self, h: &InfoHash, token: Box<OpToken>) {
unsafe {
dht_runner_cancel_listen(&mut *self, h, &*token)
}
}
pub fn shutdown(&mut self,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void)
{
unsafe {
dht_runner_shutdown(&mut *self, done_cb, cb_user_data)
}
}
pub fn public_addresses(&self) -> Vec<SocketAddr> {
let mut result = Vec::new();
unsafe {
let mut addresses = dht_runner_get_public_address(&*self);
while !addresses.is_null() && !(*addresses).is_null() {
let sock = (*(*addresses)).into_addr();
if sock.is_some() {
result.push(sock.unwrap());
}
addresses = (addresses as usize + std::mem::size_of::<*mut OsSocketAddr>()) as *mut *mut OsSocketAddr;
}
}
result
}
}
impl Drop for DhtRunner {
fn drop(&mut self) {
unsafe {
dht_runner_delete(&mut *self)
}
}
}
impl Drop for OpToken {
fn drop(&mut self) {
unsafe {
dht_op_token_delete(&mut *self)
}
}
}
+222
View File
@@ -0,0 +1,222 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use libc::{c_char, c_int, c_uint, c_void, in_port_t, size_t};
use os_socketaddr::OsSocketAddr;
const HASH_LEN: usize = 20;
const PKID_LEN: usize = 32;
#[repr(C)]
pub struct DataView
{
pub data: *const u8,
pub size: size_t
}
#[repr(C)]
pub struct Value
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct Blob
{
_opaque: [u8; 0]
}
#[repr(C)]
#[derive(PartialEq)]
pub struct InfoHash
{
pub d: [u8; HASH_LEN],
}
#[repr(C)]
pub struct PkId
{
pub d: [u8; PKID_LEN],
}
#[repr(C)]
pub struct PublicKey
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct PrivateKey
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct OpToken
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtRunner
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtNodeConfig
{
pub node_id: InfoHash,
pub network: u32,
pub is_bootstrap: bool,
pub maintain_storage: bool,
pub persist_path: *const c_char,
}
#[repr(C)]
pub struct DhtCertificate
{
_opaque: [u8; 0]
}
#[repr(C)]
pub struct DhtIdentity
{
pub privatekey: *mut PrivateKey,
pub certificate: *mut DhtCertificate,
}
#[repr(C)]
pub struct DhtSecureConfig
{
pub node_config: DhtNodeConfig,
pub id: DhtIdentity,
}
#[repr(C)]
pub struct DhtRunnerConfig
{
pub dht_config: DhtSecureConfig,
pub threaded: bool,
pub proxy_server: *const c_char,
pub push_node_id: *const c_char,
pub push_token: *const c_char,
pub peer_discovery: bool,
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
pub client_identity: DhtIdentity,
}
#[link(name = "opendht-c")]
extern {
// dht::Value
pub fn dht_value_new(data: *const u8, size: size_t) -> *mut Value;
pub fn dht_value_ref(data: *const Value) -> *mut Value;
pub fn dht_value_unref(data: *mut Value);
pub fn dht_value_get_data(data: *const Value) -> DataView;
pub fn dht_value_get_id(data: *const Value) -> u64;
pub fn dht_value_get_owner(data: *const Value) -> *mut PublicKey;
pub fn dht_value_get_recipient(data: *const Value) -> InfoHash;
pub fn dht_value_get_user_type(data: *const Value) -> *const c_char;
// dht::Blob
pub fn dht_blob_get_data(data: *const Blob) -> DataView;
pub fn dht_blob_delete(data: *mut Blob);
// dht::InfoHash
pub fn dht_infohash_print(h: *const InfoHash) -> *const c_char;
pub fn dht_infohash_random(h: *mut InfoHash);
pub fn dht_infohash_get(h: *mut InfoHash, dat: *mut u8, dat_size: size_t);
pub fn dht_infohash_from_hex(h: *mut InfoHash, dat: *const c_char);
pub fn dht_infohash_is_zero(j: *const InfoHash) -> bool;
// dht::PkId
pub fn dht_pkid_print(h: *const PkId) -> *const c_char;
// dht::crypto::PublicKey
pub fn dht_publickey_import(dat: *const u8, dat_size: size_t) -> *mut PublicKey;
pub fn dht_publickey_delete(pk: *mut PublicKey);
pub fn dht_publickey_unpack(pk: *mut PublicKey, dat: *const u8, dat_size: size_t) -> c_int;
pub fn dht_publickey_pack(pk: *mut PublicKey, out: *const c_char, out_size: size_t) -> c_int;
pub fn dht_publickey_get_id(pk: *const PublicKey) -> InfoHash;
pub fn dht_publickey_get_long_id(pk: *const PublicKey) -> PkId;
pub fn dht_publickey_check_signature(pk: *const PublicKey, data: *const c_char, data_size: size_t, signature: *const c_char, signature_size: size_t) -> bool;
pub fn dht_publickey_encrypt(pk: *const PublicKey, data: *const c_char, data_size: size_t) -> *mut Blob;
// dht::crypto::PrivateKey
pub fn dht_privatekey_generate(key_length_bits: c_uint) -> *mut PrivateKey;
pub fn dht_privatekey_import(dat: *const u8, data_size: size_t, password: *const c_char) -> *mut PrivateKey;
pub fn dht_privatekey_get_publickey(pk: *const PrivateKey) -> *mut PublicKey;
pub fn dht_privatekey_delete(pk: *mut PrivateKey);
// dht::crypto::Certificate
pub fn dht_certificate_import(dat: *const u8, dat_size: size_t) -> *mut DhtCertificate;
pub fn dht_certificate_get_id(cert: *const DhtCertificate) -> InfoHash;
pub fn dht_certificate_get_long_id(cert: *const DhtCertificate) -> PkId;
pub fn dht_certificate_get_publickey(cert: *const DhtCertificate) -> *mut PublicKey;
pub fn dht_certificate_delete(cert: *mut DhtCertificate);
pub fn dht_identity_generate(common_name: *const c_char, ca: *const DhtIdentity) -> DhtIdentity;
pub fn dht_identity_delete(ca: *mut DhtIdentity);
// dht::OpToken
pub fn dht_op_token_delete(token: *mut OpToken);
// dht::DhtRunner
pub fn dht_runner_config_default(config: *mut DhtRunnerConfig);
pub fn dht_runner_new() -> *mut DhtRunner;
pub fn dht_runner_get_id(dht: *const DhtRunner) -> InfoHash;
pub fn dht_runner_get_node_id(dht: *const DhtRunner) -> InfoHash;
pub fn dht_runner_delete(dht: *mut DhtRunner);
pub fn dht_runner_run(dht: *mut DhtRunner, port: in_port_t);
pub fn dht_runner_run_config(dht: *mut DhtRunner, port: in_port_t, config: *const DhtRunnerConfig);
pub fn dht_runner_bootstrap(dht: *mut DhtRunner, host: *const c_char, service: *const c_char);
pub fn dht_runner_get(dht: *mut DhtRunner, h: *const InfoHash,
get_cb: extern fn(*mut Value, *mut c_void) -> bool,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_put(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_signed(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_encrypted(dht: *mut DhtRunner, h: *const InfoHash,
to: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_permanent(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_cancel_put(dht: *mut DhtRunner, h: *const InfoHash, vid: u64);
pub fn dht_runner_listen(dht: *mut DhtRunner, h: *const InfoHash,
cb: extern fn(*mut Value, bool, *mut c_void) -> bool,
done_cb: extern fn(*mut c_void),
cb_user_data: *mut c_void) -> *mut OpToken;
pub fn dht_runner_cancel_listen(dht: *mut DhtRunner, h: *const InfoHash,
token: *const OpToken);
pub fn dht_runner_shutdown(dht: *mut DhtRunner, done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_get_public_address(dht: *const DhtRunner) -> *mut *mut OsSocketAddr;
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::ffi::*;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
pub use crate::ffi::InfoHash;
impl InfoHash {
pub fn new() -> InfoHash {
InfoHash {
d: [0; 20]
}
}
pub fn random() -> InfoHash {
let mut h = InfoHash::new();
unsafe {
dht_infohash_random(&mut h);
}
h
}
pub fn get(data: &str) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
let c_str = CString::new(data).unwrap();
dht_infohash_get(&mut h, c_str.as_ptr() as *mut u8, data.len());
}
h
}
pub fn from_bytes(data: &Vec<u8>) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
dht_infohash_get(&mut h, data.as_ptr() as *mut u8, data.len());
}
h
}
pub fn from_hex(data: &str) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
let c_str = CString::new(data).unwrap();
dht_infohash_from_hex(&mut h, c_str.as_ptr());
}
h
}
pub fn is_zero(&self) -> bool {
unsafe {
dht_infohash_is_zero(self)
}
}
}
impl fmt::Display for InfoHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
let self_str = CStr::from_ptr(
dht_infohash_print(self)
).to_str().unwrap_or("");
write!(f, "{}", self_str)
}
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
extern crate libc;
extern crate os_socketaddr;
mod blob;
pub mod crypto;
mod dhtrunner;
mod ffi;
mod infohash;
mod pkid;
mod value;
pub use blob::Blob;
pub use dhtrunner::{ DhtRunner, DhtRunnerConfig, OpToken };
pub use infohash::InfoHash;
pub use pkid::PkId;
pub use value::{ DataView, Value };
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::ffi::*;
use std::ffi::CStr;
use std::fmt;
pub use crate::ffi::PkId;
impl fmt::Display for PkId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
let self_str = CStr::from_ptr(
dht_pkid_print(self)
).to_str().unwrap_or("");
write!(f, "{}", self_str)
}
}
}
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use crate::ffi::*;
use std::fmt;
use std::ffi::{ CString, IntoStringError };
use std::str;
use std::slice;
pub use crate::ffi::{DataView, Value};
impl Value {
pub fn new(data: &str) -> Box<Value> {
unsafe {
Box::from_raw(dht_value_new(data.as_bytes().as_ptr(),
data.as_bytes().len()))
}
}
pub fn from_bytes(data: &Vec<u8>) -> Box<Value> {
unsafe {
Box::from_raw(dht_value_new(data.as_ptr(),
data.len()))
}
}
pub fn id(&self) -> u64 {
unsafe {
dht_value_get_id(self)
}
}
fn dataview(&self) -> DataView {
unsafe {
dht_value_get_data(self)
}
}
pub fn as_bytes(&self) -> Vec<u8> {
unsafe {
let dv = dht_value_get_data(self);
let slice = slice::from_raw_parts_mut(dv.data as *mut _, dv.size);
slice.to_vec()
}
}
pub fn boxed(&mut self) -> Box<Value> {
unsafe {
Box::from_raw(dht_value_ref(self))
}
}
pub fn recipient(&self) -> InfoHash {
unsafe {
dht_value_get_recipient(self)
}
}
pub fn owner(&self) -> Option<Box<PublicKey>> {
unsafe {
let ptr = dht_value_get_owner(self);
if ptr.is_null() {
return None;
}
Some(Box::from_raw(ptr))
}
}
pub fn user_type(&self) -> Result<String, IntoStringError> {
unsafe {
CString::from_raw(dht_value_get_user_type(self) as *mut _).into_string()
}
}
}
impl Drop for Value {
fn drop(&mut self) {
unsafe {
dht_value_unref(&mut *self)
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
let dataview = self.dataview();
let slice = slice::from_raw_parts(dataview.data, dataview.size);
write!(f, "{}", str::from_utf8(slice).unwrap_or(""))
}
}
}
+6 -3
View File
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ @OpenSSL_LDFLAGS@ @Fmt_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -27,7 +27,6 @@ libopendht_la_SOURCES = \
dhtrunner.cpp \
default_types.cpp \
log.cpp \
peer_discovery.cpp \
network_utils.cpp \
thread_pool.cpp
@@ -56,7 +55,6 @@ nobase_include_HEADERS = \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/log_enable.h \
../include/opendht/peer_discovery.h \
../include/opendht/network_utils.h \
../include/opendht/rng.h \
../include/opendht/thread_pool.h
@@ -77,6 +75,11 @@ libopendht_la_SOURCES += http.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
endif
if ENABLE_PEER_DISCOVERY
libopendht_la_SOURCES += peer_discovery.cpp
nobase_include_HEADERS += ../include/opendht/peer_discovery.h
endif
if ENABLE_INDEXATION
libopendht_la_SOURCES += indexation/pht.cpp
nobase_include_HEADERS += ../include/opendht/indexation/pht.h
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* 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
@@ -131,7 +131,7 @@ base64_encode(const std::vector<unsigned char>& str)
return base64_encode(str.cbegin(), str.cend());
}
std::string
std::vector<unsigned char>
base64_decode(const std::string& str)
{
size_t output_length = str.length() / 4 * 3 + 2;
@@ -139,5 +139,5 @@ base64_decode(const std::string& str)
output.resize(output_length);
base64_decode(str.data(), str.size(), output.data(), &output_length);
output.resize(output_length);
return std::string(output.begin(), output.end());
return output;
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* 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
@@ -33,4 +33,4 @@ std::string base64_encode(const std::vector<unsigned char>& str);
* @param str the input buffer
* @return a base64-decoded buffer
*/
std::string base64_decode(const std::string& str);
std::vector<unsigned char> base64_decode(const std::string& str);
+40
View File
@@ -1,3 +1,25 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "callbacks.h"
namespace dht {
@@ -121,6 +143,8 @@ NodeInfo::toJson() const
val["node_id"] = node_id.toString();
val["ipv4"] = ipv4.toJson();
val["ipv6"] = ipv6.toJson();
val["ops"] = Json::Value::LargestUInt(ongoing_ops);
val["metrics"] = metrics.toJson();
return val;
}
@@ -131,6 +155,22 @@ NodeInfo::NodeInfo(const Json::Value& v)
node_id = InfoHash(v["node_id"].asString());
ipv4 = NodeStats(v["ipv4"]);
ipv6 = NodeStats(v["ipv6"]);
ongoing_ops = v["ops"].asLargestUInt();
}
Json::Value
NodeMetrics::toJson() const
{
Json::Value val;
val["scheduler_size"] = Json::Value::LargestUInt(scheduler_size);
val["node_cache_size"] = Json::Value::LargestUInt(node_cache_size);
val["request_count"] = Json::Value::LargestUInt(request_count);
val["rate_limiter_size"] = Json::Value::LargestUInt(rate_limiter_size);
val["reported_addr_num"] = Json::Value::LargestUInt(reported_addr_num);
val["store_size"] = Json::Value::LargestUInt(store_size);
val["store_values"] = Json::Value::LargestUInt(store_values);
val["store_quota_size"] = Json::Value::LargestUInt(store_quota_size);
return val;
}
#endif
+45 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -52,6 +52,9 @@ static std::uniform_int_distribution<uint8_t> rand_byte;
#define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256
#endif
#define DHT_AES_LEGACY_ENCRYPT 1
#define DHT_AES_LEGACY_DECRYPT 1
namespace dht {
namespace crypto {
@@ -105,7 +108,9 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
#if DHT_AES_LEGACY_ENCRYPT
gcm_aes_update(&aes, data_length, data);
#endif
gcm_aes_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
@@ -137,21 +142,26 @@ Blob aesDecrypt(const Blob& data, const Blob& key)
size_t data_sz = data.size() - GCM_IV_SIZE - GCM_DIGEST_SIZE;
Blob ret(data_sz);
//gcm_aes_update(&aes, data_sz, data.data() + GCM_IV_SIZE);
gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
//gcm_aes_digest(aes, GCM_DIGEST_SIZE, digest.data());
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
// TODO compute the proper digest directly from the decryption pass
Blob ret_tmp(data_sz);
struct gcm_aes_ctx aes_d;
gcm_aes_set_key(&aes_d, key.size(), key.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data.data());
gcm_aes_update(&aes_d, ret.size(), ret.data());
gcm_aes_encrypt(&aes_d, ret.size(), ret_tmp.data(), ret.data());
gcm_aes_digest(&aes_d, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE)) {
#if DHT_AES_LEGACY_DECRYPT
//gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
Blob ret_tmp(data_sz);
struct gcm_aes_ctx aes_d;
gcm_aes_set_key(&aes_d, key.size(), key.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data.data());
gcm_aes_update(&aes_d, ret.size(), ret.data());
gcm_aes_encrypt(&aes_d, ret.size(), ret_tmp.data(), ret.data());
gcm_aes_digest(&aes_d, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE))
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE))
throw DecryptError("Can't decrypt data");
#else
throw DecryptError("Can't decrypt data");
#endif
}
return ret;
}
@@ -338,9 +348,7 @@ PrivateKey::serialize(const std::string& password) const
size_t buf_sz = 8192;
Blob buffer;
buffer.resize(buf_sz);
int err = password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, buffer.data(), &buf_sz)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, buffer.data(), &buf_sz);
auto err = serialize(buffer.data(), &buf_sz, password);
if (err != GNUTLS_E_SUCCESS) {
std::cerr << "Could not export private key - " << gnutls_strerror(err) << std::endl;
return {};
@@ -349,6 +357,16 @@ PrivateKey::serialize(const std::string& password) const
return buffer;
}
int
PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password) const
{
if (!x509_key)
return -1;
return password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, out, out_len)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len);
}
PublicKey
PrivateKey::getPublicKey() const
{
@@ -364,9 +382,9 @@ PublicKey::PublicKey()
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const Blob& dat) : PublicKey()
PublicKey::PublicKey(const uint8_t* dat, size_t dat_size) : PublicKey()
{
unpack(dat.data(), dat.size());
unpack(dat, dat_size);
}
PublicKey::~PublicKey()
@@ -394,12 +412,18 @@ PublicKey::pack(Blob& b) const
throw CryptoException(std::string("Could not export public key: null key"));
std::vector<uint8_t> tmp(2048);
size_t sz = tmp.size();
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
if (int err = pack(tmp.data(), &sz))
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
tmp.resize(sz);
b.insert(b.end(), tmp.begin(), tmp.end());
}
int
PublicKey::pack(uint8_t* out, size_t* out_len) const
{
return gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, out, out_len);
}
void
PublicKey::unpack(const uint8_t* data, size_t data_size)
{
@@ -429,7 +453,7 @@ PublicKey::toString() const
}
void
PublicKey::msgpack_unpack(msgpack::object o)
PublicKey::msgpack_unpack(const msgpack::object& o)
{
if (o.type == msgpack::type::BIN)
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
@@ -774,7 +798,7 @@ Certificate::unpack(const uint8_t* dat, size_t dat_size)
}
void
Certificate::msgpack_unpack(msgpack::object o)
Certificate::msgpack_unpack(const msgpack::object& o)
{
if (o.type == msgpack::type::BIN)
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
@@ -1234,7 +1258,7 @@ RevocationList::unpack(const uint8_t* dat, size_t dat_size)
}
void
RevocationList::msgpack_unpack(msgpack::object o)
RevocationList::msgpack_unpack(const msgpack::object& o)
{
try {
if (o.type == msgpack::type::BIN)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+287 -191
View File
File diff suppressed because it is too large. Load diff
+322 -353
View File
File diff suppressed because it is too large. Load diff
+336 -392
View File
File diff suppressed because it is too large. Load diff
+364 -207
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -18,26 +18,23 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dhtrunner.h"
#include "securedht.h"
#include "peer_discovery.h"
#include "network_utils.h"
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef _WIN32
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#include "dhtrunner.h"
#include "securedht.h"
#include "network_utils.h"
#ifdef OPENDHT_PEER_DISCOVERY
#include "peer_discovery.h"
#endif
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
namespace dht {
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
static constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(500);
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
struct DhtRunner::Listener {
@@ -100,9 +97,9 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Conf
void
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context)
{
if (not running) {
if (running == State::Idle) {
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
run(config, std::move(context));
}
}
@@ -111,25 +108,34 @@ void
DhtRunner::run(const Config& config, Context&& context)
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (running)
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running))
return;
if (context.logger)
if (context.logger) {
logger_ = context.logger;
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
{
std::lock_guard<std::mutex> lck(sock_mtx);
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
std::cerr << "Dropping packet: queue is full!" << std::endl;
rcv.pop();
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
while (rcv.size() > maxSize) {
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop_front();
}
rcv.emplace(std::move(pkt));
rcv.splice(rcv.end(), std::move(pkts));
ret = std::move(rcv_free);
}
cv.notify_all();
return ret;
});
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger ? *context.logger : Logger{}));
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#ifdef OPENDHT_PROXY_CLIENT
@@ -137,7 +143,7 @@ DhtRunner::run(const Config& config, Context&& context)
#endif
enableProxy(not config.proxy_server.empty());
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(*context.logger);
dht_via_proxy_->setLogger(context.logger);
}
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
@@ -148,16 +154,15 @@ DhtRunner::run(const Config& config, Context&& context)
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
}
running = true;
if (not config.threaded)
return;
dht_thread = std::thread([this]() {
while (running) {
while (running != State::Idle) {
std::unique_lock<std::mutex> lk(dht_mtx);
time_point wakeup = loop_();
auto hasJobToDo = [this]() {
if (not running)
if (running == State::Idle)
return true;
{
std::lock_guard<std::mutex> lck(sock_mtx);
@@ -182,11 +187,16 @@ DhtRunner::run(const Config& config, Context&& context)
});
if (config.peer_discovery or config.peer_publish) {
#ifdef OPENDHT_PEER_DISCOVERY
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
#else
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
#endif
}
#ifdef OPENDHT_PEER_DISCOVERY
auto netId = config.dht_config.node_config.network;
if (config.peer_discovery) {
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
@@ -202,53 +212,104 @@ DhtRunner::run(const Config& config, Context&& context)
adc.net = netId;
adc.nodeId = dht_->getNodeId();
// IPv4
if (auto bound4 = dht_->getSocket()->getBound(AF_INET)) {
if (const auto& bound4 = dht_->getSocket()->getBoundRef(AF_INET)) {
adc.port = bound4.getPort();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
// IPv6
if (auto bound6 = dht_->getSocket()->getBound(AF_INET6)) {
if (const auto& bound6 = dht_->getSocket()->getBoundRef(AF_INET6)) {
adc.port = bound6.getPort();
sbuf_node.clear();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
#endif
}
void
DhtRunner::shutdown(ShutdownCallback cb) {
if (not running) {
cb();
auto expected = State::Running;
if (not running.compare_exchange_strong(expected, State::Stopping)) {
if (expected == State::Stopping and ongoing_ops) {
std::lock_guard<std::mutex> lck(storage_mtx);
shutdownCallbacks_.emplace_back(std::move(cb));
}
else if (cb) cb();
return;
}
if (logger_)
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops_prio.emplace([=](SecureDht&) mutable {
auto onShutdown = [this]{ opEnded(); };
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
dht_via_proxy_->shutdown(onShutdown);
#endif
if (dht_)
dht_->shutdown(cb);
dht_->shutdown(onShutdown);
});
cv.notify_all();
}
void
DhtRunner::opEnded() {
if (--ongoing_ops == 0)
checkShutdown();
}
DoneCallback
DhtRunner::bindOpDoneCallback(DoneCallback&& cb) {
return [this, cb = std::move(cb)](bool ok, const std::vector<std::shared_ptr<Node>>& nodes){
if (cb) cb(ok, nodes);
opEnded();
};
}
DoneCallbackSimple
DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) {
return [this, cb = std::move(cb)](bool ok){
if (cb) cb(ok);
opEnded();
};
}
bool
DhtRunner::checkShutdown() {
if (running != State::Stopping or ongoing_ops)
return false;
decltype(shutdownCallbacks_) cbs;
{
std::lock_guard<std::mutex> lck(storage_mtx);
cbs = std::move(shutdownCallbacks_);
}
for (auto& cb : cbs)
if (cb) cb();
return true;
}
void
DhtRunner::join()
{
if (peerDiscovery_)
peerDiscovery_->stop();
{
std::lock_guard<std::mutex> lck(dht_mtx);
running = false;
if (running.exchange(State::Idle) == State::Idle)
return;
cv.notify_all();
bootstrap_cv.notify_all();
#ifdef OPENDHT_PEER_DISCOVERY
if (peerDiscovery_)
peerDiscovery_->stop();
#endif
if (dht_)
if (auto sock = dht_->getSocket())
sock->stop();
if (logger_)
logger_->d("[runner %p] state changed to Idle", this);
}
if (dht_thread.joinable())
@@ -257,14 +318,11 @@ DhtRunner::join()
if (bootstrap_thread.joinable())
bootstrap_thread.join();
if (peerDiscovery_) {
peerDiscovery_->join();
}
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops = decltype(pending_ops)();
pending_ops_prio = decltype(pending_ops_prio)();
ongoing_ops = 0;
}
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -283,6 +341,15 @@ DhtRunner::getBound(sa_family_t af) const {
return SockAddr{};
}
in_port_t
DhtRunner::getBoundPort(sa_family_t af) const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
if (auto sock = dht_->getSocket())
return sock->getPort(af);
return 0;
}
void
DhtRunner::dumpTables() const
{
@@ -340,8 +407,9 @@ DhtRunner::exportValues() const {
}
void
DhtRunner::setLogger(const Logger& logger) {
DhtRunner::setLogger(const Sp<Logger>& logger) {
std::lock_guard<std::mutex> lck(dht_mtx);
logger_ = logger;
if (dht_)
dht_->setLogger(logger);
#ifdef OPENDHT_PROXY_CLIENT
@@ -359,7 +427,6 @@ DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->setLogFilter(f);
if (dht_)
dht_->setLogFilter(f);
#ifdef OPENDHT_PROXY_CLIENT
@@ -406,14 +473,39 @@ DhtRunner::getNodesStats(sa_family_t af) const
NodeInfo
DhtRunner::getNodeInfo() const {
std::lock_guard<std::mutex> lck(dht_mtx);
NodeInfo info;
info.id = getId();
info.node_id = getNodeId();
info.ipv4 = dht_->getNodesStats(AF_INET);
info.ipv6 = dht_->getNodesStats(AF_INET6);
NodeInfo info {};
if (auto dht = activeDht()) {
info.id = dht->getId();
info.node_id = dht->getNodeId();
info.ipv4 = dht->getNodesStats(AF_INET);
info.ipv6 = dht->getNodesStats(AF_INET6);
info.metrics = dht->getNodeMetrics();
info.ongoing_ops = ongoing_ops;
}
info.ongoing_ops = ongoing_ops;
return info;
}
void
DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
{
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([cb = std::move(cb), this](SecureDht& dht){
auto sinfo = std::make_shared<NodeInfo>();
auto& info = *sinfo;
info.id = dht.getId();
info.node_id = dht.getNodeId();
info.ipv4 = dht.getNodesStats(AF_INET);
info.ipv6 = dht.getNodesStats(AF_INET6);
info.metrics = dht.getNodeMetrics();
info.ongoing_ops = ongoing_ops;
cb(std::move(sinfo));
opEnded();
});
cv.notify_all();
}
std::vector<unsigned>
DhtRunner::getNodeMessageStats(bool in) const
{
@@ -505,6 +597,7 @@ DhtRunner::loop_()
time_point wakeup {};
decltype(rcv) received {};
decltype(rcv) received_treated {};
{
std::lock_guard<std::mutex> lck(sock_mtx);
// move to stack
@@ -514,26 +607,36 @@ DhtRunner::loop_()
// Discard old packets
size_t dropped {0};
if (not received.empty()) {
auto now = clock::now();
while (not received.empty() and now - received.front()->received > RX_QUEUE_MAX_DELAY) {
received.pop();
auto limit = clock::now() - net::RX_QUEUE_MAX_DELAY;
auto it = received.begin();
while (it != received.end() and it->received < limit) {
it->data.clear();
++it;
dropped++;
}
received_treated.splice(received_treated.end(), received, received.begin(), it);
}
// Handle packets
if (not received.empty()) {
while (not received.empty()) {
auto& pck = received.front();
if (clock::now() - pck->received > RX_QUEUE_MAX_DELAY)
for (auto& pkt : received) {
auto now = clock::now();
if (now - pkt.received > net::RX_QUEUE_MAX_DELAY)
dropped++;
else
wakeup = dht->periodic(pck->data.data(), pck->data.size(), std::move(pck->from));
received.pop();
wakeup = dht->periodic(pkt.data.data(), pkt.data.size(), std::move(pkt.from), now);
pkt.data.clear();
}
received_treated.splice(received_treated.end(), std::move(received));
} else {
// Or just run the scheduler
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
wakeup = dht->periodic(nullptr, 0, nullptr, 0, clock::now());
}
if (not received_treated.empty()) {
std::lock_guard<std::mutex> lck(sock_mtx);
if (rcv_free.size() < net::RX_QUEUE_MAX_SIZE)
rcv_free.splice(rcv_free.end(), std::move(received_treated));
}
if (dropped)
@@ -563,12 +666,15 @@ DhtRunner::loop_()
void
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
});
if (running != State::Running) {
if (dcb) dcb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w));
});
cv.notify_all();
}
@@ -579,12 +685,15 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
}
void
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
});
if (running != State::Running) {
if (done_cb) done_cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q));
});
cv.notify_all();
}
@@ -592,32 +701,34 @@ std::future<size_t>
DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
auto ret_token = std::make_shared<std::promise<size_t>>();
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
if (running != State::Running) {
ret_token->set_value(0);
return ret_token->get_future();
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
cv.notify_all();
return ret_token->get_future();
}
@@ -631,73 +742,77 @@ DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Wher
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto sv = std::make_shared<Value>(std::move(value));
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, sv, cb, created, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
sv = std::make_shared<Value>(std::move(value))
] (SecureDht& dht) mutable {
dht.put(hash, sv, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, value, cb, created, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable {
dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
@@ -708,63 +823,83 @@ DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, tim
}
void
DhtRunner::cancelPut(const InfoHash& h , const Value::Id& id)
DhtRunner::cancelPut(const InfoHash& h, Value::Id id)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb)
DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putSigned(hash, value, cb);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, value->id);
});
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb)
{
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putEncrypted(hash, to, value, cb);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
](SecureDht& dht) mutable {
dht.putSigned(hash, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb, bool permanent)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb, bool permanent)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb, bool permanent)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb, bool permanent)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb), permanent);
}
void
@@ -796,7 +931,7 @@ DhtRunner::tryBootstrapContinuously()
++ping_count;
try {
bootstrap(SockAddr::resolve(it->first, it->second), [&](bool) {
if (not running)
if (running != State::Running)
return;
{
std::unique_lock<std::mutex> blck(mtx);
@@ -810,15 +945,15 @@ DhtRunner::tryBootstrapContinuously()
}
}
// wait at least until the next BOOTSTRAP_PERIOD
bootstrap_cv.wait_until(blck, next, [&]() { return not running; });
bootstrap_cv.wait_until(blck, next, [&]() { return running != State::Running; });
// wait for bootstrap requests to end.
if (running)
bootstrap_cv.wait(blck, [&]() { return not running or ping_count == 0; });
if (running != State::Running)
bootstrap_cv.wait(blck, [&]() { return running != State::Running or ping_count == 0; });
}
// update state
{
std::lock_guard<std::mutex> lck(dht_mtx);
bootstraping = running and
bootstraping = running == State::Running and
status4 == NodeStatus::Disconnected and
status6 == NodeStatus::Disconnected;
}
@@ -855,19 +990,28 @@ DhtRunner::clearBootstrap()
void
DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
ongoing_ops++;
pending_ops_prio.emplace([
cb = bindOpDoneCallback(std::move(cb)),
nodes = std::move(nodes)
] (SecureDht& dht) mutable {
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
for (auto& node : nodes) {
if (node.getPort() == 0)
node.setPort(net::DHT_DEFAULT_PORT);
dht.pingNode(std::move(node), cb ? [rem,cb](bool ok) {
dht.pingNode(std::move(node), [rem,cb](bool ok) {
auto& r = *rem;
r.first--;
r.second |= ok;
if (not r.first)
if (r.first == 0) {
cb(r.second);
} : DoneCallbackSimple{});
}
});
}
});
cv.notify_all();
@@ -876,8 +1020,13 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
if (cb) cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([addr, cb](SecureDht& dht) mutable {
ongoing_ops++;
pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
dht.pingNode(std::move(addr), std::move(cb));
});
cv.notify_all();
@@ -886,48 +1035,56 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
{
{
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
}
if (running != State::Running)
return;
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
cv.notify_all();
}
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
}
if (running != State::Running)
return;
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
cv.notify_all();
}
void
DhtRunner::connectivityChanged()
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
#ifdef OPENDHT_PEER_DISCOVERY
if (peerDiscovery_)
peerDiscovery_->connectivityChanged();
#endif
});
cv.notify_all();
}
void
DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.findCertificate(hash, cb);
});
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb) {
if (running != State::Running) {
cb({});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
cb(crt);
opEnded();
});
});
cv.notify_all();
}
@@ -992,11 +1149,11 @@ DhtRunner::enableProxy(bool proxify)
},
config_.proxy_server, config_.push_node_id, logger_)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not config_.push_token.empty())
dht_via_proxy_->setPushNotificationToken(config_.push_token);
dht_via_proxy->setPushNotificationToken(config_.push_token);
#endif
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
// add current listeners
for (auto& l: listeners_)
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
+420 -455
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+15 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -56,9 +56,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
s << std::endl;
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getStdLogger() {
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
@@ -70,22 +70,22 @@ getStdLogger() {
std::cout << def;
},
[](char const *m, va_list args) { printLog(std::cout, m, args); }
));
);
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getFileLogger(const std::string &path) {
auto logfile = std::make_shared<std::ofstream>();
logfile->open(path, std::ios::out);
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
));
);
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getSyslogLogger(const char* name) {
#ifndef _WIN32
struct Syslog {
@@ -103,34 +103,34 @@ getSyslogLogger(const char* name) {
logfile = std::make_shared<Syslog>(name);
opened_logfile = logfile;
}
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
));
);
#else
return std::unique_ptr<Logger>(new Logger());
return std::make_shared<Logger>();
#endif
}
void
enableLogging(dht::DhtRunner &dht) {
dht.setLogger(*getStdLogger());
dht.setLogger(getStdLogger());
}
void
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
dht.setLogger(*getFileLogger(path));
dht.setLogger(getFileLogger(path));
}
OPENDHT_PUBLIC void
enableSyslog(dht::DhtRunner &dht, const char* name) {
dht.setLogger(*getSyslogLogger(name));
dht.setLogger(getSyslogLogger(name));
}
void
disableLogging(dht::DhtRunner &dht) {
dht.setLogger({});
dht.setLogger();
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+147 -100
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -27,6 +27,7 @@
namespace dht {
namespace net {
using namespace std::chrono_literals;
const std::string DhtProtocolException::GET_NO_INFOHASH {"Get_values with no info_hash"};
const std::string DhtProtocolException::LISTEN_NO_INFOHASH {"Listen with no info_hash"};
@@ -41,7 +42,6 @@ constexpr std::chrono::seconds NetworkEngine::RX_MAX_PACKET_TIME;
constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
const std::string NetworkEngine::my_v {"RNG1"};
constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC;
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
@@ -99,11 +99,15 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
nodes6(std::move(msg.nodes6))
{}
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
NetworkEngine::NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
std::mt19937_64& rand,
Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
@@ -122,7 +126,10 @@ NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<Datagram
onListen(std::move(onListen)),
onAnnounce(std::move(onAnnounce)),
onRefresh(std::move(onRefresh)),
myid(myid), network(net), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
myid(myid), config(c), dht_socket(std::move(sock)), logger_(log), rd(rand),
cache(rd),
rate_limiter(config.max_req_per_sec),
scheduler(scheduler)
{}
NetworkEngine::~NetworkEngine() {
@@ -139,7 +146,8 @@ NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash,
try {
sendNodesValues(node->getAddr(), socket_id, nnodes.first, nnodes.second, values, query, ntoken);
} catch (const std::overflow_error& e) {
DHT_LOG.e("Can't send value: buffer not large enough !");
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
}
}
@@ -148,7 +156,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -159,14 +167,15 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
if (not values.empty()) {
pk.pack(KEY_REQ_REFRESHED);
pk.pack(values);
DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
if (logger_)
logger_->d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
}
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -178,7 +187,7 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -189,14 +198,15 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
if (not values.empty()) {
pk.pack(KEY_REQ_EXPIRED);
pk.pack(values);
DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
if (logger_)
logger_->d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
}
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -245,7 +255,8 @@ NetworkEngine::requestStep(Sp<Request> sreq)
auto now = scheduler.time();
auto& node = *req.node;
if (req.isExpired(now)) {
DHT_LOG.d(node.id, "[node %s] expired !", node.toString().c_str());
// if (logger_)
// logger_->d(node.id, "[node %s] expired !", node.toString().c_str());
node.setExpired();
if (not node.id)
requests.erase(req.tid);
@@ -265,12 +276,14 @@ NetworkEngine::requestStep(Sp<Request> sreq)
if (not node.id)
requests.erase(req.tid);
} else {
req.last_try = now;
if (err != EAGAIN) {
++req.attempt_count;
req.attempt_duration +=
req.attempt_duration + uniform_duration_distribution<>(0ms, ((duration)Node::MAX_RESPONSE_TIME)/4)(rd);
}
req.last_try = now;
std::weak_ptr<Request> wreq = sreq;
scheduler.add(req.last_try + Node::MAX_RESPONSE_TIME, [this,wreq] {
scheduler.add(req.last_try + req.attempt_duration, [this,wreq] {
if (auto req = wreq.lock())
requestStep(req);
});
@@ -300,7 +313,7 @@ NetworkEngine::rateLimit(const SockAddr& addr)
const auto& now = scheduler.time();
// occasional IP limiter maintenance (a few times every second at max rate)
if (limiter_maintenance++ == MAX_REQUESTS_PER_SEC/8) {
if (limiter_maintenance++ == config.max_peer_req_per_sec) {
for (auto it = address_rate_limiter.begin(); it != address_rate_limiter.end();) {
if (it->second.maintain(now) == 0)
address_rate_limiter.erase(it++);
@@ -311,7 +324,11 @@ NetworkEngine::rateLimit(const SockAddr& addr)
}
// invoke per IP, then global rate limiter
return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now);
return (config.max_peer_req_per_sec < 0
or address_rate_limiter
.emplace(addr, config.max_peer_req_per_sec).first->second
.limit(now))
and rate_limiter.limit(now);
}
bool
@@ -361,12 +378,14 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
{
auto from = f.getMappedIPv4();
if (isMartian(from)) {
DHT_LOG.w("Received packet from martian node %s", from.toString().c_str());
if (logger_)
logger_->w("Received packet from martian node %s", from.toString().c_str());
return;
}
if (isNodeBlacklisted(from)) {
DHT_LOG.w("Received packet from blacklisted node %s", from.toString().c_str());
if (logger_)
logger_->w("Received packet from blacklisted node %s", from.toString().c_str());
return;
}
@@ -375,13 +394,16 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
msgpack::unpacked msg_res = msgpack::unpack((const char*)buf, buflen);
msg->msgpack_unpack(msg_res.get());
} catch (const std::exception& e) {
DHT_LOG.w("Can't parse message of size %lu: %s", buflen, e.what());
//DHT_LOG.DBG.logPrintable(buf, buflen);
if (logger_)
logger_->w("Can't parse message of size %lu: %s", buflen, e.what());
// if (logger_)
// logger_->DBG.logPrintable(buf, buflen);
return;
}
if (msg->network != network) {
DHT_LOG.d("Received message from other network %u", msg->network);
if (msg->network != config.network) {
if (logger_)
logger_->d("Received message from other config.network %u", msg->network);
return;
}
@@ -392,12 +414,14 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
auto pmsg_it = partial_messages.find(msg->tid);
if (pmsg_it == partial_messages.end()) {
if (logIncoming_)
DHT_LOG.d("Can't find partial message");
if (logger_)
logger_->d("Can't find partial message");
rateLimit(from);
return;
}
if (!pmsg_it->second.from.equals(from)) {
DHT_LOG.d("Received partial message data from unexpected IP address");
if (logger_)
logger_->d("Received partial message data from unexpected IP address");
rateLimit(from);
return;
}
@@ -416,14 +440,16 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
}
if (msg->id == myid or not msg->id) {
DHT_LOG.d("Received message from self");
if (logger_)
logger_->d("Received message from self");
return;
}
if (msg->type > MessageType::Reply) {
/* Rate limit requests. */
if (!rateLimit(from)) {
DHT_LOG.w("Dropping request due to rate limiting");
if (logger_)
logger_->w("Dropping request due to rate limiting");
return;
}
}
@@ -442,7 +468,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
} else
DHT_LOG.e("Partial message with given TID already exists");
if (logger_)
logger_->e("Partial message with given TID already exists");
}
}
@@ -476,7 +503,9 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
node->received(now, req);
if (not node->isClient())
onNewNode(node, 1);
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find transaction", msg->id};
if (logger_)
logger_->d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
return;
}
}
@@ -487,7 +516,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
onReportedAddr(msg->id, msg->addr);
if (req and (req->cancelled() or req->expired() or req->completed())) {
DHT_LOG.w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
if (logger_)
logger_->w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
return;
}
@@ -503,7 +533,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
onError(req, DhtProtocolException {msg->error_code});
} else {
if (logIncoming_)
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
if (logger_)
logger_->w(msg->id, "[node %s %s] received unknown error message %u",
msg->id.toString().c_str(), from.toString().c_str(), msg->error_code);
}
break;
@@ -535,12 +566,14 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
case MessageType::Ping:
++in_stats.ping;
if (logIncoming_)
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
if (logger_)
logger_->d(node->id, "[node %s] sending pong", node->toString().c_str());
onPing(node);
sendPong(from, msg->tid);
break;
case MessageType::FindNode: {
//DHT_LOG.d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
// if (logger_)
// logger_->d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
++in_stats.find;
RequestAnswer answer = onFindNode(node, msg->target, msg->want);
auto nnodes = bufferNodes(from.getFamily(), msg->target, msg->want, answer.nodes4, answer.nodes6);
@@ -548,7 +581,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::GetValues: {
//DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
// if (logger_)
// logger_->d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.get;
RequestAnswer answer = onGetValues(node, msg->info_hash, msg->want, msg->query);
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
@@ -556,8 +590,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::AnnounceValue: {
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.put;
onAnnounce(node, msg->info_hash, msg->token, msg->values, msg->created);
@@ -570,15 +604,15 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::Refresh:
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
onRefresh(node, msg->info_hash, msg->token, msg->value_id);
/* Same note as above in MessageType::AnnounceValue applies. */
sendValueAnnounced(from, msg->tid, msg->value_id);
break;
case MessageType::Listen: {
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.listen;
RequestAnswer answer = onListen(node, msg->info_hash, msg->token, msg->socket_id, std::move(msg->query));
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
@@ -589,7 +623,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
} catch (const std::overflow_error& e) {
DHT_LOG.e("Can't send value: buffer not large enough !");
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
} catch (DhtProtocolException& e) {
sendError(from, msg->tid, e.getCode(), e.getMsg().c_str(), true);
}
@@ -619,7 +654,7 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
TransId tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -629,14 +664,15 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&&) {
DHT_LOG.d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
if (logger_)
logger_->d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
if (on_done) {
on_done(req_status, {});
}
@@ -656,7 +692,7 @@ void
NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -667,8 +703,8 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -680,7 +716,7 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -697,8 +733,8 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -726,28 +762,33 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 +
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
(want>0?1:0));
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
unsigned sendWant = (want > 0) ? 1 : 0;
pk.pack(KEY_A); pk.pack_map(2 + sendQuery + sendWant);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(info_hash);
pk.pack(KEY_Q); pk.pack(query);
if (want > 0) {
pk.pack(KEY_REQ_WANT);
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
if (want & WANT4) pk.pack(AF_INET);
if (want & WANT6) pk.pack(AF_INET6);
}
if (sendQuery) {
pk.pack(KEY_Q); pk.pack(query);
}
if (sendWant) {
pk.pack(KEY_REQ_WANT);
unsigned sendWant4 = (want & WANT4) ? 1 : 0;
unsigned sendWant6 = (want & WANT6) ? 1 : 0;
pk.pack_array(sendWant4 + sendWant6);
if (sendWant4) pk.pack(AF_INET);
if (sendWant6) pk.pack(AF_INET6);
}
pk.pack(KEY_Q); pk.pack(QUERY_GET);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -841,7 +882,8 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
for (const auto& b : svals)
buffer.write((const char*)b.data(), b.size());
// DHT_LOG.d("sending %lu bytes of values", total_size);
// if (logger_)
// logger_->d("sending %lu bytes of values", total_size);
svals.clear();
} else {
for (const auto& b : svals)
@@ -861,9 +903,9 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(network?1:0));
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
pk.pack_map(3+(config.network?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
@@ -886,7 +928,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -907,10 +949,10 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
}
std::vector<Blob> svals {};
if (not st.empty()) { /* pack complete values */
auto fields = query.select.getSelection();
if (fields.empty()) {
if (query.select.empty()) {
svals = packValueHeader(buffer, st);
} else { /* pack fields */
auto fields = query.select.getSelection();
pk.pack(KEY_REQ_FIELDS);
pk.pack_map(2);
pk.pack(std::string("f")); pk.pack(fields);
@@ -927,8 +969,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -1005,21 +1047,23 @@ NetworkEngine::sendListen(Sp<Node> n,
socket = previous->getSocket();
} else {
if (previous)
DHT_LOG.e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
if (logger_)
logger_->e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
socket = n->openSocket(std::move(socket_cb));
}
if (not socket) {
DHT_LOG.e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
if (logger_)
logger_->e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
return {};
}
TransId sid(socket);
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
auto has_query = not query.where.empty() or not query.select.empty();
pk.pack(KEY_A); pk.pack_map(4 + has_query);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(hash);
@@ -1035,8 +1079,8 @@ NetworkEngine::sendListen(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1060,7 +1104,7 @@ void
NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1071,8 +1115,8 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -1090,7 +1134,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1107,15 +1151,16 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
if (msg.value_id == Value::INVALID_ID) {
DHT_LOG.d(infohash, "Unknown search or announce!");
if (logger_)
logger_->d(infohash, "Unknown search or announce!");
} else {
if (on_done) {
RequestAnswer answer {};
@@ -1148,7 +1193,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1161,15 +1206,16 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
if (msg.value_id == Value::INVALID_ID) {
DHT_LOG.d(infohash, "Unknown search or announce!");
if (logger_)
logger_->d(infohash, "Unknown search or announce!");
} else {
if (on_done) {
RequestAnswer answer {};
@@ -1193,7 +1239,7 @@ void
NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1205,8 +1251,8 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -1237,8 +1283,8 @@ NetworkEngine::sendError(const SockAddr& addr,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -1252,7 +1298,8 @@ NetworkEngine::maintainRxBuffer(Tid tid)
const auto& now = scheduler.time();
if (msg->second.start + RX_MAX_PACKET_TIME < now
|| msg->second.last_part + RX_TIMEOUT < now) {
DHT_LOG.w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
if (logger_)
logger_->w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
partial_messages.erase(msg);
}
}
+81 -53
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#else
#include <sys/select.h>
#include <fcntl.h>
#endif
@@ -105,18 +106,20 @@ void udpPipe(int fds[2])
}
#endif
UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(l) {
SockAddr bind4;
bind4.setFamily(AF_INET);
bind4.setPort(port);
SockAddr bind6;
bind6.setFamily(AF_INET6);
bind6.setPort(port);
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l) : logger(l)
{
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
@@ -152,8 +155,10 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
if (sendto(s, (const char*)data, size, flags, dest.get(), dest.getLength()) == -1) {
int err = errno;
logger.d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
if (logger)
logger->d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
std::lock_guard<std::mutex> lk(lock);
auto bind4 = std::move(bound4), bind6 = std::move(bound6);
openSockets(bind4, bind6);
return sendTo(dest, data, size, false);
@@ -180,8 +185,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
udpPipe(stopfds);
#endif
int stop_readfd = stopfds[0];
stopfd = stopfds[1];
stopfd = stopfds[1];
s4 = -1;
s6 = -1;
@@ -190,7 +195,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s4 = bindSocket(bind4, bound4);
} catch (const DhtException& e) {
logger.e("Can't bind inet socket: %s", e.what());
if (logger)
logger->e("Can't bind inet socket: %s", e.what());
}
}
@@ -205,7 +211,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s6 = bindSocket(b6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
}
}
}
@@ -213,7 +220,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s6 = bindSocket(bind6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
}
}
}
@@ -224,23 +232,24 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
}
running = true;
rcv_thread = std::thread([this, stop_readfd]() {
int selectFd = std::max({s4, s6, stop_readfd}) + 1;
rcv_thread = std::thread([this, stop_readfd, ls4=s4, ls6=s6]() mutable {
int selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
try {
while (running) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
if(s4 >= 0)
FD_SET(s4, &readfds);
if(s6 >= 0)
FD_SET(s6, &readfds);
if(ls4 >= 0)
FD_SET(ls4, &readfds);
if(ls6 >= 0)
FD_SET(ls6, &readfds);
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
if (rc < 0) {
if (errno != EINTR) {
logger.e("Select error: %s", strerror(errno));
if (logger)
logger->e("Select error: %s", strerror(errno));
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
@@ -255,66 +264,84 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
if (FD_ISSET(stop_readfd, &readfds)) {
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
logger.e("Got stop packet error: %s", strerror(errno));
if (logger)
logger->e("Got stop packet error: %s", strerror(errno));
break;
}
}
else if (s4 >= 0 && FD_ISSET(s4, &readfds))
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (s6 >= 0 && FD_ISSET(s6, &readfds))
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (ls4 >= 0 && FD_ISSET(ls4, &readfds))
rc = recvfrom(ls4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (ls6 >= 0 && FD_ISSET(ls6, &readfds))
rc = recvfrom(ls6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else
continue;
if (rc > 0) {
auto pkt = std::unique_ptr<ReceivedPacket>(new ReceivedPacket);
pkt->data = {buf.begin(), buf.begin()+rc};
pkt->from = {from, from_len};
pkt->received = clock::now();
onReceived(std::move(pkt));
auto pkts = getNewPacket();
auto& pkt = pkts.front();
pkt.data.insert(pkt.data.end(), buf.begin(), buf.begin()+rc);
pkt.from = {from, from_len};
pkt.received = clock::now();
onReceived(std::move(pkts));
} else if (rc == -1) {
logger.e("Error receiving packet: %s", strerror(errno));
if (logger)
logger->e("Error receiving packet: %s", strerror(errno));
int err = errno;
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
if (s4 >= 0) {
close(s4);
try {
s4 = bindSocket(bound4, bound4);
} catch (const DhtException& e) {
logger.e("Can't bind inet socket: %s", e.what());
if (not running) break;
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
if (lk.owns_lock()) {
if (not running) break;
if (ls4 >= 0) {
close(ls4);
try {
ls4 = bindSocket(bound4, bound4);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet socket: %s", e.what());
}
}
}
if (s6 >= 0) {
close(s6);
try {
s6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
if (ls6 >= 0) {
close(ls6);
try {
ls6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
}
}
}
if (s4 < 0 && s6 < 0)
if (ls4 < 0 && ls6 < 0)
break;
s4 = ls4;
s6 = ls6;
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
} else {
break;
selectFd = std::max({s4, s6, stop_readfd}) + 1;
}
}
}
}
}
} catch (const std::exception& e) {
logger.e("Error in UdpSocket rx thread: %s", e.what());
if (logger)
logger->e("Error in UdpSocket rx thread: %s", e.what());
}
if (s4 >= 0)
close(s4);
if (s6 >= 0)
close(s6);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
if (ls4 >= 0)
close(ls4);
if (ls6 >= 0)
close(ls6);
if (stop_readfd != -1)
close(stop_readfd);
if (stopfd != -1)
close(stopfd);
stopfd = -1;
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
if (lk.owns_lock()) {
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
stopfd = -1;
}
});
}
@@ -324,7 +351,8 @@ UdpSocket::stop()
if (running.exchange(false)) {
auto sfd = stopfd;
if (sfd != -1 && write(sfd, "\0", 1) == -1) {
logger.e("Can't write to stop fd");
if (logger)
logger->e("Can't write to stop fd");
}
}
}
+3 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -30,17 +30,15 @@ constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME;
constexpr std::chrono::minutes Node::NODE_GOOD_TIME;
constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME;
Node::Node(const InfoHash& id, const SockAddr& addr, bool client)
Node::Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client)
: id(id), addr(addr), is_client(client), sockets_()
{
thread_local crypto::random_device rd {};
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
}
Node::Node(const InfoHash& id, SockAddr&& addr, bool client)
Node::Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client)
: id(id), addr(std::move(addr)), is_client(client), sockets_()
{
thread_local crypto::random_device rd {};
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
}
+8 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -37,8 +37,8 @@ NodeCache::getNode(const InfoHash& id, sa_family_t family) {
Sp<Node>
NodeCache::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client) {
if (not id)
return std::make_shared<Node>(id, addr);
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client);
return std::make_shared<Node>(id, addr, rd, client);
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client, rd);
}
std::vector<Sp<Node>>
@@ -104,13 +104,13 @@ NodeCache::NodeMap::getNode(const InfoHash& id)
}
Sp<Node>
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client)
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client, std::mt19937_64& rd)
{
auto it = emplace(id, std::weak_ptr<Node>{});
auto node = it.first->second.lock();
auto& nref = (*this)[id];
auto node = nref.lock();
if (not node) {
node = std::make_shared<Node>(id, addr, client);
it.first->second = node;
node = std::make_shared<Node>(id, addr, rd, client);
nref = node;
if (cleanup_counter++ == CLEANUP_FREQ) {
cleanup();
cleanup_counter = 0;
+13 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@ namespace dht {
constexpr const std::chrono::seconds OpCache::EXPIRATION;
bool
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
std::vector<Sp<Value>> newValues;
for (const auto& v : vals) {
auto viop = values.emplace(v->id, v);
@@ -31,16 +31,21 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
} else {
viop.first->second.refCount++;
}
viop.first->second.updated = t;
}
return newValues.empty() ? true : callback(newValues, false);
}
bool
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
std::vector<Sp<Value>> expiredValues;
for (const auto& v : vals) {
auto vit = values.find(v->id);
if (vit != values.end()) {
if (vit->second.updated > t)
continue;
vit->second.updated = t;
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
@@ -52,12 +57,16 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
}
bool
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids, const system_clock::time_point& t)
{
std::vector<Sp<Value>> expiredValues;
for (const auto& vid : vids) {
auto vit = values.find(vid);
if (vit != values.end()) {
if (vit->second.updated > t)
continue;
vit->second.updated = t;
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
+8 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@ struct OpCacheValueStorage
{
Sp<Value> data {};
unsigned refCount {1};
system_clock::time_point updated {system_clock::time_point::min()};
OpCacheValueStorage(Sp<Value> val) : data(val) {}
};
@@ -47,16 +48,16 @@ public:
};
}
bool onValue(const std::vector<Sp<Value>>& vals, bool expired) {
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
if (expired)
return onValuesExpired(vals);
return onValuesExpired(vals, t);
else
return onValuesAdded(vals);
return onValuesAdded(vals, t);
}
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Value::Id>& vals);
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
bool onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
bool onValuesExpired(const std::vector<Value::Id>& vals, const system_clock::time_point& t = system_clock::time_point::min());
void onNodeChanged(ListenSyncStatus status) {
switch (status) {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+189 -352
View File
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,328 +22,120 @@
#include "network_utils.h"
#include "utils.h"
#ifdef _WIN32
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#include <cstring>
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#define close(x) closesocket(x)
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#ifndef IPV6_JOIN_GROUP
#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
#include <asio.hpp>
namespace dht {
// Organization-local Scope multicast
constexpr char MULTICAST_ADDRESS_IPV4[12] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[10] = "ff08::101";
constexpr char MULTICAST_ADDRESS_IPV4[] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[] = "ff08::101";
class PeerDiscovery::DomainPeerDiscovery
{
public:
DomainPeerDiscovery(sa_family_t domain, in_port_t port);
DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext = {}, Sp<Logger> logger = {});
~DomainPeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
/**
* Thread Stopper
*/
void stop();
/**
* Remove possible callBack to discovery
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
bool stopPublish(const std::string &type);
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
void connectivityChanged();
/**
* Join the threads
*/
void join() {
if(listening_.joinable()) listening_.join();
if(sending_.joinable()) sending_.join();
}
private:
Sp<Logger> logger_;
//dmtx_ for callbackmap_ and drunning_ (write)
std::mutex dmtx_;
//mtx_ for messages_ and lrunning (listen)
std::mutex mtx_;
std::condition_variable cv_;
bool lrunning_ {false};
bool drunning_ {false};
sa_family_t domain_ {AF_UNSPEC};
int port_;
int sockFd_ {-1};
int stopWriteFd_ {-1};
std::shared_ptr<asio::io_context> ioContext_;
asio::ip::udp::socket sockFd_;
asio::ip::udp::endpoint sockAddrSend_;
SockAddr sockAddrSend_;
//Thread export to be joined
std::thread listening_;
std::thread sending_;
std::array<char, 64 * 1024> receiveBuf_;
asio::ip::udp::endpoint receiveFrom_;
msgpack::sbuffer sbuf_;
std::map<std::string, msgpack::sbuffer> messages_;
std::map<std::string, ServiceDiscoveredCallback> callbackmap_;
bool lrunning_ {false};
bool drunning_ {false};
/**
* Multicast Socket Initialization, accept IPV4, IPV6
*/
static int init(sa_family_t domain);
/**
* Receive messages
*/
std::pair<SockAddr, msgpack::object_handle> recvFrom();
/**
* Listener pack thread loop
*/
void loopListener();
/**
* Listener Parameters Setup
*/
void setupListener();
/**
* Sender Parameters Setup
*/
void setupSender();
/**
* Sender Parameters Setup
*/
void query(const asio::ip::udp::endpoint& peer);
void reloadMessages();
void stopDiscovery();
void stopPublish();
void publish(const asio::ip::udp::endpoint& peer);
void reDiscover();
};
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(sa_family_t domain, in_port_t port)
: domain_(domain), port_(port), sockFd_(init(domain))
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
: logger_(logger)
, ioContext_(ioContext)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
{
joinMulticast(sockFd_, domain);
setupListener();
setupSender();
try {
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()));
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
sockFd_.bind({domain, port});
} catch (const std::exception& e) {
if (logger_)
logger_->e("Can't start peer discovery for %s: %s",
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
}
}
PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
{
stop();
join();
if (sockFd_ != -1)
close(sockFd_);
#ifdef _WIN32
WSACleanup();
#endif
}
int
PeerDiscovery::DomainPeerDiscovery::init(sa_family_t domain)
{
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
throw std::runtime_error(std::string("Can't initialize Winsock2 ") + strerror(errno));
}
#endif
int sockfd = socket(domain, SOCK_DGRAM, 0);
if (sockfd < 0) {
throw std::runtime_error(std::string("Socket Creation Error: ") + strerror(errno));
}
net::setNonblocking(sockfd);
return sockfd;
}
void
PeerDiscovery::DomainPeerDiscovery::setupListener()
{
SockAddr sockAddrListen_;
sockAddrListen_.setFamily(domain_);
sockAddrListen_.setPort(port_);
sockAddrListen_.setAny();
unsigned int opt = 1;
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEADDR failed: " << strerror(errno) << std::endl;
}
#ifdef SO_REUSEPORT
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEPORT failed: " << strerror(errno) << std::endl;
}
#endif
// bind to receive address
if (bind(sockFd_, sockAddrListen_.get(), sockAddrListen_.getLength()) < 0){
throw std::runtime_error(std::string("Error binding socket: ") + strerror(errno));
}
}
void
PeerDiscovery::DomainPeerDiscovery::joinMulticast(int sockfd, sa_family_t family)
{
switch (family)
{
case AF_INET:{
ip_mreq config_ipv4;
//This option can be used to set the interface for sending outbound
//multicast datagrams from the sockets application.
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&config_ipv4.imr_interface, sizeof( struct in_addr )) < 0 ) {
throw std::runtime_error(std::string("Bound Network Interface IPv4 Error: ") + strerror(errno));
}
//The IP_MULTICAST_TTL socket option allows the application to primarily
//limit the lifetime of the packet in the Internet and prevent it from circulating indefinitely
unsigned char ttl4 = 20;
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl4, sizeof( ttl4 )) < 0 ) {
throw std::runtime_error(std::string("TTL Sockopt Error: ") + strerror(errno));
}
// config the listener to be interested in joining in the multicast group
config_ipv4.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS_IPV4);
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&config_ipv4, sizeof(config_ipv4)) < 0){
throw std::runtime_error(std::string(" Member Addition IPv4 Error: ") + strerror(errno));
}
break;
}
case AF_INET6: {
ipv6_mreq config_ipv6;
/* unsigned int outif = 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof(outif)) < 0) {
std::cerr << "Can't assign multicast interface: " << strerror(errno) << std::endl;
} */
unsigned int ttl6 = 20;
if( setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl6, sizeof( ttl6 )) < 0 ) {
throw std::runtime_error(std::string("Hop Count Set Error: ") + strerror(errno));
}
config_ipv6.ipv6mr_interface = 0;
inet_pton(AF_INET6, MULTICAST_ADDRESS_IPV6, &config_ipv6.ipv6mr_multiaddr);
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&config_ipv6, sizeof(config_ipv6)) < 0){
throw std::runtime_error(std::string("Member Addition IPv6 Error: ") + strerror(errno));
}
break;
}
}
sockFd_.close();
}
void
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
std::unique_lock<std::mutex> lck(dmtx_);
std::lock_guard<std::mutex> lck(dmtx_);
callbackmap_[type] = callback;
if (not drunning_) {
if (listening_.joinable())
listening_.join();
drunning_ = true;
listening_ = std::thread(&DomainPeerDiscovery::loopListener, this);
ioContext_->post([this] () {
loopListener();
query(sockAddrSend_);
});
}
}
std::pair<SockAddr, msgpack::object_handle>
PeerDiscovery::DomainPeerDiscovery::recvFrom()
{
sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
std::array<uint8_t, 64 * 1024> buf;
ssize_t nbytes = recvfrom(
sockFd_,
(char*)buf.data(), buf.size(),
0,
(sockaddr*)&sa, &sa_len
);
if (nbytes < 0)
throw std::runtime_error(std::string("Error receiving packet: ") + strerror(errno));
return { SockAddr { sa, sa_len }, msgpack::unpack(reinterpret_cast<char*>(buf.data()), nbytes) };
}
void
PeerDiscovery::DomainPeerDiscovery::loopListener()
{
int stopfds_pipe[2];
#ifndef _WIN32
if (pipe(stopfds_pipe) == -1)
throw std::runtime_error(std::string("Can't open pipe: ") + strerror(errno));
#else
net::udpPipe(stopfds_pipe);
#endif
int stop_readfd = stopfds_pipe[0];
stopWriteFd_ = stopfds_pipe[1];
while (true) {
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
return;
sockFd_.async_receive_from(asio::buffer(receiveBuf_), receiveFrom_, [this](const asio::error_code& error, size_t bytes) {
if (error == asio::error::operation_aborted)
return;
if (error) {
if (logger_)
logger_->e("Error receiving message: %s", error.message().c_str());
}
try {
auto rcv = msgpack::unpack(receiveBuf_.data(), bytes);
msgpack::object obj = rcv.get();
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
FD_SET(sockFd_, &readfds);
int data_coming = select(std::max(sockFd_, stop_readfd) + 1, &readfds, nullptr, nullptr, nullptr);
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
}
if (data_coming < 0) {
if(errno != EINTR) {
perror("Select Error");
std::this_thread::sleep_for( std::chrono::seconds(1) );
}
} else if (data_coming > 0) {
if (FD_ISSET(stop_readfd, &readfds)) {
std::array<uint8_t, 64 * 1024> buf;
recv(stop_readfd, (char*)buf.data(), buf.size(), 0);
}
try {
auto rcv = recvFrom();
msgpack::object obj = rcv.second.get();
if (obj.type != msgpack::type::MAP)
continue;
if (obj.type == msgpack::type::STR) {
if (lrunning_ and obj.as<std::string>() == "q")
publish(receiveFrom_);
} else if (obj.type == msgpack::type::MAP) {
for (unsigned i = 0; i < obj.via.map.size; i++) {
auto& o = obj.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
@@ -351,72 +144,82 @@ PeerDiscovery::DomainPeerDiscovery::loopListener()
ServiceDiscoveredCallback cb;
{
std::lock_guard<std::mutex> lck(dmtx_);
auto callback = callbackmap_.find(key);
if (callback != callbackmap_.end())
cb = callback->second;
if (drunning_) {
auto callback = callbackmap_.find(key);
if (callback != callbackmap_.end())
cb = callback->second;
} else
return;
}
if (cb)
cb(std::move(o.val), std::move(rcv.first));
cb(std::move(o.val), SockAddr{ receiveFrom_.data(), (socklen_t)receiveFrom_.size() });
}
} catch (const std::exception& e) {
std::cerr << "Error receiving packet: " << e.what() << std::endl;
} else {
throw msgpack::type_error{};
}
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error receiving packet: %s", e.what());
}
}
if (stop_readfd != -1)
close(stop_readfd);
if (stopWriteFd_ != -1) {
close(stopWriteFd_);
stopWriteFd_ = -1;
}
loopListener();
});
}
void
PeerDiscovery::DomainPeerDiscovery::setupSender()
PeerDiscovery::DomainPeerDiscovery::query(const asio::ip::udp::endpoint& peer)
{
// Setup sender address
sockAddrSend_.setFamily(domain_);
sockAddrSend_.setAddress(domain_ == AF_INET ? MULTICAST_ADDRESS_IPV4 : MULTICAST_ADDRESS_IPV6);
sockAddrSend_.setPort(port_);
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
return;
msgpack::sbuffer pbuf_request;
msgpack::pack(pbuf_request, "q");
sockFd_.async_send_to(asio::buffer(pbuf_request.data(), pbuf_request.size()), peer,
[logger=logger_, peer] (const asio::error_code& ec, size_t)
{
if (ec and (ec != asio::error::operation_aborted) and logger)
logger->w("Error sending packet to: %s with err: %s",
peer.address().to_string().c_str(),
ec.message().c_str());
}
);
}
void
PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
{
std::lock_guard<std::mutex> lck(mtx_);
if (not lrunning_)
return;
sockFd_.async_send_to(asio::buffer(sbuf_.data(), sbuf_.size()), peer,
[logger=logger_, peer] (const asio::error_code& ec, size_t)
{
if (ec and (ec != asio::error::operation_aborted) and logger)
logger->w("Error sending packet to: %s with err: %s",
peer.address().to_string().c_str(),
ec.message().c_str());
}
);
}
void
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
{
//Set up New Sending pack
msgpack::sbuffer pack_buf_c;
pack_buf_c.write(pack_buf.data(),pack_buf.size());
std::unique_lock<std::mutex> lck(mtx_);
std::lock_guard<std::mutex> lck(mtx_);
messages_[type] = std::move(pack_buf_c);
reloadMessages();
if (not lrunning_) {
if (sending_.joinable())
sending_.join();
lrunning_ = true;
sending_ = std::thread([this](){
std::unique_lock<std::mutex> lck(mtx_);
while (lrunning_) {
ssize_t nbytes = sendto(
sockFd_,
sbuf_.data(),
sbuf_.size(),
0,
sockAddrSend_.get(),
sockAddrSend_.getLength()
);
if (nbytes < 0) {
std::cerr << "Error sending packet: " << strerror(errno) << std::endl;
}
if (cv_.wait_for(lck,std::chrono::seconds(3),[&]{ return !lrunning_; }))
break;
}
});
}
lrunning_ = true;
ioContext_->post([this] () { publish(sockAddrSend_); });
}
bool
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
{
std::lock_guard<std::mutex> lck(dmtx_);
if (callbackmap_.erase(type) > 0) {
@@ -428,7 +231,7 @@ PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
}
bool
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
{
std::lock_guard<std::mutex> lck(mtx_);
if (messages_.erase(type) > 0) {
@@ -444,40 +247,24 @@ PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
void
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
{
#ifdef _WIN32
#define write(s, b, f) send((s), (b), (f), 0)
#endif
if (drunning_) {
drunning_ = false;
if (stopWriteFd_ != -1) {
if (write(stopWriteFd_, "\0", 1) == -1) {
std::cerr << "Can't send stop message: " << strerror(errno) << std::endl;
}
}
}
#ifdef _WIN32
#undef write
#endif
drunning_ = false;
}
void
PeerDiscovery::DomainPeerDiscovery::stopPublish()
{
if (lrunning_) {
lrunning_ = false;
cv_.notify_all();
}
lrunning_ = false;
}
void
PeerDiscovery::DomainPeerDiscovery::stop()
{
{
std::unique_lock<std::mutex> lck(dmtx_);
std::lock_guard<std::mutex> lck(dmtx_);
stopDiscovery();
}
{
std::unique_lock<std::mutex> lck(mtx_);
std::lock_guard<std::mutex> lck(mtx_);
stopPublish();
}
}
@@ -494,38 +281,85 @@ PeerDiscovery::DomainPeerDiscovery::reloadMessages()
}
}
PeerDiscovery::PeerDiscovery(in_port_t port)
void
PeerDiscovery::DomainPeerDiscovery::reDiscover()
{
asio::error_code ec;
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()), ec);
if (ec and logger_)
logger_->w("can't multicast on %s: %s",
sockAddrSend_.address().to_string().c_str(),
ec.message().c_str());
query(sockAddrSend_);
}
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
reDiscover();
publish(sockAddrSend_);
}
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
{
if (not ioContext) {
ioContext = std::make_shared<asio::io_context>();
ioContext_ = ioContext;
ioRunnner_ = std::thread([logger, ioContext] {
try {
if (logger)
logger->d("[peerdiscovery] starting io_context");
auto work = asio::make_work_guard(*ioContext);
ioContext->run();
if (logger)
logger->d("[peerdiscovery] io_context stopped");
}
catch (const std::exception& ex){
if (logger)
logger->e("[peerdiscovery] run error: %s", ex.what());
}
});
}
try {
peerDiscovery4_.reset(new DomainPeerDiscovery(AF_INET, port));
peerDiscovery4_.reset(new DomainPeerDiscovery(asio::ip::udp::v4(), port, ioContext, logger));
} catch(const std::exception& e){
std::cerr << "Can't start peer discovery (IPv4): " << e.what() << std::endl;
if (logger)
logger->e("[peerdiscovery] can't start IPv4: %s", e.what());
}
try {
peerDiscovery6_.reset(new DomainPeerDiscovery(AF_INET6, port));
peerDiscovery6_.reset(new DomainPeerDiscovery(asio::ip::udp::v6(), port, ioContext, logger));
} catch(const std::exception& e) {
std::cerr << "Can't start peer discovery (IPv6): " << e.what() << std::endl;
if (logger)
logger->e("[peerdiscovery] can't start IPv6: %s", e.what());
}
}
PeerDiscovery::~PeerDiscovery(){}
void
PeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
if(peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if(peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
PeerDiscovery::~PeerDiscovery() {
stop();
if (ioContext_)
ioContext_->stop();
if (ioRunnner_.joinable())
ioRunnner_.join();
}
void
PeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
PeerDiscovery::startDiscovery(const std::string& type, ServiceDiscoveredCallback callback)
{
if(peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if(peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
if (peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if (peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf)
PeerDiscovery::startPublish(const std::string& type, const msgpack::sbuffer& pack_buf)
{
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string& type, const msgpack::sbuffer& pack_buf)
{
if (domain == AF_INET) {
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
@@ -537,8 +371,8 @@ PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const m
void
PeerDiscovery::stop()
{
if(peerDiscovery4_) peerDiscovery4_->stop();
if(peerDiscovery6_) peerDiscovery6_->stop();
if (peerDiscovery4_) peerDiscovery4_->stop();
if (peerDiscovery6_) peerDiscovery6_->stop();
}
bool
@@ -558,7 +392,7 @@ PeerDiscovery::stopPublish(const std::string &type)
}
bool
PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
{
if (domain == AF_INET) {
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
@@ -569,9 +403,12 @@ PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
}
void
PeerDiscovery::join() {
if(peerDiscovery4_) peerDiscovery4_->join();
if(peerDiscovery6_) peerDiscovery6_->join();
PeerDiscovery::connectivityChanged()
{
if (peerDiscovery4_)
peerDiscovery4_->connectivityChanged();
if (peerDiscovery6_)
peerDiscovery6_->connectivityChanged();
}
}
} /* namespace dht */
+16 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -29,6 +29,8 @@ namespace net {
class NetworkEngine;
struct ParsedMessage;
extern std::atomic<size_t> REQ_COUNT;
/*!
* @class Request
* @brief An atomic request destined to a node.
@@ -67,14 +69,22 @@ struct Request {
}
}
Request(State state = State::PENDING) : state_(state) {}
Request(State state = State::PENDING) : state_(state) {
REQ_COUNT++;
}
Request(MessageType type, Tid tid,
Sp<Node> node,
Blob&& msg,
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<void(const Request&, bool)> on_expired,
Tid socket = 0) :
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) { }
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) {
REQ_COUNT++;
}
~Request() {
REQ_COUNT--;
}
Tid getTid() const { return tid; }
MessageType getType() const { return type; }
@@ -108,13 +118,13 @@ private:
static const constexpr size_t MAX_ATTEMPT_COUNT {3};
bool isExpired(time_point now) const {
return pending() and now > last_try + Node::MAX_RESPONSE_TIME and attempt_count >= Request::MAX_ATTEMPT_COUNT;
return pending() and now > last_try + attempt_duration and attempt_count >= Request::MAX_ATTEMPT_COUNT;
}
void clear() {
on_done = {};
on_expired = {};
msg.clear();
msg = {};
}
const Tid tid {0}; /* the request id. */
@@ -122,6 +132,7 @@ private:
State state_ {State::PENDING};
unsigned attempt_count {0}; /* number of attempt to process the request. */
duration attempt_duration {((duration)Node::MAX_RESPONSE_TIME)/2};
time_point start {time_point::min()}; /* time when the request is created. */
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@ namespace dht {
namespace crypto {
random_device::random_device() :
gen(std::chrono::system_clock::now().time_since_epoch().count())
gen(std::chrono::system_clock::now().time_since_epoch().count() ^ std::chrono::high_resolution_clock::now().count())
{}
random_device::result_type
+9 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,15 +25,8 @@
namespace dht {
static std::mt19937 rd{ dht::crypto::random_device{}() };
#ifdef _WIN32
static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
Sp<Node>
Bucket::randomNode()
Bucket::randomNode(std::mt19937_64& rd)
{
if (nodes.empty())
return nullptr;
@@ -65,7 +58,7 @@ void Bucket::sendCachedPing(net::NetworkEngine& ne)
}
InfoHash
RoutingTable::randomId(const RoutingTable::const_iterator& it) const
RoutingTable::randomId(const RoutingTable::const_iterator& it, std::mt19937_64& rd) const
{
int bit1 = it->first.lowbit();
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
@@ -74,6 +67,12 @@ RoutingTable::randomId(const RoutingTable::const_iterator& it) const
if (bit >= 8*(int)HASH_LEN)
return it->first;
#ifdef _WIN32
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
std::uniform_int_distribution<uint8_t> rand_byte;
#endif
int b = bit/8;
InfoHash id_return;
std::copy_n(it->first.cbegin(), b, id_return.begin());
+70 -57
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -67,9 +67,8 @@ struct Dht::SearchNode {
Sp<net::Request> req {};
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
CachedListenStatus(CachedListenStatus&&) = default;
CachedListenStatus(CachedListenStatus&&) = delete;
CachedListenStatus(const CachedListenStatus&) = delete;
CachedListenStatus& operator=(const CachedListenStatus&) = delete;
};
using NodeListenerStatus = std::map<Sp<Query>, CachedListenStatus>;
@@ -86,15 +85,15 @@ struct Dht::SearchNode {
Blob token {}; /* last token the node sent to us after a get request */
time_point last_get_reply {time_point::min()}; /* last time received valid token */
Sp<Scheduler::Job> syncJob {};
bool candidate {false}; /* A search node is candidate if the search is/was synced and this
node is a new candidate for inclusion. */
Sp<Scheduler::Job> syncJob {};
SearchNode() : node() {}
SearchNode(const SearchNode&) = delete;
SearchNode(SearchNode&&) = default;
SearchNode(SearchNode&&) = delete;
SearchNode& operator=(const SearchNode&) = delete;
SearchNode& operator=(SearchNode&&) = default;
SearchNode& operator=(SearchNode&&) = delete;
SearchNode(const Sp<Node>& node) : node(node) {}
~SearchNode() {
@@ -263,7 +262,7 @@ struct Dht::SearchNode {
* @return true if there exists an expired request, else false.
*/
static bool pending(const SyncStatus& status) {
return std::find_if(status.begin(), status.end(),
return std::find_if(status.cbegin(), status.cend(),
[](const SyncStatus::value_type& r){
return r.second and r.second->pending();
}) != status.end();
@@ -293,26 +292,26 @@ struct Dht::SearchNode {
acked.clear();
}
bool isListening(time_point now) const {
inline bool isListening(time_point now, duration listen_expire) const {
auto ls = listenStatus.begin();
for ( ; ls != listenStatus.end() ; ++ls) {
if (isListening(now, ls)) {
if (isListening(now, ls, listen_expire)) {
break;
}
}
return ls != listenStatus.end();
}
bool isListening(time_point now, const Sp<Query>& q) const {
inline bool isListening(time_point now, const Sp<Query>& q, duration listen_expire) const {
const auto& ls = listenStatus.find(q);
if (ls == listenStatus.end())
return false;
else
return isListening(now, ls);
return isListening(now, ls, listen_expire);
}
bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status) const {
inline bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status, duration listen_expire) const {
if (listen_status == listenStatus.end() or not listen_status->second.req)
return false;
return listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME > now;
return listen_status->second.req->reply_time + listen_expire > now;
}
void cancelListen() {
for (const auto& status : listenStatus)
@@ -345,12 +344,12 @@ struct Dht::SearchNode {
* Assuming the node is synced, should the "listen" request with Query q be
* sent to this node now ?
*/
time_point getListenTime(const Sp<Query>& q) const {
time_point getListenTime(const Sp<Query>& q, duration listen_expire) const {
auto listen_status = listenStatus.find(q);
if (listen_status == listenStatus.end() or not listen_status->second.req)
return time_point::min();
return listen_status->second.req->pending() ? time_point::max() :
listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME - REANNOUNCE_MARGIN;
listen_status->second.req->reply_time + listen_expire - REANNOUNCE_MARGIN;
}
/**
@@ -376,7 +375,7 @@ struct Dht::Search {
bool expired {false}; /* no node, or all nodes expired */
bool done {false}; /* search is over, cached for later */
std::vector<SearchNode> nodes {};
std::vector<std::unique_ptr<SearchNode>> nodes {};
/* pending puts */
std::vector<Announce> announce {};
@@ -416,17 +415,17 @@ struct Dht::Search {
bool insertNode(const Sp<Node>& n, time_point now, const Blob& token={});
SearchNode* getNode(const Sp<Node>& n) {
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](SearchNode& sn) {
return n == sn.node;
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](std::unique_ptr<SearchNode>& sn) {
return n == sn->node;
});
return (srn == nodes.end()) ? nullptr : &(*srn);
return (srn == nodes.end()) ? nullptr : (*srn).get();
}
/* number of concurrent sync requests */
unsigned currentlySolicitedNodeCount() const {
unsigned count = 0;
for (const auto& n : nodes)
if (not n.isBad() and n.pendingGet())
if (not n->isBad() and n->pendingGet())
count++;
return count;
}
@@ -460,12 +459,12 @@ struct Dht::Search {
*/
void setDone(const Get& get) {
for (auto& n : nodes) {
auto pqs = n.pagination_queries.find(get.query);
if (pqs != n.pagination_queries.cend()) {
auto pqs = n->pagination_queries.find(get.query);
if (pqs != n->pagination_queries.cend()) {
for (auto& pq : pqs->second)
n.getStatus.erase(pq);
n->getStatus.erase(pq);
}
n.getStatus.erase(get.query);
n->getStatus.erase(get.query);
}
if (get.done_cb)
get.done_cb(true, getNodes());
@@ -478,15 +477,15 @@ struct Dht::Search {
*/
void setDone() {
for (auto& n : nodes) {
n.getStatus.clear();
n.listenStatus.clear();
n.acked.clear();
n->getStatus.clear();
n->listenStatus.clear();
n->acked.clear();
}
done = true;
}
bool isAnnounced(Value::Id id) const;
bool isListening(time_point now) const;
bool isListening(time_point now, duration exp) const;
void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
if (gcb or qcb) {
@@ -522,9 +521,9 @@ struct Dht::Search {
}
for (auto& sn : nodes) {
if (listeners.empty())
sn.cancelListen();
sn->cancelListen();
else if (query)
sn.cancelListen(query);
sn->cancelListen(query);
}
});
scheduler.edit(opExpirationJob, nextExpire);
@@ -558,6 +557,14 @@ struct Dht::Search {
else
++it;
}
for (auto& n : nodes) {
auto ackIt = n->acked.find(vid);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
n->acked.erase(ackIt);
}
}
return canceled;
}
@@ -565,14 +572,14 @@ struct Dht::Search {
* @return The number of non-good search nodes.
*/
unsigned getNumberOfBadNodes() const {
return std::count_if(nodes.begin(), nodes.end(), [](const SearchNode& sn) {
return sn.isBad();
return std::count_if(nodes.begin(), nodes.end(), [](const std::unique_ptr<SearchNode>& sn) {
return sn->isBad();
});
}
unsigned getNumberOfConsecutiveBadNodes() const {
unsigned count = 0;
std::find_if(nodes.begin(), nodes.end(), [&count](const SearchNode& sn) {
if (not sn.isBad())
std::find_if(nodes.begin(), nodes.end(), [&count](const std::unique_ptr<SearchNode>& sn) {
if (not sn->isBad())
return true;
++count;
return false;
@@ -591,7 +598,7 @@ struct Dht::Search {
*/
bool removeExpiredNode(const time_point& now) {
for (auto e = nodes.cend(); e != nodes.cbegin();) {
const Node& n = *(--e)->node;
const Node& n = *(*(--e))->node;
if (n.isRemovable(now)) {
//std::cout << "Removing expired node " << n.id << " from IPv" << (af==AF_INET?'4':'6') << " search " << id << std::endl;
nodes.erase(e);
@@ -663,8 +670,14 @@ struct Dht::Search {
});
// remove acked for cleared annouces
for (auto it = announced; it != announce.end(); ++it) {
for (auto& n : nodes)
n.acked.erase(it->value->id);
for (auto& n : nodes) {
auto ackIt = n->acked.find(it->value->id);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
n->acked.erase(ackIt);
}
}
}
announce.erase(announced, announce.end());
}
@@ -697,13 +710,13 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
auto n = nodes.end();
while (n != nodes.begin()) {
--n;
if (n->node == snode) {
if ((*n)->node == snode) {
found = true;
break;
}
/* Node not found. We could insert it after this one. */
if (id.xorCmp(nid, n->node->id) > 0) {
if (id.xorCmp(nid, (*n)->node->id) > 0) {
++n;
break;
}
@@ -727,7 +740,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
full = nodes.size() - bad >= SEARCH_NODES;
while (std::distance(nodes.cbegin(), t) - bad > SEARCH_NODES) {
--t;
if (t->isBad())
if ((*t)->isBad())
bad--;
}
}
@@ -743,7 +756,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
if (nodes.empty()) {
step_time = time_point::min();
}
n = nodes.insert(n, SearchNode(snode));
n = nodes.emplace(n, std::make_unique<SearchNode>(snode));
node.setTime(now);
new_search_node = true;
if (node.isExpired()) {
@@ -755,16 +768,16 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
}
while (nodes.size() - bad > SEARCH_NODES) {
if (not expired and nodes.back().isBad())
if (not expired and nodes.back()->isBad())
bad--;
nodes.pop_back();
}
}
if (not token.empty()) {
n->candidate = false;
n->last_get_reply = now;
(*n)->candidate = false;
(*n)->last_get_reply = now;
if (token.size() <= 64)
n->token = token;
(*n)->token = token;
expired = false;
}
if (new_search_node)
@@ -778,7 +791,7 @@ Dht::Search::getNodes() const
std::vector<Sp<Node>> ret {};
ret.reserve(nodes.size());
for (const auto& sn : nodes)
ret.emplace_back(sn.node);
ret.emplace_back(sn->node);
return ret;
}
@@ -787,9 +800,9 @@ Dht::Search::isSynced(time_point now) const
{
unsigned i = 0;
for (const auto& n : nodes) {
if (n.isBad())
if (n->isBad())
continue;
if (not n.isSynced(now))
if (not n->isSynced(now))
return false;
if (++i == TARGET_NODES)
break;
@@ -820,9 +833,9 @@ Dht::Search::isDone(const Get& get) const
{
unsigned i = 0;
for (const auto& sn : nodes) {
if (sn.isBad())
if (sn->isBad())
continue;
if (not sn.isDone(get))
if (not sn->isDone(get))
return false;
if (++i == TARGET_NODES)
break;
@@ -837,9 +850,9 @@ Dht::Search::isAnnounced(Value::Id id) const
return false;
unsigned i = 0;
for (const auto& n : nodes) {
if (n.isBad())
if (n->isBad())
continue;
if (not n.isAnnounced(id))
if (not n->isAnnounced(id))
return false;
if (++i == TARGET_NODES)
return true;
@@ -848,20 +861,20 @@ Dht::Search::isAnnounced(Value::Id id) const
}
bool
Dht::Search::isListening(time_point now) const
Dht::Search::isListening(time_point now, duration listen_expire) const
{
if (nodes.empty() or listeners.empty())
return false;
unsigned i = 0;
for (const auto& n : nodes) {
if (n.isBad())
if (n->isBad())
continue;
SearchNode::NodeListenerStatus::const_iterator ls {};
for (ls = n.listenStatus.begin(); ls != n.listenStatus.end() ; ++ls) {
if (n.isListening(now, ls))
for (ls = n->listenStatus.begin(); ls != n->listenStatus.end() ; ++ls) {
if (n->isListening(now, ls, listen_expire))
break;
}
if (ls == n.listenStatus.end())
if (ls == n->listenStatus.end())
return false;
if (++i == LISTEN_NODES)
break;
+57 -26
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -17,6 +17,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "securedht.h"
#include "rng.h"
@@ -34,7 +37,7 @@ extern "C" {
namespace dht {
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second)
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
{
if (!dht_) return;
for (const auto& type : DEFAULT_TYPES)
@@ -46,7 +49,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
registerInsecureType(CERTIFICATE_TYPE);
if (certificate_) {
auto certId = certificate_->getPublicKey().getId();
auto certId = certificate_->getId();
if (key_ and certId != key_->getPublicKey().getId())
throw DhtException("SecureDht: provided certificate doesn't match private key.");
@@ -56,7 +59,8 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
1
}, [this, certId](bool ok) {
if (ok)
DHT_LOG.d(certId, "SecureDht: public key announced successfully");
if (logger_)
logger_->d(certId, "SecureDht: public key announced successfully");
}, {}, true);
}
}
@@ -73,7 +77,8 @@ SecureDht::secureType(ValueType&& type)
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
}
if (!v->signatureValid) {
DHT_LOG.w("Signature verification failed");
if (logger_)
logger_->w("Signature verification failed");
return false;
}
}
@@ -83,7 +88,8 @@ SecureDht::secureType(ValueType&& type)
if (!o->isSigned())
return type.editPolicy(id, o, n, nid, a);
if (o->owner != n->owner) {
DHT_LOG.w("Edition forbidden: owner changed.");
if (logger_)
logger_->w("Edition forbidden: owner changed.");
return false;
}
if (!n->signatureChecked) {
@@ -91,14 +97,16 @@ SecureDht::secureType(ValueType&& type)
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
}
if (!n->signatureValid) {
DHT_LOG.w("Edition forbidden: signature verification failed.");
if (logger_)
logger_->w("Edition forbidden: signature verification failed.");
return false;
}
if (o->seq == n->seq) {
// If the data is exactly the same,
// it can be reannounced, possibly by someone else.
if (o->getToSign() != n->getToSign()) {
DHT_LOG.w("Edition forbidden: sequence number must be increasing.");
if (logger_)
logger_->w("Edition forbidden: sequence number must be increasing.");
return false;
}
}
@@ -144,7 +152,8 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
}
InfoHash h = crt->getPublicKey().getId();
if (node == h) {
DHT_LOG.d("Registering certificate for %s", h.toString().c_str());
if (logger_)
logger_->d("Registering certificate for %s", h.toString().c_str());
auto it = nodesCertificates_.find(h);
if (it == nodesCertificates_.end())
std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
@@ -152,7 +161,8 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
it->second = std::move(crt);
return it->second;
} else {
DHT_LOG.w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
if (logger_)
logger_->w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
return nullptr;
}
}
@@ -169,7 +179,8 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
{
Sp<crypto::Certificate> b = getCertificate(node);
if (b && *b) {
DHT_LOG.d("Using certificate from cache for %s", node.toString().c_str());
if (logger_)
logger_->d("Using certificate from cache for %s", node.to_c_str());
if (cb)
cb(b);
return;
@@ -177,7 +188,8 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
if (localQueryMethod_) {
auto res = localQueryMethod_(node);
if (not res.empty()) {
DHT_LOG.d("Registering certificate from local store for %s", node.toString().c_str());
if (logger_)
logger_->d("Registering certificate from local store for %s", node.to_c_str());
nodesCertificates_.emplace(node, res.front());
if (cb)
cb(res.front());
@@ -192,7 +204,8 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
DHT_LOG.d("Found certificate for %s", node.toString().c_str());
if (logger_)
logger_->d(node, "Found certificate for %s", node.to_c_str());
if (cb)
cb(cert);
return false;
@@ -210,7 +223,8 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
{
auto pk = getPublicKey(node);
if (pk && *pk) {
DHT_LOG.d("Found public key from cache for %s", node.toString().c_str());
if (logger_)
logger_->d(node, "Found public key from cache for %s", node.to_c_str());
if (cb)
cb(pk);
return;
@@ -254,7 +268,8 @@ SecureDht::checkValue(const Sp<Value>& v)
}
// Ignore values belonging to other people
} catch (const std::exception& e) {
DHT_LOG.w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
if (logger_)
logger_->w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
}
}
// Check signed values
@@ -265,11 +280,12 @@ SecureDht::checkValue(const Sp<Value>& v)
v->signatureChecked = true;
if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
v->signatureValid = true;
nodesPubKeys_[v->owner->getId()] = v->owner;
if (enableCache_)
nodesPubKeys_[v->owner->getId()] = v->owner;
return v;
}
else
DHT_LOG.w("Signature verification failed for %s", v->toString().c_str());
else if (logger_)
logger_->w("Signature verification failed for %s", v->toString().c_str());
}
// Forward normal values
else {
@@ -337,6 +353,11 @@ SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
void
SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
if (val->id == Value::INVALID_ID) {
crypto::random_device rdev;
std::uniform_int_distribution<Value::Id> rand_id;
@@ -352,13 +373,16 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
// Check if data already exists on the dht
get(hash,
[val,this] (const std::vector<Sp<Value>>& vals) {
DHT_LOG.d("Found online previous value being announced.");
if (logger_)
logger_->d("Found online previous value being announced.");
for (const auto& v : vals) {
if (!v->isSigned())
DHT_LOG.e("Existing non-signed value seems to exists at this location.");
else if (not v->owner or v->owner->getId() != getId())
DHT_LOG.e("Existing signed value belonging to someone else seems to exists at this location.");
else if (val->seq <= v->seq)
if (!v->isSigned()) {
if (logger_)
logger_->e("Existing non-signed value seems to exists at this location.");
} else if (not v->owner or v->owner->getId() != getId()) {
if (logger_)
logger_->e("Existing signed value belonging to someone else seems to exists at this location.");
} else if (val->seq <= v->seq)
val->seq = v->seq + 1;
}
return true;
@@ -375,17 +399,24 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
void
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
DHT_LOG.w("Encrypting data for PK: %s", pk->getId().toString().c_str());
if (logger_)
logger_->w("Encrypting data for PK: %s", pk->getId().toString().c_str());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
DHT_LOG.e("Error putting encrypted data: %s", e.what());
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+35 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -34,6 +34,9 @@
#endif
namespace dht {
namespace net {
std::atomic<size_t> REQ_COUNT {0};
}
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
@@ -236,17 +239,27 @@ bool operator==(const SockAddr& a, const SockAddr& b) {
}
time_point from_time_t(std::time_t t) {
return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now());
auto dt = system_clock::from_time_t(t) - system_clock::now();
auto now = clock::now();
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
return time_point::max();
else if (dt < system_clock::duration(0) and now < time_point::min() - dt)
return time_point::min();
return now + dt;
}
std::time_t to_time_t(time_point t) {
return std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() +
std::chrono::duration_cast<std::chrono::system_clock::duration>(t - clock::now()));
auto dt = t - clock::now();
auto now = system_clock::now();
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
return system_clock::to_time_t(system_clock::time_point::max());
else if (dt < duration(0) and now <= system_clock::time_point::min() - dt)
return system_clock::to_time_t(system_clock::time_point::min());
return system_clock::to_time_t(now + std::chrono::duration_cast<system_clock::duration>(dt));
}
Blob
unpackBlob(msgpack::object& o) {
unpackBlob(const msgpack::object& o) {
switch (o.type) {
case msgpack::type::BIN:
return {o.via.bin.ptr, o.via.bin.ptr+o.via.bin.size};
@@ -270,11 +283,25 @@ unpackMsg(Blob b) {
}
msgpack::object*
findMapValue(msgpack::object& map, const std::string& key) {
findMapValue(const msgpack::object& map, const char* key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if (o.key.type == msgpack::type::STR && o.key.as<std::string>() == key)
if (o.key.type == msgpack::type::STR
&& std::strncmp(o.key.via.str.ptr, key, o.key.via.str.size) == 0)
return &o.val;
}
return nullptr;
}
msgpack::object*
findMapValue(const msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if (o.key.type == msgpack::type::STR
&& key.size() == o.key.via.str.size
&& std::strncmp(o.key.via.str.ptr, key.data(), o.key.via.str.size) == 0)
return &o.val;
}
return nullptr;
+194 -187
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -17,6 +17,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "value.h"
#include "default_types.h"
@@ -41,7 +45,7 @@ Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data) {
std::ostream& operator<< (std::ostream& s, const Value& v)
{
auto flags(s.flags());
s << "Value[id:" << std::hex << v.id << std::dec << " ";
s << "Value[id:" << std::hex << v.id << std::dec << ' ';
if (v.isEncrypted())
s << "encrypted ";
else if (v.isSigned()) {
@@ -63,14 +67,23 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
}
#endif
} else {
s << "Data (type: " << v.type << " ): ";
s << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
if (v.user_type.empty())
s << "data:";
else
s << "data(" << v.user_type << "):";
if (v.user_type == "text/plain") {
s << '"';
s.write((const char*)v.data.data(), v.data.size());
s << '"';
} else {
s << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
}
}
}
s << "]";
s << ']';
s.flags(flags);
return s;
}
@@ -83,20 +96,6 @@ ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const
return v->size() <= MAX_VALUE_SIZE;
}
msgpack::object*
findMapValue(const msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if(o.key.type != msgpack::type::STR)
continue;
if (o.key.as<std::string>() == key) {
return &o.val;
}
}
return nullptr;
}
size_t
Value::size() const
{
@@ -104,20 +103,24 @@ Value::size() const
}
void
Value::msgpack_unpack(msgpack::object o)
Value::msgpack_unpack(const msgpack::object& o)
{
if (o.type != msgpack::type::MAP) throw msgpack::type_error();
if (o.via.map.size < 2) throw msgpack::type_error();
if (o.type != msgpack::type::MAP or o.via.map.size < 2)
throw msgpack::type_error();
if (auto rid = findMapValue(o, "id")) {
if (auto rid = findMapValue(o, VALUE_KEY_ID)) {
id = rid->as<Id>();
} else
throw msgpack::type_error();
if (auto rdat = findMapValue(o, "dat")) {
if (auto rdat = findMapValue(o, VALUE_KEY_DAT)) {
msgpack_unpack_body(*rdat);
} else
throw msgpack::type_error();
if (auto rprio = findMapValue(o, VALUE_KEY_PRIO)) {
priority = rprio->as<unsigned>();
}
}
void
@@ -136,37 +139,37 @@ Value::msgpack_unpack_body(const msgpack::object& o)
} else {
if (o.type != msgpack::type::MAP)
throw msgpack::type_error();
auto rbody = findMapValue(o, "body");
auto rbody = findMapValue(o, VALUE_KEY_BODY);
if (not rbody)
throw msgpack::type_error();
if (auto rdata = findMapValue(*rbody, "data")) {
if (auto rdata = findMapValue(*rbody, VALUE_KEY_DATA)) {
data = unpackBlob(*rdata);
} else
throw msgpack::type_error();
if (auto rtype = findMapValue(*rbody, "type")) {
if (auto rtype = findMapValue(*rbody, VALUE_KEY_TYPE)) {
type = rtype->as<ValueType::Id>();
} else
throw msgpack::type_error();
if (auto rutype = findMapValue(*rbody, "utype")) {
if (auto rutype = findMapValue(*rbody, VALUE_KEY_USERTYPE)) {
user_type = rutype->as<std::string>();
}
if (auto rowner = findMapValue(*rbody, "owner")) {
if (auto rseq = findMapValue(*rbody, "seq"))
if (auto rowner = findMapValue(*rbody, VALUE_KEY_OWNER)) {
if (auto rseq = findMapValue(*rbody, VALUE_KEY_SEQ))
seq = rseq->as<decltype(seq)>();
else
throw msgpack::type_error();
crypto::PublicKey new_owner;
new_owner.msgpack_unpack(*rowner);
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
if (auto rrecipient = findMapValue(*rbody, "to")) {
if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) {
recipient = rrecipient->as<InfoHash>();
}
if (auto rsig = findMapValue(o, "sig")) {
if (auto rsig = findMapValue(o, VALUE_KEY_SIGNATURE)) {
signature = unpackBlob(*rsig);
} else
throw msgpack::type_error();
@@ -175,63 +178,65 @@ Value::msgpack_unpack_body(const msgpack::object& o)
}
#ifdef OPENDHT_JSONCPP
Value::Value(Json::Value& json)
Value::Value(const Json::Value& json)
{
id = Value::Id(unpackId(json, "id"));
if (json.isMember("cypher")) {
auto cypherStr = json["cypher"].asString();
cypherStr = base64_decode(cypherStr);
cypher = std::vector<unsigned char>(cypherStr.begin(), cypherStr.end());
}
if (json.isMember("sig")) {
auto sigStr = json["sig"].asString();
sigStr = base64_decode(sigStr);
signature = std::vector<unsigned char>(sigStr.begin(), sigStr.end());
}
if (json.isMember("seq"))
seq = json["seq"].asInt();
if (json.isMember("owner")) {
auto ownerStr = json["owner"].asString();
id = Value::Id(unpackId(json, VALUE_KEY_ID));
const auto& jcypher = json["cypher"];
if (jcypher.isString())
cypher = base64_decode(jcypher.asString());
const auto& jsig = json[VALUE_KEY_SIGNATURE];
if (jsig.isString())
signature = base64_decode(jsig.asString());
const auto& jseq = json[VALUE_KEY_SEQ];
if (!jseq.isNull())
seq = jseq.asInt();
const auto& jowner = json[VALUE_KEY_OWNER];
if (jowner.isString()) {
auto ownerStr = jowner.asString();
auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end());
owner = std::make_shared<const crypto::PublicKey>(ownerBlob);
}
if (json.isMember("to")) {
auto toStr = json["to"].asString();
recipient = InfoHash(toStr);
}
if (json.isMember("type"))
type = json["type"].asInt();
if (json.isMember("data")){
auto dataStr = json["data"].asString();
dataStr = base64_decode(dataStr);
data = std::vector<unsigned char>(dataStr.begin(), dataStr.end());
}
if (json.isMember("utype"))
user_type = json["utype"].asString();
const auto& jto = json[VALUE_KEY_TO];
if (jto.isString())
recipient = InfoHash(jto.asString());
const auto& jtype = json[VALUE_KEY_TYPE];
if (!jtype.isNull())
type = jtype.asInt();
const auto& jdata = json[VALUE_KEY_DATA];
if (jdata.isString())
data = base64_decode(jdata.asString());
const auto& jutype = json[VALUE_KEY_USERTYPE];
if (jutype.isString())
user_type = jutype.asString();
const auto& jprio = json["prio"];
if (jprio.isIntegral())
priority = jprio.asUInt();
}
Json::Value
Value::toJson() const
{
Json::Value val;
val["id"] = std::to_string(id);
val[VALUE_KEY_ID] = std::to_string(id);
if (isEncrypted()) {
val["cypher"] = base64_encode(cypher);
} else {
if (isSigned())
val["sig"] = base64_encode(signature);
val[VALUE_KEY_SIGNATURE] = base64_encode(signature);
bool has_owner = owner && *owner;
if (has_owner) { // isSigned
val["seq"] = seq;
val["owner"] = owner->toString();
val[VALUE_KEY_SEQ] = seq;
val[VALUE_KEY_OWNER] = owner->toString();
if (recipient)
val["to"] = recipient.toString();
val[VALUE_KEY_TO] = recipient.toString();
}
val["type"] = type;
val["data"] = base64_encode(data);
val[VALUE_KEY_TYPE] = type;
val[VALUE_KEY_DATA] = base64_encode(data);
if (not user_type.empty())
val["utype"] = user_type;
val[VALUE_KEY_USERTYPE] = user_type;
}
if (priority)
val["prio"] = priority;
return val;
}
@@ -239,13 +244,11 @@ uint64_t
unpackId(const Json::Value& json, const std::string& key) {
uint64_t ret = 0;
try {
if (json.isMember(key)) {
const auto& t = json[key];
if (t.isString()) {
ret = std::stoull(t.asString());
} else {
ret = t.asLargestUInt();
}
const auto& t = json[key];
if (t.isString()) {
ret = std::stoull(t.asString());
} else {
ret = t.asLargestUInt();
}
} catch (...) {}
return ret;
@@ -258,18 +261,18 @@ FieldValue::operator==(const FieldValue& vfd) const
if (field != vfd.field)
return false;
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
return intValue == vfd.intValue;
case Value::Field::OwnerPk:
return hashValue == vfd.hashValue;
case Value::Field::UserType:
return blobValue == vfd.blobValue;
case Value::Field::None:
return true;
default:
return false;
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
return intValue == vfd.intValue;
case Value::Field::OwnerPk:
return hashValue == vfd.hashValue;
case Value::Field::UserType:
return blobValue == vfd.blobValue;
case Value::Field::None:
return true;
default:
return false;
}
}
@@ -277,25 +280,25 @@ Value::Filter
FieldValue::getLocalFilter() const
{
switch (field) {
case Value::Field::Id:
return Value::IdFilter(intValue);
case Value::Field::ValueType:
return Value::TypeFilter(intValue);
case Value::Field::OwnerPk:
return Value::OwnerFilter(hashValue);
case Value::Field::SeqNum:
return Value::SeqNumFilter(intValue);
case Value::Field::UserType:
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
default:
return {};
case Value::Field::Id:
return Value::IdFilter(intValue);
case Value::Field::ValueType:
return Value::TypeFilter(intValue);
case Value::Field::OwnerPk:
return Value::OwnerFilter(hashValue);
case Value::Field::SeqNum:
return Value::SeqNumFilter(intValue);
case Value::Field::UserType:
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
default:
return {};
}
}
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
{
auto selection = s.getSelection();
if (not selection.empty()) {
if (not s.empty()) {
auto selection = s.getSelection();
std::transform(selection.begin(), selection.end(), std::inserter(index, index.end()),
[](const std::set<Value::Field>::value_type& f) {
return std::make_pair(f, FieldValue {});
@@ -308,23 +311,23 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
for (const auto& fvp : index) {
const auto& f = fvp.first;
switch (f) {
case Value::Field::Id:
index[f] = {f, v.id};
break;
case Value::Field::ValueType:
index[f] = {f, v.type};
break;
case Value::Field::OwnerPk:
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
break;
case Value::Field::SeqNum:
index[f] = {f, v.seq};
break;
case Value::Field::UserType:
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
break;
default:
break;
case Value::Field::Id:
index[f] = {f, v.id};
break;
case Value::Field::ValueType:
index[f] = {f, v.type};
break;
case Value::Field::OwnerPk:
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
break;
case Value::Field::SeqNum:
index[f] = {f, v.seq};
break;
case Value::Field::UserType:
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
break;
default:
break;
}
}
}
@@ -344,28 +347,28 @@ std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi) {
os << "Index[";
for (auto v = fvi.index.begin(); v != fvi.index.end(); ++v) {
switch (v->first) {
case Value::Field::Id: {
auto flags(os.flags());
os << "Id:" << std::hex << v->second.getInt();
os.flags(flags);
break;
}
case Value::Field::ValueType:
os << "ValueType:" << v->second.getInt();
break;
case Value::Field::OwnerPk:
os << "Owner:" << v->second.getHash().toString();
break;
case Value::Field::SeqNum:
os << "Seq:" << v->second.getInt();
break;
case Value::Field::UserType: {
auto ut = v->second.getBlob();
os << "UserType:" << std::string(ut.begin(), ut.end());
break;
}
default:
break;
case Value::Field::Id: {
auto flags(os.flags());
os << "Id:" << std::hex << v->second.getInt();
os.flags(flags);
break;
}
case Value::Field::ValueType:
os << "ValueType:" << v->second.getInt();
break;
case Value::Field::OwnerPk:
os << "Owner:" << v->second.getHash();
break;
case Value::Field::SeqNum:
os << "Seq:" << v->second.getInt();
break;
case Value::Field::UserType: {
auto ut = v->second.getBlob();
os << "UserType:" << std::string(ut.begin(), ut.end());
break;
}
default:
break;
}
os << (std::next(v) != fvi.index.end() ? "," : "");
}
@@ -381,19 +384,19 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
for (const auto& field : fields) {
auto& field_value = o.via.array.ptr[offset+(j++)];
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
index[field] = FieldValue(field, field_value.as<uint64_t>());
break;
case Value::Field::OwnerPk:
index[field] = FieldValue(field, field_value.as<InfoHash>());
break;
case Value::Field::UserType:
index[field] = FieldValue(field, field_value.as<Blob>());
break;
default:
throw msgpack::type_error();
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
index[field] = FieldValue(field, field_value.as<uint64_t>());
break;
case Value::Field::OwnerPk:
index[field] = FieldValue(field, field_value.as<InfoHash>());
break;
case Value::Field::UserType:
index[field] = FieldValue(field, field_value.as<Blob>());
break;
default:
throw msgpack::type_error();
}
}
}
@@ -415,13 +418,13 @@ Select::Select(const std::string& q_str) {
while (std::getline(fields, token, ',')) {
trim_str(token);
if (token == "id")
if (token == VALUE_KEY_ID)
field(Value::Field::Id);
else if (token == "value_type")
field(Value::Field::ValueType);
else if (token == "owner_pk")
field(Value::Field::OwnerPk);
if (token == "seq")
if (token == VALUE_KEY_SEQ)
field(Value::Field::SeqNum);
else if (token == "user_type")
field(Value::Field::UserType);
@@ -457,13 +460,13 @@ Where::Where(const std::string& q_str) {
s = value_str.substr(1, value_str.size()-2);
else
s = value_str;
if (field_str == "id")
if (field_str == VALUE_KEY_ID)
id(v);
else if (field_str == "value_type")
valueType(v);
else if (field_str == "owner_pk")
owner(InfoHash(s));
else if (field_str == "seq")
else if (field_str == VALUE_KEY_SEQ)
seq(v);
else if (field_str == "user_type")
userType(s);
@@ -519,11 +522,14 @@ bool Query::isSatisfiedBy(const Query& q) const {
}
std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
s << "SELECT " << (select.fieldSelection_.empty() ? "*" : "");
for (auto fs = select.fieldSelection_.begin() ; fs != select.fieldSelection_.end() ; ++fs) {
switch (*fs) {
s << "SELECT ";
if (select.fieldSelection_.empty())
s << '*';
else
for (auto fs = select.fieldSelection_.begin(); fs != select.fieldSelection_.end();) {
switch (*fs) {
case Value::Field::Id:
s << "id";
s << VALUE_KEY_ID;
break;
case Value::Field::ValueType:
s << "value_type";
@@ -535,13 +541,14 @@ std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
s << "owner_public_key";
break;
case Value::Field::SeqNum:
s << "seq";
s << VALUE_KEY_SEQ;
break;
default:
break;
}
if (++fs != select.fieldSelection_.end())
s << ',';
}
s << (std::next(fs) != select.fieldSelection_.end() ? "," : "");
}
return s;
}
@@ -550,25 +557,25 @@ std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
s << "WHERE ";
for (auto f = where.filters_.begin() ; f != where.filters_.end() ; ++f) {
switch (f->getField()) {
case Value::Field::Id:
s << "id=" << f->getInt();
break;
case Value::Field::ValueType:
s << "value_type=" << f->getInt();
break;
case Value::Field::OwnerPk:
s << "owner_pk_hash=" << f->getHash().toString();
break;
case Value::Field::SeqNum:
s << "seq=" << f->getInt();
break;
case Value::Field::UserType: {
auto b = f->getBlob();
s << "user_type=" << std::string {b.begin(), b.end()};
break;
}
default:
break;
case Value::Field::Id:
s << VALUE_KEY_ID << '=' << f->getInt();
break;
case Value::Field::ValueType:
s << "value_type=" << f->getInt();
break;
case Value::Field::OwnerPk:
s << "owner_pk_hash=" << f->getHash();
break;
case Value::Field::SeqNum:
s << VALUE_KEY_SEQ << '=' << f->getInt();
break;
case Value::Field::UserType: {
auto b = f->getBlob();
s << "user_type=" << std::string {b.begin(), b.end()};
break;
}
default:
break;
}
s << (std::next(f) != where.filters_.end() ? "," : "");
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
-1
View File
@@ -1 +0,0 @@
g++ -Wall -Wextra -Wfatal-errors -pedantic -g ../src/http.cpp tests_runner.cpp httptester.cpp -o run.out -lopendht -lpthread -lcppunit -ljsoncpp -DOPENDHT_JSONCPP -I../include/opendht -DASIO_STANDALONE
+33 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -19,7 +19,7 @@
#include "cryptotester.h"
#include "opendht/crypto.h"
#include <opendht/crypto.h>
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTester);
@@ -34,16 +34,41 @@ CryptoTester::testSignatureEncryption() {
auto key = dht::crypto::PrivateKey::generate();
auto public_key = key.getPublicKey();
std::vector<uint8_t> data {5, 10};
std::vector<uint8_t> signature = key.sign(data);
std::vector<uint8_t> data1 {5, 10};
std::vector<uint8_t> data2(64 * 1024, 10);
std::vector<uint8_t> signature1 = key.sign(data1);
std::vector<uint8_t> signature2 = key.sign(data2);
// check signature
CPPUNIT_ASSERT(public_key.checkSignature(data, signature));
CPPUNIT_ASSERT(public_key.checkSignature(data1, signature1));
CPPUNIT_ASSERT(public_key.checkSignature(data2, signature2));
// encrypt data
std::vector<uint8_t> encrypted = public_key.encrypt(data);
std::vector<uint8_t> decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data == decrypted);
{
std::vector<uint8_t> encrypted = public_key.encrypt(data1);
std::vector<uint8_t> decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data1 == decrypted);
}
{
std::vector<uint8_t> encrypted = public_key.encrypt(data2);
std::vector<uint8_t> decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data2 == decrypted);
}
// encrypt data (invalid)
{
std::vector<uint8_t> encrypted = public_key.encrypt(data1);
encrypted[1]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
{
std::vector<uint8_t> encrypted = public_key.encrypt(data2);
encrypted[2]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
}
void
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff. Show more