Compare commits

...
Author SHA1 Message Date
Adrien Béraud 29fe7d5f92 http: add Resolver 2019-07-17 15:22:27 -04:00
Adrien Béraud 459217b6d6 dhtnode: avoid deadlock in shutdown 2019-07-17 14:53:41 -04:00
Adrien Béraud d8aa94c8f5 proxy: cleanup 2019-07-17 14:53:41 -04:00
Seva 8a88ca94db WIP http: transform client into request 2019-07-17 11:53:53 -04:00
Seva a72ddfdb03 dhtnode: fix shutdown deadlock 2019-07-16 15:57:19 -04:00
Seva e7b03e4d53 dhtproxy: unify client destruction & shutdown with stop() 2019-07-16 15:46:13 -04:00
Seva baf43d96ff dhtproxy: encapsulate server expire handlers 2019-07-16 15:12:38 -04:00
Seva 0f9df9a62b dhtproxy: fix server send push notif underflow 2019-07-16 13:04:37 -04:00
Seva 630112601c dhtproxy: fix client connectivity change
add handle resubscribe
          ignore operation aborted signals
2019-07-16 12:48:29 -04:00
Seva b0500af062 dhtproxy: fix client proxy confirmation 2019-07-15 13:47:31 -04:00
Seva 6c985e8fda dhtproxy: fix restart client listeners 2019-07-15 13:42:10 -04:00
Seva 9c1e55279c dhtproxy: fix refresh permanent put timer 2019-07-15 13:29:21 -04:00
Adrien Béraud 593d024f51 proxy client: fix cancelListen, add locks 2019-07-15 11:35:01 -04:00
Seva a6e57d95d6 dhtproxy: fix cancelListen & rm duplicated logging 2019-07-12 15:59:51 -04:00
Seva 846f495202 dhtproxy: fix indirect mem leak in create router 2019-07-11 11:06:36 -04:00
Seva 6f603bfc0a dhtproxy: fix options route 2019-07-11 10:46:33 -04:00
Seva 9c106f9efe http: make connection data unique & fix init warn 2019-07-11 10:26:51 -04:00
Seva ff288fb4a3 autotools: add dhtproxy dependencies checks 2019-07-09 15:28:57 -04:00
Seva 17ff4c0224 http: one line init of conn context 2019-07-09 14:17:17 -04:00
Seva 45a2c6dadb dhtproxy: sanitized by fixing client memory leaks 2019-07-09 12:21:56 -04:00
Seva 477ff59e91 dhtproxy: enhance error handling & msg for push 2019-07-09 10:20:39 -04:00
Seva a001e0cafd dhtproxy: fix client multi-line data in get/listen 2019-07-08 16:47:52 -04:00
Seva ac63527e0b http: split header & body processing
this allow to handle a case when an incomplete body is attached to a
header to forward it to the body processing for full recovery.
2019-07-08 16:46:49 -04:00
Seva 4b3d8d1231 dhtproxy: move operations into async_connect handler 2019-07-06 12:25:14 -04:00
Seva d04a741d5e http: better error handling
use async::connect instead of manually
2019-07-05 18:44:10 -04:00
Seva ac2b7deda8 http: add set_connection_timeout 2019-07-03 17:03:53 -04:00
Seva c8b08b5ed1 dhtproxy: fix client stop by cancelling io_context 2019-07-03 14:30:10 -04:00
Seva f556987e47 http: handle unavailable server 2019-07-03 14:23:49 -04:00
Seva 2daf36c97e Merge branch 'master' into proxy_restinio 2019-07-03 14:07:35 -04:00
Seva 2a2555f0c2 dhtproxy: fix type nomenclature & compile warnings 2019-07-03 12:10:49 -04:00
Seva bdfb0148e4 dhtproxy: use legacy listen route in client 2019-07-03 11:27:51 -04:00
Seva 01be4d2eb8 dhtproxy: enhance new api routes 2019-07-03 11:01:32 -04:00
Seva 93f7251805 http: segment resolving & connection from request
set connection id to unsigned int
      use service string instead of int port
      segment connection from request
      save endpoint associated with a conn
      add Connection is_v6 ip method
      propagate resolve errors
2019-07-03 10:30:33 -04:00
Adrien Béraud a8718242cd net: fix build on MSVC2017 2019-07-02 14:51:28 -04:00
Adrien Béraud 297a23fb1f dhtrunner: run shutdown on op queue 2019-07-02 12:09:31 -04:00
Adrien Béraud 0d641161e8 dhtrunner: fix minor warning 2019-07-01 23:22:00 -04:00
Adrien Béraud 27b3c0d47e dhtrunner: add appropriate lock to setProxyServer 2019-07-01 23:20:03 -04:00
Adrien Béraud 149b33ef57 dht: simplify error message to avoid use-after-move 2019-07-01 15:07:10 -04:00
Adrien Béraud 150e62de0b sockaddr: fix npe if address is not set 2019-07-01 14:08:41 -04:00
Adrien Béraud 89bdfce840 dhtrunner: add proper locks for push notification 2019-07-01 12:10:51 -04:00
Adrien Béraud bce41ecd69 proxy client: fix build with push notifications 2019-07-01 01:12:21 -04:00
Adrien Béraud 4374d206ab op_cache: simplify addListener 2019-07-01 00:34:05 -04:00
Adrien Béraud b64820af59 proxy client: remove unneeded filter
Filters are applied at the SearchCache level
2019-07-01 00:34:05 -04:00
Adrien Béraud 0e509318bb build: only build http with proxy 2019-06-28 20:56:22 -04:00
Seva bcc2baa94a http: ensure http_parser on_message_complete cb is always called 2019-06-28 15:28:12 -04:00
Seva bbed9d530d http: remove unnecessary resolve iteration log 2019-06-28 14:49:37 -04:00
Seva 5a3612be98 dhtproxy: default client port to 80 2019-06-28 14:32:24 -04:00
Seva 8202c1f7d7 http: add default port to 80 2019-06-28 13:55:36 -04:00
Seva a200b0e14c http: open client to public api 2019-06-27 09:48:33 -04:00
Seva bd32edc6c5 dhtproxy: uniform client logging 2019-06-25 17:04:38 -04:00
Seva d0d3ef7394 http: don't process resps & reqs on closed conn 2019-06-25 16:49:48 -04:00
Seva 712da15ae2 readme: change optional restbed mention to restinio 2019-06-25 16:08:19 -04:00
Seva fcdc997d29 cmake: fix undefined ref to pthreads for dhtnode 2019-06-25 15:45:12 -04:00
Seva cf18effebb dhtnode: fix logging 2019-06-25 15:21:49 -04:00
Seva b8c2ff8a11 dhtproxy: cleanup client handle proxy status 2019-06-25 14:35:04 -04:00
Seva 1fad1b9ce3 dhtrunner: use user logger with proxy client 2019-06-25 13:37:45 -04:00
Seva 117fedb641 dhtproxy: test with http client lib everything 2019-06-25 13:36:14 -04:00
Seva 422f5a6c45 dhtproxy: use one io_context, rm scheduler, fix get,proxyInfo 2019-06-25 13:35:26 -04:00
Seva 51a42aa2c8 dhtproxy: fix inconsistencies & add comments 2019-06-25 10:16:40 -04:00
Adrien Béraud be0baefee8 net: recompute selectFd in case of rebind 2019-06-22 22:51:56 -04:00
Adrien Béraud 2ac5157ab8 net: attempt to use the same port for IPv4 and IPv6 if 0 2019-06-22 21:30:49 -04:00
Adrien Béraud fbe8834e04 net: compute selectFd once 2019-06-22 18:49:50 -04:00
Adrien Béraud 89ff131750 tools: close stdin on sigint 2019-06-22 18:37:58 -04:00
Adrien Béraud feb498305f network engine: convert mapped IPv4 2019-06-22 18:37:58 -04:00
Seva b00f56c94a dhtproxy: fix server logging of non c str 2019-06-21 14:41:10 -04:00
Seva 2067cb052f dhtproxy: default to curly brakets instead of nullptr 2019-06-21 13:10:33 -04:00
Seva 51aeaeaeab dhtproxy: use logger everywhere & use same format 2019-06-21 12:49:47 -04:00
Seva c0bb8f065c dhtproxy: ensure client asio timers are initialized 2019-06-21 11:33:51 -04:00
Seva 126318956a dhtproxy: fix unintialized refresh timer in listen 2019-06-21 11:13:54 -04:00
Seva 9014c0a7bb dhtproxy: log subscribe to debug instead of warning 2019-06-21 11:12:49 -04:00
Seva 728782921c dhtproxy: test resubscribe with random port 2019-06-21 11:07:20 -04:00
Adrien Béraud d438d4ef1b sockaddr: add getMappedIPv6 2019-06-21 11:00:48 -04:00
Seva 2959709462 dhtproxy: log in client only if logger is defined 2019-06-20 16:44:13 -04:00
Seva 4a26168248 dhtproxy: ensure client http processing keeps running 2019-06-20 16:13:01 -04:00
Seva 9c348b1df4 dhtproxy: use same client logger 2019-06-20 15:31:43 -04:00
Seva 7e7654d1ae dhtproxy: use two io_contexts periodic & http 2019-06-20 14:43:16 -04:00
Seva 69ee1d212a http: replace tabs by 4 spaces 2019-06-20 12:30:42 -04:00
Seva 21ec9129c3 tools: rename proxy benchmark to loadtester 2019-06-20 12:24:44 -04:00
Seva b7185fa87c dhtproxy: rewrite client restartListeners & save listener connId 2019-06-20 12:14:27 -04:00
Seva 54acd67a1f dhtproxy: rewrite client cancelAllListeners with RESTinio 2019-06-20 11:56:16 -04:00
Seva 045de8602c dhtproxy: rewrite client doCancelListen with RESTinio 2019-06-20 11:52:15 -04:00
Seva 390fa48700 dhtproxy: replace status thread by asio timer 2019-06-20 11:24:56 -04:00
Seva 0d08f0d356 dhtproxy: replace client threads by asio timers 2019-06-20 11:23:38 -04:00
Adrien Béraud 738424b1ae dhtrunner: use default values for config 2019-06-19 19:27:54 -04:00
Seva d123d8f768 http: remove typo 2019-06-19 12:23:00 -04:00
Seva a20a48506d http: fix resolve & externalize conn close 2019-06-19 12:07:46 -04:00
Seva 063a2b4860 http: make conn async & resolve hostnames 2019-06-19 11:34:50 -04:00
Seva 829d365475 http: detect & handle close connection 2019-06-19 10:24:51 -04:00
Seva 11e6671e60 Merge branch 'proxy_asio_client' into proxy_restinio 2019-06-18 23:27:51 -04:00
Seva 6fe473d3cc http: fragment client into async operations 2019-06-18 23:17:49 -04:00
Seva 9f493b9572 http: make continious reads non blocking 2019-06-18 16:55:52 -04:00
Seva 2164c5ddc7 dhtproxy: add control for max_pipelined_requests 2019-06-18 14:57:17 -04:00
Seva a57a4d55e8 dhtproxy: optimize for concurency 2019-06-18 14:13:42 -04:00
Seva b98cc78b42 dhtproxy: add if logger before using it 2019-06-18 10:17:21 -04:00
Seva 789d41ff07 dhtproxy: fix join on terminated thread 2019-06-17 16:42:12 -04:00
Seva 632403875c dhtproxy: switch entirely to one thread 2019-06-17 16:27:39 -04:00
Seva bc2737cdc9 dhtproxy: move resp msgs to cpp file as constexpr 2019-06-17 15:29:25 -04:00
Seva 0c6bfde1c5 docker: cp restinio deps build files to system path 2019-06-17 15:13:32 -04:00
Seva cfeeaf7950 tools: add listen & subscribe to proxy_benchmark 2019-06-17 13:57:46 -04:00
Seva e31ebfea32 docker: finalize restinio conan setup 2019-06-17 13:06:04 -04:00
Seva 07efe8c76e tools: add locust proxy_benchmark.py 2019-06-17 11:46:29 -04:00
Seva 5c78bf386d docker: update restinio run commands 2019-06-16 22:04:05 -04:00
Adrien Béraud 86088b043b thread pool: getShared returns shared_future instead of shared_ptr<future> 2019-06-14 13:06:06 -04:00
Seva fad8bb1631 dhtrunner: change context logger from unique to shared ptr 2019-06-14 11:46:13 -04:00
Seva 9a56c099a1 docker: rename pip unknown cmd to pip3 & remove comments 2019-06-14 10:23:59 -04:00
Seva 8298c0c868 docker: add restinio & conan depsllvm 2019-06-13 18:44:23 -04:00
Seva 971f590941 Merge branch 'master' github.com:savoirfairelinux/opendht into proxy_restinio 2019-06-13 17:19:49 -04:00
Seva 1813d83273 docker: add restinio & conan dependency 2019-06-13 16:04:14 -04:00
Seva e87d164f0b dhtproxy: refactor client to use external io_context 2019-06-13 13:24:44 -04:00
Seva b9604807ea dhtproxy: replace threads by io_context
replace scheduler and its jobs by asio timers
2019-06-13 11:13:48 -04:00
Seva 9f12b44179 dhtproxy: move custom methods to http & default thread pool to 1 2019-06-11 16:30:42 -04:00
Seva 0772d5435c dhtproxy: replace listener thread with a conn state observer 2019-06-11 15:37:47 -04:00
Seva 368ee9e22e dhtproxy: ensure io_context thread pool & isolate settings 2019-06-11 11:31:43 -04:00
Seva dd56bdd8e2 dhtproxy: add conn listener & make http services singletons 2019-06-10 17:08:37 -04:00
Seva 71b36e0643 dhtproxy: set logger in sendPushNotification 2019-06-10 14:16:18 -04:00
Seva 61b43759df dhtproxy: set required timeout times 2019-06-10 10:12:08 -04:00
Adrien Béraud 96e12e88c3 dhtproxytester: add more checks, cleanup 2019-06-09 23:34:38 -04:00
Adrien Béraud 8da933c01a dhtrunner: use threaded mode by default 2019-06-09 23:31:40 -04:00
Adrien Béraud 20c0069867 dhtrunner/peerdiscovery: only advertise bound address families 2019-06-09 23:15:31 -04:00
Adrien Béraud 8942e0d00e dht: init parent class with logger 2019-06-09 19:07:04 -04:00
Adrien Béraud bc760f9348 Update README.md 2019-06-09 19:06:44 -04:00
Adrien Béraud 59702190a7 update to version 1.10.0 2019-06-09 09:06:36 -04:00
Adrien Béraud cb3e94d0be dhtnode: improve manpage 2019-06-08 13:28:52 -04:00
Adrien Béraud ab7b8f6027 dhtnode: improve manpage 2019-06-08 12:59:57 -04:00
Adrien Béraud 6e5231047b dhtrunnner: properly lock mutex in run & join 2019-06-08 10:20:25 -04:00
Adrien Béraud 777505434c tools: always handle signals, don't block in signal handling 2019-06-08 09:23:34 -04:00
Adrien Béraud 18c3161261 tools: allow to use existing certificate/private key 2019-06-08 01:43:07 -04:00
Seva 1060038bdf dhtproxy: write into dht logger 2019-06-07 16:46:28 -04:00
Seva 9d427a6a80 http: add optional client conn controls 2019-06-07 15:46:21 -04:00
Seva f1dbac2aff dhtproxy: fix client context lost in the abyss 2019-06-07 14:57:16 -04:00
Adrien Béraud a63c5d172b build: install network utils 2019-06-07 14:41:10 -04:00
Adrien Béraud 9c6de8cc16 net: add logger support for UdpSocket 2019-06-07 14:14:15 -04:00
Adrien Béraud fe9de44867 dhtrunner: stop socket after dht 2019-06-07 14:14:15 -04:00
Adrien Béraud 4bfd6bb545 dhtrunner: add pluggable transport 2019-06-07 14:14:15 -04:00
Adrien Béraud 120c017399 net: add DatagramSocket, UdpSocket transport 2019-06-07 14:14:15 -04:00
Seva 7fc7597564 dhtproxy: fix indent 2019-06-06 14:51:01 -04:00
Seva f8d62dc6a7 dhtproxy: add support for legacy http methods
Legacy non-standard http methods: LISTEN, STATS, SIGN, ECNRYPT

NOTE: Supported with RESTinio > 0.5.0 and custom http_parser
- https://github.com/Stiffstream/restinio/issues/26
- https://github.com/binarytrails/http-parser
2019-06-06 13:30:37 -04:00
Seva fc3686d817 dhtproxy: comment/remove restbed leftovers to build w/o 2019-06-06 11:08:39 -04:00
Seva a692f7fbe2 dhtproxy: add logger to tester & disable client proxy 2019-06-05 16:50:50 -04:00
Seva cb349d9cf6 dhtproxy: stop server eventloop on cmd 2019-06-05 16:39:18 -04:00
Seva 6266f88cd5 dhtproxy: port doPut,sendListen logic new http client 2019-06-04 17:21:44 -04:00
Seva 0a3320e2c8 dhtproxy: enhance http async api & finish client get 2019-06-04 16:14:37 -04:00
Mingrui Zhang d6ad67d8e2 peerdiscovery: change comment 2019-06-04 15:30:45 -04:00
Mingrui Zhang 19d0aa55f7 Test: change ip multicast address to organization local 2019-06-04 15:30:45 -04:00
Adrien Béraud 941e53425f update to version 1.9.5 2019-06-04 09:54:02 -04:00
Seva 10971f700f dhtproxy: add http classes with fully async client
use server's pushNotifications of this client
2019-06-03 17:10:19 -04:00
Seva 2e7767d192 dhtproxy: fix restinio start w/o dhtlogger 2019-06-03 13:52:35 -04:00
Adrien Béraud baf811bfe9 dhtrunner: don't override statusCallback if not provided 2019-05-31 19:29:59 -04:00
Adrien Béraud 76f0672e63 context: add statusCallback, certificateStore 2019-05-31 10:12:42 -04:00
Seva 330ad8ed12 dhtproxy: pipe restinio logs to opendht logger 2019-05-29 16:02:25 -04:00
Seva 3252e6daa3 dhtproxy: rewrite sendListen with restinio 2019-05-29 11:59:09 -04:00
Seva 07599239a6 dhtproxy: port restbed client listen to server 2019-05-28 11:39:04 -04:00
Seva eac61678f4 dhtproxy: add client request conn_cb for listeners 2019-05-28 10:26:47 -04:00
Seva 078c1198b0 Merge branch savoirfairelinux 'master' changes 2019-05-27 15:23:26 -04:00
Seva 3d525030b9 dhtproxy: add async put & swap threading for io_context 2019-05-27 15:06:11 -04:00
Seva 3733fc2890 dhtproxy: switch threading to io_context 2019-05-27 15:06:11 -04:00
Seva c40f35fa06 dhtproxy: fix context type casting in client get 2019-05-27 14:59:19 -04:00
Seva 13661929d1 dhtproxy: switch server to ipv6 (implicit ipv4 support) 2019-05-27 14:59:19 -04:00
Seva 4e934f8902 dhtproxy: add ipv6 to restinio client & get method 2019-05-27 14:59:19 -04:00
Seva 125a05a5fc dhtproxy: fix sendPushNotification 2019-05-27 14:59:19 -04:00
Seva 868c114bcb dhtproxy: fix restinio client rx by parts 2019-05-27 14:59:19 -04:00
Seva f0acc3e735 dhtproxy: add sendPushNotification to server 2019-05-27 14:59:19 -04:00
Seva 171e2b130b dhtproxy: implement restinio client 2019-05-27 14:59:19 -04:00
Seva cb5a261b82 dhtproxy: cleanup server 2019-05-27 14:59:19 -04:00
Seva feb8bd0d4f dhtproxy: rewrite listen with restinio 2019-05-27 14:59:19 -04:00
Seva 3955368c01 dhtproxy: rewrite putEncrypted with restinio 2019-05-27 14:59:19 -04:00
Seva b841ff1b83 dhtproxy: rewrite putSigned with restinio 2019-05-27 14:59:19 -04:00
Seva 7a04c0eb66 dhtproxy: rewrite getFiltered with restinio 2019-05-27 14:59:19 -04:00
Seva fe1659bd2f dhtproxy: rewrite un/subscribe with restinio 2019-05-27 14:59:19 -04:00
Seva b90e14edd6 dhtproxy: rewrite stats with restinio 2019-05-27 14:59:19 -04:00
Seva 9e3e9e65e6 dhtproxy: switch server to restinio
rewrite options, getNodeInfo, get & put
opendht: bump to c++14
2019-05-27 14:59:19 -04:00
Seva 1c3132e0ef dhtproxy: add async put & swap threading for io_context 2019-05-27 14:57:05 -04:00
Seva f3e304e661 dhtproxy: switch threading to io_context 2019-05-27 11:17:51 -04:00
Seva 2545282624 dhtproxy: fix context type casting in client get 2019-05-26 09:50:44 -04:00
Seva 52c413f056 dhtproxy: switch server to ipv6 (implicit ipv4 support) 2019-05-24 13:18:06 -04:00
Seva ab082543ea dhtproxy: add ipv6 to restinio client & get method 2019-05-24 11:01:35 -04:00
Adrien Béraud ff6be81929 peer discovery: add default port 2019-05-23 10:39:43 -04:00
Seva bd994384f0 dhtproxy: fix sendPushNotification 2019-05-22 17:23:36 -04:00
Seva 598e38dbf4 dhtproxy: fix restinio client rx by parts 2019-05-22 16:21:07 -04:00
Seva b1a35b82a2 dhtproxy: add sendPushNotification to server 2019-05-22 11:55:37 -04:00
Adrien Béraud e4516772ee dht: log cleanup 2019-05-22 11:20:27 -04:00
Seva c7844fc320 dhtproxy: implement restinio client 2019-05-22 10:29:27 -04:00
Adrien Béraud c7e2483160 dht: add logger to constructor 2019-05-22 00:47:25 -04:00
Adrien Béraud 37b12c114d dht: cleanup 2019-05-22 00:17:18 -04:00
MingruiZhangW 77bd34ad9c Merge pull request #405 from savoirfairelinux/context
dhtrunner: add context
2019-05-21 16:21:45 -04:00
Adrien Béraud 44490bd9ca dhtrunner: add context 2019-05-21 13:43:55 -04:00
Adrien Béraud ca01568824 dhtrunner: add API to access PeerDiscovery instance 2019-05-20 10:21:35 -04:00
Adrien Béraud 2b259639d2 peer discovery: fix occasional use-after-free in unit test 2019-05-20 10:21:26 -04:00
Adrien Béraud 84d322e428 peer discovery: check running before select 2019-05-20 10:21:26 -04:00
Seva 6d5e3d8cd2 dhtproxy: cleanup server 2019-05-17 14:27:18 -04:00
Seva b56518f258 dhtproxy: rewrite listen with restinio 2019-05-17 14:03:07 -04:00
Sébastien Blin d807af3951 Merge pull request #402 from MingruiZhangW/peerdiscovery_fix_bind
peerdiscovery: bind socket problem fix
2019-05-16 17:19:02 -04:00
Seva 5f393490a5 dhtproxy: rewrite putEncrypted with restinio 2019-05-16 17:15:31 -04:00
Seva efe869fe42 dhtproxy: rewrite putSigned with restinio 2019-05-16 16:06:47 -04:00
Seva a31cecdeac dhtproxy: rewrite getFiltered with restinio 2019-05-16 15:19:26 -04:00
Seva 4a4becdbec dhtproxy: rewrite un/subscribe with restinio 2019-05-16 14:09:13 -04:00
Seva eef2838a12 dhtproxy: rewrite stats with restinio 2019-05-16 12:31:58 -04:00
Seva a520657fac dhtproxy: switch server to restinio
rewrite options, getNodeInfo, get & put
opendht: bump to c++14
2019-05-16 11:30:41 -04:00
Mingrui Zhang 29003700db peerdiscovery: fix the issue where bind() can be interrupted after calling publish() first 2019-05-15 15:42:32 -04:00
Sébastien Blin b143bc459d default_types: add metadatas map into ImMessage
Give the ability to store more datas into an ImMessage

Issue: #345
2019-05-03 14:54:43 -04:00
Adrien Béraud 4d6e5ab877 peer discovery: fix warning 2019-05-03 10:13:05 -04:00
Adrien Béraud 248d2e3f73 update to version 1.9.4 2019-05-02 12:44:27 -04:00
Adrien Béraud 0692bd9bc9 proxy server: fix warning when building without push notifications 2019-04-30 17:47:40 -04:00
Adrien Béraud 7f48c4808b network engine: minor cleanup 2019-04-30 17:47:40 -04:00
Adrien Béraud 32a443a1d8 thread pool: add unit test 2019-04-30 17:47:40 -04:00
Adrien Béraud 6d0fcba3b5 thread pool: add Executor 2019-04-30 17:47:40 -04:00
Adrien Béraud 76e2efb19b peerdiscovery: undef write macro after use 2019-04-26 11:50:25 -04:00
Adrien Béraud bbe1b9233f dhtrunner: use recv instead of recvfrom for stoppipe 2019-04-26 02:29:49 -04:00
Adrien Béraud 7558ca0dca peerdiscovery: unit test cleanup 2019-04-26 02:29:49 -04:00
Adrien Béraud 38141322f1 peerdiscovery: stop threads when stopping services 2019-04-26 02:29:49 -04:00
Adrien Béraud 6c5ea125ca peerdiscovery: add automatic template serialization 2019-04-26 02:29:49 -04:00
Adrien Béraud d0362e58e0 dhtnode: update dht instance name
Avoid confusion with the namespace
2019-04-25 23:33:22 -04:00
Adrien Béraud 1b3a40f345 dhtrunner: clear stop file descriptor if still running 2019-04-25 22:12:28 -04:00
Adrien Béraud 38d854e6f4 dhtrunner: read correct size from buffer 2019-04-25 22:11:20 -04:00
Adrien Béraud e0241ccfbd dhtrunner: drop older packets in batch 2019-04-25 22:10:46 -04:00
Adrien Béraud d4311925b4 dhtrunner: shutdown: return if not running 2019-04-25 21:38:52 -04:00
Adrien Béraud 9aa56dd464 dhtnode/systemd: use simple service mode 2019-04-25 21:32:35 -04:00
Adrien Béraud ec3b259ead dhtnode/systemd: update default bootstrap 2019-04-25 21:18:11 -04:00
Adrien Béraud 332cab10ef tools: don't chdir to / when deamonizing 2019-04-25 21:17:44 -04:00
Adrien Béraud 85f2b618c7 logs: use ofstream for file logging 2019-04-25 14:31:06 -04:00
Adrien Béraud bcf18fda53 update to version 1.9.3 2019-04-25 11:10:42 -04:00
Adrien Béraud 6b78a4cad6 peerdiscovery: catch parsing errors 2019-04-25 10:25:36 -04:00
Adrien Béraud 66d3a8aeaa dhtrunner: cleanup 2019-04-24 14:51:43 -04:00
Adrien Béraud 958cb250a3 dhtnode: show both IPv4, IPv6 bound ports 2019-04-23 12:13:53 -04:00
Adrien Béraud 6a5724a868 peerdiscovery: allow per-domain publish, cleanup 2019-04-23 12:09:08 -04:00
Adrien Béraud 11ac84de54 Merge pull request #392 from MingruiZhangW/peer_discovery_version_2
peerdiscovery: modify to add support for sending and receiving msgpack
2019-04-23 11:20:18 -04:00
MingruiZhangW f65e8c1a1f Merge branch 'master' into peer_discovery_version_2 2019-04-22 09:13:17 -04:00
Adrien Béraud c2fdf6ae92 dhtnode: show grouped get results, improve duration display 2019-04-21 21:39:54 -04:00
Adrien Béraud 91a81f64ac thread pool: make public 2019-04-21 21:39:54 -04:00
Adrien Béraud 17b772e6cc proxy client: close all sockets before joining 2019-04-20 22:38:36 -04:00
Adrien Béraud 75738ac28b proxy client: don't hold lock while calling callback 2019-04-20 22:07:48 -04:00
Adrien Béraud 84a2d771c1 dht: add some missing override 2019-04-20 22:07:48 -04:00
Adrien Béraud f6273f9efc tools/dhtnode: improve documentation 2019-04-20 17:30:39 -04:00
Adrien Béraud 5881c91510 utils: include config.h 2019-04-19 20:24:01 -04:00
Adrien Béraud e09c55ca42 update to version 1.9.2 2019-04-19 16:15:56 -04:00
Andreas Traczyk c737e4690e update visual studio build 2019-04-19 15:53:42 -04:00
Adrien Béraud 35a9d1f612 proxy client: catch exception in Http::close() 2019-04-18 17:38:00 -04:00
Mingrui Zhang 0f3396cd66 peerdiscovery: make nested classes to hide ip versions 2019-04-18 12:20:17 -04:00
Mingrui Zhang 98cd6cc61e peerdiscovery: fix memory leakage cased by sbuffer release 2019-04-18 10:20:00 -04:00
Mingrui Zhang 092cb9551e peerdiscovery: add testpack into tester to verify the possibility of sending & receiving 2 packages simultaneously (including stop functions) 2019-04-18 09:33:15 -04:00
Mingrui Zhang a2bbca792c peerdiscovery: add dmtx_ to distinguish send & listen shared resources, add stopDiscovery, stoplisten to stop listen or discover certain type of service 2019-04-17 10:26:49 -04:00
Adrien Béraud 5ec72e213e dht: add override 2019-04-17 10:00:15 -04:00
Mingrui Zhang 0f51115f44 peerdiscovery: modify maps to handle more services in one instance 2019-04-16 15:11:07 -04:00
Adrien Béraud 683a111726 autotools: build versioned shared library 2019-04-16 12:23:32 -04:00
Adrien Béraud 0fd4fed537 search: add fallback return 2019-04-16 12:23:32 -04:00
Mingrui Zhang 18aa6ddb7b peerdiscovery: modify function signatures to make service consistent 2019-04-15 18:24:15 -04:00
Mingrui Zhang 0a436e17b0 peerdiscovery: modifications on tester fit for the updates 2019-04-15 17:26:59 -04:00
Mingrui Zhang 763ffddf51 peerdiscovery: modify to add support for sending and receiving msgpack 2019-04-15 16:50:48 -04:00
Adrien Béraud ef82652a1e network: header cleanup 2019-04-14 11:30:10 -04:00
Adrien Béraud 4f03a5c64e network: tid, socket_id, value_id: default to 0 2019-04-14 09:15:16 -04:00
Adrien Béraud 5257ac314f add API to retrieve version string 2019-04-14 00:19:01 -04:00
Adrien Béraud 0580a4e7dd update to version 1.9.1 2019-04-13 23:29:43 -04:00
Yanfei Han fd1f2cd0e4 add peer_discovery.o object into auto configure lib 2019-04-13 23:04:18 -04:00
Adrien Béraud af940c63b1 proxy: mute unused variable warning if disabled 2019-04-13 23:02:57 -04:00
Adrien Béraud 15da502354 dhtrunner: make peer discovery port static constexpr 2019-04-13 22:56:31 -04:00
Adrien Béraud b7a9a52f97 network engine: DhtProtocolException cleanup 2019-04-13 22:56:31 -04:00
Adrien Béraud 6e10756e28 peerdiscovery: cleanup 2019-04-13 22:56:31 -04:00
Adrien Béraud aad4ad03cf network utils: add missing includes 2019-04-13 22:56:31 -04:00
Adrien Béraud 3d1e055c7b peerdiscovery: always use local node id 2019-04-13 20:50:00 -04:00
Adrien Béraud b02e9cfff7 peerdiscovery: flush stop socket if not stopping 2019-04-13 20:50:00 -04:00
Adrien Béraud 453db29058 dht: add override to getNodeId 2019-04-13 20:43:57 -04:00
Adrien Béraud a8ba536d44 update to version 1.9.0 2019-04-09 16:25:39 -04:00
Adrien Béraud a238183031 peerdiscovery: don't assign IPv6 multicast interface 2019-04-09 16:11:21 -04:00
Adrien Béraud 73827cd34d peerdiscovery: allow IPV6_MULTICAST_IF failure 2019-04-09 15:12:37 -04:00
Adrien Béraud 876190a392 peerdiscovery: SO_REUSEADDR, SO_REUSEPORT in different calls 2019-04-09 14:58:22 -04:00
Adrien Béraud 7fe321e4fc peerdiscovery: cleanup data serialization 2019-04-09 14:57:48 -04:00
Adrien Béraud 7f7075ca9a peerdiscovery: support IPV6_JOIN_GROUP 2019-04-09 12:31:23 -04:00
Adrien Béraud 9b9f12d87e tests: accept null token if callback returns false 2019-04-08 15:58:46 -04:00
Adrien Béraud 26ad6de3a4 dhtrunner: avoid race condition when setting token 2019-04-08 15:57:25 -04:00
Adrien Béraud ae91f8bd55 dhtrunner: default-initialize tokens 2019-04-08 15:36:24 -04:00
Adrien Béraud 28eeee24ba runnertester: reduce number of test values 2019-04-08 15:35:55 -04:00
Adrien Béraud 671c55a01d dhtrunner: print peer discovery error message to cerr 2019-04-08 14:36:15 -04:00
Adrien Béraud a4f2e6efdd tests: avoid use-after-free in proxytester 2019-04-08 13:06:32 -04:00
Adrien Béraud 60831ee898 peerdiscovery: avoid crashing if message can't be sent 2019-04-08 13:02:39 -04:00
Adrien Béraud 98dbe1cba7 gitignore: ignore files from vscode, eclipse 2019-04-08 12:07:35 -04:00
Adrien Béraud 6c705e525f net: factorize logic to network_utils 2019-04-08 12:07:11 -04:00
Adrien Béraud 96347d83e1 tools: add argument for peer discovery 2019-04-08 11:34:52 -04:00
Adrien Béraud 01d8e513a1 peerdiscovery: cleanup 2019-04-08 11:34:52 -04:00
Mingrui Zhang b5921b0d9d peerdiscovery: error correction for tester, distinguish creation error(ip version support) and listen/receive error 2019-04-08 11:32:08 -04:00
Mingrui Zhang 8ee7883c53 peerdiscovery: Exception added for supporting construction error 2019-04-08 11:32:08 -04:00
Mingrui Zhang 4240820463 peerdiscovery: add multicast node discovery mechanism 2019-04-08 11:32:08 -04:00
Adrien Béraud 7ebbf17f37 InfoHash: use static size 2019-04-05 11:21:23 -04:00
Adrien Béraud 6821e5bd96 dhtrunner: default to null function instead of AllFilter 2019-04-05 10:49:40 -04:00
Adrien Béraud c4ec1e78e0 tests: fix occasional testListen failure 2019-04-05 10:49:35 -04:00
Adrien Béraud e86d717e81 dht: make getPut() const 2019-04-05 10:49:35 -04:00
Adrien Béraud db2b48d2af dhtrunner: select on maxfd+1 2019-04-03 16:18:35 -04:00
Adrien Béraud 2b938110fd cmake: force indexation if python is enabled 2019-04-03 14:52:35 -04:00
Adrien Béraud c647b19e91 infohash: make some methods constexpr, noexcept 2019-04-03 14:52:35 -04:00
Sébastien Blin 8cd14646a6 Merge pull request #387 from savoirfairelinux/cert_request
crypto: add certificate request support
2019-04-01 09:30:33 -04:00
Adrien Béraud d80aab9399 pingpong: cleanup 2019-03-29 13:13:29 -04:00
Adrien Béraud 9b881d4e95 crypto: add initial certificate request support 2019-03-29 13:13:29 -04:00
Adrien Béraud b4c3c2cba0 update to version 1.8.2 2019-03-18 13:47:41 -04:00
Sébastien Blin 4519a23996 Merge pull request #386 from savoirfairelinux/parse_perf
Network: improve parsing performance
2019-03-18 13:13:57 -04:00
Adrien Béraud 1ac4e08f45 build: add clang-tidy configuration 2019-03-17 19:23:26 -04:00
Adrien Béraud 5e92777702 fix clang-tidy warnings 2019-03-17 19:22:28 -04:00
Adrien Béraud 4401e47002 cleanup, fix clang-tidy warnings 2019-03-17 17:43:52 -04:00
Adrien Béraud 215b44ca3b search: don't store filter in search
Filter is not supported anymore at the search listen stage.
Filters are now stored and called by the op cache.
2019-03-17 17:30:30 -04:00
Adrien Béraud 379fdae212 cmake: don't explicitly disable stack protector 2019-03-17 16:07:20 -04:00
Adrien Béraud 1e10e28fd7 network: improve message parsing performance 2019-03-17 16:07:20 -04:00
Adrien Béraud dccdb84836 tests: add Value tester 2019-03-16 14:27:46 -04:00
Adrien Béraud 71599da8ea value: add "not" method 2019-03-16 14:27:23 -04:00
Adrien Béraud f418b3651f update copyright date 2019-03-16 12:37:23 -04:00
Adrien Béraud 313f54c840 dht: disable some verbose logs 2019-03-10 17:27:37 -04:00
Adrien Béraud cdb721ade4 dht: move store logic to storage 2019-03-10 17:04:26 -04:00
Adrien Béraud 57ea09808e value: fix chain null check 2019-03-10 16:39:31 -04:00
Adrien Béraud fec5a6ede7 make move operators noexcept 2019-03-10 16:39:16 -04:00
Adrien Béraud 5f8e9d9480 storage: make non-movable 2019-03-10 16:39:16 -04:00
Adrien Béraud 311a8981fc thread pool: add computation, io pools 2019-03-10 16:39:16 -04:00
Adrien Béraud 04850e1701 dht: add configuration to persist state 2019-03-10 16:39:16 -04:00
Adrien Béraud a30f1b8032 dht: make exportNodes const 2019-03-10 16:39:16 -04:00
Sébastien Blin 41f8b06743 Merge pull request #376 from savoirfairelinux/server_thread_pool
Server thread pool
2019-02-19 19:57:13 -05:00
Adrien Béraud 1c74c2207f proxy server: cache json StreamBuilder 2019-02-19 18:43:14 -05:00
Adrien Béraud 9319bec7b8 proxy client: close previous request on resubscribe 2019-02-19 18:43:14 -05:00
Adrien Béraud e5f2a6eef5 proxy: send expired to sync values 2019-02-19 18:43:14 -05:00
Adrien Béraud 55f6c847b8 build: use define flags for proxy 2019-02-19 18:43:14 -05:00
Adrien Béraud 00cc4ebe28 proxy server: send push notification on thread pool 2019-02-19 18:43:14 -05:00
Adrien Béraud aa93db4fa6 proxy server: move json to sendPushNotification 2019-02-19 18:43:14 -05:00
Adrien Béraud 683570a3da add ThreadPool 2019-02-19 18:43:14 -05:00
Sébastien Blin 43559577f6 Merge pull request #377 from savoirfairelinux/proxy_sync_expired
Proxy: sync expired state
2019-02-19 18:42:32 -05:00
Adrien Béraud ba2e179abe dht: optimize get 2019-02-19 01:59:59 -05:00
Adrien Béraud a5d29c904c op cache: optimize cache insertion 2019-02-19 01:59:59 -05:00
Adrien Béraud 989f32eb56 filter: cleanup and optimize 2019-02-19 01:59:59 -05:00
Adrien Béraud b66fa73c56 test: include cppunit headers 2019-02-19 01:59:59 -05:00
Adrien Béraud 1ca181db1d value: simplify expression 2019-02-19 01:59:59 -05:00
Adrien Béraud 1f3bf697c3 search: use syncStatus for get 2019-02-19 01:59:59 -05:00
Adrien Béraud a1f8cc906c proxy client: use SyncCallback 2019-02-19 01:59:59 -05:00
Adrien Béraud 35c6a57526 dht: add synced status 2019-02-19 01:59:59 -05:00
Adrien Béraud 39e69f813c network engine: cleanup 2019-02-19 01:59:59 -05:00
Sébastien Blin 8045c2cbf2 dhtrunner: avoid startNetwork failure if only one binding is failing 2019-02-19 01:44:47 -05:00
Sébastien Blin 79a2f4280f proxy: resolve url with protocol and port 2019-02-14 11:04:11 -05:00
Sébastien Blin 769ce45740 proxy_client: support prototype in serverHost 2019-01-22 07:56:27 -08:00
Sébastien Blin 75a14d3608 proxy: only get old values at first subscribe 2019-01-18 22:53:24 -08:00
Sébastien Blin d523e9f259 tests: test retrieve values when resubscribe 2019-01-14 10:53:08 -08:00
Sébastien Blin 3a3933e6d5 dhtproxy: remove sendSubscribe 2019-01-14 10:53:08 -08:00
Sébastien Blin 70f09ded3f dhtproxy: avoid notification after subscribe to retrieve values 2019-01-14 10:53:08 -08:00
Sébastien Blin 824a1bf5fa proxy_server: return old values when resubscribe 2019-01-14 10:53:08 -08:00
Sébastien Blin e5b56cc0a5 dht: link to tellListenerRefreshed
When a permanent put is refreshed, the node has to tell to its
remote listeners that the value is refreshed.
2019-01-09 13:34:51 -08:00
Sébastien Blin 36cf70f2a7 proxy: remove useless token for push listeners
Since we authentificate listeners with the clientId and the hash and
we use only one listener by hash/clientId, we doesn't need to store
a token always equals to 0.

Note: also avoid to get multiple hashes for one push notification.
2018-12-30 13:35:18 -05:00
Adrien Béraud 459c1344aa update to version 1.8.1 2018-12-28 11:38:15 -05:00
Adrien Béraud c0e376e15a dht: reduce log verbosity 2018-12-28 01:41:10 -05:00
Adrien Béraud 71b9672b96 value: don't print certificate id in toString by default 2018-12-28 01:38:45 -05:00
Adrien Béraud 086f37a71a op cache: remove listener if callback returned false 2018-12-28 01:38:02 -05:00
Adrien Béraud 87e76a5e4e tests: reverse nodes 2018-12-26 13:03:36 -05:00
Adrien Béraud 7f0a5dfda3 dht: increase max number of searches and hashes 2018-12-26 10:28:55 -05:00
Adrien Béraud 6d7f8004bf connectivity change: reset routing table instead of searches 2018-12-26 10:28:30 -05:00
Adrien Béraud 8168c39b63 dht: cleanup 2018-12-26 01:22:37 -05:00
Adrien Béraud d0fdbe5340 dhtrunner: print proper message on bind error 2018-12-26 00:58:43 -05:00
Adrien Béraud c7604fbb8d tests: wait for put before performing get 2018-12-26 00:56:49 -05:00
Adrien Béraud 56773baa98 unit tests: add listen test 2018-12-24 19:09:32 -05:00
Adrien Béraud e6cf67c575 dht: clear local listener if callback returns false 2018-12-24 18:37:06 -05:00
Adrien Béraud 00ebc5e2bf op cache: check callback return value 2018-12-24 18:36:29 -05:00
Adrien Béraud ccef94c11b Revert "storage: make non-movable"
This reverts commit 7ebad7d3c5.
2018-12-24 17:16:15 -05:00
Adrien Béraud 0066be49b9 python: add more bindings for SockAddr 2018-12-24 16:55:25 -05:00
Adrien Béraud 592ed4ee90 op cache: don't call callback if no value 2018-12-24 15:50:41 -05:00
Adrien Béraud 353a6f9db6 op cache: add onCancel callback 2018-12-24 15:41:17 -05:00
Adrien Béraud 7ebad7d3c5 storage: make non-movable 2018-12-24 15:28:03 -05:00
Adrien Béraud 14f6e6e5f3 proxy client: catch exceptions in restbed::Http::async 2018-12-22 23:45:37 -05:00
Adrien Béraud 9ce5b30931 securedht: use query to check for existing value 2018-12-22 11:42:45 -05:00
Adrien Béraud 92979fa96a dhtchat: add logging support 2018-12-21 19:55:27 -05:00
Adrien Béraud 0c1e7d2763 dht: run node confirmation if bucket was empty 2018-12-19 14:07:55 -05:00
Adrien Béraud 14a744f6cd dht: log cleanup 2018-12-19 14:07:55 -05:00
Adrien Béraud 3b26684a87 network engine: add default values for sendFindNodes 2018-12-19 14:07:55 -05:00
Sébastien Blin 0a764ee440 Merge pull request #361 from savoirfairelinux/schedule_restart
proxy client: schedule listener restart
2018-12-18 16:07:39 -05:00
Adrien Béraud 7dda5a3d5a proxy client: schedule listener restart 2018-12-18 10:10:14 -05:00
Adrien Béraud 306d573223 proxy client: fix race condition 2018-12-17 16:41:00 -05:00
Sébastien Blin 20f4355b73 Merge pull request #356 from savoirfairelinux/build
securedht: add override
2018-12-11 14:52:07 -05:00
Adrien Béraud a2d7cd56a8 Merge pull request #358 from atraczyk/master
replace _write with send when building for windows
2018-12-11 14:48:26 -05:00
Andreas Traczyk 5cd53f3624 replace _write with send when building for windows 2018-12-11 14:37:14 -05:00
Adrien Béraud 32eea55f10 autotools: don't build doc if doxygen not found 2018-12-11 14:04:35 -05:00
Adrien Béraud f2f913f93f securedht: add override for relevant methods 2018-12-11 14:04:35 -05:00
Adrien Béraud cb9fe9d1fe Merge pull request #354 from atraczyk/master
msvc: replace write with _write when building on windows
2018-12-06 12:23:36 -05:00
Andreas Traczyk dcab32ef4f replace write with _write when building with msvc 2018-12-06 12:16:59 -05:00
Adrien Béraud 4948bd7ad3 node cache: remove expired weak pointers from cache
Remove expired Node weak pointers regularly,
in a way that ensures that:
* every expired pointer gets eventually cleaned up
* expired pointer ratio remains reasonably low
* no cleanup pass blocks the node for too long,
* impact on performance is negligible

Impact on performance:
Every N insertions, at most N nodes are tested by iterating the map
-> performance impact in O(1) (constant).
2018-11-29 19:27:32 -05:00
Adrien Béraud 4416b91461 update to version 1.8.0 2018-11-28 18:44:03 -05:00
Adrien Béraud 378ae396f0 Merge pull request #351 from hanyf/master
A obvious bug on network engine
2018-11-28 12:48:02 -05:00
Yanfei Han dc4a790a38 A obviouse bug on network engine 2018-11-29 00:47:00 +08:00
Sébastien Blin 07dd8f5648 Merge pull request #350 from savoirfairelinux/feature/cache
Feature/cache
2018-11-28 09:22:06 -05:00
Adrien Béraud f7433a2289 travis: update to xenial 2018-11-26 16:48:00 -05:00
Adrien Béraud ce4a65ff00 dhtrunner: add APIs for listen<T> with expiration information 2018-11-26 16:34:19 -05:00
Adrien Béraud 092f5cfef0 network_engine: fix warning 2018-11-26 16:34:19 -05:00
Adrien Béraud 12a45e7558 cmake: remove unnecessary flags for lto 2018-11-26 16:30:18 -05:00
Adrien Béraud 18d359a7d2 dht: refresh value if already exists 2018-11-26 01:57:57 -05:00
Adrien Béraud c6bb67d1ac dht: add storageRefresh 2018-11-26 01:57:57 -05:00
Adrien Béraud f4cd7636ce securedht: use signature cache in storePolicy, editPolicy 2018-11-26 01:57:57 -05:00
Adrien Béraud 2dd4e640c4 dhtrunner: add APIs for listen<T> with expiration information 2018-11-25 23:01:03 -05:00
Adrien Béraud 9a301e3590 Revert "cmake: use CMAKE_INTERPROCEDURAL_OPTIMIZATION for LTO"
This reverts commit b7b5152348.
2018-11-24 15:32:29 -05:00
Sébastien Blin aa16b9a235 Merge pull request #348 from savoirfairelinux/feature/probepermanent
dht: don't send probe query for non permanent puts
2018-11-23 10:10:35 -05:00
Adrien Béraud b2542a57df securedht: cache value signature check/decryption results 2018-11-22 15:43:55 -05:00
Adrien Béraud 00c1be9cdc logger: use DBG for DEBUG to avoid name conflicts 2018-11-22 15:43:55 -05:00
Adrien Béraud e414ca89c7 dht: don't send probe query for non permanent puts 2018-11-22 15:43:55 -05:00
Adrien Béraud 4d26537b93 Merge pull request #346 from AmarOk1412/fix/finished
dht_proxy_client: fix finished behavior
2018-11-11 22:19:50 -05:00
Sébastien Blin 00a9333de7 dht_proxy_client: fix finished behavior
callback_.emplace_back() returns immediately, so, in some case,
finished can be set to true even before we execute one callback.
Finished should not be used into callback. This patch adds a
finished variable only used by the callbacks to avoid this
case.

This improve the reactivity of the proxy client.
2018-11-11 15:27:57 -05:00
Adrien Béraud 971f96bf95 dhtrunner: improve getId()/getNodeId() documentation. 2018-10-29 16:23:21 -04:00
Adrien Béraud f9a12a9dca crypto: use proper size for getRandom()
Provided size should be the number of elements, not the number of bytes.
Also, if secure_vector where used with sizeof(T) > 1 (currently not the case),
there would be memory write to invalid address.
2018-10-29 16:21:51 -04:00
Adrien Béraud c05a93ae54 proxy server: cleanup 2018-10-29 12:45:52 -04:00
Adrien Béraud ff83a6daab proxy: support value expiration 2018-10-29 12:45:52 -04:00
Adrien Béraud b7b5152348 cmake: use CMAKE_INTERPROCEDURAL_OPTIMIZATION for LTO 2018-10-27 16:38:37 -04:00
Adrien Béraud a3768d1e50 cmake: use LINK_FLAGS for LTO 2018-10-27 14:57:51 -04:00
Adrien Béraud 94926cea22 proxy server: avoid early session close 2018-10-27 13:21:26 -04:00
Adrien Béraud 82ca2d1993 cmake: use single target_link_libraries for static library 2018-10-27 12:30:40 -04:00
Adrien Béraud 3e148599c5 proxy server: stop get if session is closed 2018-10-27 12:20:00 -04:00
Adrien Béraud 02d5592fdb cmake: improve restbed, jsoncpp search & usage 2018-10-27 11:51:42 -04:00
Adrien Béraud 328b306fd0 crypto: add documentation 2018-10-27 11:50:26 -04:00
Adrien Béraud 522a89b6f8 dht: use search cache for get ops 2018-10-27 11:49:55 -04:00
Adrien Béraud 897b451f44 crypto: fix build on Win32 2018-10-26 13:16:02 -04:00
Adrien Béraud ba3a42697c Merge pull request #331 from Dale-M/master
Some additions to automake infrastructure to get clean default build.
2018-09-20 14:24:34 -04:00
Adrien Béraud 5112a322de dht: reschedule permanent put refresh after request 2018-09-19 01:54:54 -04:00
Adrien Béraud 85961c6a62 storage: properly refresh expiration 2018-09-19 01:54:54 -04:00
Adrien Béraud 1eb1f3d5ac storageStore: add permanent mode 2018-09-19 01:54:54 -04:00
Adrien Béraud 726c138d90 dht: move storageStore to put 2018-09-19 01:54:54 -04:00
Adrien Béraud 1b6b1ca072 comments: fix typos 2018-09-19 01:54:54 -04:00
Dale Mellor 77da72c603 Some additions to automake infrastructure to get clean default build.
Be sure to pull in paths to headers for json and MsgPack dependencies.

Be sure to always build the base64 encoder and decoder, as they are
needed.
2018-09-17 09:40:07 +01:00
Adrien Béraud 7fb2da7c54 dhtrunner: avoid polling, use pipe to stop select 2018-09-15 17:22:12 -04:00
Sébastien Blin 6721a272ea Merge pull request #327 from savoirfairelinux/value_cache
value_cache: expire value if expiration is now
2018-08-12 10:42:22 -04:00
Adrien Béraud 246af2f065 value_cache: expire value if expiration is now 2018-08-11 21:27:18 -04:00
Adrien Béraud 57aba453b0 Merge pull request #325 from AmarOk1412/siteProxy
proxyserver: add stats endpoint for monitoring
2018-08-10 15:05:07 -04:00
Sébastien Blin f54fcd768f proxyserver: add stats endpoint for monitoring 2018-08-10 15:03:09 -04:00
Sébastien Blin 5b81476baf Merge pull request #326 from savoirfairelinux/tests
tests: add unit tests for certificate revocation
2018-08-09 17:11:20 -04:00
Adrien Béraud 5b510cadfb tests: add unit tests for certificate revocation 2018-08-09 14:51:02 -04:00
Adrien Béraud c794781644 update to version 1.7.4 2018-07-31 13:45:56 -04:00
Adrien Béraud 2ef4999b0f Merge pull request #322 from AmarOk1412/incorrectOk
dhtproxyclient: fix ok when a permanent PUT operations fails
2018-07-31 10:16:05 -04:00
Sébastien Blin 6069fba18f dhtproxyclient: fix ok when a permanent PUT operations fails 2018-07-31 09:42:23 -04:00
Adrien Béraud 37ddd8c7f9 update to version 1.7.3 2018-07-25 16:40:47 -04:00
Adrien Béraud 23057a3082 unit tests: fix race condition 2018-07-25 11:54:28 -04:00
Adrien Béraud dbdd3f8f63 Merge pull request #319 from AmarOk1412/fixLD
dhtrunner: don't use listeners structure without proxy client enabled
2018-07-25 11:32:55 -04:00
Sébastien Blin 751e79a250 dhtrunner: don't use listeners structure without proxy client enabled
The token used to cancel a listener was wrong. Indeed, tokenBGlobal
was used to get the linked listener, not to identify the listener
inside dhtrunner.
2018-07-25 11:28:46 -04:00
Adrien Béraud 7a961ffc51 Merge pull request #318 from atraczyk/master
build: replace WIN32_NATIVE macro with _MSC_VER
2018-07-23 14:01:17 -04:00
Andreas Traczyk bfada958b9 build: replace WIN32_NATIVE macro with _MSC_VER 2018-07-23 13:45:52 -04:00
Sébastien Blin 78d91a8e0d Merge pull request #316 from savoirfairelinux/proxy_server
dhtrunner: decrease max packet handling delay to 500ms
2018-07-13 14:37:09 -04:00
Adrien Béraud cd5dc38a57 dhtrunner: decrease max packet handling delay to 500ms
Allows for faster recovery in case of CPU contention
2018-07-13 14:29:59 -04:00
Sébastien Blin 1ff2eeb220 Merge pull request #313 from savoirfairelinux/proxy_server
Proxy server
2018-06-28 09:16:13 -04:00
Adrien Béraud ffbb9e23ef dht: show usage at the end, print max store size 2018-06-27 11:54:15 -04:00
Adrien Béraud af0a30c9c5 dhtrunner: drop oldest packet if queue is full 2018-06-26 20:41:04 -04:00
Sébastien Blin 97d5e3875d Merge pull request #312 from savoirfairelinux/dht_performance
Dht performance
2018-06-21 11:49:09 -04:00
Adrien Béraud 2509e8bc5c Revert "search: use pointer to SearchNode"
This reverts commit 3a41f2ce56.
2018-06-20 14:50:40 -04:00
Adrien Béraud e349912c07 search: improve canGet performance 2018-06-20 14:50:40 -04:00
Adrien Béraud a1fc266eac dhtrunner: add max rx queue size 2018-06-19 14:10:57 -04:00
Adrien Béraud 3e3679bebf dhtrunner: drop packet if processing took too long 2018-06-18 15:52:20 -04:00
Adrien Béraud e9cf16f361 cmake: allow to enable push notifications without proxy server 2018-06-15 21:09:37 -04:00
Adrien Béraud 3dca4db408 dhtrunner: don't setProxyServer in headers
Don't define setProxyServer in headers since it depends on a configuration option
2018-06-15 12:18:56 -04:00
Sébastien Blin fb6d290692 Merge pull request #309 from savoirfairelinux/searchnode
SearchNode: refresh token
2018-06-13 10:35:51 -04:00
Adrien Béraud 96c60d39ed proxy server: reschedule after using function 2018-06-12 18:19:12 -04:00
Adrien Béraud 3a41f2ce56 search: use pointer to SearchNode 2018-06-12 16:54:12 -04:00
Adrien Béraud 5bd88533fe SearchNode: refresh token in Query, Listen answers 2018-06-12 16:50:15 -04:00
Adrien Béraud c48e24403b Merge pull request #296 from AmarOk1412/resub
proxy: refresh puts and subscriptions when connectivity changes
2018-06-06 12:18:58 -04:00
Sébastien Blin 3cf2c092f2 proxy: remove useless convertion from InfoHash to InfoHash 2018-06-06 12:16:10 -04:00
Sébastien Blin aef8aa545b proxy: reschedule printStatsJob 2018-06-06 12:08:31 -04:00
Sébastien Blin 0c61a605ad proxy: refresh puts and subscriptions when connectivity changes 2018-06-06 11:29:40 -04:00
Sébastien Blin e6b247bead Merge pull request #307 from savoirfairelinux/crypto_tests
test: add crypto unit test
2018-06-06 10:05:10 -04:00
Sébastien Blin 6f1f18f128 Merge pull request #302 from savoirfairelinux/getnodeinfo
dhtrunner: add getNodeInfo()
2018-06-06 10:04:57 -04:00
Adrien Béraud f24458860d test: add crypto unit test 2018-06-06 01:12:18 -04:00
Adrien Béraud 07bed77714 proxy server: schedule task from outside thread 2018-06-05 19:43:56 -04:00
Adrien Béraud aa202b2cd8 dhtrunner: add getNodeInfo()
Allow to retrieve all dht stats in a single API call using
the new method getNodeInfo() and the JSON-serializable
new structure NodeInfo.
2018-06-05 19:43:56 -04:00
Adrien Béraud 4c89ce9d3f Merge pull request #303 from AmarOk1412/getNodeStats
dht_proxy_server: avoid mutex when getting /
2018-05-30 17:01:56 -04:00
Sébastien Blin 709a2c7b7c dht_proxy_server: avoid mutex when getting /
The dht_proxy_server should be always up, so getNodesStats will
be pretty always up-to-date. We can add it into a job and avoid
to wait for this method to finish (and this method use an
internal lock) to have a quick answer about the status of the proxy.

Note: the update is forced during the initialization of the proxy
2018-05-30 14:25:46 -04:00
Adrien Béraud b7e483078a proxy: fix typo 2018-05-25 10:26:58 -04:00
Adrien Béraud b2171d707a network engine: properly apply flag MSG_NOSIGNAL 2018-05-25 10:26:58 -04:00
Adrien Béraud 60db9fd9cd logs: reduce node expiration to debug level 2018-05-25 10:26:58 -04:00
Adrien Béraud e8989f1f79 network engine: handle EPERM 2018-05-24 16:07:16 -04:00
Adrien Béraud b7218bd1c9 Merge pull request #299 from savoirfairelinux/tests
travis: run CI with ASAN
2018-05-24 15:46:56 -04:00
Adrien Béraud 43aab40968 travis: run CI with ASAN 2018-05-24 15:31:52 -04:00
Sébastien Blin ed57b3bfa9 Merge pull request #300 from savoirfairelinux/leak
network engine: fix node leak during destruction
2018-05-24 15:14:22 -04:00
Adrien Béraud 9249f34c47 network engine: fix node leak during destruction 2018-05-24 15:01:23 -04:00
Sébastien Blin 57401e8d53 Merge pull request #297 from savoirfairelinux/logs
log: fix LogMethod copy
2018-05-24 14:55:06 -04:00
Adrien Béraud f5f71a0365 log: fix LogMethod copy 2018-05-24 11:57:12 -04:00
Adrien Béraud 1fe9f2fdb1 dhtnode: default-initialize dht config 2018-05-23 11:21:25 -04:00
Sébastien Blin 59d129b8ff Merge pull request #293 from savoirfairelinux/proxy_fixes
Proxy fixes
2018-05-17 14:47:16 -04:00
Adrien Béraud 5b5349d7ad proxy client: lock proxy info thread, catch detach exceptions 2018-05-17 11:34:25 -04:00
Adrien Béraud b2ba1ca002 proxy server: close socket if no token 2018-05-17 11:33:32 -04:00
Adrien Béraud 8606e87684 proxy client: allow concurrent proxy info requests (#292) 2018-05-11 15:47:24 -04:00
Adrien Béraud e4f640f11b update to version 1.7.2 2018-05-08 15:58:24 -04:00
Adrien Béraud e31d301d90 dhtrunner: run connectivityChanged() even when disconnected 2018-05-08 15:58:24 -04:00
Adrien Béraud 2a15435be3 Merge pull request #291 from AmarOk1412/fixPushIdle
proxy: set status to CONNECTED when receiving a push notifications
2018-05-08 13:46:59 -04:00
Adrien Béraud 44a411ba96 Merge pull request #279 from savoirfairelinux/testsproxy
tests: begin tests for dht_proxy_server
2018-05-08 13:46:42 -04:00
Sébastien Blin bf2f2369b1 proxy: set status to CONNECTED when receiving a push notifications
If a device receives a push notification, we can assume that the
proxy is up and running (because it sends a push notification).

Indeed, if the proxy is declared as disconnected, no operatons will
be executed when a push notification is received. This state is logic
when not using push notifications (because the local node is down),
but here, the status depends more on the proxy than the local node.
2018-05-08 13:35:13 -04:00
Adrien Béraud b8b1f61268 search: announce immediately if synced and not pending/completed 2018-05-07 17:43:31 -04:00
Adrien Béraud 63db2eafd9 dht: print detailed request state in search log 2018-05-07 17:43:31 -04:00
Adrien Béraud 68f52a815d proxy client: refactor (#289)
Factor various ways of sending listen requests.
2018-05-07 14:54:32 -04:00
Adrien Béraud 9f35acf559 dhtnode: continue cmd loop on connectivity change 2018-05-05 18:23:52 -04:00
Adrien Béraud d8e82ca7c4 dhtrunner: check dht before getting public addresses 2018-05-04 21:41:39 -04:00
Adrien Béraud 981bcfc0ba dht: handle error when sending listen 2018-05-02 14:26:24 -04:00
Adrien Béraud 4a49a53222 Revert "network engine: expire node on next run on network failure"
This reverts commit 8489433060.
2018-05-02 11:55:01 -04:00
Sébastien Blin 9f987e24fe Merge pull request #277 from savoirfairelinux/proxy_refresh
proxy client: independently resubscribe push listeners
2018-04-30 10:56:18 -04:00
Sébastien Blin 95f1d59a7f proxy: add comment for refresh job 2018-04-30 10:42:39 -04:00
Adrien Béraud a4fe27223f immessage: fix warning 2018-04-30 10:40:47 -04:00
Adrien Béraud 5408dc6f09 Merge pull request #287 from AmarOk1412/immsgwithdt
immessage: add support for custom datatypes
2018-04-27 13:34:23 -04:00
Adrien Béraud 35d4c1d332 Merge pull request #288 from AmarOk1412/restartListenerWithoutPush
proxy: restart listeners if the proxy server close the connection
2018-04-27 13:33:59 -04:00
Sébastien Blin c583b7284c tests: add testListen for DhtProxyTester 2018-04-26 17:05:23 -04:00
Sébastien Blin 2ce0c5c4c9 proxy: restart listeners if the proxy server close the connection
Detect if the proxy server close the connection linked to a listener and
relaunch listeners
2018-04-26 16:45:14 -04:00
Sébastien Blin 484194c114 immessage: add support for custom datatypes 2018-04-23 17:39:37 -04:00
Adrien Béraud b26b78c049 dhtrunner: fix warnings 2018-04-21 17:57:59 -04:00
Adrien Béraud 522a15c410 proxy client: refresh persistent put with margin 2018-04-21 17:57:59 -04:00
Adrien Béraud 6a981772fd proxy server: cleanup 2018-04-21 17:57:59 -04:00
Adrien Béraud cc37fb50e2 proxy client: take persistent put by reference 2018-04-21 17:44:45 -04:00
Sébastien Blin 7f943e07a5 tests: begin tests for dht_proxy_server
Like dhtrunnertester add testGetPut for the dht_proxy_server.
2018-04-19 13:08:26 -04:00
Adrien Béraud f98658f10f proxy client: independently resubscribe push listeners 2018-04-19 11:32:22 -04:00
120 changed files with 8599 additions and 3474 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
Checks: '-*,clang-diagnostic-*,performance-*,bugprone-*,llvm-*,clang-analyzer-*,misc-*,-llvm-namespace-comment,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-llvm-header-guard,-llvm-include-order,-bugprone-suspicious-string-compare'
+9
View File
@@ -46,6 +46,15 @@ Makefile.in
.kdev4/
*.kdev4
# VSCode
.vscode/*
# Eclipse CDT
.cproject
.project
.autotools
language.settings.xml
# Python
*.pyc
*.stamp
+2 -1
View File
@@ -1,3 +1,4 @@
dist: xenial
sudo: required
services:
@@ -37,7 +38,7 @@ script:
# proxy builds
if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]] && [[ "$OPENDHT_TEST_JOB" != *"opendht.classic"* ]]; then
docker build -t opendht-proxy -f docker/DockerfileTravisProxy .;
options='';
options='-DOPENDHT_SANITIZE=On ';
if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then
options+='-DOPENDHT_PROXY_SERVER=ON ';
else
+81 -41
View File
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.1)
project (opendht)
set (opendht_VERSION_MAJOR 1)
set (opendht_VERSION_MINOR 7.1)
set (opendht_VERSION_MINOR 10.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -16,10 +16,10 @@ option (OPENDHT_SYSTEMD "Install systemd module" OFF)
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restbed and jsoncpp" OFF)
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restbed and jsoncpp" OFF)
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS "Add unit tests executable" OFF)
@@ -47,13 +47,31 @@ if (NOT OPENDHT_ARGON2)
set(OPENDHT_ARGON2 ON)
endif()
endif ()
pkg_search_module(Jsoncpp jsoncpp)
if (Jsoncpp_FOUND)
add_definitions(-DOPENDHT_JSONCPP)
list (APPEND opendht_SOURCES
src/base64.h
src/base64.cpp
)
endif()
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
find_package(Restbed REQUIRED)
pkg_search_module(Jsoncpp jsoncpp)
find_package(Restinio REQUIRED)
if (Restinio_FOUND)
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
find_library(HTTP_PARSER_LIBRARY http_parser)
add_library(http_parser SHARED IMPORTED)
endif()
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
endif()
# Build flags
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD_REQUIRED on)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
if (OPENDHT_SANITIZE)
@@ -63,6 +81,7 @@ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
add_definitions(-DPACKAGE_VERSION="${opendht_VERSION}")
if (OPENDHT_LOG)
add_definitions(-DOPENDHT_LOG=true)
else ()
@@ -87,8 +106,8 @@ endif ()
if (Nettle_INCLUDE_DIRS)
include_directories (SYSTEM "${Nettle_INCLUDE_DIRS}")
endif ()
if (RESTBED_INCLUDE)
include_directories (SYSTEM "${RESTBED_INCLUDE}")
if (Restinio_INCLUDE_DIR)
include_directories (SYSTEM "${Restinio_INCLUDE_DIR}")
endif ()
if (Jsoncpp_INCLUDE_DIRS)
include_directories (SYSTEM "${Jsoncpp_INCLUDE_DIRS}")
@@ -137,6 +156,9 @@ 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
)
list (APPEND opendht_HEADERS
@@ -160,9 +182,16 @@ 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_PYTHON)
message("Indexation enabled since it is required for Python support")
set(OPENDHT_INDEX ON)
endif()
if (OPENDHT_INDEX)
list (APPEND opendht_SOURCES src/indexation/pht.cpp)
list (APPEND opendht_HEADERS include/opendht/indexation/pht.h)
@@ -170,11 +199,9 @@ if (OPENDHT_INDEX)
endif()
if (OPENDHT_PROXY_SERVER)
add_definitions(-DOPENDHT_PROXY_SERVER=true)
add_definitions(-DOPENDHT_PROXY_SERVER)
if (OPENDHT_PROXY_SERVER_IDENTITY)
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=true)
else ()
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=false)
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY)
endif()
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_server.h
@@ -182,38 +209,32 @@ if (OPENDHT_PROXY_SERVER)
list (APPEND opendht_SOURCES
src/dht_proxy_server.cpp
)
if (OPENDHT_PUSH_NOTIFICATIONS)
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=true)
else ()
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=false)
endif ()
else ()
add_definitions(-DENABLE_PROXY_SERVER=false)
endif ()
if (OPENDHT_PROXY_CLIENT)
add_definitions(-DOPENDHT_PROXY_CLIENT=true)
add_definitions(-DOPENDHT_PROXY_CLIENT)
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_client.h
)
list (APPEND opendht_SOURCES
src/dht_proxy_client.cpp
)
else ()
add_definitions(-DOPENDHT_PROXY_CLIENT=false)
endif ()
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_PUSH_NOTIFICATIONS)
message("Using push notification")
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
endif ()
list (APPEND opendht_HEADERS
include/opendht/proxy.h
include/opendht/http.h
)
list (APPEND opendht_SOURCES
src/base64.h
src/base64.cpp
src/http.cpp
)
endif ()
if(OPENDHT_ARGON2)
# make sure argon2 submodule is up to date and initialized
message("Initializing Argon2 submodule")
@@ -238,16 +259,15 @@ if (OPENDHT_STATIC)
${opendht_HEADERS}
)
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht")
if (OPENDHT_LTO)
target_link_libraries(opendht-static -flto -fuse-linker-plugin)
endif ()
if (OPENDHT_ARGON2)
target_include_directories(opendht-static SYSTEM PRIVATE argon2)
else ()
target_link_libraries(opendht-static ${argon2_LIBRARIES})
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_link_libraries(opendht-static ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Restbed_LIBRARIES} ${Jsoncpp_LIBRARIES})
target_link_libraries(opendht-static
PRIVATE ${argon2_LIBRARIES}
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES} ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
@@ -259,16 +279,18 @@ if (OPENDHT_SHARED)
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
if (OPENDHT_LTO)
target_link_libraries(opendht PRIVATE -flto -fuse-linker-plugin)
endif ()
if (OPENDHT_ARGON2)
target_include_directories(opendht SYSTEM PRIVATE argon2)
else ()
target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES})
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_link_libraries(opendht PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Restbed_LIBRARIES} ${Jsoncpp_LIBRARIES})
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
@@ -301,26 +323,44 @@ install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE o
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
# Unit tests
IF(OPENDHT_TESTS)
if (OPENDHT_TESTS)
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
add_executable(opendht_unit_tests
tests/tests_runner.cpp
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
)
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
list (APPEND test_FILES
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
add_executable(opendht_unit_tests
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
target_link_libraries(opendht_unit_tests
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
)
enable_testing()
add_test(TEST opendht_unit_tests)
ENDIF()
endif()
+22 -22
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -21,32 +21,32 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}</ProjectGuid>
<RootNamespace>dhtchat</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -86,14 +86,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -102,14 +102,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -120,16 +120,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -140,16 +140,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
+22 -22
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -21,32 +21,32 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}</ProjectGuid>
<RootNamespace>dhtnode</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -86,14 +86,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -102,14 +102,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -120,16 +120,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -140,16 +140,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
+22 -22
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -21,32 +21,32 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{78443BCD-4689-4007-A246-F8F34B27F561}</ProjectGuid>
<RootNamespace>dhtscanner</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -86,14 +86,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -102,14 +102,14 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -120,16 +120,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\..\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;blake.lib;argon.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\lib\x64</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
@@ -140,16 +140,16 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;$(ProjectDir)contrib\build\include;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source;$(ProjectDir)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4267;4244;4800;4273;4101;</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>crypt32.lib;Argon2Ref.lib;libgnutls.lib;opendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)contrib\build\lib\x64;$(ProjectDir)..\..\lib\x64;$(ProjectDir)vs2015\build</AdditionalLibraryDirectories>
<AdditionalDependencies>restbed.lib;libeay32.lib;ssleay32.lib;crypt32.lib;Argon2Ref.lib;lib_json.lib;libgnutls.lib;libopendht.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\msvc\lib\$(PlatformTarget);$(ProjectDir)..\..\restbed\build\Release;$(ProjectDir)..\..\restbed\dependency\openssl\out32dll;$(ProjectDir)..\..\argon2\vs2015\Argon2Ref\vs2015\build</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
+50 -35
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -19,6 +19,17 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\dht_proxy_client.cpp" />
<ClCompile Include="..\src\network_utils.cpp" />
<ClCompile Include="..\src\op_cache.cpp" />
<ClCompile Include="..\src\peer_discovery.cpp" />
<ClCompile Include="..\src\rng.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\src\thread_pool.cpp" />
<ClCompile Include="wingetopt.c" />
<ClCompile Include="..\src\base64.cpp" />
<ClCompile Include="..\src\callbacks.cpp" />
@@ -39,6 +50,8 @@
<ClCompile Include="..\src\value.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\network_utils.h" />
<ClInclude Include="..\src\thread_pool.h" />
<ClInclude Include="unistd.h" />
<ClInclude Include="wingetopt.h" />
<ClInclude Include="..\include\opendht.h" />
@@ -75,32 +88,32 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{711397CE-E5D5-467D-9457-8716C047E50C}</ProjectGuid>
<RootNamespace>opendht</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
@@ -123,33 +136,34 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(ProjectDir)..\..\</OutDir>
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>opendhtd</TargetName>
<TargetName>libopendht</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(ProjectDir)..\..\</OutDir>
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>opendht</TargetName>
<TargetName>libopendht</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(ProjectDir)..\..\</OutDir>
<TargetName>opendhtd</TargetName>
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<TargetName>libopendht</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)..\..\</OutDir>
<TargetName>opendht</TargetName>
<OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
<TargetName>libopendht</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<SuppressStartupBanner>false</SuppressStartupBanner>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
@@ -160,7 +174,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -168,10 +182,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
@@ -182,7 +197,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -192,11 +207,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\include;..\include;..\include\opendht;..\..\msgpack-c\include;</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -211,7 +226,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
@@ -222,11 +237,11 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(ProjectDir)contrib\build\include;$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)contrib\build\msgpack-c\include;$(ProjectDir)contrib\build\argon2\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)..\include;$(ProjectDir)..\include\opendht;$(ProjectDir)..\..\..\msvc\include;$(ProjectDir)..\..\include;$(ProjectDir)..\..\argon2\include;$(ProjectDir)..\..\msgpack-c\include;$(ProjectDir)..\..\jsoncpp\include;$(ProjectDir)..\..\restbed\source</AdditionalIncludeDirectories>
<PreprocessorDefinitions>OPENDHT_JSONCPP;OPENDHT_PROXY_CLIENT;OPENDHT_PROXY_SERVER;OPENDHT_PUSH_NOTIFICATIONS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4804;4800;4101;4267;4244;4503;4273;</DisableSpecificWarnings>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
<AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<ProgramDataBaseFileName>$(OutDir)lib\$(PlatformTarget)\$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -241,7 +256,7 @@ copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
<OutputFile>$(OutDir)lib\$(PlatformTarget)\$(TargetName)$(TargetExt)</OutputFile>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
<AdditionalLibraryDirectories>
</AdditionalLibraryDirectories>
+36 -4
View File
@@ -53,12 +53,26 @@
<Filter>Source Files\indexation</Filter>
</ClCompile>
<ClCompile Include="wingetopt.c" />
<ClCompile Include="..\src\rng.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\op_cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\dht_proxy_client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\peer_discovery.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\network_utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\thread_pool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\opendht\def.h" />
<ClInclude Include="..\include\opendht\sockaddr.h" />
<ClInclude Include="..\src\net.h" />
<ClInclude Include="..\src\parsed_message.h" />
<ClInclude Include="..\src\base64.h">
<Filter>Source Files</Filter>
</ClInclude>
@@ -139,6 +153,24 @@
</ClInclude>
<ClInclude Include="unistd.h" />
<ClInclude Include="wingetopt.h" />
<ClInclude Include="..\include\opendht\def.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\net.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\parsed_message.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\opendht\sockaddr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\network_utils.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
<ClInclude Include="..\src\thread_pool.h">
<Filter>Header Files\opendht</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
+2
View File
@@ -16,7 +16,9 @@ if ENABLE_TESTS
SUBDIRS += tests
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
+6 -6
View File
@@ -4,7 +4,7 @@
<a id="user-content-opendht-" class="anchor" href="/savoirfairelinux/opendht/blob/master/README.md#opendht-" aria-hidden="true"></a>OpenDHT
</h1>
A lightweight C++11 Distributed Hash Table implementation.
A lightweight C++14 Distributed Hash Table implementation.
OpenDHT provides an easy to use distributed in-memory data store.
Every node in the network can read and write values to the store.
@@ -14,7 +14,7 @@ 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++11 map API
* Clean and powerful C++14 map API
* Python 3 bindings
* REST API
@@ -27,13 +27,13 @@ Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-
#### How-to build a simple client app
```bash
g++ main.cpp -std=c++11 -lopendht -lgnutls
g++ main.cpp -std=c++14 -lopendht -lgnutls
```
## Examples
### C++ example
The `tools` directory includes simple example programs :
* `dhtnode`, a command line tool, mostly used for debuging, allowing to perform operations supported by the library (get, put etc.) with text values.
* `dhtnode`, a command line tool, allowing to run a DHT node and perform operations supported by the library (get, put etc.) with text values.
* `dhtchat`, a very simple IM client working over the dht.
Example program launching a DHT node, connecting to the network and performing some basic operations:
@@ -96,7 +96,7 @@ for r in results:
- msgpack-c 1.2+, used for data serialization.
- GnuTLS 3.3+, used for cryptographic operations.
- Nettle 2.4+, a GnuTLS dependency for crypto.
- (optional) restbed used for the REST API. commit fb84213e170bc171fecd825a8e47ed9f881a12cd (https://github.com/AmarOk1412/restbed/tree/async_read_until)
- (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
@@ -106,7 +106,7 @@ for r in results:
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## License
Copyright (C) 2014-2018 Savoir-faire Linux Inc.
Copyright (C) 2014-2019 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.
-17
View File
@@ -1,17 +0,0 @@
find_path (RESTBED_INCLUDE restbed
HINTS
"/usr/include"
"/usr/local/include"
"/opt/local/include"
)
if (RESTBED_INCLUDE)
message(STATUS "${green}Found Restbed: ${RESTBED_INCLUDE}")
else()
message(FATAL_ERROR "${red}Failed to locate Restbed.}")
endif()
if (RESTBED_INCLUDE)
set(RESTBED_FOUND TRUE)
set(Restbed_LIBRARIES restbed)
endif()
+14
View File
@@ -0,0 +1,14 @@
# header-only does not produce a library
if(NOT Restinio_FOUND)
find_path (Restinio_INCLUDE_DIR restinio
HINTS
"/usr/include"
"/usr/local/include"
"/opt/local/include")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Restinio DEFAULT_MSG Restinio_INCLUDE_DIR)
if (Restinio_INCLUDE_DIR)
set(Restinio_FOUND TRUE)
set(Restinio_INCLUDE_DIRS ${Restinio_INCLUDE_DIR})
endif()
endif()
+55 -55
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 1)
m4_define([opendht_minor_version], 7)
m4_define([opendht_patch_version], 1)
m4_define([opendht_minor_version], 10)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -101,9 +101,55 @@ LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER, test x$proxy_server == xyes)
AC_ARG_ENABLE([push_notifications], AS_HELP_STRING([--enable-push-notifications], [Enable push notifications support]), push_notifications=yes, push_notifications=no)
AM_CONDITIONAL(ENABLE_PUSH_NOTIFICATIONS, test x$push_notifications == xyes)
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes -a x$proxy_server == xyes)
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable proxy client ability]), proxy_client=yes, proxy_client=no)
AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes)
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no)
AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes)
AM_COND_IF([ENABLE_TESTS], [
PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12])
])
AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes | test x$proxy_server == xyes)
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support]))
AS_IF([test "x$with_jsoncpp" != "xno"],
[PKG_CHECK_MODULES([JsonCpp], [jsoncpp >= 1.7.2], [have_jsoncpp=yes], [have_jsoncpp=no])],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS+=" -DOPENDHT_JSONCPP=1"
], [
AC_MSG_NOTICE([Not using JsonCpp])
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
PKG_CHECK_MODULES([Asio], [fmt >= 1.12.2])
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0])
# http_parser has no pkgconfig, instead we check with:
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
dnl Check for Argon2
@@ -135,61 +181,15 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER, test x$proxy_server == xyes)
AC_ARG_ENABLE([push_notifications], AS_HELP_STRING([--enable-push-notifications], [Enable push notifications support]), push_notifications=yes, push_notifications=no)
AM_CONDITIONAL(ENABLE_PUSH_NOTIFICATIONS, test x$push_notifications == xyes)
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes)
AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable proxy client ability]), proxy_client=yes, proxy_client=no)
AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes)
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_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([ENABLE_PROXY_SERVER], [
AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files]))
PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.2])
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true -ljsoncpp -lrestbed"
], [
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false"
AM_COND_IF([HAVE_DOXYGEN], [
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
])
AM_COND_IF([ENABLE_PUSH_NOTIFICATIONS], [
CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true"
], [
CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false"
])
AC_ARG_ENABLE([proxy_server_identity], AS_HELP_STRING([--enable-proxy-server-identity],
[Enable proxy server ability]), proxy_server_identity=yes, proxy_server_identity=no)
AM_CONDITIONAL(ENABLE_PROXY_SERVER_IDENTITY, test x$proxy_server_identity == xyes -a x$proxy_server == xyes)
AM_COND_IF([ENABLE_PROXY_SERVER_IDENTITY], [
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=true"
], [
CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=false"
])
AM_COND_IF([ENABLE_PROXY_CLIENT], [
CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=true"
], [
CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=false"
])
AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes | test x$proxy_server == xyes)
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_LIB(restbed, exit,, AC_MSG_ERROR([Missing restbed files]))
PKG_CHECK_MODULES([Jsoncpp], [jsoncpp >= 1.7.4])
CPPFLAGS="${CPPFLAGS} ${Jsoncpp_CFLAGS}"
LDFLAGS="${LDFLAGS} ${Jsoncpp_LIBS} -lrestbed"
], [])
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no)
AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes)
AM_COND_IF([ENABLE_TESTS], [
PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12])
])
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, ".")
@@ -202,6 +202,6 @@ AM_COND_IF([USE_CYTHON], [
AC_CONFIG_FILES([Makefile
src/Makefile
tools/Makefile
tests/Makefile
tests/Makefile
opendht.pc])
AC_OUTPUT
+57 -35
View File
@@ -1,22 +1,24 @@
.TH DHTNODE 1 2016-07-29
.TH DHTNODE 1 2019-06-08
.SH NAME
.B dhtnode
- a simple OpenDHT command line node runner.
.SH SYNOPSIS
.B dhtnode [-h]
.B dhtnode [-v [-l \fIlogfile\fP]] [-i] [-d] [-n \fInetwork_id\fP] [-p \fIlocal_port\fP] [-b \fIbootstrap_host\fP[:\fIport\fP]]
.B dhtnode
[\fB\-h\fR]
[\fB\-v\fR [\fB\-l\fR \fIlogfile\fR] [\fB\-L\fR]]
[\fB\-i\fR [\fB\-\-save\-identity\fR \fIfile\fR]]
[\fB\-d\fR] [\fB\-s\fR]
[\fB\-n\fR \fInetwork_id\fR]
[\fB\-p\fR \fIlocal_port\fR]
[\fB\-b\fR \fIbootstrap_host\fR[:\fIport\fR]]
[\fB\-\-certificate\fR \fIfile\fR]
[\fB\-\-privkey\fR \fIfile\fR]
[\fB\-\-privkey\-password\fR \fIpassword\fR]
[\fB\-\-proxyserver\fR \fIport\fR]
[\fB\-\-proxyclient\fR \fIserver\fR]
.SH DESCRIPTION
This program runs a simple OpenDHT node in an interactive way. If you rather
want to run the node in daemon mode, option \fB'-d'\fP is provided. When running
in the interactive shell, you benefit from the readline capabilities for writing
your commands such as command history. Here are the available commands in the
interactive shell:
Runs an OpenDHT node, with a CLI (default) or as a daemon (with \fB'-d'\fP or \fB'-s'\fP).
Commands available in the interactive shell are:
.EE
h, help Print this help message.
q, quit Quit the program.
@@ -37,43 +39,63 @@ interactive shell:
private key.
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
its public key (if found).
.SH OPTIONS
.TP
\fB-h\fP
\fB\-h\fP
Prints some help.
.TP
\fB-v\fP
Enable the verbose mode (log to stdout by default)
\fB\-v\fP
Enable the verbose mode (log to stdout/stderr by default)
.TP
\fB-l\fP \fIlog_file\fP
Write log to file instead of stdout
\fB\-l\fP \fIlog_file\fP
Write log to file instead of stdout/stderr
.TP
\fB-i\fP
\fB\-L\fP
Write log to syslog instead of stdout/stderr
.TP
\fB\-i\fP
Generate cryptographic identity for the node.
.TP
\fB-d\fP
\fB\-\-save\-identity\fP \fIfile\fP
Save generated identity (certificate and private key) to given file prefix.
.TP
\fB\-\-certificate\fP \fIfile\fP
Load identity certificate from given file.
.TP
\fB\-\-privkey\fP \fIfile\fP
Load identity private key from given file.
.TP
\fB\-\-privkey\-password\fP \fIpassword\fP
Password to use for private key encryption or decryption (optional).
.TP
\fB\-d\fP
Run the program in daemon mode (will fork in the background).
.TP
\fB-n\fP \fInetwork_id\fP
\fB\-s\fP
Run the program in service mode (non\-forking daemon).
.TP
\fB\-D\fP
Enables multicast automatic local peer discovery.
.TP
\fB\-f\fP \fIfile\fP
Specify a file path to persist/load the node state.
.TP
\fB\-n\fP \fInetwork_id\fP
Specify the network id. This let you connect to distinct networks and prevents
the merge of two different networks (available since OpenDHT v0.6.1).
.TP
\fB-p\fP \fIlocal_port\fP
Use port \fIlocal_port\fP for the program to bind to.
\fB\-p\fP \fIlocal_port\fP
Use UDP port \fIlocal_port\fP for the program to bind to.
.TP
\fB-b\fP \fIbootstrap_host\fP[:\fIport\fP]
\fB\-b\fP \fIbootstrap_host\fP[:\fIport\fP]
The program needs to be given a node to connect to the network. You use this
option to provide the ip address of that node.
.TP
\fB\-\-proxyserver\fP \fIlocal_port\fP
Run a proxy server bound to this DHT node on HTTP port \fIlocal_port\fP
.TP
\fB\-\-proxyclient\fP \fIserver\fP
Run this DHT node in proxy client mode, and connect to \fIserver\fP
.SH AUTHORS
.TP
Program written by
+39 -12
View File
@@ -1,18 +1,45 @@
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 libasio-dev libssl-dev python3-setuptools && apt-get clean
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 \
libasio-dev libssl-dev python3-setuptools \
&& apt-get clean
# build restbed from sources
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
&& cd restbed && mkdir build && cd build \
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
&& make -j8 install \
&& cd .. && rm -rf restbed
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
RUN apt-get update && apt-get install -y \
python3-pip libasio-dev
RUN pip3 install --upgrade cmake
#install conan & add restinio remotes
RUN pip3 install conan && \
conan remote add stiffstream https://api.bintray.com/conan/stiffstream/public && \
conan remote add public-conan https://api.bintray.com/conan/bincrafters/public-conan
#setup restinio docker project
RUN mkdir restinio-conan
COPY conan/restinio/conanfile.txt restinio-conan/conanfile.txt
COPY conan/restinio/conanfile.py restinio-conan/conanfile.py
#build restinio from source
RUN echo "*** Installing RESTinio & dependencies ***" \
&& cd restinio-conan \
&& conan source . \
&& conan install -o restinio:boost_libs=none --build=missing . \
&& conan package . -pf /usr/local \
&& cd ../ && rm -rf restinio*
#installing dependencies
RUN echo "*** Installing asio & fmt dependencies ***" \
&& cp -r ~/.conan/data/asio/*/bincrafters/stable/package/*/include/* /usr/local/include/ \
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/lib/* /usr/local/lib/ \
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/include/* /usr/local/include/
#build http_parser fork
RUN echo "*** Building http_parser dependency for custom HTTP methods ***" \
&& git clone https://github.com/eao197/http-parser.git \
&& cd http-parser && make -j8 && make install PREFIX=/usr \
&& cd ../ && rm -rf restinio-conan/
#build msgpack from source
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
+36 -13
View File
@@ -1,23 +1,46 @@
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 python3-setuptools libcppunit-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
&& 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 python3-setuptools libcppunit-dev python3-pip \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
ENV CXX c++
# build restbed from sources
RUN git clone --recursive https://github.com/corvusoft/restbed.git \
&& cd restbed && mkdir build && cd build \
&& cmake -DBUILD_TESTS=NO -DBUILD_EXAMPLES=NO -DBUILD_SSL=NO -DBUILD_SHARED=YES -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib .. \
&& make -j8 install \
&& cd .. && rm -rf restbed
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
RUN apt-get update && apt-get install -y \
python3-pip libasio-dev
RUN pip3 install --upgrade cmake
#install conan & add restinio remotes
RUN pip3 install conan && \
conan remote add stiffstream https://api.bintray.com/conan/stiffstream/public && \
conan remote add public-conan https://api.bintray.com/conan/bincrafters/public-conan
#setup restinio docker project
RUN mkdir restinio-conan
COPY conan/restinio/conanfile.txt restinio-conan/conanfile.txt
COPY conan/restinio/conanfile.py restinio-conan/conanfile.py
#build restinio from source
RUN echo "*** Installing RESTinio & dependencies ***" \
&& cd restinio-conan \
&& conan source . \
&& conan install -o restinio:boost_libs=none --build=missing . \
&& conan package . -pf /usr/local \
&& cd ../ && rm -rf restinio*
#installing dependencies
RUN echo "*** Installing asio & fmt dependencies ***" \
&& cp -r ~/.conan/data/asio/*/bincrafters/stable/package/*/include/* /usr/local/include/ \
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/lib/* /usr/local/lib/ \
&& cp -r ~/.conan/data/fmt/*/bincrafters/stable/package/*/include/* /usr/local/include/
#build http_parser fork
RUN echo "*** Building http_parser dependency for custom HTTP methods ***" \
&& git clone https://github.com/eao197/http-parser.git \
&& cd http-parser && make -j8 && make install PREFIX=/usr \
&& cd ../ && rm -rf restinio-conan/
#build msgpack from source
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz \
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
&& tar -xzf msgpack-2.1.5.tar.gz \
&& cd msgpack-2.1.5 && mkdir build && cd build \
&& cmake -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX=/usr .. \
&& make -j8 && make install \
&& cd ../.. && rm -rf msgpack-2.1.5 msgpack-2.1.5.tar.gz
+59
View File
@@ -0,0 +1,59 @@
from conans import ConanFile, CMake, tools
import os
class SobjectizerConan(ConanFile):
name = "restinio"
version = "0.5.1"
license = "BSD-3-Clause"
url = "https://github.com/Stiffstream/restinio-conan"
description = (
"RESTinio is a header-only C++14 library that gives you "
"an embedded HTTP/Websocket server."
)
settings = "os", "compiler", "build_type", "arch"
options = {'boost_libs': ['none', 'static', 'shared']}
default_options = {'boost_libs': 'none'}
generators = "cmake"
source_subfolder = "restinio"
build_policy = "missing"
def requirements(self):
self.requires.add("http-parser/2.8.1@bincrafters/stable")
self.requires.add("fmt/5.3.0@bincrafters/stable")
if self.options.boost_libs == "none":
self.requires.add("asio/1.12.2@bincrafters/stable")
else:
self.requires.add("boost/1.69.0@conan/stable")
if self.options.boost_libs == "shared":
self.options["boost"].shared = True
else:
self.options["boost"].shared = False
def source(self):
source_url = "https://bitbucket.org/sobjectizerteam/restinio/downloads"
tools.get("{0}/restinio-{1}.zip".format(source_url, self.version))
extracted_dir = "restinio-" + self.version
os.rename(extracted_dir, self.source_subfolder)
def _configure_cmake(self):
cmake = CMake(self)
cmake.definitions['RESTINIO_INSTALL'] = True
cmake.definitions['RESTINIO_FIND_DEPS'] = False
cmake.definitions['RESTINIO_USE_BOOST_ASIO'] = self.options.boost_libs
cmake.configure(source_folder = self.source_subfolder + "/dev/restinio")
return cmake
def package(self):
cmake = self._configure_cmake()
self.output.info(cmake.definitions)
cmake.install()
def package_info(self):
self.info.header_only()
if self.options.boost_libs != "none":
self.cpp_info.defines.append("RESTINIO_USE_BOOST_ASIO")
+11
View File
@@ -0,0 +1,11 @@
[requires]
restinio/0.5.1@stiffstream/stable
[generators]
cmake
[options]
[imports]
bin, *.dll -> ./bin # Copies all dll files from packages bin folder to my "bin" folder
lib, *.dylib* -> ./bin # Copies all dylib files from packages lib folder to my "bin" folder
+2 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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,9 @@
#pragma once
#include "opendht/dhtrunner.h"
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
#include "opendht/dht_proxy_server.h"
#endif
#include "opendht/log.h"
#include "opendht/default_types.h"
#ifdef OPENDHT_INDEXATION
#include "opendht/indexation/pht.h"
+42 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
@@ -27,9 +27,9 @@
#include <memory>
#include <functional>
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif //OPENDHT_PROXY_SERVER
#endif
namespace dht {
@@ -51,15 +51,37 @@ struct OPENDHT_PUBLIC NodeStats {
incoming_nodes {0};
unsigned table_depth {0};
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
std::string toString() const;
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
NodeStats() {};
explicit NodeStats(const Json::Value& v);
#endif //OPENDHT_PROXY_SERVER
#endif
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth)
};
struct OPENDHT_PUBLIC NodeInfo {
InfoHash id;
InfoHash node_id;
NodeStats ipv4;
NodeStats ipv6;
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
NodeInfo() {};
explicit NodeInfo(const Json::Value& v);
#endif
MSGPACK_DEFINE_MAP(id, node_id, ipv4, ipv6)
};
/**
@@ -67,20 +89,23 @@ struct OPENDHT_PUBLIC NodeStats {
*/
struct OPENDHT_PUBLIC Config {
/** DHT node ID */
InfoHash node_id;
InfoHash node_id {};
/**
* DHT network ID. A node will only talk with other nodes having
* the same network ID.
* Network ID 0 (default) represents the main public network.
*/
NetId network;
NetId network {0};
/** For testing purposes only, enables bootstrap mode */
bool is_bootstrap;
bool is_bootstrap {false};
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
bool maintain_storage;
bool maintain_storage {false};
/** 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 {};
};
/**
@@ -88,8 +113,8 @@ struct OPENDHT_PUBLIC Config {
*/
struct OPENDHT_PUBLIC SecureDhtConfig
{
Config node_config;
crypto::Identity id;
Config node_config {};
crypto::Identity id {};
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
@@ -106,8 +131,8 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
@@ -117,10 +142,10 @@ typedef bool (*FilterRaw)(const Value&, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
}
+82 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -66,7 +66,7 @@ using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certific
*/
struct OPENDHT_PUBLIC PublicKey
{
PublicKey() {}
PublicKey();
/**
* Takes ownership of an existing gnutls_pubkey.
@@ -86,8 +86,16 @@ struct OPENDHT_PUBLIC PublicKey
PublicKey& operator=(PublicKey&& o) noexcept;
/**
* Get public key fingerprint
*/
InfoHash getId() const;
/**
* Get public key long fingerprint
*/
PkId getLongId() const;
bool checkSignature(const Blob& data, const Blob& signature) const;
Blob encrypt(const Blob&) const;
@@ -107,7 +115,9 @@ struct OPENDHT_PUBLIC PublicKey
void msgpack_unpack(msgpack::object o);
gnutls_pubkey_t pk {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_pubkey_t pk {nullptr};
private:
PublicKey(const PublicKey&) = delete;
PublicKey& operator=(const PublicKey&) = delete;
@@ -133,6 +143,7 @@ struct OPENDHT_PUBLIC PrivateKey
PrivateKey(const Blob& import, const std::string& password = {});
~PrivateKey();
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
Blob serialize(const std::string& password = {}) const;
@@ -177,7 +188,7 @@ class OPENDHT_PUBLIC RevocationList
public:
RevocationList();
RevocationList(const Blob& b);
RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
RevocationList(RevocationList&& o) noexcept : crl(o.crl) { o.crl = nullptr; }
~RevocationList();
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
@@ -245,14 +256,48 @@ private:
RevocationList& operator=(const RevocationList&) = delete;
};
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
class OPENDHT_PUBLIC CertificateRequest {
public:
CertificateRequest();
CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
o.request = nullptr;
}
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
~CertificateRequest();
void setName(const std::string& name);
void setUID(const std::string& name);
void setAltName(NameType type, const std::string& name);
std::string getName() const;
std::string getUID() const;
void sign(const PrivateKey& key, const std::string& password = {});
bool verify() const;
Blob pack() const;
gnutls_x509_crq_t get() const { return request; }
private:
CertificateRequest(const CertificateRequest& o) = delete;
CertificateRequest& operator=(const CertificateRequest& o) = delete;
gnutls_x509_crq_t request {nullptr};
};
struct OPENDHT_PUBLIC Certificate {
Certificate() {}
Certificate() noexcept {}
/**
* Take ownership of existing gnutls structure
*/
Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
@@ -368,6 +413,7 @@ struct OPENDHT_PUBLIC Certificate {
/** Same as getPublicKey().getId() */
InfoHash getId() const;
/** Same as getPublicKey().getLongId() */
PkId getLongId() const;
/** Read certificate Common Name (CN) */
@@ -382,8 +428,6 @@ struct OPENDHT_PUBLIC Certificate {
/** Read certificate issuer User ID (UID) */
std::string getIssuerUID() const;
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
/** Read certificate alternative names */
std::vector<std::pair<NameType, std::string>> getAltNames() const;
@@ -404,12 +448,25 @@ struct OPENDHT_PUBLIC Certificate {
std::string print() const;
/**
* As a CA, revoke a certificate, adding it to
* the attached Certificate Revocation List (CRL)
*/
void revoke(const PrivateKey&, const Certificate&);
/**
* Get the list of certificates revoked as as CA.
*/
std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
/**
* Attach existing revocation list.
*/
void addRevocationList(RevocationList&&);
void addRevocationList(std::shared_ptr<RevocationList>);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
static Certificate generate(const CertificateRequest& request, const Identity& ca);
gnutls_x509_crt_t getCopy() const {
if (not cert)
@@ -450,7 +507,9 @@ struct OPENDHT_PUBLIC Certificate {
return {crts, crls};
}
gnutls_x509_crt_t cert {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
private:
Certificate(const Certificate&) = delete;
@@ -478,10 +537,10 @@ struct OPENDHT_PUBLIC TrustList
};
TrustList();
TrustList(TrustList&& o) : trust(std::move(o.trust)) {
TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
o.trust = nullptr;
}
TrustList& operator=(TrustList&& o);
TrustList& operator=(TrustList&& o) noexcept;
~TrustList();
void add(const Certificate& crt);
void add(const RevocationList& crl);
@@ -491,7 +550,7 @@ struct OPENDHT_PUBLIC TrustList
private:
TrustList(const TrustList& o) = delete;
TrustList& operator=(const TrustList& o) = delete;
gnutls_x509_trust_list_t trust;
gnutls_x509_trust_list_t trust {nullptr};
};
template <class T>
@@ -508,9 +567,13 @@ public:
~secure_vector() { clean(); }
static secure_vector<T> getRandom(size_t size) {
secure_vector<T> ret(size/sizeof(T));
secure_vector<T> ret(size);
crypto::random_device rdev;
#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
std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
return ret;
}
@@ -585,12 +648,13 @@ using SecureBlob = secure_vector<uint8_t>;
* If not set, the generated certificate will be a self-signed CA.
* @param key_length stength of the generated private key (bits).
*/
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
/**
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
+10 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
public:
static const ValueType TYPE;
DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
DhtMessage(const std::string& s = {}, const Blob& msg = {}) : service(s), data(msg) {}
std::string getService() const {
return service;
@@ -48,7 +48,7 @@ public:
static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr&);
static Value::Filter ServiceFilter(std::string s);
static Value::Filter ServiceFilter(const std::string& s);
/** print value for debugging */
friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
@@ -114,6 +114,10 @@ public:
ImMessage() {}
ImMessage(dht::Value::Id id, std::string&& m, long d = 0)
: id(id), msg(std::move(m)), date(d) {}
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, long d = 0)
: id(id), msg(std::move(m)), datatype(std::move(dt)), date(d) {}
ImMessage(dht::Value::Id id, std::string &&dt, std::string &&m, std::map<std::string, std::string> &&md, long d = 0)
: id(id), msg(std::move(m)), datatype(std::move(dt)), metadatas(std::move(md)), date(d) {}
virtual void unpackValue(const Value& v) override {
to = v.recipient;
@@ -123,10 +127,12 @@ public:
dht::InfoHash to;
dht::Value::Id id {0};
std::string msg;
std::string datatype;
std::map<std::string, std::string> metadatas;
long date {0};
ImStatus status {ImStatus::NONE};
MSGPACK_DEFINE_MAP(id, msg, date, status)
MSGPACK_DEFINE_MAP(id, msg, date, status, datatype, metadatas)
};
class OPENDHT_PUBLIC TrustRequest : public EncryptedValue<TrustRequest>
+76 -75
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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,27 +68,29 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(const int& s, const int& s6, Config config);
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {});
virtual ~Dht();
/**
* Get the ID of the node.
*/
inline const InfoHash& getNodeId() const { return myid; }
inline const InfoHash& getNodeId() const override { return myid; }
/**
* Get the current status of the node for the given family.
*/
NodeStatus getStatus(sa_family_t af) const;
NodeStatus getStatus(sa_family_t af) const override;
NodeStatus getStatus() const {
NodeStatus getStatus() const override {
return std::max(getStatus(AF_INET), getStatus(AF_INET6));
}
net::DatagramSocket* getSocket() const override { return network_engine.getSocket(); };
/**
* Performs final operations before quitting.
*/
void shutdown(ShutdownCallback cb);
void shutdown(ShutdownCallback cb) override;
/**
* Returns true if the node is running (have access to an open socket).
@@ -96,12 +98,12 @@ public:
* af: address family. If non-zero, will return true if the node
* is running for the provided family.
*/
bool isRunning(sa_family_t af = 0) const;
bool isRunning(sa_family_t af = 0) const override;
virtual void registerType(const ValueType& type) {
virtual void registerType(const ValueType& type) override {
types.registerType(type);
}
const ValueType& getType(ValueType::Id type_id) const {
const ValueType& getType(ValueType::Id type_id) const override {
return types.getType(type_id);
}
@@ -110,18 +112,18 @@ public:
* The node is not pinged, so this should be
* used to bootstrap efficiently from previously known nodes.
*/
void insertNode(const InfoHash& id, const SockAddr&);
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) {
void insertNode(const InfoHash& id, const SockAddr&) override;
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) override {
insertNode(id, SockAddr(sa, salen));
}
void insertNode(const NodeExport& n) {
void insertNode(const NodeExport& n) override {
insertNode(n.id, SockAddr(n.ss, n.sslen));
}
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={}) override;
time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr&);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
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));
}
@@ -135,14 +137,14 @@ public:
cb and donecb won't be called again afterward.
* @param f a filter function used to prefilter values.
*/
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {});
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) {
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override;
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/**
@@ -155,20 +157,20 @@ public:
* @param q a query used to filter values on the remotes before they send a
* response.
*/
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {});
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) {
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) override;
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
}
/**
* Get locally stored data for the given hash.
*/
std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const;
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override;
/**
* Get locally stored data for the given key and value id.
*/
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override;
/**
* Announce a value on all available protocols (IPv4, IPv6).
@@ -180,12 +182,12 @@ public:
Sp<Value>,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false);
bool permanent = false) override;
void put(const InfoHash& key,
const Sp<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
put(key, v, bindDoneCb(cb), created, permanent);
}
@@ -194,7 +196,7 @@ public:
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
}
@@ -202,7 +204,7 @@ public:
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
}
@@ -210,18 +212,18 @@ public:
/**
* Get data currently being put at the given hash.
*/
std::vector<Sp<Value>> getPut(const InfoHash&);
std::vector<Sp<Value>> getPut(const InfoHash&) const override;
/**
* Get data currently being put at the given hash with the given id.
*/
Sp<Value> getPut(const InfoHash&, const Value::Id&);
Sp<Value> getPut(const InfoHash&, const Value::Id&) const override;
/**
* Stop any put/announce operation at the given location,
* for the value with the given id.
*/
bool cancelPut(const InfoHash&, const Value::Id&);
bool cancelPut(const InfoHash&, const Value::Id&) override;
/**
* Listen on the network for any changes involving a specified hash.
@@ -230,28 +232,28 @@ public:
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={});
size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override;
virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) {
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) {
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual bool cancelListen(const InfoHash&, size_t token);
bool cancelListen(const InfoHash&, size_t token) override;
/**
* Inform the DHT of lower-layer connectivity changes.
* This will cause the DHT to assume a public IP address change.
* The DHT will recontact neighbor nodes, re-register for listen ops etc.
*/
void connectivityChanged(sa_family_t);
void connectivityChanged() {
void connectivityChanged(sa_family_t) override;
void connectivityChanged() override {
reported_addr.clear();
connectivityChanged(AF_INET);
connectivityChanged(AF_INET6);
@@ -261,29 +263,32 @@ public:
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
std::vector<NodeExport> exportNodes();
std::vector<NodeExport> exportNodes() const override;
std::vector<ValuesExport> exportValues() const;
void importValues(const std::vector<ValuesExport>&);
std::vector<ValuesExport> exportValues() const override;
void importValues(const std::vector<ValuesExport>&) override;
NodeStats getNodesStats(sa_family_t af) const;
void saveState(const std::string& path) const;
void loadState(const std::string& path);
std::string getStorageLog() const;
std::string getStorageLog(const InfoHash&) const;
NodeStats getNodesStats(sa_family_t af) const override;
std::string getRoutingTablesLog(sa_family_t) const;
std::string getSearchesLog(sa_family_t) const;
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
std::string getStorageLog() const override;
std::string getStorageLog(const InfoHash&) const override;
void dumpTables() const;
std::vector<unsigned> getNodeMessageStats(bool in = false) {
std::string getRoutingTablesLog(sa_family_t) const override;
std::string getSearchesLog(sa_family_t) const override;
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const override;
void dumpTables() const override;
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
return network_engine.getNodeMessageStats(in);
}
/**
* Set the in-memory storage limit in bytes
*/
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) {
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
max_store_size = limit;
}
@@ -291,13 +296,13 @@ public:
* Returns the total memory usage of stored values and the number
* of stored values.
*/
std::pair<size_t, size_t> getStoreSize() const {
std::pair<size_t, size_t> getStoreSize() const override {
return {total_store_size, total_values};
}
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
void pushNotificationReceived(const std::map<std::string, std::string>&) {}
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
void resubscribe(unsigned) {}
private:
@@ -324,10 +329,10 @@ private:
static constexpr unsigned LISTEN_NODES {4};
/* The maximum number of hashes we're willing to track. */
static constexpr unsigned MAX_HASHES {16384};
static constexpr unsigned MAX_HASHES {64 * 1024};
/* The maximum number of searches we keep data about. */
static constexpr unsigned MAX_SEARCHES {16384};
static constexpr unsigned MAX_SEARCHES {64 * 1024};
static constexpr std::chrono::minutes MAX_STORAGE_MAINTENANCE_EXPIRE_TIME {10};
@@ -359,13 +364,6 @@ private:
// registred types
TypeStore types;
// are we a bootstrap node ?
// note: Any running node can be used as a bootstrap node.
// Only nodes running only as bootstrap nodes should
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
// the stuff
RoutingTable buckets4 {};
RoutingTable buckets6 {};
@@ -400,6 +398,15 @@ private:
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
std::string persistPath;
// are we a bootstrap node ?
// note: Any running node can be used as a bootstrap node.
// Only nodes running only as bootstrap nodes should
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
void rotateSecrets();
Blob makeToken(const SockAddr&, bool old) const;
@@ -409,7 +416,9 @@ private:
// Storage
void storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t tid, Query&& = {});
bool storageStore(const InfoHash& id, const Sp<Value>& value, time_point created, const SockAddr& sa = {});
bool storageStore(const InfoHash& id, const Sp<Value>& value, time_point created, const SockAddr& sa = {}, bool permanent = false);
bool storageErase(const InfoHash& id, Value::Id vid);
bool storageRefresh(const InfoHash& id, Value::Id vid);
void expireStore();
void expireStorage(InfoHash h);
void expireStore(decltype(store)::iterator);
@@ -423,23 +432,15 @@ private:
* nodes.
*/
void dataPersistence(InfoHash id);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
// Buckets
RoutingTable& buckets(sa_family_t af) { return af == AF_INET ? buckets4 : buckets6; }
const RoutingTable& buckets(sa_family_t af) const { return af == AF_INET ? buckets4 : buckets6; }
Bucket* findBucket(const InfoHash& id, sa_family_t af) {
RoutingTable::iterator b;
switch (af) {
case AF_INET:
b = buckets4.findBucket(id);
return b == buckets4.end() ? nullptr : &(*b);
case AF_INET6:
b = buckets6.findBucket(id);
return b == buckets6.end() ? nullptr : &(*b);
default:
return nullptr;
}
auto& b = buckets(af);
auto it = b.findBucket(id);
return it == b.end() ? nullptr : &(*it);
}
const Bucket* findBucket(const InfoHash& id, sa_family_t af) const {
return const_cast<Dht*>(this)->findBucket(id, af);
@@ -464,10 +465,10 @@ private:
* Low-level method that will perform a search on the DHT for the specified
* infohash (id), using the specified IP version (IPv4 or IPv6).
*/
Sp<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, Query q = {});
Sp<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, const Sp<Query>& q = {});
void announce(const InfoHash& id, sa_family_t af, Sp<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
size_t listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filter f = Value::AllFilter(), const Sp<Query>& q = {});
size_t listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filter f = {}, const Sp<Query>& q = {});
/**
* Refill the search with good nodes if possible.
+22 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -23,9 +23,14 @@
namespace dht {
namespace net {
class DatagramSocket;
}
class OPENDHT_PUBLIC DhtInterface {
public:
DhtInterface() = default;
DhtInterface(const Logger& l) : DHT_LOG(l) {};
virtual ~DhtInterface() = default;
// [[deprecated]]
@@ -39,8 +44,10 @@ public:
virtual NodeStatus getStatus(sa_family_t af) const = 0;
virtual NodeStatus getStatus() const = 0;
virtual net::DatagramSocket* getSocket() const { return {}; };
/**
* Get the ID of the node.
* Get the ID of the DHT node.
*/
virtual const InfoHash& getNodeId() const = 0;
@@ -72,7 +79,7 @@ public:
virtual void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={}) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr&) = 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;
/**
@@ -106,7 +113,7 @@ public:
/**
* Get locally stored data for the given hash.
*/
virtual std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const = 0;
virtual std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const = 0;
/**
* Get locally stored data for the given key and value id.
@@ -143,12 +150,12 @@ public:
/**
* Get data currently being put at the given hash.
*/
virtual std::vector<Sp<Value>> getPut(const InfoHash&) = 0;
virtual std::vector<Sp<Value>> getPut(const InfoHash&) const = 0;
/**
* Get data currently being put at the given hash with the given id.
*/
virtual Sp<Value> getPut(const InfoHash&, const Value::Id&) = 0;
virtual Sp<Value> getPut(const InfoHash&, const Value::Id&) const = 0;
/**
* Stop any put/announce operation at the given location,
@@ -181,7 +188,7 @@ public:
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
virtual std::vector<NodeExport> exportNodes() = 0;
virtual std::vector<NodeExport> exportNodes() const = 0;
virtual std::vector<ValuesExport> exportValues() const = 0;
virtual void importValues(const std::vector<ValuesExport>&) = 0;
@@ -214,13 +221,18 @@ public:
/**
* Enable or disable logging of DHT internal messages
*/
virtual void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG)
{
DHT_LOG.DEBUG = debug;
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
DHT_LOG.DBG = debug;
DHT_LOG.WARN = warn;
DHT_LOG.ERR = error;
}
virtual void setLogger(const Logger& l) {
DHT_LOG.DBG = l.DBG;
DHT_LOG.WARN = l.WARN;
DHT_LOG.ERR = l.ERR;
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
@@ -238,8 +250,6 @@ public:
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
bool logFilerEnable_ {};
InfoHash logFiler_ {};
Logger DHT_LOG;
};
+85 -47
View File
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 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>
*
* 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
@@ -17,42 +18,51 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_CLIENT
#pragma once
#include <functional>
#include <thread>
#include <mutex>
#include "callbacks.h"
#include "def.h"
#include "dht_interface.h"
#include "scheduler.h"
#include "proxy.h"
namespace restbed {
class Request;
}
#include <restinio/all.hpp>
#include <http_parser.h>
#include <json/json.h>
#include "http.h"
#include <chrono>
#include <vector>
#include <functional>
namespace Json {
class Value;
}
namespace dht {
namespace http {
class Client;
}
class SearchCache;
namespace dht {
class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface {
public:
DhtProxyClient();
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "");
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "",
std::shared_ptr<dht::Logger> logger = {});
restinio::http_header_fields_t initHeaderFields();
virtual void setPushNotificationToken(const std::string& token) {
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#else
(void) token;
#endif
}
@@ -174,6 +184,10 @@ public:
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/*
* This function relies on the cache implementation.
* It means that there are no true cancel here, it keeps the caching in higher priority.
*/
virtual bool cancelListen(const InfoHash& key, size_t token);
/**
@@ -182,12 +196,11 @@ public:
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification);
time_point periodic(const uint8_t*, size_t, const SockAddr&);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
time_point periodic(const uint8_t*, size_t, SockAddr);
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
return periodic(buf, buflen, SockAddr(from, fromlen));
}
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
* @param key the key for which to query data for.
@@ -206,12 +219,12 @@ public:
/**
* Get data currently being put at the given hash.
*/
std::vector<Sp<Value>> getPut(const InfoHash&);
std::vector<Sp<Value>> getPut(const InfoHash&) const;
/**
* Get data currently being put at the given hash with the given id.
*/
Sp<Value> getPut(const InfoHash&, const Value::Id&);
Sp<Value> getPut(const InfoHash&, const Value::Id&) const;
/**
* Stop any put/announce operation at the given location,
@@ -228,7 +241,7 @@ public:
return types.getType(type_id);
}
std::vector<Sp<Value>> getLocal(const InfoHash& k, Value::Filter filter) const;
std::vector<Sp<Value>> getLocal(const InfoHash& k, const Value::Filter& filter) const;
Sp<Value> getLocalById(const InfoHash& k, Value::Id id) const;
/**
@@ -239,7 +252,7 @@ public:
void insertNode(const InfoHash&, const sockaddr*, socklen_t) { }
void insertNode(const NodeExport&) { }
std::pair<size_t, size_t> getStoreSize() const { return {}; }
std::vector<NodeExport> exportNodes() { return {}; }
std::vector<NodeExport> exportNodes() const { return {}; }
std::vector<ValuesExport> exportValues() const { return {}; }
void importValues(const std::vector<ValuesExport>&) {}
std::string getStorageLog() const { return {}; }
@@ -264,21 +277,42 @@ private:
* Start the connection with a server.
*/
void startProxy();
void stop();
/**
* Get informations from the proxy node
* @return the JSON returned by the proxy
*/
struct InfoState;
void getProxyInfos();
void handleProxyStatus(const asio::error_code &ec, std::shared_ptr<InfoState> infoState);
void onProxyInfos(const Json::Value& val, sa_family_t family);
SockAddr parsePublicAddress(const Json::Value& val);
void opFailed();
size_t doListen(const InfoHash& key, ValueCallback, Value::Filter);
bool doCancelListen(const InfoHash& key, size_t token);
void handleExpireListener(const asio::error_code &ec, const InfoHash& key);
struct Listener;
struct ListenState;
enum class ListenMethod {
LISTEN,
SUBSCRIBE,
RESUBSCRIBE,
};
/**
* Send Listen with httpClient_
*/
void sendListen(const restinio::http_request_header_t header,
const ValueCallback &cb,
const Sp<ListenState> &state, Listener &listener,
ListenMethod method = ListenMethod::LISTEN);
void handleResubscribe(const asio::error_code &ec, const InfoHash& key,
const size_t token, std::shared_ptr<ListenState> state);
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);
/**
* Initialize statusIpvX_
@@ -293,10 +327,24 @@ private:
*/
void cancelAllOperations();
std::string serverHost_;
std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
std::atomic_flag ongoingStatusUpdate_ = ATOMIC_FLAG_INIT;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
/*
* http::Client instance used on http io_context
*/
std::unique_ptr<http::Client> httpClient_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
mutable std::mutex lockCurrentProxyInfos_;
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
NodeStatus statusIpv6_ {NodeStatus::Disconnected};
NodeStats stats4_ {};
@@ -312,39 +360,29 @@ private:
/**
* Store listen requests.
*/
struct Listener;
struct ProxySearch;
size_t listenerToken_ {0};
std::map<InfoHash, ProxySearch> searches_;
mutable std::mutex searchLock_;
/**
* Store current put and get requests.
*/
struct Operation
{
std::shared_ptr<restbed::Request> req;
std::thread thread;
std::shared_ptr<std::atomic_bool> finished;
};
std::vector<Operation> operations_;
std::mutex lockOperations_;
/**
* Callbacks should be executed in the main thread.
*/
std::vector<std::function<void()>> callbacks_;
std::mutex lockCallbacks;
std::mutex lockCallbacks_;
std::thread statusThread_;
mutable std::mutex lockCurrentProxyInfos_;
Sp<InfoState> infoState_;
Sp<asio::steady_timer> statusTimer_;
mutable std::mutex statusLock_;
Scheduler scheduler;
/**
* Retrieve if we can connect to the proxy (update statusIpvX_)
*/
void confirmProxy();
Sp<Scheduler::Job> nextProxyConfirmation {};
void handleProxyConfirm(const asio::error_code &ec);
Sp<asio::steady_timer> nextProxyConfirmationTimer_;
Sp<asio::steady_timer> listenerRestartTimer_;
/**
* Relaunch LISTEN requests if the client disconnect/reconnect.
*/
@@ -354,7 +392,7 @@ private:
* Refresh a listen via a token
* @param token
*/
void resubscribe(const InfoHash& key, Listener& listener);
void resubscribe(const InfoHash& key, const size_t token, Listener& listener);
/**
* If we want to use push notifications by default.
@@ -364,14 +402,14 @@ private:
const std::function<void()> loopSignal_;
#if OPENDHT_PUSH_NOTIFICATIONS
void fillBodyToGetToken(std::shared_ptr<restbed::Request> request, unsigned token = 0);
#ifdef OPENDHT_PUSH_NOTIFICATIONS
std::string fillBody(bool resubscribe);
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
bool isDestroying_ {false};
std::atomic_bool isDestroying_ {false};
std::shared_ptr<dht::Logger> logger_;
};
}
#endif // OPENDHT_PROXY_CLIENT
+168 -57
View File
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 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>
*
* 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
@@ -17,21 +18,51 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_SERVER
#pragma once
#include "callbacks.h"
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "scheduler.h"
#include "value.h"
#include "proxy.h"
#include "scheduler.h"
#include "sockaddr.h"
#include "value.h"
#include "dht_proxy_client.h"
#include <thread>
#include <memory>
#include <mutex>
#include <restbed>
#include <restinio/all.hpp>
#include "http.h"
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
namespace http {
class Client;
class opendht_logger_t;
struct ListenerSession;
class ConnectionListener;
}
namespace restinio {
class opendht_logger_t;
struct custom_http_methods_t;
}
using RestRouter = restinio::router::express_router_t<>;
struct RestRouterTraits : public restinio::default_traits_t
{
using timer_manager_t = restinio::asio_timer_manager_t;
using http_methods_mapper_t = restinio::custom_http_methods_t;
using logger_t = restinio::opendht_logger_t;
using request_handler_t = RestRouter;
using connection_state_listener_t = http::ConnectionListener;
};
using ServerSettings = restinio::run_on_this_thread_settings_t<RestRouterTraits>;
using RequestStatus = restinio::request_handling_status_t;
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
namespace Json {
class Value;
@@ -55,7 +86,9 @@ public:
* @note if the server fails to start (if port is already used or reserved),
* it will fails silently
*/
DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port = 8000, const std::string& pushServer = "");
DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port = 8000,
const std::string& pushServer = "",
std::shared_ptr<dht::Logger> logger = {});
virtual ~DhtProxyServer();
DhtProxyServer(const DhtProxyServer& other) = delete;
@@ -72,15 +105,44 @@ public:
size_t pushListenersCount;
/** Average requests per second */
double requestRate;
/** Node Info **/
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;;
}
return ss.str();
}
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const {
Json::Value result;
result["listenCount"] = static_cast<Json::UInt64>(listenCount);
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["requestRate"] = requestRate;
result["nodeInfo"] = nodeInfo.toJson();
return result;
}
#endif
};
ServerStats getStats() const;
ServerStats stats() const { return stats_; }
void updateStats() const;
std::shared_ptr<DhtRunner> getNode() const { return dht_; }
@@ -90,6 +152,14 @@ public:
void stop();
private:
template <typename HttpResponse>
HttpResponse initHttpResponse(HttpResponse response) const;
ServerSettings makeHttpServerSettings(
const unsigned int max_pipelined_requests = 16);
std::unique_ptr<RestRouter> createRestRouter();
/**
* Return the PublicKey id, the node id and node stats
* Method: GET "/"
@@ -97,7 +167,17 @@ private:
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
void getNodeInfo(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus getNodeInfo(restinio::request_handle_t request,
restinio::router::route_params_t params) const;
/**
* Return ServerStats in JSON format
* Method: STATS "/"
* Result: HTTP 200, body: Node infos in JSON format
* @param session
*/
RequestStatus getStats(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Return Values of an infoHash
@@ -109,7 +189,8 @@ private:
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
void get(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus get(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Listen incoming Values of an infoHash.
@@ -121,7 +202,8 @@ private:
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
void listen(const std::shared_ptr<restbed::Session>& session);
RequestStatus listen(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Put a value on the DHT
@@ -132,11 +214,12 @@ private:
* HTTP 400, body: {"err":"xxxx"} if bad json or HTTP 502 if put fails
* @param session
*/
void put(const std::shared_ptr<restbed::Session>& session);
RequestStatus put(restinio::request_handle_t request,
restinio::router::route_params_t params);
void cancelPut(const InfoHash& key, Value::Id vid);
void handleCancelPermamentPut(const asio::error_code &ec, const InfoHash& key, Value::Id vid);
#if OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
/**
* Put a value to sign by the proxy on the DHT
* Method: SIGN "/{InfoHash: .*}"
@@ -146,7 +229,8 @@ private:
* HTTP 400, body: {"err":"xxxx"} if bad json
* @param session
*/
void putSigned(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus putSigned(restinio::request_handle_t request,
restinio::router::route_params_t params) const;
/**
* Put a value to encrypt by the proxy on the DHT
@@ -157,7 +241,9 @@ private:
* HTTP 400, body: {"err":"xxxx"} if bad json
* @param session
*/
void putEncrypted(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus putEncrypted(restinio::request_handle_t request,
restinio::router::route_params_t params);
#endif // OPENDHT_PROXY_SERVER_IDENTITY
/**
@@ -170,7 +256,8 @@ private:
* On error: HTTP 503, body: {"err":"xxxx"}
* @param session
*/
void getFiltered(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus getFiltered(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Respond allowed Methods
@@ -179,15 +266,10 @@ private:
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
* @param session
*/
void handleOptionsMethod(const std::shared_ptr<restbed::Session>& session) const;
RequestStatus options(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Remove finished listeners
* @param testSession if we remove the listener only if the session is closed
*/
void removeClosedListeners(bool testSession = true);
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
/**
* Subscribe to push notifications for an iOS or Android device.
* Method: SUBSCRIBE "/{InfoHash: .*}"
@@ -197,7 +279,9 @@ private:
* so you need to refresh the operation each six hours.
* @param session
*/
void subscribe(const std::shared_ptr<restbed::Session>& session);
RequestStatus subscribe(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Unsubscribe to push notifications for an iOS or Android device.
* Method: UNSUBSCRIBE "/{InfoHash: .*}"
@@ -205,53 +289,75 @@ private:
* Return: nothing
* @param session
*/
void unsubscribe(const std::shared_ptr<restbed::Session>& session);
RequestStatus unsubscribe(restinio::request_handle_t request,
restinio::router::route_params_t params);
/**
* Send a push notification via a gorush push gateway
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, const Json::Value& json, bool isAndroid) const;
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid) const;
/**
* Send push notification with an expire timeout.
* @param ec
* @param pushToken
* @param json
* @param isAndroid
*/
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
Json::Value json, const bool isAndroid);
/**
* Remove a push listener between a client and a hash
* @param ec
* @param pushToken
* @param key
* @param clientId
*/
void cancelPushListen(const std::string& pushToken, const InfoHash& key, const std::string& clientId);
void handleCancelPushListen(const asio::error_code &ec, const std::string pushToken,
const InfoHash key, const std::string clientId);
#endif //OPENDHT_PUSH_NOTIFICATIONS
void handlePrintStats(const asio::error_code &ec);
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
std::thread server_thread {};
std::unique_ptr<restbed::Service> service_;
std::shared_ptr<DhtRunner> dht_;
std::shared_ptr<dht::Logger> logger_;
Json::StreamWriterBuilder jsonBuilder_;
std::mutex schedulerLock_;
std::condition_variable schedulerCv_;
Scheduler scheduler_;
std::thread schedulerThread_;
std::thread httpServerThread_;
std::unique_ptr<restinio::http_server_t<RestRouterTraits>> httpServer_;
std::unique_ptr<http::Client> httpClient_;
Sp<Scheduler::Job> printStatsJob_;
mutable std::mutex statsMutex_;
mutable ServerStats stats_;
mutable NodeInfo nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
// Handle client quit for listen.
// NOTE: can be simplified when we will supports restbed 5.0
std::thread listenThread_;
struct SessionToHashToken {
std::shared_ptr<restbed::Session> session;
InfoHash hash;
std::future<size_t> token;
// Thread-safe access to listeners map.
std::shared_ptr<std::mutex> lockListener_;
// Shared with connection listener.
std::shared_ptr<std::map<restinio::connection_id_t,
http::ListenerSession>> listeners_;
// Connection Listener observing conn state changes.
std::shared_ptr<http::ConnectionListener> connListener_;
struct PermanentPut {
time_point expiration;
std::string pushToken;
std::string clientId;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
};
std::vector<SessionToHashToken> currentListeners_;
std::mutex lockListener_;
std::atomic_bool stopListeners {false};
struct PermanentPut;
struct SearchPuts;
struct SearchPuts {
std::map<dht::Value::Id, PermanentPut> puts;
};
std::mutex lockSearchPuts_;
std::map<InfoHash, SearchPuts> puts_;
mutable std::atomic<size_t> requestNum_ {0};
@@ -259,9 +365,16 @@ private:
const std::string pushServer_;
#if OPENDHT_PUSH_NOTIFICATIONS
struct Listener;
struct PushListener;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener {
std::string clientId;
std::future<size_t> internalToken;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
};
struct PushListener {
std::map<InfoHash, std::vector<Listener>> listeners;
};
std::mutex lockPushListeners_;
std::map<std::string, PushListener> pushListeners_;
proxy::ListenToken tokenPushNotif_ {0};
@@ -269,5 +382,3 @@ private:
};
}
#endif //OPENDHT_PROXY_SERVER
+95 -64
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
@@ -20,12 +20,13 @@
#pragma once
#include "def.h"
#include "infohash.h"
#include "value.h"
#include "callbacks.h"
#include "sockaddr.h"
#include "log_enable.h"
#include "def.h"
#include "network_utils.h"
#include <thread>
#include <mutex>
@@ -40,6 +41,7 @@ namespace dht {
struct Node;
class SecureDht;
class PeerDiscovery;
struct SecureDhtConfig;
/**
@@ -51,32 +53,43 @@ struct SecureDhtConfig;
class OPENDHT_PUBLIC DhtRunner {
public:
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
using StatusCallback = std::function<void(NodeStatus, NodeStatus)>;
struct Config {
SecureDhtConfig dht_config;
bool threaded;
std::string proxy_server;
std::string push_node_id;
SecureDhtConfig dht_config {};
bool threaded {true};
std::string proxy_server {};
std::string push_node_id {};
bool peer_discovery {false};
bool peer_publish {false};
};
struct Context {
std::shared_ptr<Logger> logger {};
std::unique_ptr<net::DatagramSocket> sock;
std::shared_ptr<PeerDiscovery> peerDiscovery {};
StatusCallback statusChangedCallback {};
CertificateStoreQuery certificateStore {};
Context() {}
};
DhtRunner();
virtual ~DhtRunner();
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
}
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
}
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={}, Where w = {});
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = {}, Where w = {}) {
get(id, cb, bindDoneCb(donecb), f, w);
}
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter(), Where w = {});
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = {}, Where w = {});
template <class T>
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
@@ -105,7 +118,7 @@ public:
getFilterSet<T>());
}
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter(), Where w = {}) {
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = {}, Where w = {}) {
auto p = std::make_shared<std::promise<std::vector<std::shared_ptr< dht::Value >>>>();
auto values = std::make_shared<std::vector<std::shared_ptr< dht::Value >>>();
get(key, [=](const std::vector<std::shared_ptr<dht::Value>>& vlist) {
@@ -136,7 +149,7 @@ public:
query(hash, cb, bindDoneCb(done_cb), q);
}
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = Value::AllFilter(), Where w = {});
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {});
std::future<size_t> listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
@@ -145,8 +158,8 @@ public:
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = Value::AllFilter(), Where w = {});
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = Value::AllFilter(), Where w = {}) {
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = {}, Where w = {});
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = {}, Where w = {}) {
return listen(key, bindGetCb(cb), f, w);
}
@@ -158,8 +171,17 @@ public:
},
getFilterSet<T>());
}
template <class T>
std::future<size_t> listen(InfoHash hash, std::function<bool(std::vector<T>&&, bool)> cb)
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
return cb(unpackVector<T>(vals), expired);
},
getFilterSet<T>());
}
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter(), Where w = {})
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = {}, Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
for (const auto& v : vals) {
@@ -174,6 +196,22 @@ public:
},
getFilterSet<T>(f), w);
}
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&, bool)> cb, Value::Filter f = {}, Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
for (const auto& v : vals) {
try {
if (not cb(Value::unpack<T>(*v), expired))
return false;
} catch (const std::exception&) {
continue;
}
}
return true;
},
getFilterSet<T>(f), w);
}
void cancelListen(InfoHash h, size_t token);
void cancelListen(InfoHash h, std::shared_future<size_t> token);
@@ -234,6 +272,12 @@ public:
*/
void bootstrap(const std::string& host, const std::string& service);
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
*/
void bootstrap(const InfoHash& id, const SockAddr& address);
/**
* Clear the list of bootstrap added using bootstrap(const std::string&, const std::string&).
*/
@@ -248,17 +292,21 @@ public:
void dumpTables() const;
/**
* Get the public key fingerprint if an identity is used with this node, 0 otherwise.
*/
InfoHash getId() const;
/**
* Get the ID of the DHT node.
*/
InfoHash getNodeId() const;
/**
* Returns the currently bound address.
* @param f: address family of the bound address to retreive.
*/
const SockAddr& getBound(sa_family_t f = AF_INET) const {
return (f == AF_INET) ? bound4 : bound6;
}
SockAddr getBound(sa_family_t f = AF_INET) const;
/**
* Returns the currently bound port, in host byte order.
@@ -276,7 +324,8 @@ public:
std::vector<ValuesExport> exportValues() const;
void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
void setLogger(const Logger& logger = {});
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
@@ -293,6 +342,7 @@ public:
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;
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
std::string getStorageLog() const;
@@ -315,23 +365,14 @@ public:
* @param threaded: If false, ::loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(in_port_t port = 4222, const crypto::Identity identity = {}, bool threaded = false, NetId network = 0) {
run(port, {
/*.dht_config = */{
/*.node_config = */{
/*.node_id = */{},
/*.network = */network,
/*.is_bootstrap = */false,
/*.maintain_storage*/false
},
/*.id = */identity
},
/*.threaded = */threaded,
/*.proxy_server = */"",
/*.push_node_id = */""
});
void run(in_port_t port = 4222, const crypto::Identity& identity = {}, bool threaded = true, NetId network = 0) {
Config config;
config.dht_config.node_config.network = network;
config.dht_config.id = identity;
config.threaded = threaded;
run(port, config);
}
void run(in_port_t port, Config config);
void run(in_port_t port, const Config& config, Context&& context = {});
/**
* @param local4: Local IPv4 address and port to bind. Can be null.
@@ -341,12 +382,14 @@ public:
* @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(const SockAddr& local4, const SockAddr& local6, Config config);
void run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context = {});
/**
* Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
*/
void run(const char* ip4, const char* ip6, const char* service, Config config);
void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {});
void run(const Config& config, Context&& context);
void setOnStatusChanged(StatusCallback&& cb) {
statusCb = std::move(cb);
@@ -359,13 +402,7 @@ public:
*/
time_point loop() {
std::lock_guard<std::mutex> lck(dht_mtx);
time_point wakeup = time_point::min();
try {
wakeup = loop_();
} catch (const dht::SocketException& e) {
startNetwork(bound4, bound6);
}
return wakeup;
return loop_();
}
/**
@@ -380,15 +417,9 @@ public:
*/
void join();
void setProxyServer(const std::string& proxy, const std::string& pushNodeId = "") {
#if OPENDHT_PROXY_CLIENT
if (config_.proxy_server == proxy and config_.push_node_id == pushNodeId)
return;
config_.proxy_server = proxy;
config_.push_node_id = pushNodeId;
enableProxy(use_proxy and not config_.proxy_server.empty());
#endif
}
std::shared_ptr<PeerDiscovery> getPeerDiscovery() const { return peerDiscovery_; };
void setProxyServer(const std::string& proxy, const std::string& pushNodeId = "");
/**
* Start or stop the proxy
@@ -423,7 +454,6 @@ private:
*/
void tryBootstrapContinuously();
void startNetwork(const SockAddr sin4, const SockAddr sin6);
time_point loop_();
NodeStatus getStatus() const {
@@ -461,10 +491,8 @@ private:
mutable std::mutex dht_mtx {};
std::thread dht_thread {};
std::condition_variable cv {};
std::thread rcv_thread {};
std::mutex sock_mtx {};
std::vector<std::pair<Blob, SockAddr>> rcv {};
std::queue<std::unique_ptr<net::ReceivedPacket>> rcv {};
/** true if currently actively boostraping */
std::atomic_bool bootstraping {false};
@@ -472,7 +500,6 @@ private:
std::vector<std::pair<std::string,std::string>> bootstrap_nodes_all {};
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
std::thread bootstrap_thread {};
/** protects bootstrap_nodes, bootstrap_thread */
std::mutex bootstrap_mtx {};
std::condition_variable bootstrap_cv {};
@@ -481,18 +508,22 @@ private:
std::mutex storage_mtx {};
std::atomic_bool running {false};
std::atomic_bool running_network {false};
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
StatusCallback statusCb {nullptr};
int s4 {-1}, s6 {-1};
SockAddr bound4 {};
SockAddr bound6 {};
/** Push notification token */
std::string pushToken_;
/** PeerDiscovery Parameters */
std::shared_ptr<PeerDiscovery> peerDiscovery_;
/**
* The Logger instance is used in enableProxy and other methods that
* would create instances of classes using a common logger.
*/
std::shared_ptr<dht::Logger> logger_;
};
}
+240
View File
@@ -0,0 +1,240 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@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/>.
*/
#pragma once
#include <asio.hpp>
#include <json/json.h>
#include <http_parser.h>
#include <restinio/all.hpp>
#include <opendht.h>
#include <opendht/def.h>
#include <opendht/log.h>
namespace http {
class Connection;
// basic types
using Id = unsigned int;
// asio handlers callbacks
using HandlerCb = std::function<void(const asio::error_code& ec)>;
using ConnectionCb = std::function<void(const asio::error_code& ec, std::shared_ptr<Connection>)>;
class OPENDHT_PUBLIC Connection
{
public:
Connection(asio::ip::tcp::socket socket, std::shared_ptr<dht::Logger> logger = {});
~Connection();
Id id();
bool is_open();
bool is_v6();
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
// TODO abort to silence error in request?
void close();
private:
friend class Client;
Id id_;
static Id ids_;
std::shared_ptr<dht::Logger> logger_;
asio::ip::tcp::socket socket_;
asio::ip::tcp::endpoint endpoint_;
asio::streambuf request_;
std::string response_body_;
asio::streambuf response_chunk_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
};
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
class ConnectionListener
{
public:
ConnectionListener();
ConnectionListener(std::shared_ptr<dht::DhtRunner> dht,
std::shared_ptr<std::map<restinio::connection_id_t, http::ListenerSession>> listeners,
std::shared_ptr<std::mutex> lock, std::shared_ptr<dht::Logger> logger);
~ConnectionListener();
/**
* Connection state change used to handle Listeners disconnects.
* RESTinio >= 0.5.1 https://github.com/Stiffstream/restinio/issues/28
*/
void state_changed(const restinio::connection_state::notice_t& notice) noexcept;
private:
std::string to_str( restinio::connection_state::cause_t cause ) noexcept;
std::shared_ptr<dht::DhtRunner> dht_;
std::shared_ptr<std::mutex> lock_;
std::shared_ptr<std::map<restinio::connection_id_t,
http::ListenerSession>> listeners_;
std::shared_ptr<dht::Logger> logger_;
};
class Resolver {
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service = "80");
using ResolvedCb = std::function<void(const asio::error_code&, const asio::ip::basic_resolver_results<asio::ip::tcp>&)>;
void addOnResolved(ResolvedCb cb);
private:
std::mutex cbsMutex_;
asio::ip::tcp::resolver resolver_;
asio::error_code error_;
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
std::queue<ResolvedCb> cbs_;
bool completed_ {false};
};
class OPENDHT_PUBLIC Request
{
public:
Request(asio::io_context& ctx, const std::string host, const std::string service = "80",
const bool resolve = true, std::shared_ptr<dht::Logger> logger = {});
~Request();
void set_logger(std::shared_ptr<dht::Logger> logger);
void terminate();
void resolve(const std::string host, const std::string service, HandlerCb cb = {});
bool resolved();
void connect(ConnectionCb cb = {});
std::string build(const restinio::http_request_header_t header,
const restinio::http_header_fields_t header_fields,
const restinio::http_connection_header_t connection, const std::string body);
void send(std::string request, std::unique_ptr<http_parser> parser,
std::unique_ptr<http_parser_settings> parser_s, HandlerCb cb = {});
private:
void handle_request(const asio::error_code& ec, HandlerCb cb = {});
void handle_response_header(const asio::error_code& ec, const size_t bytes, HandlerCb cb = {});
void handle_response_body(const asio::error_code& ec, const size_t bytes, HandlerCb cb = {});
void parse_request(const std::string request);
size_t get_content_length(const std::string str);
Resolver resolver_;
/* std::string service_;
std::string host_;
asio::ip::tcp::resolver resolver_;
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
*/
Id id_;
static Id ids_;
std::shared_ptr<Connection> conn_;
std::string request_;
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
std::shared_ptr<dht::Logger> logger_;
};
} // namespace http
namespace restinio
{
class opendht_logger_t
{
public:
opendht_logger_t(std::shared_ptr<dht::Logger> logger = {}){
if (logger)
m_logger = logger;
}
template <typename Builder>
void trace(Builder && msg_builder){
if (m_logger)
m_logger->d("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void info(Builder && msg_builder){
if (m_logger)
m_logger->d("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void warn(Builder && msg_builder){
if (m_logger)
m_logger->w("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void error(Builder && msg_builder){
if (m_logger)
m_logger->e("[proxy:server] %s", msg_builder().c_str());
}
private:
std::shared_ptr<dht::Logger> m_logger;
};
/* Custom HTTP-methods for RESTinio > 0.5.0.
* https://github.com/Stiffstream/restinio/issues/26
*/
constexpr const restinio::http_method_id_t method_listen{HTTP_LISTEN, "LISTEN"};
constexpr const restinio::http_method_id_t method_stats{HTTP_STATS, "STATS"};
constexpr const restinio::http_method_id_t method_sign{HTTP_SIGN, "SIGN"};
constexpr const restinio::http_method_id_t method_encrypt{HTTP_ENCRYPT, "ENCRYPT"};
struct custom_http_methods_t
{
static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept {
if(m == method_listen.raw_id())
return method_listen;
else if(m == method_stats.raw_id())
return method_stats;
else if(m == method_sign.raw_id())
return method_sign;
else if(m == method_encrypt.raw_id())
return method_encrypt;
else
return restinio::default_http_methods_t::from_nodejs(m);
}
};
} // namespace restinio
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -65,7 +65,7 @@ public:
typedef typename T::iterator iterator;
typedef typename T::const_iterator const_iterator;
Hash () {
Hash () noexcept {
data_.fill(0);
}
Hash (const uint8_t* h, size_t data_len) {
@@ -85,7 +85,7 @@ public:
msgpack_unpack(o);
}
size_t size() const { return data_.size(); }
static constexpr size_t size() noexcept { return N; }
const uint8_t* data() const { return data_.data(); }
uint8_t* data() { return data_.data(); }
iterator begin() { return data_.begin(); }
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -66,6 +66,15 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getStdLogger();
OPENDHT_PUBLIC
std::unique_ptr<Logger> getFileLogger(const std::string &path);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getSyslogLogger(const char* name);
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
+27 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -32,19 +32,29 @@ namespace dht {
// Logging related utility functions
/**
* Dummy function used to disable logging
*/
inline void NOLOG(char const*, va_list) {}
/**
* Wrapper for logging methods
*/
struct LogMethod {
LogMethod() = default;
LogMethod(LogMethod&& l) : func(std::move(l.func)) {}
LogMethod(const LogMethod& l) : func(l.func) {}
LogMethod& operator=(dht::LogMethod&& l) {
func = std::forward<LogMethod>(l.func);
return *this;
}
LogMethod& operator=(const dht::LogMethod& l) {
func = l.func;
return *this;
}
template<typename T>
LogMethod(T&& t) : func(std::forward<T>(t)) {}
explicit LogMethod(T&& t) : func(std::forward<T>(t)) {}
template<typename T>
LogMethod(const T& t) : func(t) {}
void operator()(char const* format, ...) const {
va_list args;
@@ -70,9 +80,13 @@ private:
};
struct Logger {
LogMethod DEBUG = NOLOG;
LogMethod WARN = NOLOG;
LogMethod ERR = NOLOG;
LogMethod DBG = {};
LogMethod WARN = {};
LogMethod ERR = {};
Logger() = default;
Logger(LogMethod&& err, LogMethod&& warn, LogMethod&& dbg)
: DBG(std::move(dbg)), WARN(std::move(warn)), ERR(std::move(err)) {}
void setFilter(const InfoHash& f) {
filter_ = f;
filterEnable_ = static_cast<bool>(filter_);
@@ -99,7 +113,7 @@ struct Logger {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(DEBUG, format, args);
log0(DBG, format, args);
va_end(args);
#endif
}
@@ -107,7 +121,7 @@ struct Logger {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(DEBUG, f, format, args);
log1(DBG, f, format, args);
va_end(args);
#endif
}
@@ -115,7 +129,7 @@ struct Logger {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(DEBUG, f1, f2, format, args);
log2(DBG, f1, f2, format, args);
va_end(args);
#endif
}
+29 -24
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -27,6 +27,8 @@
#include "utils.h"
#include "rng.h"
#include "rate_limiter.h"
#include "log_enable.h"
#include "network_utils.h"
#include <vector>
#include <string>
@@ -68,14 +70,14 @@ public:
DhtProtocolException(uint16_t code, const std::string& msg="", InfoHash failing_node_id={})
: DhtException(msg), msg(msg), code(code), failing_node_id(failing_node_id) {}
std::string getMsg() const { return msg; }
const std::string& getMsg() const { return msg; }
uint16_t getCode() const { return code; }
const InfoHash getNodeId() const { return failing_node_id; }
const InfoHash& getNodeId() const { return failing_node_id; }
private:
std::string msg;
uint16_t code;
const InfoHash failing_node_id;
InfoHash failing_node_id;
};
struct ParsedMessage;
@@ -204,19 +206,21 @@ public:
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler, const int& s = -1, const int& s6 = -1);
NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
decltype(NetworkEngine::onPing) onPing,
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce,
decltype(NetworkEngine::onRefresh) onRefresh);
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
decltype(NetworkEngine::onPing)&& onPing,
decltype(NetworkEngine::onFindNode)&& onFindNode,
decltype(NetworkEngine::onGetValues)&& onGetValues,
decltype(NetworkEngine::onListen)&& onListen,
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
decltype(NetworkEngine::onRefresh)&& onRefresh);
virtual ~NetworkEngine();
~NetworkEngine();
net::DatagramSocket* getSocket() const { return dht_socket.get(); };
void clear();
@@ -241,7 +245,7 @@ public:
void tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values);
bool isRunning(sa_family_t af) const;
inline want_t want () const { return dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; }
inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; }
void connectivityChanged(sa_family_t);
@@ -290,9 +294,9 @@ public:
*/
Sp<Request> sendFindNode(Sp<Node> n,
const InfoHash& hash,
want_t want,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
want_t want = -1,
RequestCb&& on_done = {},
RequestExpiredCb&& on_expired = {});
/**
* Send a "get" request to a given node.
*
@@ -393,7 +397,7 @@ public:
* @param fromlen The length of the corresponding sockaddr structure.
* @param now The time to adjust the clock in the network engine.
*/
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr& addr);
void processMessage(const uint8_t *buf, size_t buflen, SockAddr addr);
Sp<Node> insertNode(const InfoHash& myid, const SockAddr& addr) {
auto n = cache.getNode(myid, addr, scheduler.time(), 0);
@@ -468,7 +472,7 @@ private:
// basic wrapper for socket sendto function
int send(const char *buf, size_t len, int flags, const SockAddr& addr);
int send(const SockAddr& addr, const char *buf, size_t len, bool confirmed = false);
void sendValueParts(const TransId& tid, const std::vector<Blob>& svals, const SockAddr& addr);
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<Sp<Value>>&);
@@ -510,8 +514,7 @@ private:
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const int& dht_socket;
const int& dht_socket6;
const std::unique_ptr<DatagramSocket> dht_socket;
const Logger& DHT_LOG;
NodeCache cache {};
@@ -531,6 +534,8 @@ private:
std::set<SockAddr> blacklist {};
Scheduler& scheduler;
bool logIncoming_ {false};
};
} /* namespace net */
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2019 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/>.
*/
#pragma once
#include "def.h"
#include "sockaddr.h"
#include "utils.h"
#include "log_enable.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <functional>
#include <thread>
#include <atomic>
#include <iostream>
namespace dht {
namespace net {
int bindSocket(const SockAddr& addr, SockAddr& bound);
bool setNonblocking(int fd, bool nonblocking = true);
#ifdef _WIN32
void udpPipe(int fds[2]);
#endif
struct ReceivedPacket {
Blob data;
SockAddr from;
time_point received;
};
class OPENDHT_PUBLIC DatagramSocket {
public:
using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>;
virtual ~DatagramSocket() {};
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
inline void setOnReceive(OnReceive&& cb) {
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();
}
virtual void stop() = 0;
protected:
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
if (rx_callback)
rx_callback(std::move(packet));
}
private:
OnReceive rx_callback;
};
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();
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 {
return (family == AF_INET6) ? bound6 : bound4;
}
bool hasIPv4() const override { return s4 != -1; }
bool hasIPv6() const override { return s6 != -1; }
void stop() override;
private:
Logger logger;
int s4 {-1};
int s6 {-1};
int stopfd {-1};
SockAddr bound4, bound6;
std::thread rcv_thread {};
std::atomic_bool running {false};
void openSockets(const SockAddr& bind4, const SockAddr& bind6);
};
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+6 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -40,12 +40,16 @@ struct NodeCache {
~NodeCache();
private:
class NodeMap : public std::map<InfoHash, std::weak_ptr<Node>> {
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);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, size_t count) const;
void clearBadNodes();
void setExpired();
void cleanup();
private:
size_t cleanup_counter {0};
};
const NodeMap& cache(sa_family_t af) const { return af == AF_INET ? cache_4 : cache_6; }
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@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/>.
*/
#pragma once
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include <thread>
#include <mutex>
#include <condition_variable>
namespace dht {
class OPENDHT_PUBLIC PeerDiscovery
{
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();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
template<typename T>
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
cb(ob.as<T>(), std::move(addr));
});
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
*/
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);
template<typename T>
void startPublish(const std::string &type, const T& object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, 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);
bool stopPublish(sa_family_t domain, const std::string &type);
/**
* Configure the sockopt to be able to listen multicast group
*/
static void socketJoinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
};
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 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,7 +22,7 @@
namespace dht {
namespace proxy {
constexpr const std::chrono::seconds OP_TIMEOUT {1 * 60 * 60}; // onw hour
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 char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 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-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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 {
#ifndef WIN32_NATIVE
#ifndef _MSC_VER
#ifdef _WIN32
/**
@@ -43,8 +43,8 @@ public:
* result_type is unsigned int so this is currently safe.
*/
static_assert(
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 8,
"result_type must be 16, 32 or 64 bits");
+7 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -42,6 +42,11 @@ struct Bucket {
Sp<Node> randomNode();
void sendCachedPing(net::NetworkEngine& ne);
void connectivityChanged() {
time = time_point::min();
for (auto& node : nodes)
node->setTime(time_point::min());
}
};
class RoutingTable : public std::list<Bucket> {
@@ -76,7 +81,7 @@ public:
void connectivityChanged(const time_point& now) {
grow_time = now;
for (auto& b : *this)
b.time = time_point::min();
b.connectivityChanged();
}
bool onNewNode(const Sp<Node>& node, int comfirm, const time_point& now, const InfoHash& myid, net::NetworkEngine& ne);
+1 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -21,7 +21,6 @@
#pragma once
#include "utils.h"
#include "log_enable.h"
#include <functional>
#include <map>
+66 -65
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
@@ -37,9 +37,9 @@ public:
using Config = SecureDhtConfig;
static dht::Config& getConfig(SecureDht::Config& conf)
static dht::Config getConfig(const SecureDht::Config& conf)
{
auto& c = conf.node_config;
auto c = conf.node_config;
if (not c.node_id and conf.id.second)
c.node_id = InfoHash::get("node:"+conf.id.second->getId().toString());
return c;
@@ -71,7 +71,7 @@ public:
return secureType(std::move(tmp_type));
}
void registerType(const ValueType& type) {
void registerType(const ValueType& type) override {
if (dht_)
dht_->registerType(secureType(type));
}
@@ -89,14 +89,14 @@ public:
* If the signature can't be checked, or if the data can't be decrypted, it is not returned.
* Public, non-signed & non-encrypted data is retransmitted as-is.
*/
void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {});
void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}, Where&& w = {}) {
void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {}) override;
void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}, Where&& w = {}) override {
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
@@ -127,8 +127,8 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb);
void findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb);
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
@@ -148,99 +148,103 @@ public:
/**
* SecureDht to Dht proxy
*/
void shutdown(ShutdownCallback cb) {
void shutdown(ShutdownCallback cb) override {
dht_->shutdown(cb);
}
void dumpTables() const {
void dumpTables() const override {
dht_->dumpTables();
}
inline const InfoHash& getNodeId() const { return dht_->getNodeId(); }
std::pair<size_t, size_t> getStoreSize() const {
inline const InfoHash& getNodeId() const override { return dht_->getNodeId(); }
std::pair<size_t, size_t> getStoreSize() const override {
return dht_->getStoreSize();
}
std::string getStorageLog() const {
std::string getStorageLog() const override {
return dht_->getStorageLog();
}
std::string getStorageLog(const InfoHash& h) const {
std::string getStorageLog(const InfoHash& h) const override {
return dht_->getStorageLog(h);
}
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) {
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
dht_->setStorageLimit(limit);
}
std::vector<NodeExport> exportNodes() {
std::vector<NodeExport> exportNodes() const override {
return dht_->exportNodes();
}
std::vector<ValuesExport> exportValues() const {
std::vector<ValuesExport> exportValues() const override {
return dht_->exportValues();
}
void importValues(const std::vector<ValuesExport>& v) {
void importValues(const std::vector<ValuesExport>& v) override {
dht_->importValues(v);
}
NodeStats getNodesStats(sa_family_t af) const {
NodeStats getNodesStats(sa_family_t af) const override {
return dht_->getNodesStats(af);
}
std::vector<unsigned> getNodeMessageStats(bool in = false) {
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
return dht_->getNodeMessageStats(in);
}
std::string getRoutingTablesLog(sa_family_t af) const {
std::string getRoutingTablesLog(sa_family_t af) const override {
return dht_->getRoutingTablesLog(af);
}
std::string getSearchesLog(sa_family_t af) const {
std::string getSearchesLog(sa_family_t af) const override {
return dht_->getSearchesLog(af);
}
std::string getSearchLog(const InfoHash& h, sa_family_t af = AF_UNSPEC) const {
std::string getSearchLog(const InfoHash& h, sa_family_t af = AF_UNSPEC) const override {
return dht_->getSearchLog(h, af);
}
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) {
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
return dht_->getPublicAddress(family);
}
time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr& sa) {
return dht_->periodic(buf, buflen, sa);
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, const sockaddr* from, socklen_t fromlen) {
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return dht_->periodic(buf, buflen, from, fromlen);
}
NodeStatus getStatus(sa_family_t af) const {
NodeStatus getStatus(sa_family_t af) const override {
return dht_->getStatus(af);
}
NodeStatus getStatus() const {
NodeStatus getStatus() const override {
return dht_->getStatus();
}
bool isRunning(sa_family_t af = 0) const {
net::DatagramSocket* getSocket() const override {
return dht_->getSocket();
};
bool isRunning(sa_family_t af = 0) const override {
return dht_->isRunning(af);
}
const ValueType& getType(ValueType::Id type_id) const {
const ValueType& getType(ValueType::Id type_id) const override {
return dht_->getType(type_id);
}
void insertNode(const InfoHash& id, const SockAddr& sa) {
void insertNode(const InfoHash& id, const SockAddr& sa) override {
dht_->insertNode(id, sa);
}
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) {
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) override {
dht_->insertNode(id, sa, salen);
}
void insertNode(const NodeExport& n) {
void insertNode(const NodeExport& n) override {
dht_->insertNode(n);
}
void pingNode(const sockaddr* sa, socklen_t salen, DoneCallbackSimple&& cb={}) {
void pingNode(const sockaddr* sa, socklen_t salen, DoneCallbackSimple&& cb={}) override {
dht_->pingNode(sa, salen, std::move(cb));
}
void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) {
void query(const InfoHash& key, QueryCallback cb, DoneCallback done_cb = {}, Query&& q = {}) override {
dht_->query(key, cb, done_cb, std::move(q));
}
void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) {
void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
dht_->query(key, cb, done_cb, std::move(q));
}
std::vector<Sp<Value>> getLocal(const InfoHash& key, Value::Filter f = Value::AllFilter()) const {
std::vector<Sp<Value>> getLocal(const InfoHash& key, const Value::Filter& f = {}) const override {
return dht_->getLocal(key, f);
}
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const {
Sp<Value> getLocalById(const InfoHash& key, Value::Id vid) const override {
return dht_->getLocalById(key, vid);
}
void put(const InfoHash& key,
Sp<Value> v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
dht_->put(key, v, cb, created, permanent);
}
@@ -248,7 +252,7 @@ public:
const Sp<Value>& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
dht_->put(key, v, cb, created, permanent);
}
@@ -257,7 +261,7 @@ public:
Value&& v,
DoneCallback cb=nullptr,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
dht_->put(key, std::move(v), cb, created, permanent);
}
@@ -265,32 +269,32 @@ public:
Value&& v,
DoneCallbackSimple cb,
time_point created=time_point::max(),
bool permanent = false)
bool permanent = false) override
{
dht_->put(key, std::move(v), cb, created, permanent);
}
std::vector<Sp<Value>> getPut(const InfoHash& h) {
std::vector<Sp<Value>> getPut(const InfoHash& h) const override {
return dht_->getPut(h);
}
Sp<Value> getPut(const InfoHash& h, const Value::Id& vid) {
Sp<Value> getPut(const InfoHash& h, const Value::Id& vid) const override {
return dht_->getPut(h, vid);
}
bool cancelPut(const InfoHash& h, const Value::Id& vid) {
bool cancelPut(const InfoHash& h, const Value::Id& vid) override {
return dht_->cancelPut(h, vid);
}
size_t listen(const InfoHash& key, ValueCallback, Value::Filter={}, Where={});
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter = {}, Where w = {});
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) {
size_t listen(const InfoHash& key, ValueCallback, Value::Filter={}, Where={}) override;
size_t listen(const InfoHash& key, GetCallback cb, Value::Filter = {}, Where w = {}) override;
size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w = {}) override {
return listen(key, bindGetCb(cb), f, w);
}
bool cancelListen(const InfoHash& h, size_t token) {
bool cancelListen(const InfoHash& h, size_t token) override {
return dht_->cancelListen(h, token);
}
void connectivityChanged(sa_family_t af) {
void connectivityChanged(sa_family_t af) override {
dht_->connectivityChanged(af);
}
void connectivityChanged() {
void connectivityChanged() override {
dht_->connectivityChanged();
}
@@ -298,7 +302,7 @@ public:
forward_all_ = forward;
}
void setPushNotificationToken(const std::string& token = "") {
void setPushNotificationToken(const std::string& token = "") override {
dht_->setPushNotificationToken(token);
}
@@ -306,22 +310,19 @@ public:
* Call linked callback with push_notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) {
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
dht_->pushNotificationReceived(notification);
}
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG)
{
DHT_LOG.DEBUG = debug;
DHT_LOG.WARN = warn;
DHT_LOG.ERR = error;
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
void setLogger(const 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) {
void setLogFilter(const InfoHash& f) override {
DHT_LOG.setFilter(f);
dht_->setLogFilter(f);
}
@@ -333,8 +334,8 @@ private:
SecureDht& operator=(const SecureDht&) = delete;
Sp<Value> checkValue(const Sp<Value>& v);
ValueCallback getCallbackFilter(ValueCallback, Value::Filter&&);
GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
Sp<crypto::PrivateKey> key_ {};
Sp<crypto::Certificate> certificate_ {};
+28 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 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,6 +23,7 @@
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef __ANDROID__
typedef uint16_t in_port_t;
#endif
@@ -58,7 +59,7 @@ public:
SockAddr(const SockAddr& o) {
set(o.get(), o.getLength());
}
SockAddr(SockAddr&& o) : len(o.len), addr(std::move(o.addr)) {
SockAddr(SockAddr&& o) noexcept : addr(std::move(o.addr)), len(o.len) {
o.len = 0;
}
@@ -118,7 +119,7 @@ public:
/**
* Returns the address family or AF_UNSPEC if the address is not set.
*/
sa_family_t getFamily() const { return len > sizeof(sa_family_t) ? addr->sa_family : AF_UNSPEC; }
sa_family_t getFamily() const { return len ? addr->sa_family : AF_UNSPEC; }
/**
* Resize the managed structure to the appropriate size (if needed),
@@ -146,6 +147,21 @@ public:
addr->sa_family = af;
}
/**
* Set Network Interface to any
*/
void setAny() {
auto family = getFamily();
switch(family) {
case AF_INET:
getIPv4().sin_addr.s_addr = htonl(INADDR_ANY);
break;
case AF_INET6:
getIPv6().sin6_addr = in6addr_any;
break;
}
}
/**
* Retreive the port (in host byte order) or 0 if the address is not
* of a supported family.
@@ -175,6 +191,12 @@ public:
}
}
/**
* Set the address part of the socket address from a numeric IP address (string representation).
* Family must be already set. Throws in case of parse failue.
*/
void setAddress(const char* address);
/**
* Returns the accessible byte length at the pointer returned by #get().
* If zero, #get() returns null.
@@ -226,7 +248,8 @@ public:
bool isUnspecified() const;
bool isMappedIPv4() const;
SockAddr getMappedIPv4() const;
SockAddr getMappedIPv4();
SockAddr getMappedIPv6();
/**
* A comparator to classify IP addresses, only considering the
@@ -257,9 +280,9 @@ public:
}
};
private:
socklen_t len {0};
struct free_delete { void operator()(void* p) { ::free(p); } };
std::unique_ptr<sockaddr, free_delete> addr {};
socklen_t len {0};
void set(const sockaddr* sa, socklen_t length) {
if (len != length) {
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "def.h"
#include <condition_variable>
#include <vector>
#include <queue>
#include <future>
#include <functional>
namespace dht {
class OPENDHT_PUBLIC ThreadPool {
public:
static ThreadPool& computation();
static ThreadPool& io();
ThreadPool();
ThreadPool(size_t maxThreads);
~ThreadPool();
void run(std::function<void()>&& cb);
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)));
return ret->get_future();
}
template<class T>
std::shared_future<T> getShared(std::function<T()>&& cb) {
return get(std::move(cb));
}
void stop();
void join();
private:
struct ThreadState;
std::queue<std::function<void()>> tasks_ {};
std::vector<std::unique_ptr<ThreadState>> threads_;
unsigned readyThreads_ {0};
std::mutex lock_ {};
std::condition_variable cv_ {};
const unsigned maxThreads_;
bool running_ {true};
};
class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this<Executor> {
public:
Executor(ThreadPool& pool, unsigned maxConcurrent = 1)
: threadPool_(pool), maxConcurrent_(maxConcurrent)
{}
void run(std::function<void()>&& task);
private:
std::reference_wrapper<ThreadPool> threadPool_;
const unsigned maxConcurrent_ {1};
std::mutex lock_ {};
unsigned current_ {0};
std::queue<std::function<void()>> tasks_ {};
void run_(std::function<void()>&& task);
void schedule();
};
}
+15 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -40,6 +40,8 @@ namespace dht {
using NetId = uint32_t;
using want_t = int_fast8_t;
OPENDHT_PUBLIC const char* version();
// shortcut for std::shared_ptr
template<class T>
using Sp = std::shared_ptr<T>;
@@ -90,6 +92,18 @@ print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
template <class DT>
static std::string
print_duration(DT d) {
if (d < std::chrono::milliseconds(1)) {
return std::to_string(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";
} else {
return std::to_string(print_dt(d)) + " s";
}
}
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>;
+34 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -37,9 +37,9 @@
#include <chrono>
#include <set>
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif //OPENDHT_PROXY_SERVER
#endif
namespace dht {
@@ -79,7 +79,7 @@ static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
struct OPENDHT_PUBLIC ValueType {
typedef uint16_t Id;
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
return false;
}
@@ -122,6 +122,8 @@ private:
std::map<ValueType::Id, ValueType> types {};
};
struct CryptoValueCache;
/**
* A "value" is data potentially stored on the Dht, with some metadata.
*
@@ -163,6 +165,13 @@ struct OPENDHT_PUBLIC Value
return chainOr(std::move(f1), std::move(f2));
}
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(v) and f2(v);
};
}
static Filter chain(const Filter& f1, const Filter& f2) {
if (not f1) return f2;
if (not f2) return f1;
return [f1,f2](const Value& v) {
@@ -182,11 +191,15 @@ struct OPENDHT_PUBLIC Value
return chainAll(std::vector<Filter>(l.begin(), l.end()));
}
static Filter chainOr(Filter&& f1, Filter&& f2) {
if (not f1 or not f2) return AllFilter();
if (not f1 or not f2) return {};
return [f1,f2](const Value& v) {
return f1(v) or f2(v);
};
}
static Filter notFilter(Filter&& f) {
if (not f) return [](const Value&) { return false; };
return [f](const Value& v) { return not f(v); };
}
std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values) {
if (not (*this))
return values;
@@ -372,13 +385,13 @@ struct OPENDHT_PUBLIC Value
Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID)
: id(id), type(t), data(dat_ptr, dat_ptr+dat_len) {}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
/**
* Build a value from a json object
* @param json
*/
Value(Json::Value& json);
#endif //OPENDHT_PROXY_SERVER
#endif
template <typename Type>
Value(ValueType::Id t, const Type& d, Id id = INVALID_ID)
@@ -451,7 +464,7 @@ struct OPENDHT_PUBLIC Value
return ss.str();
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a value
* Example:
@@ -461,7 +474,7 @@ struct OPENDHT_PUBLIC Value
* }
*/
Json::Value toJson() const;
#endif //OPENDHT_PROXY_SERVER
#endif
/** Return the size in bytes used by this value in memory (minimum). */
size_t size() const;
@@ -588,6 +601,14 @@ struct OPENDHT_PUBLIC Value
* Hold encrypted version of the data.
*/
Blob cypher {};
private:
friend class SecureDht;
/* Cache for crypto ops */
bool signatureChecked {false};
bool signatureValid {false};
bool decrypted {false};
Sp<Value> decryptedValue {};
};
using ValuesExport = std::pair<InfoHash, Blob>;
@@ -864,7 +885,7 @@ struct OPENDHT_PUBLIC Query
{
static const std::string QUERY_PARSE_ERROR;
Query(Select s = {}, Where w = {}, bool none = false) : select(s), where(w), none(none) { };
Query(Select s = {}, Where w = {}, bool none = false) : select(std::move(s)), where(std::move(w)), none(none) { };
/**
* Initializes a query based on a SQL-ish formatted string. The abstract
@@ -926,7 +947,7 @@ struct OPENDHT_PUBLIC Query
*/
struct OPENDHT_PUBLIC FieldValueIndex {
FieldValueIndex() {}
FieldValueIndex(const Value& v, Select s = {});
FieldValueIndex(const Value& v, const Select& s = {});
/**
* Tells if all the fields of this are contained in the other
* FieldValueIndex with the same value.
@@ -980,7 +1001,7 @@ template <typename T,
Value::Filter
getFilterSet()
{
return Value::AllFilter();
return {};
}
template <class T>
@@ -996,7 +1017,7 @@ unpackVector(const std::vector<std::shared_ptr<Value>>& vals) {
return ret;
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
uint64_t unpackId(const Json::Value& json, const std::string& key);
#endif
+8 -2
View File
@@ -1,11 +1,11 @@
# distutils: language = c++
# distutils: extra_compile_args = -std=c++11
# distutils: extra_compile_args = -std=c++14
# distutils: include_dirs = ../../include
# distutils: library_dirs = ../../src
# distutils: libraries = opendht gnutls
# cython: language_level=3
#
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
@@ -139,6 +139,12 @@ cdef class SockAddr(object):
return self._addr.setPort(port)
def setFamily(SockAddr self, cpp.sa_family_t af):
return self._addr.setFamily(af)
def isLoopback(SockAddr self):
return self._addr.isLoopback()
def isPrivate(SockAddr self):
return self._addr.isPrivate()
def isUnspecified(SockAddr self):
return self._addr.isUnspecified()
def __str__(self):
return self.toString().decode()
def __repr__(self):
+4 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
@@ -77,6 +77,9 @@ cdef extern from "opendht/sockaddr.h" namespace "dht":
void setPort(in_port_t p)
sa_family_t getFamily() const
void setFamily(sa_family_t f)
bool isLoopback() const
bool isPrivate() const
bool isUnspecified() const
ctypedef vector[uint8_t] Blob
+3 -3
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
@@ -50,8 +50,8 @@ setup(name="opendht",
["@CURRENT_SOURCE_DIR@/opendht.pyx"],
include_dirs = ['@PROJECT_SOURCE_DIR@/include'],
language="c++",
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"],
extra_compile_args=["-std=c++14"],
extra_link_args=["-std=c++14"],
libraries=["opendht"],
library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@']
))
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 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-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 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,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015 Savoir-Faire Linux Inc.
# Copyright (C) 2015-2019 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-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 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,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 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 @@
#!/usr/bin/env python3
# Copyright (c) 2016 Savoir-faire Linux Inc.
# Copyright (c) 2016-2019 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 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 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 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2017 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@ ping_node.run()
pong_node = dht.DhtRunner()
pong_node.run()
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound());
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
@@ -42,7 +42,7 @@ def done(h, ok):
def ping(node, h):
global i
time.sleep(0.0075)
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
@@ -51,7 +51,7 @@ def ping(node, h):
def pong(node, h):
print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h);
loop.call_soon_threadsafe(ping, node, h)
return True
ping_node.listen(loc_ping, lambda v: pong(pong_node, loc_pong))
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+12 -6
View File
@@ -1,8 +1,8 @@
lib_LTLIBRARIES = libopendht.la
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -26,7 +26,10 @@ libopendht_la_SOURCES = \
securedht.cpp \
dhtrunner.cpp \
default_types.cpp \
log.cpp
log.cpp \
peer_discovery.cpp \
network_utils.cpp \
thread_pool.cpp
if WIN32
libopendht_la_SOURCES += rng.cpp
@@ -53,7 +56,10 @@ nobase_include_HEADERS = \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/log_enable.h \
../include/opendht/rng.h
../include/opendht/peer_discovery.h \
../include/opendht/network_utils.h \
../include/opendht/rng.h \
../include/opendht/thread_pool.h
if ENABLE_PROXY_SERVER
libopendht_la_SOURCES += dht_proxy_server.cpp
@@ -65,8 +71,8 @@ libopendht_la_SOURCES += dht_proxy_client.cpp
nobase_include_HEADERS += ../include/opendht/dht_proxy_client.h ../include/opendht/dht_interface.h
endif
if PROXY_CLIENT_OR_SERVER
libopendht_la_SOURCES += base64.h base64.cpp
if PROXY_CLIENT_OR_SERVER
nobase_include_HEADERS += ../include/opendht/proxy.h
endif
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 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
@@ -17,8 +17,8 @@
#include "base64.h"
#include <stdint.h>
#include <stdlib.h>
#include <cstdint>
#include <cstdlib>
/* Mainly based on the following stackoverflow question:
* http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 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
+35 -11
View File
@@ -4,7 +4,7 @@ namespace dht {
GetCallbackSimple
bindGetCb(GetCallbackRaw raw_cb, void* user_data)
bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](const std::shared_ptr<Value>& value) {
@@ -13,7 +13,7 @@ bindGetCb(GetCallbackRaw raw_cb, void* user_data)
}
GetCallback
bindGetCb(GetCallbackSimple cb)
bindGetCb(const GetCallbackSimple& cb)
{
if (not cb) return {};
return [=](const std::vector<std::shared_ptr<Value>>& values) {
@@ -25,7 +25,7 @@ bindGetCb(GetCallbackSimple cb)
}
ShutdownCallback
bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data)
bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data)
{
return [=]() { shutdown_cb_raw(user_data); };
}
@@ -39,7 +39,7 @@ bindDoneCb(DoneCallbackSimple donecb)
}
DoneCallback
bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](bool success, const std::vector<std::shared_ptr<Node>>& nodes) {
@@ -48,7 +48,7 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
}
DoneCallbackSimple
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](bool success) {
raw_cb(success, user_data);
@@ -62,13 +62,12 @@ NodeStats::toString() const
ss << "Known nodes: " << good_nodes << " good, " << dubious_nodes << " dubious, " << incoming_nodes << " incoming." << std::endl;
if (table_depth > 1) {
ss << "Routing table depth: " << table_depth << std::endl;
unsigned long tot_nodes = 8 * std::exp2(table_depth);
ss << "Network size estimation: " << tot_nodes << " nodes" << std::endl;
ss << "Network size estimation: " << getNetworkSizeEstimation() << " nodes" << std::endl;
}
return ss.str();
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
@@ -81,8 +80,7 @@ NodeStats::toJson() const
val["incoming"] = static_cast<Json::LargestUInt>(incoming_nodes);
if (table_depth > 1) {
val["table_depth"] = static_cast<Json::LargestUInt>(table_depth);
unsigned long tot_nodes = 8 * std::exp2(table_depth);
val["network_size_estimation"] = static_cast<Json::LargestUInt>(tot_nodes);
val["network_size_estimation"] = static_cast<Json::LargestUInt>(getNetworkSizeEstimation());
}
return val;
}
@@ -98,6 +96,32 @@ NodeStats::NodeStats(const Json::Value& val)
if (val.isMember("table_depth"))
table_depth = static_cast<unsigned>(val["table_depth"].asLargestUInt());
}
#endif //OPENDHT_PROXY_SERVER
/**
* Build a json object from a NodeStats
*/
Json::Value
NodeInfo::toJson() const
{
Json::Value val;
if (id)
val["id"] = id.toString();
val["node_id"] = node_id.toString();
val["ipv4"] = ipv4.toJson();
val["ipv6"] = ipv6.toJson();
return val;
}
NodeInfo::NodeInfo(const Json::Value& v)
{
if (v.isMember("id"))
id = InfoHash(v["id"].asString());
node_id = InfoHash(v["node_id"].asString());
ipv4 = NodeStats(v["ipv4"]);
ipv6 = NodeStats(v["ipv6"]);
}
#endif
}
+281 -106
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,7 @@ extern "C" {
#include <random>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <cassert>
@@ -40,31 +41,6 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey)
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt)
{
gnutls_pubkey_t pubkey;
gnutls_pubkey_init(&pubkey);
int result = gnutls_pubkey_import_x509(pubkey, crt, 0);
if (result < 0) {
gnutls_pubkey_deinit(pubkey);
return GNUTLS_DIG_UNKNOWN;
}
gnutls_digest_algorithm_t dig = get_dig_for_pub(pubkey);
gnutls_pubkey_deinit(pubkey);
return dig;
}
// support for GnuTLS < 3.4.
#if GNUTLS_VERSION_NUMBER < 0x030400
#define GNUTLS_PKCS_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES
@@ -377,15 +353,19 @@ PrivateKey::serialize(const std::string& password) const
PublicKey
PrivateKey::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret {pk};
if (gnutls_pubkey_import_privkey(pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0) != GNUTLS_E_SUCCESS)
return {};
return pk_ret;
PublicKey pk;
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
return pk;
}
PublicKey::PublicKey(const Blob& dat) : pk(nullptr)
PublicKey::PublicKey()
{
if (auto err = gnutls_pubkey_init(&pk))
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const Blob& dat) : PublicKey()
{
unpack(dat.data(), dat.size());
}
@@ -415,8 +395,7 @@ 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();
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, 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());
@@ -425,9 +404,6 @@ PublicKey::pack(Blob& b) const
void
PublicKey::unpack(const uint8_t* data, size_t data_size)
{
if (pk)
gnutls_pubkey_deinit(pk);
gnutls_pubkey_init(&pk);
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)data_size};
int err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
@@ -446,10 +422,9 @@ PublicKey::toString() const
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
ret.resize(sz);
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
} else if (err != GNUTLS_E_SUCCESS)
err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
}
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
return ret;
}
@@ -572,7 +547,180 @@ PublicKey::getLongId() const
#endif
}
Certificate::Certificate(const Blob& certData) : cert(nullptr)
gnutls_digest_algorithm_t
PublicKey::getPreferredDigest() const
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pk, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
// Certificate Request
static NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return NameType::RFC822;
case GNUTLS_SAN_URI:
return NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return NameType::IP;
default:
return NameType::UNKNOWN;
}
}
static gnutls_x509_subject_alt_name_t
GnuTLSFromType(NameType type)
{
switch(type) {
case NameType::DNS:
return GNUTLS_SAN_DNSNAME;
case NameType::RFC822:
return GNUTLS_SAN_RFC822NAME;
case NameType::URI:
return GNUTLS_SAN_URI;
case NameType::IP:
return GNUTLS_SAN_IPADDRESS;
default:
return (gnutls_x509_subject_alt_name_t)0;
}
}
static std::string
getDN(gnutls_x509_crq_t request, const char* oid)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = gnutls_x509_crq_get_dn_by_oid(request, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
CertificateRequest::CertificateRequest()
{
if (auto err = gnutls_x509_crq_init(&request))
throw CryptoException(std::string("Can't initialize certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::CertificateRequest(const uint8_t* data, size_t size) : CertificateRequest()
{
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)size};
if (auto err = gnutls_x509_crq_import(request, &dat, GNUTLS_X509_FMT_PEM))
throw CryptoException(std::string("Can't import certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::~CertificateRequest()
{
if (request) {
gnutls_x509_crq_deinit(request);
request = nullptr;
}
}
CertificateRequest&
CertificateRequest::operator=(CertificateRequest&& o) noexcept
{
if (request)
gnutls_x509_crq_deinit(request);
request = o.request;
o.request = nullptr;
return *this;
}
void
CertificateRequest::setAltName(NameType type, const std::string& name)
{
gnutls_x509_crq_set_subject_alt_name(request, GnuTLSFromType(type), name.data(), name.size(), 0);
}
void
CertificateRequest::setName(const std::string& name)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
}
std::string
CertificateRequest::getName() const
{
return getDN(request, GNUTLS_OID_X520_COMMON_NAME);
}
std::string
CertificateRequest::getUID() const
{
return getDN(request, GNUTLS_OID_LDAP_UID);
}
void
CertificateRequest::setUID(const std::string& uid)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_LDAP_UID, 0, uid.data(), uid.length());
}
void
CertificateRequest::sign(const PrivateKey& key, const std::string& password)
{
gnutls_x509_crq_set_version(request, 1);
if (not password.empty())
gnutls_x509_crq_set_challenge_password(request, password.c_str());
if (auto err = gnutls_x509_crq_set_key(request, key.x509_key))
throw CryptoException(std::string("Can't set certificate request key: ") + gnutls_strerror(err));
#if GNUTLS_VERSION_NUMBER < 0x030601
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, key.getPublicKey().getPreferredDigest(), 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#else
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, GNUTLS_DIG_UNKNOWN, 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#endif
}
bool
CertificateRequest::verify() const
{
return gnutls_x509_crq_verify(request, 0) >= 0;
}
Blob
CertificateRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
Blob ret(dat.data, dat.data + dat.size);
gnutls_free(dat.data);
return ret;
}
// Certificate
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
Certificate::Certificate(const Blob& certData)
{
unpack(certData.data(), certData.size());
}
@@ -656,11 +804,9 @@ Certificate::~Certificate()
PublicKey
Certificate::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret(pk);
if (gnutls_pubkey_import_x509(pk, cert, 0) != GNUTLS_E_SUCCESS)
return {};
PublicKey pk_ret;
if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
return pk_ret;
}
@@ -696,21 +842,6 @@ Certificate::getLongId() const
#endif
}
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
std::string
Certificate::getName() const
{
@@ -735,24 +866,7 @@ Certificate::getIssuerUID() const
return getDN(cert, GNUTLS_OID_LDAP_UID, true);
}
static Certificate::NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return Certificate::NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return Certificate::NameType::RFC822;
case GNUTLS_SAN_URI:
return Certificate::NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return Certificate::NameType::IP;
default:
return Certificate::NameType::UNKNOWN;
}
}
std::vector<std::pair<Certificate::NameType, std::string>>
std::vector<std::pair<NameType, std::string>>
Certificate::getAltNames() const
{
std::vector<std::pair<NameType, std::string>> names;
@@ -867,6 +981,14 @@ Certificate::getExpiration() const
return std::chrono::system_clock::from_time_t(t);
}
gnutls_digest_algorithm_t
Certificate::getPreferredDigest() const
{
return getPublicKey().getPreferredDigest();
}
// PrivateKey
PrivateKey
PrivateKey::generate(unsigned key_length)
{
@@ -896,7 +1018,7 @@ PrivateKey::generateEC()
}
Identity
generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca)
{
auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -905,12 +1027,12 @@ generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_leng
Identity
generateIdentity(const std::string& name, Identity ca, unsigned key_length) {
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length) {
return generateIdentity(name, ca, key_length, !ca.first || !ca.second);
}
Identity
generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca)
{
auto key = std::make_shared<PrivateKey>(PrivateKey::generateEC());
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -918,25 +1040,55 @@ generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
}
Identity
generateEcIdentity(const std::string& name, Identity ca) {
generateEcIdentity(const std::string& name, const Identity& ca) {
return generateEcIdentity(name, ca, !ca.first || !ca.second);
}
void
saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password)
{
{
auto ca_key_data = id.first->serialize(privkey_password);
std::ofstream key_file(path + ".pem");
key_file.write((char*)ca_key_data.data(), ca_key_data.size());
}
{
auto ca_key_data = id.second->getPacked();
std::ofstream crt_file(path + ".crt");
crt_file.write((char*)ca_key_data.data(), ca_key_data.size());
}
}
void
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
{
int64_t now = time(nullptr);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + validity));
}
void
setRandomSerial(gnutls_x509_crt_t cert)
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
Certificate
Certificate::generate(const PrivateKey& key, const std::string& name, Identity ca, bool is_ca)
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
{
gnutls_x509_crt_t cert;
if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
return {};
Certificate ret {cert};
int64_t now = time(NULL);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + (10 * 365 * 24 * 60 * 60)));
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate key" << std::endl;
return {};
@@ -947,19 +1099,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
}
// TODO: compute the subject key using the recommended RFC method
auto pk_id = key.getPublicKey().getId();
auto pk = key.getPublicKey();
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
@@ -975,15 +1123,13 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
// Signing certificate must be CA.
return {};
}
//if (gnutls_x509_crt_sign2(cert, ca.second->cert, ca.first->x509_key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
ret.issuer = ca.second;
} else {
//if (gnutls_x509_crt_sign2(cert, cert, key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
@@ -992,6 +1138,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
return ret.getPacked();
}
Certificate
Certificate::generate(const CertificateRequest& request, const Identity& ca)
{
gnutls_x509_crt_t cert;
if (auto err = gnutls_x509_crt_init(&cert))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
Certificate ret {cert};
if (auto err = gnutls_x509_crt_set_crq(cert, request.get()))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crt_set_version(cert, 3)) {
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
}
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
setRandomSerial(cert);
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
throw CryptoException(std::string("Can't sign certificate: ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
return ret.getPacked();
}
std::vector<std::shared_ptr<RevocationList>>
Certificate::getRevocationLists() const
{
@@ -1002,6 +1173,8 @@ Certificate::getRevocationLists() const
return ret;
}
// RevocationList
RevocationList::RevocationList()
{
gnutls_x509_crl_init(&crl);
@@ -1219,6 +1392,8 @@ RevocationList::toString() const
return ret;
}
// TrustList
TrustList::TrustList() {
gnutls_x509_trust_list_init(&trust, 0);
}
@@ -1228,11 +1403,11 @@ TrustList::~TrustList() {
}
TrustList&
TrustList::operator=(TrustList&& o)
TrustList::operator=(TrustList&& o) noexcept
{
if (trust)
gnutls_x509_trust_list_deinit(trust, true);
trust = std::move(o.trust);
trust = o.trust;
o.trust = nullptr;
return *this;
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ DhtMessage::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const InfoHash& f
}
Value::Filter
DhtMessage::ServiceFilter(std::string s)
DhtMessage::ServiceFilter(const std::string& s)
{
return Value::Filter::chain(
Value::TypeFilter(TYPE),
+419 -339
View File
File diff suppressed because it is too large. Load diff
+992 -681
View File
File diff suppressed because it is too large. Load diff
+887 -653
View File
File diff suppressed because it is too large. Load diff
+286 -212
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
@@ -20,40 +20,44 @@
#include "dhtrunner.h"
#include "securedht.h"
#include "peer_discovery.h"
#include "network_utils.h"
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
#ifndef _WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#ifndef _WIN32
#include <sys/socket.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#ifdef _WIN32
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#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 {
size_t tokenClassicDht;
size_t tokenProxyDht;
size_t tokenClassicDht {0};
size_t tokenProxyDht {0};
ValueCallback gcb;
InfoHash hash;
InfoHash hash {};
Value::Filter f;
Where w;
};
struct NodeInsertionPack {
dht::InfoHash nodeId;
in_port_t port;
dht::NetId net;
MSGPACK_DEFINE(nodeId, port, net)
};
DhtRunner::DhtRunner() : dht_()
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
, dht_via_proxy_()
#endif //OPENDHT_PROXY_CLIENT
{
@@ -73,7 +77,7 @@ DhtRunner::~DhtRunner()
}
void
DhtRunner::run(in_port_t port, DhtRunner::Config config)
DhtRunner::run(in_port_t port, const Config& config, Context&& context)
{
SockAddr sin4;
sin4.setFamily(AF_INET);
@@ -81,45 +85,76 @@ DhtRunner::run(in_port_t port, DhtRunner::Config config)
SockAddr sin6;
sin6.setFamily(AF_INET6);
sin6.setPort(port);
run(sin4, sin6, config);
run(sin4, sin6, config, std::move(context));
}
void
DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner::Config config)
DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context)
{
auto res4 = SockAddr::resolve(ip4, service);
auto res6 = SockAddr::resolve(ip6, service);
run(res4.empty() ? SockAddr() : res4.front(),
res6.empty() ? SockAddr() : res6.front(), config);
res6.empty() ? SockAddr() : res6.front(), config, std::move(context));
}
void
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config config)
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context)
{
if (not running) {
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
run(config, std::move(context));
}
}
void
DhtRunner::run(const Config& config, Context&& context)
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (running)
return;
startNetwork(local4, local6);
auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config)));
if (context.logger)
logger_ = context.logger;
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
{
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();
}
rcv.emplace(std::move(pkt));
}
cv.notify_all();
});
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config)));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
config_ = config;
#endif
enableProxy(not config.proxy_server.empty());
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(*context.logger);
}
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
}
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
}
running = true;
if (not config.threaded)
return;
dht_thread = std::thread([this, local4, local6]() {
dht_thread = std::thread([this]() {
while (running) {
std::unique_lock<std::mutex> lk(dht_mtx);
time_point wakeup;
try {
wakeup = loop_();
} catch (const dht::SocketException& e) {
startNetwork(local4, local6);
}
time_point wakeup = loop_();
auto hasJobToDo = [this]() {
if (not running)
@@ -145,17 +180,57 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
cv.wait_until(lk, wakeup, hasJobToDo);
}
});
if (config.peer_discovery or config.peer_publish) {
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
}
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){
addr.setPort(v.port);
if (v.nodeId != dht_->getNodeId() && netId == v.net){
bootstrap(v.nodeId, addr);
}
});
}
if (config.peer_publish) {
msgpack::sbuffer sbuf_node;
NodeInsertionPack adc;
adc.net = netId;
adc.nodeId = dht_->getNodeId();
// IPv4
if (auto bound4 = dht_->getSocket()->getBound(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)) {
adc.port = bound6.getPort();
sbuf_node.clear();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
}
void
DhtRunner::shutdown(ShutdownCallback cb) {
#if OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
#endif
if (not running) {
cb();
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
dht.shutdown(cb);
pending_ops_prio.emplace([=](SecureDht&) mutable {
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
#endif
if (dht_)
dht_->shutdown(cb);
});
cv.notify_all();
}
@@ -163,16 +238,28 @@ DhtRunner::shutdown(ShutdownCallback cb) {
void
DhtRunner::join()
{
running_network = false;
running = false;
cv.notify_all();
bootstrap_cv.notify_all();
if (peerDiscovery_)
peerDiscovery_->stop();
{
std::lock_guard<std::mutex> lck(dht_mtx);
running = false;
cv.notify_all();
bootstrap_cv.notify_all();
if (dht_)
if (auto sock = dht_->getSocket())
sock->stop();
}
if (dht_thread.joinable())
dht_thread.join();
if (bootstrap_thread.joinable())
bootstrap_thread.join();
if (rcv_thread.joinable())
rcv_thread.join();
if (peerDiscovery_) {
peerDiscovery_->join();
}
{
std::lock_guard<std::mutex> lck(storage_mtx);
@@ -187,6 +274,15 @@ DhtRunner::join()
}
}
SockAddr
DhtRunner::getBound(sa_family_t af) const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
if (auto sock = dht_->getSocket())
return sock->getBound(af);
return SockAddr{};
}
void
DhtRunner::dumpTables() const
{
@@ -197,17 +293,17 @@ DhtRunner::dumpTables() const
InfoHash
DhtRunner::getId() const
{
if (!activeDht())
return {};
return activeDht()->getId();
if (auto dht = activeDht())
return dht->getId();
return {};
}
InfoHash
DhtRunner::getNodeId() const
{
if (!activeDht())
return {};
return activeDht()->getNodeId();
if (auto dht = activeDht())
return dht->getNodeId();
return {};
}
@@ -244,23 +340,29 @@ DhtRunner::exportValues() const {
}
void
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
DhtRunner::setLogger(const Logger& logger) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
#if OPENDHT_PROXY_CLIENT
dht_->setLogger(logger);
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
dht_via_proxy_->setLogger(logger);
#endif
}
void
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
Logger logger {std::move(error), std::move(warn), std::move(debug)};
setLogger(logger);
}
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->setLogFilter(f);
if (dht_)
dht_->setLogFilter(f);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLogFilter(f);
#endif
@@ -301,6 +403,17 @@ DhtRunner::getNodesStats(sa_family_t af) const
return activeDht()->getNodesStats(af);
}
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);
return info;
}
std::vector<unsigned>
DhtRunner::getNodeMessageStats(bool in) const
{
@@ -342,7 +455,9 @@ std::vector<SockAddr>
DhtRunner::getPublicAddress(sa_family_t af)
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getPublicAddress(af);
if (auto dht = activeDht())
return dht->getPublicAddress(af);
return {};
}
std::vector<std::string>
DhtRunner::getPublicAddressStr(sa_family_t af)
@@ -361,7 +476,7 @@ DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
void
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
#endif
@@ -395,17 +510,35 @@ DhtRunner::loop_()
// move to stack
received = std::move(rcv);
}
// Discard old packets
size_t dropped {0};
if (not received.empty()) {
for (const auto& pck : received) {
auto& buf = pck.first;
auto& from = pck.second;
wakeup = dht->periodic(buf.data(), buf.size()-1, from);
auto now = clock::now();
while (not received.empty() and now - received.front()->received > RX_QUEUE_MAX_DELAY) {
received.pop();
dropped++;
}
}
// Handle packets
if (not received.empty()) {
while (not received.empty()) {
auto& pck = received.front();
if (clock::now() - pck->received > RX_QUEUE_MAX_DELAY)
dropped++;
else
wakeup = dht->periodic(pck->data.data(), pck->data.size(), std::move(pck->from));
received.pop();
}
received.clear();
} else {
// Or just run the scheduler
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
}
if (dropped)
std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl;
NodeStatus nstatus4 = dht->getStatus(AF_INET);
NodeStatus nstatus6 = dht->getStatus(AF_INET6);
if (nstatus4 != status4 || nstatus6 != status6) {
@@ -427,113 +560,13 @@ DhtRunner::loop_()
return wakeup;
}
int bindSocket(const SockAddr& addr, SockAddr& bound)
{
bool is_ipv6 = addr.getFamily() == AF_INET6;
int sock = socket(is_ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
if (sock < 0)
throw DhtException(std::string("Can't open socket: ") + strerror(sock));
int set = 1;
#ifdef SO_NOSIGPIPE
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&set, sizeof(set));
#endif
if (is_ipv6)
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&set, sizeof(set));
int rc = bind(sock, addr.get(), addr.getLength());
if(rc < 0)
throw DhtException("Can't bind socket on " + addr.toString() + " " + strerror(rc));
sockaddr_storage ss;
socklen_t ss_len = sizeof(ss);
getsockname(sock, (sockaddr*)&ss, &ss_len);
bound = {ss, ss_len};
return sock;
}
void
DhtRunner::startNetwork(const SockAddr sin4, const SockAddr sin6)
{
running_network = false;
if (rcv_thread.joinable())
rcv_thread.join();
s4 = -1;
s6 = -1;
bound4 = {};
if (sin4)
s4 = bindSocket(sin4, bound4);
#if 1
bound6 = {};
if (sin6)
s6 = bindSocket(sin6, bound6);
#endif
running_network = true;
rcv_thread = std::thread([this]() {
try {
while (running_network) {
struct timeval tv {/*.tv_sec = */0, /*.tv_usec = */250000};
fd_set readfds;
FD_ZERO(&readfds);
if(s4 >= 0)
FD_SET(s4, &readfds);
if(s6 >= 0)
FD_SET(s6, &readfds);
int rc = select(s4 > s6 ? s4 + 1 : s6 + 1, &readfds, nullptr, nullptr, &tv);
if(rc < 0) {
if(errno != EINTR) {
perror("select");
std::this_thread::sleep_for( std::chrono::seconds(1) );
}
}
if (not running_network)
break;
if(rc > 0) {
std::array<uint8_t, 1024 * 64> buf;
sockaddr_storage from;
socklen_t from_len = sizeof(from);
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
break;
if (rc > 0) {
{
std::lock_guard<std::mutex> lck(sock_mtx);
rcv.emplace_back(Blob {buf.begin(), buf.begin()+rc+1}, SockAddr(from, from_len));
}
cv.notify_all();
}
}
}
} catch (const std::exception& e) {
std::cerr << "Error in DHT networking thread: " << e.what() << std::endl;
}
if (s4 >= 0)
close(s4);
if (s6 >= 0)
close(s6);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
});
}
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, vcb, dcb, std::move(f), std::move(w));
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
});
}
cv.notify_all();
@@ -542,14 +575,14 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
void
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
{
get(InfoHash::get(key), vcb, dcb, f, w);
get(InfoHash::get(key), std::move(vcb), std::move(dcb), std::move(f), std::move(w));
}
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, cb, done_cb, std::move(q));
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
});
}
cv.notify_all();
@@ -562,28 +595,27 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
Listener listener {};
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){
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
#if OPENDHT_PROXY_CLIENT
cancelListen(hash, tokenbGlobal);
#endif
return false;
}
return true;
};
#if OPENDHT_PROXY_CLIENT
if (use_proxy)
listener.tokenProxyDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
else
#endif
listener.tokenClassicDht = dht.listen(hash, listener.gcb, listener.f, listener.w);
listeners_.emplace(tokenbGlobal, std::move(listener));
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();
@@ -593,26 +625,30 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
std::future<size_t>
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
{
return listen(InfoHash::get(key), vcb, f, w);
return listen(InfoHash::get(key), std::move(vcb), std::move(f), std::move(w));
}
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
#if OPENDHT_PROXY_CLIENT
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);
{
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);
});
#else
dht.cancelListen(h, token);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
#endif // OPENDHT_PROXY_CLIENT
});
}
cv.notify_all();
}
@@ -621,20 +657,21 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
auto token = ftoken.get();
#if OPENDHT_PROXY_CLIENT
auto it = listeners_.find(token);
#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);
#else
dht.cancelListen(h, token);
#endif // OPENDHT_PROXY_CLIENT
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
@@ -667,7 +704,7 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
void
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
{
put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
put(InfoHash::get(key), std::forward<Value>(value), std::move(cb), created, permanent);
}
void
@@ -697,13 +734,13 @@ DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback c
void
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
{
putSigned(hash, std::make_shared<Value>(std::move(value)), cb);
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), cb);
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
}
void
@@ -721,13 +758,13 @@ DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), cb);
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
}
void
@@ -833,6 +870,18 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
cv.notify_all();
}
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);
});
}
cv.notify_all();
}
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
@@ -851,7 +900,7 @@ DhtRunner::connectivityChanged()
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
}
@@ -872,8 +921,9 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_p
void
DhtRunner::resetDht()
{
peerDiscovery_.reset();
#ifdef OPENDHT_PROXY_CLIENT
listeners_.clear();
#if OPENDHT_PROXY_CLIENT
dht_via_proxy_.reset();
#endif // OPENDHT_PROXY_CLIENT
dht_.reset();
@@ -882,17 +932,33 @@ DhtRunner::resetDht()
SecureDht*
DhtRunner::activeDht() const
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
return use_proxy? dht_via_proxy_.get() : dht_.get();
#else
return dht_.get();
#endif // OPENDHT_PROXY_CLIENT
}
void
DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeId)
{
#ifdef OPENDHT_PROXY_CLIENT
std::lock_guard<std::mutex> lck(dht_mtx);
if (config_.proxy_server == proxy and config_.push_node_id == pushNodeId)
return;
config_.proxy_server = proxy;
config_.push_node_id = pushNodeId;
enableProxy(use_proxy and not config_.proxy_server.empty());
#else
if (not proxy.empty())
std::cerr << "DHT proxy requested but OpenDHT built without proxy support." << std::endl;
#endif
}
void
DhtRunner::enableProxy(bool proxify)
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_) {
dht_via_proxy_->shutdown({});
}
@@ -907,10 +973,10 @@ DhtRunner::enableProxy(bool proxify)
}
cv.notify_all();
}
}, config_.proxy_server, config_.push_node_id)
}, 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));
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not pushToken_.empty())
dht_via_proxy_->setPushNotificationToken(pushToken_);
#endif
@@ -943,13 +1009,16 @@ DhtRunner::enableProxy(bool proxify)
void
DhtRunner::forwardAllMessages(bool forward)
{
#if OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
std::lock_guard<std::mutex> lck(dht_mtx);
#ifdef OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->forwardAllMessages(forward);
#endif // OPENDHT_PROXY_CLIENT
if (dht_)
dht_->forwardAllMessages(forward);
#else
(void) forward;
#endif // OPENDHT_PROXY_SERVER
}
@@ -958,25 +1027,30 @@ DhtRunner::forwardAllMessages(bool forward)
*/
void
DhtRunner::setPushNotificationToken(const std::string& token) {
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
std::lock_guard<std::mutex> lck(dht_mtx);
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
pushToken_ = token;
if (dht_via_proxy_)
dht_via_proxy_->setPushNotificationToken(token);
#else
(void) token;
#endif
}
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
{
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
pending_ops_prio.emplace([=](SecureDht&) {
if (dht_via_proxy_)
dht_via_proxy_->pushNotificationReceived(data);
});
}
cv.notify_all();
#else
(void) data;
#endif
}
+519
View File
@@ -0,0 +1,519 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@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/>.
*/
#include "http.h"
namespace http {
constexpr char HTTP_HEADER_CONTENT_LENGTH[] = "Content-Length:";
// connection
Connection::Connection(asio::ip::tcp::socket socket, std::shared_ptr<dht::Logger> logger):
id_(++ids_), socket_(std::move(socket)), logger_(logger)
{}
Connection::~Connection(){
close();
}
ConnectionId
Connection::id(){
return id_;
}
bool
Connection::is_open(){
return socket_.is_open();
}
bool
Connection::is_v6(){
return endpoint_.address().is_v6();
}
void
Connection::timeout(const std::chrono::seconds timeout, HandlerCb cb)
{
if (!is_open()){
if (logger_)
logger_->e("[connection:%i] closed, can't timeout", id_);
return;
}
if (!timeout_timer_)
timeout_timer_ = std::make_unique<asio::steady_timer>(io_context());
timeout_timer_->expires_at(std::chrono::steady_clock::now() + timeout);
timeout_timer_->async_wait([this, cb](const asio::error_code &ec){
if (ec == asio::error_code::operation_aborted)
return;
else if (ec){
if (logger_)
logger_->e("[connection:%i] timeout error: %s", id_, ec.message().c_str());
}
if (cb)
cb(ec);
});
}
void
Connection::close(){
socket_.close();
}
// connection listener
ConnectionListener::ConnectionListener()
{}
ConnectionListener::ConnectionListener(std::shared_ptr<dht::DhtRunner> dht,
std::shared_ptr<std::map<restinio::connection_id_t, http::ListenerSession>> listeners,
std::shared_ptr<std::mutex> lock, std::shared_ptr<dht::Logger> logger):
dht_(dht), lock_(lock), listeners_(listeners), logger_(logger)
{}
ConnectionListener::~ConnectionListener()
{
}
void
ConnectionListener::state_changed(const restinio::connection_state::notice_t& notice) noexcept
{
std::lock_guard<std::mutex> lock(*lock_);
auto id = notice.connection_id();
auto cause = to_str(notice.cause());
if (listeners_->find(id) != listeners_->end()){
if (notice.cause() == restinio::connection_state::cause_t::closed){
if (logger_)
logger_->d("[proxy:server] [connection:%li] cancelling listener", id);
dht_->cancelListen(listeners_->at(id).hash,
std::move(listeners_->at(id).token));
listeners_->erase(id);
if (logger_)
logger_->d("[proxy:server] %li listeners are connected", listeners_->size());
}
}
}
std::string
ConnectionListener::to_str(restinio::connection_state::cause_t cause) noexcept
{
std::string result;
switch(cause)
{
case restinio::connection_state::cause_t::accepted:
result = "accepted";
break;
case restinio::connection_state::cause_t::closed:
result = "closed";
break;
case restinio::connection_state::cause_t::upgraded_to_websocket:
result = "upgraded";
break;
default:
result = "unknown";
}
return result;
}
// request
Request::Request(asio::io_context& ctx, const std::string host, const std::string service,
const bool resolve, std::shared_ptr<dht::Logger> logger):
id_(++ids_), resolver_(ctx), logger_(logger)
{
if (resolve)
resolve(host, service);
}
Request::~Request()
{
terminate();
}
void
Request::set_logger(std::shared_ptr<dht::Logger> logger)
{
logger_ = logger;
}
void
Request::terminate()
{
if (parser_)
// ensure on_message_complete callback is called
http_parser_execute(parser_.get(), parser_s_.get(), "", 0);
if (logger_)
logger_->d("[http:request:%i] done", id_);
}
bool
Request::resolved()
{
return !endpoints_.empty();
}
void
Request::resolve(const std::string host, const std::string service, HandlerCb cb)
{
// build the query
asio::ip::tcp::resolver::query query(host, service);
// resolve the query to the server
resolver_.async_resolve(query, [this, host, service, cb]
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
{
if (ec){
if (logger_)
logger_->e("[http:request:%i] error resolving %s:%s: %s",
id_, host.c_str(), service.c_str(), ec.message().c_str());
}
else {
for (auto it = endpoints.begin(); it != endpoints.end(); ++it){
if (logger_){
asio::ip::tcp::endpoint endpoint = *it;
logger_->d("[http:request:%i] resolved %s:%s: address=%s ipv%i",
id_, host.c_str(), service.c_str(), endpoint.address().to_string().c_str(),
endpoint.address().is_v6() ? 6 : 4);
}
}
endpoints_ = endpoints;
}
if (cb)
cb(ec);
});
}
std::string
Request::build(const restinio::http_request_header_t header,
const restinio::http_header_fields_t header_fields,
const restinio::http_connection_header_t connection, const std::string body)
{
std::stringstream request;
// first header
request << header.method().c_str() << " " << header.request_target() << " " <<
"HTTP/" << header.http_major() << "." << header.http_minor() << "\r\n";
// other headers
for (auto header_field: header_fields)
request << header_field.name() << ": " << header_field.value() << "\r\n";
// last connection header
std::string conn_str;
switch (connection){
case restinio::http_connection_header_t::keep_alive:
conn_str = "keep-alive";
break;
case restinio::http_connection_header_t::close:
conn_str = "close";
break;
case restinio::http_connection_header_t::upgrade:
throw std::invalid_argument("upgrade");
break;
}
request << "Connection: " << conn_str << "\r\n";
// body & content-length
if (!body.empty()){
request << "Content-Length: " << body.size() << "\r\n\r\n";
request << body;
}
// last delim
request << "\r\n";
return request.str();
}
void
Request::connect(ConnectionCb cb)
{
if (endpoints_.empty()){
if (logger_)
logger_->e("[http:request] [connect] host not resolved");
if (cb)
cb(asio::error::connection_aborted, nullptr);
return;
}
auto socket = asio::ip::tcp::socket{resolver_.get_io_context()};
conn_ = std::make_shared<Connection>(std::move(socket));
// try to connect to any until one works
asio::async_connect(conn_->socket_, endpoints_, [this, conn, cb]
(const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint){
if (ec){ // all endpoints failed
if (logger_)
logger_->e("[http:request:%i] [connect] failed to connect to any endpoints", id_);
}
else {
if (logger_)
logger_->d("[http:request:%i] [connect] success", id_);
// save the associated endpoint
conn_->endpoint_ = endpoint;
}
if (cb)
cb(ec, conn_);
});
}
void
Request::send(std::string request, std::unique_ptr<http_parser> parser,
std::unique_ptr<http_parser_settings> parser_s, HandlerCb cb)
{
if (endpoints_.empty()){
if (logger_)
logger_->e("[http:request:%i] [send] unresolved destination", id_);
if (cb)
cb(asio::error::addrinfo_errors::service_not_found);
}
if (!conn_){
if (logger_)
logger_->e("[http:request:%i] [send] uninitialized connection", id_);
if (cb)
cb(asio::error::not_connected);
}
else if (!conn_->is_open()){
if (logger_)
logger_->e("[http:request] [send] closed connection");
if (cb)
cb(asio::error::not_connected);
}
else {
// save the request context
request_ = request;
parser_ = std::move(parser);
parser_s_ = std::move(parser_s);
// write the request to buffer
std::ostream request_stream(&conn_->request_);
request_stream << request;
// send the request
asio::async_write(conn_->socket_, conn_->request_,
std::bind(&Request::handle_request, this, std::placeholders::_1, cb));
}
}
void
Request::handle_request(const asio::error_code& ec, HandlerCb cb)
{
if (!conn_->is_open()){
if (logger_)
logger_->e("[http:request:%i] [write] closed connection", id_);
terminate();
if (cb)
cb(asio::error::not_connected);
return;
}
if (ec and ec != asio::error::eof){
if (logger_)
logger_->e("[http:request:%i] [write] error: %s", id_, ec.message().c_str());
terminate();
if (cb)
cb(ec);
return;
}
if (logger_)
logger_->d("[http:request:%i] [write] success", id_);
// read response
asio::async_read_until(conn_->socket_, conn_->response_chunk_, "\r\n\r\n",
std::bind(&Request::handle_response_header, this,
std::placeholders::_1, std::placeholders::_2, cb));
}
void
Request::handle_response_header(const asio::error_code& ec, const size_t bytes, HandlerCb cb)
{
if (!conn_->is_open()){
if (logger_)
logger_->e("[http:request:%i] [read:header] closed connection", id_);
terminate();
if (cb)
cb(asio::error::not_connected);
return;
}
if (ec && ec != asio::error::eof){
if (logger_)
logger_->e("[http:request:%i] [read:header] error: %s", id_, ec.message().c_str());
terminate();
if (cb)
cb(ec);
return;
}
else if ((ec == asio::error::eof) || (ec == asio::error::connection_reset)){
terminate();
if (cb)
cb(ec);
return;
}
// read the response buffer
std::ostringstream str_s;
str_s << &conn_->response_chunk_;
auto chunk = str_s.str();
auto header = chunk.substr(0, bytes);
if (logger_)
logger_->d("[http:request:%i] [read:header]:\n%s", id_, header.c_str());
// parse the header right away
parse_request(header, conn_->id());
unsigned int content_length = get_content_length(header);
// has body size
if (content_length){
// append current body chunk
auto body_chunk = chunk.substr(bytes, std::string::npos);
conn_->response_body_.append(body_chunk);
// read the rest of body
asio::async_read(conn_->socket_, conn_->response_chunk_,
asio::transfer_exactly(content_length - (body_chunk.size())),
std::bind(&Request::handle_response_body, this,
std::placeholders::_1, content_length, conn, cb));
return;
}
// has potential body but no content-length (current proxy behavior on key get/listen)
else if (header.find("Content-Type: application/json") != std::string::npos){
auto body_chunk = chunk.substr(bytes, std::string::npos);
if (!body_chunk.empty()){
parse_request(body_chunk, conn_->id());
}
// keep reading
asio::async_read(conn_->socket_, conn_->response_chunk_, asio::transfer_at_least(1),
std::bind(&Request::handle_response_body, this,
std::placeholders::_1, std::placeholders::_2, conn, cb));
}
}
void
Request::handle_response_body(const asio::error_code& ec, const size_t bytes,
std::shared_ptr<Connection> conn, HandlerCb cb)
{
if (!conn_->is_open()){
if (logger_)
logger_->e("[http:request] [read:body] closed connection");
terminate();
if (cb)
cb(asio::error::not_connected);
return;
}
if (ec && ec != asio::error::eof){
if (logger_)
logger_->e("[http:request:%i] [read:body] error: %s", id_, ec.message().c_str());
terminate();
if (cb)
cb(ec);
return;
}
else if ((ec == asio::error::eof) || (ec == asio::error::connection_reset)){
terminate();
if (cb)
cb(ec);
return;
}
std::string body;
if (!conn_->response_body_.empty()){
// append previous incomplete chunk from header
body.append(conn_->response_body_);
}
// read the response buffer
std::ostringstream str_s;
str_s << &conn_->response_chunk_;
body.append(str_s.str().substr(0, bytes));
if (logger_)
logger_->d("[http:request:%i] [read:body] success:\n%s", id_, body.c_str());
parse_request(body);
conn_->response_body_.clear();
asio::async_read(conn_->socket_, conn_->response_chunk_, asio::transfer_at_least(1),
std::bind(&Request::handle_response_body, this,
std::placeholders::_1, std::placeholders::_2, conn, cb));
}
void
Request::parse_request(const std::string request)
{
http_parser_execute(parser_.get(), parser_s_.get(), request.c_str(), request.size());
// detect parsing errors
if (HPE_OK != parser_->http_errno && HPE_PAUSED != parser_->http_errno){
if (logger_){
auto err = HTTP_PARSER_ERRNO(parser_.get());
logger_->e("[http:request:%i] [parse] error: %s", id_, http_errno_name(err));
}
}
}
size_t
Request::get_content_length(const std::string str)
{
size_t content_length = 0;
auto content_length_i = str.find(HTTP_HEADER_CONTENT_LENGTH);
if (content_length_i != std::string::npos){
auto content_length_str = str.substr(content_length_i + std::strlen(HTTP_HEADER_CONTENT_LENGTH) + 1,
str.find("\r\n", content_length_i));
try {
content_length = atoi(content_length_str.c_str());
}
catch (const std::exception& e){
if (logger_)
logger_->d("[http:request:%i] [content-length] invalid '%s': %s",
id_, content_length_str.c_str(), e.what());
}
}
return content_length;
}
Resolver::Resolver(asio::io_context& ctx, const std::string& host, const std::string& service)
{
resolver_.async_resolve({host, service}, [this]
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
{
std::lock_guard<std::mutex> lock(cbsMutex_);
while (not cbs_.empty()) {
cbs_.front()(ec, endpoints);
cbs_.pop();
}
error_ = ec;
endpoints_ = endpoints;
completed_ = true;
}
}
void
Resolver::addOnResolved(ResolvedCb cb)
{
std::lock_guard<std::mutex> lock(cbsMutex_);
if (completed_) {
cb(error_, endpoints_);
} else {
cbs_.push(std::move(cb));
}
}
/*
private:
std::mutex cbsMutex_;
std::queue<ResolvedCb> cbs_;
asio::ip::tcp::resolver resolver_;
asio::error_code error_;
asio::ip::basic_resolver_results<asio::ip::tcp> endpoints_;
} */
} // namespace http
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -48,11 +48,4 @@ struct LocalListener {
ValueCallback get_cb;
};
struct SearchListener {
Sp<Query> query;
Value::Filter filter;
ValueCallback get_cb;
};
}
+32 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -55,9 +55,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
s << std::endl;
}
void
enableLogging(dht::DhtRunner &dht) {
dht.setLoggers(
std::unique_ptr<Logger>
getStdLogger() {
return std::unique_ptr<Logger>(new Logger(
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
@@ -69,23 +69,23 @@ enableLogging(dht::DhtRunner &dht) {
std::cout << def;
},
[](char const *m, va_list args) { printLog(std::cout, m, args); }
);
));
}
void
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
auto logfile = std::make_shared<std::fstream>();
std::unique_ptr<Logger>
getFileLogger(const std::string &path) {
auto logfile = std::make_shared<std::ofstream>();
logfile->open(path, std::ios::out);
dht.setLoggers(
return std::unique_ptr<Logger>(new 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); }
);
));
}
OPENDHT_PUBLIC void
enableSyslog(dht::DhtRunner &dht, const char* name) {
std::unique_ptr<Logger>
getSyslogLogger(const char* name) {
#ifndef _WIN32
struct Syslog {
Syslog(const char* n) {
@@ -102,17 +102,34 @@ enableSyslog(dht::DhtRunner &dht, const char* name) {
logfile = std::make_shared<Syslog>(name);
opened_logfile = logfile;
}
dht.setLoggers(
return std::unique_ptr<Logger>(new 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());
#endif
}
void
enableLogging(dht::DhtRunner &dht) {
dht.setLogger(*getStdLogger());
}
void
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
dht.setLogger(*getFileLogger(path));
}
OPENDHT_PUBLIC void
enableSyslog(dht::DhtRunner &dht, const char* name) {
dht.setLogger(*getSyslogLogger(name));
}
void
disableLogging(dht::DhtRunner &dht) {
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
dht.setLogger({});
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2019 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
+208 -265
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -17,7 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "network_engine.h"
#include "request.h"
#include "default_types.h"
@@ -26,17 +25,6 @@
#include <msgpack.hpp>
#ifndef _WIN32
#include <arpa/inet.h>
#include <unistd.h>
#else
#include <ws2tcpip.h>
#include <io.h>
#endif
#include <fcntl.h>
#include <cstring>
namespace dht {
namespace net {
@@ -55,38 +43,10 @@ constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
const std::string NetworkEngine::my_v {"RNG1"};
constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC;
static const uint8_t v4prefix[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0
};
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
constexpr unsigned SEND_NODES {8};
#ifdef _WIN32
static bool
set_nonblocking(int fd, int nonblocking)
{
unsigned long mode = !!nonblocking;
int rc = ioctlsocket(fd, FIONBIO, &mode);
return rc == 0;
}
extern const char *inet_ntop(int, const void *, char *, socklen_t);
#else
static bool
set_nonblocking(int fd, int nonblocking)
{
int rc = fcntl(fd, F_GETFL, 0);
if (rc < 0)
return false;
rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
return rc >= 0;
}
#endif
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
* the kind of request, and the remaining two a sequence number in
@@ -139,32 +99,31 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
nodes6(std::move(msg.nodes6))
{}
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, const int& s, const int& s6)
: myid(zeroes), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
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(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
decltype(NetworkEngine::onPing)&& onPing,
decltype(NetworkEngine::onFindNode)&& onFindNode,
decltype(NetworkEngine::onGetValues)&& onGetValues,
decltype(NetworkEngine::onListen)&& onListen,
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
decltype(NetworkEngine::onRefresh)&& onRefresh) :
onError(std::move(onError)),
onNewNode(std::move(onNewNode)),
onReportedAddr(std::move(onReportedAddr)),
onPing(std::move(onPing)),
onFindNode(std::move(onFindNode)),
onGetValues(std::move(onGetValues)),
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)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
decltype(NetworkEngine::onPing) onPing,
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce,
decltype(NetworkEngine::onRefresh) onRefresh) :
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), onRefresh(onRefresh), myid(myid),
network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{
if (dht_socket >= 0) {
if (!set_nonblocking(dht_socket, 1))
throw DhtException("Can't set socket to non-blocking mode");
}
if (dht_socket6 >= 0) {
if (!set_nonblocking(dht_socket6, 1))
throw DhtException("Can't set socket to non-blocking mode");
}
}
NetworkEngine::~NetworkEngine() {
clear();
@@ -185,63 +144,63 @@ NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash,
}
void
NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& token, const std::vector<Value::Id>& values)
NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("u"));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
if (not values.empty()) {
pk.pack(std::string("re"));
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());
}
pk.pack(std::string("t")); pk.pack(socket_id);
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
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(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
send(buffer.data(), buffer.size(), 0, n->getAddr());
send(n->getAddr(), buffer.data(), buffer.size());
}
void
NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& token, const std::vector<Value::Id>& values)
NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("u"));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
if (not values.empty()) {
pk.pack(std::string("exp"));
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());
}
pk.pack(std::string("t")); pk.pack(socket_id);
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
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(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
send(buffer.data(), buffer.size(), 0, n->getAddr());
send(n->getAddr(), buffer.data(), buffer.size());
}
@@ -250,11 +209,11 @@ NetworkEngine::isRunning(sa_family_t af) const
{
switch (af) {
case 0:
return dht_socket >= 0 || dht_socket6 >= 0;
return dht_socket->hasIPv4() or dht_socket->hasIPv6();
case AF_INET:
return dht_socket >= 0;
return dht_socket->hasIPv4();
case AF_INET6:
return dht_socket6 >= 0;
return dht_socket->hasIPv6();
default:
return false;
}
@@ -262,7 +221,13 @@ NetworkEngine::isRunning(sa_family_t af) const
void
NetworkEngine::clear()
{}
{
for (auto& request : requests) {
request.second->cancel();
request.second->node->setExpired();
}
requests.clear();
}
void
NetworkEngine::connectivityChanged(sa_family_t af)
@@ -280,7 +245,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
auto now = scheduler.time();
auto& node = *req.node;
if (req.isExpired(now)) {
DHT_LOG.e(node.id, "[node %s] expired !", node.toString().c_str());
DHT_LOG.d(node.id, "[node %s] expired !", node.toString().c_str());
node.setExpired();
if (not node.id)
requests.erase(req.tid);
@@ -289,27 +254,22 @@ NetworkEngine::requestStep(Sp<Request> sreq)
req.on_expired(req, false);
}
auto err = send((char*)req.msg.data(), req.msg.size(),
(node.getReplyTime() >= now - UDP_REPLY_TIME) ? 0 : MSG_CONFIRM,
node.getAddr());
std::weak_ptr<Request> wreq = sreq;
auto err = send(node.getAddr(), (char*)req.msg.data(), req.msg.size(), node.getReplyTime() < now - UDP_REPLY_TIME);
if (err == ENETUNREACH ||
err == EHOSTUNREACH ||
err == EAFNOSUPPORT ||
err == EPIPE)
err == EPIPE ||
err == EPERM)
{
scheduler.add(now, [this,wreq]() mutable {
if (auto req = wreq.lock()) {
req->node->setExpired();
if (not req->node->id)
requests.erase(req->tid);
}
});
node.setExpired();
if (not node.id)
requests.erase(req.tid);
} else {
if (err != EAGAIN) {
++req.attempt_count;
}
req.last_try = now;
std::weak_ptr<Request> wreq = sreq;
scheduler.add(req.last_try + Node::MAX_RESPONSE_TIME, [this,wreq] {
if (auto req = wreq.lock())
requestStep(req);
@@ -324,11 +284,11 @@ NetworkEngine::requestStep(Sp<Request> sreq)
void
NetworkEngine::sendRequest(const Sp<Request>& request)
{
auto& node = request->node;
if (not node->id)
auto& node = *request->node;
if (not node.id)
requests.emplace(request->tid, request);
request->start = scheduler.time();
node->requested(request);
node.requested(request);
requestStep(request);
}
@@ -350,9 +310,8 @@ NetworkEngine::rateLimit(const SockAddr& addr)
limiter_maintenance = 0;
}
auto it = address_rate_limiter.emplace(addr, IpLimiter{});
// invoke per IP, then global rate limiter
return it.first->second.limit(now) and rate_limiter.limit(now);
return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now);
}
bool
@@ -398,8 +357,9 @@ NetworkEngine::isNodeBlacklisted(const SockAddr& addr) const
}
void
NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr& from)
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());
return;
@@ -416,7 +376,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr&
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.DEBUG.logPrintable(buf, buflen);
//DHT_LOG.DBG.logPrintable(buf, buflen);
return;
}
@@ -431,7 +391,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr&
if (msg->type == MessageType::ValueData) {
auto pmsg_it = partial_messages.find(msg->tid);
if (pmsg_it == partial_messages.end()) {
DHT_LOG.d("Can't find partial message");
if (logIncoming_)
DHT_LOG.d("Can't find partial message");
rateLimit(from);
return;
}
@@ -471,15 +432,15 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const SockAddr&
process(std::move(msg), from);
} else {
// starting partial message session
PartialMessage pmsg;
pmsg.from = from;
pmsg.msg = std::move(msg);
pmsg.start = now;
pmsg.last_part = now;
auto wmsg = partial_messages.emplace(pmsg.msg->tid, std::move(pmsg));
if (wmsg.second) {
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, wmsg.first->first));
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, wmsg.first->first));
auto k = msg->tid;
auto& pmsg = partial_messages[k];
if (not pmsg.msg) {
pmsg.from = from;
pmsg.msg = std::move(msg);
pmsg.start = now;
pmsg.last_part = now;
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");
}
@@ -541,19 +502,21 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
req->reply_time = time_point::min();
onError(req, DhtProtocolException {msg->error_code});
} else {
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
if (logIncoming_)
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
msg->id.toString().c_str(), from.toString().c_str(), msg->error_code);
}
break;
}
case MessageType::Reply:
if (req) { /* request reply */
if (msg->type == MessageType::AnnounceValue or msg->type == MessageType::Listen)
req->node->authSuccess();
req->reply_time = scheduler.time();
auto& r = *req;
if (r.getType() == MessageType::AnnounceValue or r.getType() == MessageType::Listen)
r.node->authSuccess();
r.reply_time = scheduler.time();
deserializeNodes(*msg, from);
req->setDone(std::move(*msg));
r.setDone(std::move(*msg));
break;
} else { /* request socket data */
deserializeNodes(*msg, from);
@@ -571,7 +534,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
switch (msg->type) {
case MessageType::Ping:
++in_stats.ping;
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
if (logIncoming_)
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
onPing(node);
sendPong(from, msg->tid);
break;
@@ -592,7 +556,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::AnnounceValue: {
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_)
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());
++in_stats.put;
onAnnounce(node, msg->info_hash, msg->token, msg->values, msg->created);
@@ -605,13 +570,15 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::Refresh:
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_)
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());
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: {
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_)
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());
++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);
@@ -642,33 +609,9 @@ insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const SockAddr& addr)
}
int
NetworkEngine::send(const char *buf, size_t len, int flags, const SockAddr& addr)
NetworkEngine::send(const SockAddr& addr, const char *buf, size_t len, bool confirmed)
{
if (not addr)
return EFAULT;
int s;
if (addr.getFamily() == AF_INET)
s = dht_socket;
else if (addr.getFamily() == AF_INET6)
s = dht_socket6;
else
s = -1;
if (s < 0)
return EAFNOSUPPORT;
#ifdef MSG_NOSIGNAL
flags &= MSG_NOSIGNAL;
#endif
if (sendto(s, buf, len, flags, addr.get(), addr.getLength()) == -1) {
int err = errno;
DHT_LOG.e("Can't send message to %s: %s", addr.toString().c_str(), strerror(err));
if (err == EPIPE) {
throw SocketException(EPIPE);
}
return err;
}
return 0;
return dht_socket ? dht_socket->sendTo(addr, (const uint8_t*)buf, len, confirmed) : ENOTCONN;
}
Sp<Request>
@@ -678,16 +621,16 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(1);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(std::string("q")); pk.pack(std::string("ping"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_PING);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
@@ -715,20 +658,20 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
}
Sp<Request>
@@ -739,23 +682,23 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("target")); pk.pack(target);
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_TARGET); pk.pack(target);
if (want > 0) {
pk.pack(std::string("w"));
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);
}
pk.pack(std::string("q")); pk.pack(std::string("find"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_FIND);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -785,26 +728,26 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(2 +
pk.pack(KEY_A); pk.pack_map(2 +
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
(want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(info_hash);
pk.pack(std::string("q")); pk.pack(query);
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(std::string("w"));
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);
}
pk.pack(std::string("q")); pk.pack(std::string("get"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
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(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -892,13 +835,13 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
total_size += v.size();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack(std::string("values"));
pk.pack(KEY_REQ_VALUES);
pk.pack_array(svals.size());
// try to put everything in a single UDP packet
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);
// DHT_LOG.d("sending %lu bytes of values", total_size);
svals.clear();
} else {
for (const auto& b : svals)
@@ -920,17 +863,17 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(network?1:0));
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
pk.pack(std::string("y")); pk.pack(std::string("v"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("p")); pk.pack_map(1);
pk.pack(KEY_V); pk.pack_map(1);
pk.pack(i); pk.pack_map(2);
pk.pack(std::string("o")); pk.pack(start);
pk.pack(std::string("d")); pk.pack_bin(end-start);
pk.pack_bin_body((const char*)v.data()+start, end-start);
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
start = end;
} while (start != v.size());
i++;
@@ -945,22 +888,22 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r"));
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));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
if (nodes.size() > 0) {
pk.pack(std::string("n4"));
pk.pack(KEY_REQ_NODES4);
pk.pack_bin(nodes.size());
pk.pack_bin_body((const char*)nodes.data(), nodes.size());
}
if (nodes6.size() > 0) {
pk.pack(std::string("n6"));
pk.pack(KEY_REQ_NODES6);
pk.pack_bin(nodes6.size());
pk.pack_bin_body((const char*)nodes6.data(), nodes6.size());
}
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
std::vector<Blob> svals {};
if (not st.empty()) { /* pack complete values */
@@ -968,28 +911,28 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
if (fields.empty()) {
svals = packValueHeader(buffer, st);
} else { /* pack fields */
pk.pack(std::string("fields"));
pk.pack(KEY_REQ_FIELDS);
pk.pack_map(2);
pk.pack(std::string("f")); pk.pack(fields);
pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size());
for (const auto& v : st)
v->msgpack_pack_fields(fields, pk);
//DHT_LOG_DEBUG("sending closest nodes (%d+%d nodes.), %u value headers containing %u fields",
//DHT_LOG_DBG("sending closest nodes (%d+%d nodes.), %u value headers containing %u fields",
// nodes.size(), nodes6.size(), st.size(), fields.size());
}
}
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_TID); pk.pack_bin(t.size());
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(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
// send parts
if (not svals.empty())
@@ -1077,23 +1020,23 @@ NetworkEngine::sendListen(Sp<Node> n,
pk.pack_map(5+(network?1:0));
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
pk.pack(std::string("a")); pk.pack_map(4 + has_query);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(hash);
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(std::string("sid")); pk.pack_bin(sid.size());
pk.pack_bin_body((const char*)sid.data(), sid.size());
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);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
pk.pack(KEY_REQ_SID); pk.pack_bin(sid.size());
pk.pack_bin_body((const char*)sid.data(), sid.size());
if (has_query) {
pk.pack(std::string("q")); pk.pack(query);
pk.pack(KEY_REQ_QUERY); pk.pack(query);
}
pk.pack(std::string("q")); pk.pack(std::string("listen"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_LISTEN);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1119,20 +1062,20 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
}
Sp<Request>
@@ -1149,23 +1092,23 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(infohash);
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(infohash);
auto v = packValueHeader(buffer, {value});
if (created < scheduler.time()) {
pk.pack(std::string("c"));
pk.pack(KEY_REQ_CREATION);
pk.pack(to_time_t(created));
}
pk.pack(std::string("token")); pk.pack(token);
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
pk.pack(std::string("q")); pk.pack(std::string("put"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Q); pk.pack(QUERY_PUT);
pk.pack(KEY_TID); pk.pack_bin(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(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
@@ -1207,19 +1150,19 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(4);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(infohash);
pk.pack(std::string("vid")); pk.pack(vid);
pk.pack(std::string("token")); pk.pack(token);
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(infohash);
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
pk.pack(std::string("q")); pk.pack(std::string("refresh"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_REFRESH);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
@@ -1252,21 +1195,21 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(3);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("vid")); pk.pack(vid);
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
insertAddr(pk, addr);
TransId t(tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
}
void
@@ -1280,25 +1223,25 @@ NetworkEngine::sendError(const SockAddr& addr,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (include_id?1:0));
pk.pack(std::string("e")); pk.pack_array(2);
pk.pack(KEY_E); pk.pack_array(2);
pk.pack(code);
pk.pack(message);
if (include_id) {
pk.pack(std::string("r")); pk.pack_map(1);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
}
TransId t(tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("e"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
send(addr, buffer.data(), buffer.size());
}
void
+333
View File
@@ -0,0 +1,333 @@
/*
* Copyright (C) 2019 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/>.
*/
#include "network_utils.h"
#ifdef _WIN32
#include "utils.h"
#include <io.h>
#include <string>
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#else
#include <fcntl.h>
#endif
#include <iostream>
namespace dht {
namespace net {
int
bindSocket(const SockAddr& addr, SockAddr& bound)
{
bool is_ipv6 = addr.getFamily() == AF_INET6;
int sock = socket(is_ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
if (sock < 0)
throw DhtException(std::string("Can't open socket: ") + strerror(sock));
int set = 1;
#ifdef SO_NOSIGPIPE
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&set, sizeof(set));
#endif
if (is_ipv6)
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&set, sizeof(set));
net::setNonblocking(sock);
int rc = bind(sock, addr.get(), addr.getLength());
if (rc < 0) {
rc = errno;
close(sock);
throw DhtException("Can't bind socket on " + addr.toString() + " " + strerror(rc));
}
sockaddr_storage ss;
socklen_t ss_len = sizeof(ss);
getsockname(sock, (sockaddr*)&ss, &ss_len);
bound = {ss, ss_len};
return sock;
}
bool
setNonblocking(int fd, bool nonblocking)
{
#ifdef _WIN32
unsigned long mode = !!nonblocking;
int rc = ioctlsocket(fd, FIONBIO, &mode);
return rc == 0;
#else
int rc = fcntl(fd, F_GETFL, 0);
if (rc < 0)
return false;
rc = fcntl(fd, F_SETFL, nonblocking ? (rc | O_NONBLOCK) : (rc & ~O_NONBLOCK));
return rc >= 0;
#endif
}
#ifdef _WIN32
void udpPipe(int fds[2])
{
int lst = socket(AF_INET, SOCK_DGRAM, 0);
if (lst < 0)
throw DhtException(std::string("Can't open socket: ") + strerror(WSAGetLastError()));
sockaddr_in inaddr;
sockaddr addr;
memset(&inaddr, 0, sizeof(inaddr));
memset(&addr, 0, sizeof(addr));
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
inaddr.sin_port = 0;
int yes = 1;
setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
int rc = bind(lst, (sockaddr*)&inaddr, sizeof(inaddr));
if (rc < 0) {
close(lst);
throw DhtException("Can't bind socket on " + print_addr((sockaddr*)&inaddr, sizeof(inaddr)) + " " + strerror(rc));
}
socklen_t len = sizeof(addr);
getsockname(lst, &addr, &len);
fds[0] = lst;
fds[1] = socket(AF_INET, SOCK_DGRAM, 0);
connect(fds[1], &addr, len);
}
#endif
UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
SockAddr bind4;
bind4.setFamily(AF_INET);
bind4.setPort(port);
SockAddr bind6;
bind6.setFamily(AF_INET6);
bind6.setPort(port);
openSockets(bind4, bind6);
}
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
{
openSockets(bind4, bind6);
}
UdpSocket::~UdpSocket() {
stop();
if (rcv_thread.joinable())
rcv_thread.join();
}
int
UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) {
if (not dest)
return EFAULT;
int s;
switch (dest.getFamily()) {
case AF_INET: s = s4; break;
case AF_INET6: s = s6; break;
default: s = -1; break;
}
if (s < 0)
return EAFNOSUPPORT;
int flags = 0;
#ifdef MSG_CONFIRM
if (replied)
flags |= MSG_CONFIRM;
#endif
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
#endif
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 (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
auto bind4 = std::move(bound4), bind6 = std::move(bound6);
openSockets(bind4, bind6);
return sendTo(dest, data, size, false);
}
return err;
}
return 0;
}
void
UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
{
stop();
if (rcv_thread.joinable())
rcv_thread.join();
int stopfds[2];
#ifndef _WIN32
auto status = pipe(stopfds);
if (status == -1) {
throw DhtException(std::string("Can't open pipe: ") + strerror(errno));
}
#else
udpPipe(stopfds);
#endif
int stop_readfd = stopfds[0];
stopfd = stopfds[1];
s4 = -1;
s6 = -1;
bound4 = {};
if (bind4) {
try {
s4 = bindSocket(bind4, bound4);
} catch (const DhtException& e) {
logger.e("Can't bind inet socket: %s", e.what());
}
}
#if 1
bound6 = {};
if (bind6) {
if (bind6.getPort() == 0) {
// Attempt to use the same port as IPv4 with IPv6
if (auto p4 = bound4.getPort()) {
auto b6 = bind6;
b6.setPort(p4);
try {
s6 = bindSocket(b6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
}
if (s6 == -1) {
try {
s6 = bindSocket(bind6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
}
#endif
if (s4 == -1 && s6 == -1) {
throw DhtException("Can't bind socket");
}
running = true;
rcv_thread = std::thread([this, stop_readfd]() {
int selectFd = std::max({s4, s6, 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);
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
if (rc < 0) {
if (errno != EINTR) {
logger.e("Select error: %s", strerror(errno));
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
if (not running)
break;
if (rc > 0) {
std::array<uint8_t, 1024 * 64> buf;
sockaddr_storage from;
socklen_t from_len = sizeof(from);
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));
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
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));
} else if (rc == -1) {
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 (s6 >= 0) {
close(s6);
try {
s6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
if (s4 < 0 && s6 < 0)
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 (s4 >= 0)
close(s4);
if (s6 >= 0)
close(s6);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
if (stop_readfd != -1)
close(stop_readfd);
if (stopfd != -1)
close(stopfd);
stopfd = -1;
});
}
void
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");
}
}
}
}
}
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -49,7 +49,7 @@ Node::isGood(time_point now) const
bool
Node::isPendingMessage() const
{
for (auto r : requests_) {
for (const auto& r : requests_) {
if (r.second->pending())
return true;
}
@@ -60,7 +60,7 @@ size_t
Node::getPendingMessageCount() const
{
size_t count {0};
for (auto r : requests_) {
for (const auto& r : requests_) {
if (r.second->pending())
count++;
}
+39 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -20,6 +20,9 @@
namespace dht {
constexpr size_t CLEANUP_MAX_NODES {1024};
constexpr size_t CLEANUP_FREQ {1024};
NodeCache::~NodeCache()
{
cache_4.setExpired();
@@ -41,29 +44,33 @@ NodeCache::getNode(const InfoHash& id, const SockAddr& addr, time_point now, boo
std::vector<Sp<Node>>
NodeCache::getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const
{
const auto& c = cache(sa_f);
return cache(sa_f).getCachedNodes(id, count);
}
std::vector<Sp<Node>>
NodeCache::NodeMap::getCachedNodes(const InfoHash& id, size_t count) const
{
std::vector<Sp<Node>> nodes;
nodes.reserve(std::min(c.size(), count));
NodeMap::const_iterator it;
auto dec_it = [&c](NodeMap::const_iterator& it) {
nodes.reserve(std::min(size(), count));
const_iterator it;
auto dec_it = [this](const_iterator& it) {
auto ret = it;
it = (it == c.cbegin()) ? c.cend() : std::prev(it);
it = (it == cbegin()) ? cend() : std::prev(it);
return ret;
};
auto it_p = c.lower_bound(id),
auto it_p = lower_bound(id),
it_n = it_p;
if (not c.empty())
if (not empty())
dec_it(it_p); /* Create 2 separate iterator if we could */
while (nodes.size() < count and (it_n != c.cend() or it_p != c.cend())) {
while (nodes.size() < count and (it_n != cend() or it_p != cend())) {
/* If one of the iterator is at the end, then take the other one
If they are both in middle of somewhere comapre both and take
the closest to the id. */
if (it_p == c.cend()) it = it_n++;
else if (it_n == c.cend()) it = dec_it(it_p);
else it = id.xorCmp(it_p->first, it_n->first) < 0 ? dec_it(it_p) : it_n++;
if (it_p == cend()) it = it_n++;
else if (it_n == cend()) it = dec_it(it_p);
else it = id.xorCmp(it_p->first, it_n->first) < 0 ? dec_it(it_p) : it_n++;
if (auto n = it->second.lock())
if ( not n->isExpired() and not n->isClient() )
@@ -104,6 +111,10 @@ NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point
if (not node) {
node = std::make_shared<Node>(id, addr, client);
it.first->second = node;
if (cleanup_counter++ == CLEANUP_FREQ) {
cleanup();
cleanup_counter = 0;
}
} else if (confirm or node->isOld(now)) {
node->update(addr);
}
@@ -120,6 +131,7 @@ NodeCache::NodeMap::clearBadNodes() {
erase(it++);
}
}
cleanup_counter = 0;
}
void
@@ -128,6 +140,21 @@ NodeCache::NodeMap::setExpired() {
if (auto n = wn.second.lock())
n->setExpired();
clear();
cleanup_counter = 0;
}
void
NodeCache::NodeMap::cleanup()
{
auto it = lower_bound(InfoHash::getRandom());
for (size_t n = 0, maxNodes = std::min(size(), CLEANUP_MAX_NODES); n != maxNodes; n++) {
if (it == end())
it = begin();
if (it->second.expired())
erase(it++);
else
++it;
}
}
}
+74 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 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,7 +25,7 @@ bool
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
std::vector<Sp<Value>> newValues;
for (const auto& v : vals) {
auto viop = values.emplace(v->id, OpCacheValueStorage{v});
auto viop = values.emplace(v->id, v);
if (viop.second) {
newValues.emplace_back(v);
} else {
@@ -34,6 +34,7 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
}
return newValues.empty() ? true : callback(newValues, false);
}
bool
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
std::vector<Sp<Value>> expiredValues;
@@ -49,8 +50,26 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
}
return expiredValues.empty() ? true : callback(expiredValues, true);
}
bool
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
{
std::vector<Sp<Value>> expiredValues;
for (const auto& vid : vids) {
auto vit = values.find(vid);
if (vit != values.end()) {
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
values.erase(vit);
}
}
}
return expiredValues.empty() ? true : callback(expiredValues, true);
}
std::vector<Sp<Value>>
OpValueCache::get(Value::Filter& filter) const {
OpValueCache::get(const Value::Filter& filter) const {
std::vector<Sp<Value>> ret;
if (not filter)
ret.reserve(values.size());
@@ -108,33 +127,57 @@ OpCache::getExpiration() const {
return lastRemoved + EXPIRATION;
}
size_t
SearchCache::listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, std::function<size_t(Sp<Query>, ValueCallback)> onListen)
SearchCache::OpMap::iterator
SearchCache::getOp(const Sp<Query>& q)
{
// find exact match
auto op = ops.find(q);
if (op == ops.end()) {
// find satisfying query
for (auto it = ops.begin(); it != ops.end(); it++) {
if (q->isSatisfiedBy(*it->first)) {
op = it;
break;
}
if (op != ops.end())
return op;
// find satisfying query
for (auto it = ops.begin(); it != ops.end(); it++) {
if (q->isSatisfiedBy(*it->first)) {
return it;
}
}
return ops.end();
}
SearchCache::OpMap::const_iterator
SearchCache::getOp(const Sp<Query>& q) const
{
// find exact match
auto op = ops.find(q);
if (op != ops.cend())
return op;
// find satisfying query
for (auto it = ops.begin(); it != ops.end(); it++) {
if (q->isSatisfiedBy(*it->first)) {
return it;
}
}
return ops.cend();
}
size_t
SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
{
// find exact match
auto op = getOp(q);
if (op == ops.end()) {
// New query
op = ops.emplace(q, std::unique_ptr<OpCache>(new OpCache)).first;
auto& cache = *op->second;
cache.searchToken = onListen(q, [&](const std::vector<Sp<Value>>& values, bool expired){
return cache.onValue(values, expired);
}, [&](ListenSyncStatus status) {
cache.onNodeChanged(status);
});
}
auto token = nextToken_++;
if (nextToken_ == 0)
nextToken_++;
op->second->addListener(token, get_cb, q, filter);
return token;
return op->second->addListener(token, get_cb, q, filter) ? token : 0;
}
bool
@@ -149,7 +192,7 @@ SearchCache::cancelListen(size_t gtoken, const time_point& now) {
}
void
SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
SearchCache::cancelAll(const std::function<void(size_t)>& onCancel) {
for (auto& op : ops) {
auto cache = std::move(op.second);
cache->removeAll();
@@ -159,7 +202,7 @@ SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
}
time_point
SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel) {
SearchCache::expire(const time_point& now, const std::function<void(size_t)>& onCancel) {
nextExpiration_ = time_point::max();
auto ret = nextExpiration_;
for (auto it = ops.begin(); it != ops.end();) {
@@ -177,8 +220,22 @@ SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel)
return ret;
}
bool
SearchCache::get(const Value::Filter& f, const Sp<Query>& q, const GetCallback& gcb, const DoneCallback& dcb) const
{
auto op = getOp(q);
if (op != ops.end()) {
auto vals = op->second->get(f);
if ((not vals.empty() and not gcb(vals)) or op->second->isSynced()) {
dcb(true, {});
return true;
}
}
return false;
}
std::vector<Sp<Value>>
SearchCache::get(Value::Filter& filter) const {
SearchCache::get(const Value::Filter& filter) const {
if (ops.size() == 1)
return ops.begin()->second->get(filter);
std::map<Value::Id, Sp<Value>> c;
+51 -16
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 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,20 +27,23 @@ struct OpCacheValueStorage
{
Sp<Value> data {};
unsigned refCount {1};
OpCacheValueStorage(Sp<Value> val = {}) : data(val) {}
OpCacheValueStorage(Sp<Value> val) : data(val) {}
};
class OpValueCache {
public:
OpValueCache(ValueCallback&& cb) : callback(std::forward<ValueCallback>(cb)) {}
OpValueCache(OpValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)) {
OpValueCache(ValueCallback&& cb) noexcept : callback(std::forward<ValueCallback>(cb)) {}
OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) {
o.callback = {};
}
static ValueCallback cacheCallback(ValueCallback&& cb) {
static ValueCallback cacheCallback(ValueCallback&& cb, std::function<void()>&& onCancel) {
auto cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb));
return [cache](const std::vector<Sp<Value>>& vals, bool expired){
return cache->onValue(vals, expired);
return [cache, onCancel](const std::vector<Sp<Value>>& vals, bool expired){
auto ret = cache->onValue(vals, expired);
if (not ret)
onCancel();
return ret;
};
}
@@ -53,8 +56,20 @@ public:
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Value::Id>& vals);
std::vector<Sp<Value>> get(Value::Filter& filter) const;
void onNodeChanged(ListenSyncStatus status) {
switch (status) {
case ListenSyncStatus::ADDED: nodes++; break;
case ListenSyncStatus::REMOVED: nodes--; break;
case ListenSyncStatus::SYNCED : syncedNodes++; break;
case ListenSyncStatus::UNSYNCED: syncedNodes--; break;
}
}
bool isSynced() const { return nodes > 0 and syncedNodes == nodes; }
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
Sp<Value> get(Value::Id id) const;
std::vector<Sp<Value>> getValues() const;
@@ -62,6 +77,8 @@ private:
OpValueCache(const OpValueCache&) = delete;
OpValueCache& operator=(const OpValueCache&) = delete;
size_t nodes {0};
size_t syncedNodes {0};
std::map<Value::Id, OpCacheValueStorage> values {};
ValueCallback callback;
};
@@ -80,13 +97,20 @@ public:
cache.onValue(vals, expired);
return not listeners.empty();
}
void onNodeChanged(ListenSyncStatus status) {
cache.onNodeChanged(status);
}
void onValuesAdded(const std::vector<Sp<Value>>& vals);
void onValuesExpired(const std::vector<Sp<Value>>& vals);
void addListener(size_t token, ValueCallback cb, Sp<Query> q, Value::Filter filter) {
bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
auto cached = cache.get(filter);
if (not cached.empty() and not cb(cached, false)) {
return false;
}
listeners.emplace(token, LocalListener{q, filter, cb});
cb(cache.get(filter), false);
return true;
}
bool removeListener(size_t token, const time_point& now) {
@@ -102,7 +126,7 @@ public:
return listeners.empty();
}
std::vector<Sp<Value>> get(Value::Filter& filter) const {
std::vector<Sp<Value>> get(const Value::Filter& filter) const {
return cache.get(filter);
}
@@ -110,6 +134,10 @@ public:
return cache.get(id);
}
bool isSynced() const {
return cache.isSynced();
}
bool isExpired(const time_point& now) const {
return listeners.empty() and (lastRemoved + EXPIRATION < now);
}
@@ -130,24 +158,31 @@ class SearchCache {
public:
SearchCache() {}
SearchCache(SearchCache&&) = default;
size_t listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, std::function<size_t(Sp<Query>, ValueCallback)> onListen);
using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
bool cancelListen(size_t gtoken, const time_point& now);
void cancelAll(std::function<void(size_t)> onCancel);
void cancelAll(const std::function<void(size_t)>& onCancel);
time_point expire(const time_point& now, std::function<void(size_t)> onCancel);
time_point expire(const time_point& now, const std::function<void(size_t)>& onCancel);
time_point getExpiration() const {
return nextExpiration_;
}
std::vector<Sp<Value>> get(Value::Filter& filter) const;
bool get(const Value::Filter& f, const Sp<Query>& q, const GetCallback& gcb, const DoneCallback& dcb) const;
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
Sp<Value> get(Value::Id id) const;
private:
SearchCache(const SearchCache&) = delete;
SearchCache& operator=(const SearchCache&) = delete;
std::map<Sp<Query>, std::unique_ptr<OpCache>> ops {};
using OpMap = std::map<Sp<Query>, std::unique_ptr<OpCache>>;
OpMap ops {};
OpMap::iterator getOp(const Sp<Query>& q);
OpMap::const_iterator getOp(const Sp<Query>& q) const;
size_t nextToken_ {1};
time_point nextExpiration_ {time_point::max()};
};
+159 -96
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2019 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,42 @@
namespace dht {
namespace net {
static const std::string KEY_Y {"y"};
static const std::string KEY_R {"r"};
static const std::string KEY_U {"u"};
static const std::string KEY_E {"e"};
static const std::string KEY_V {"p"};
static const std::string KEY_TID {"t"};
static const std::string KEY_UA {"v"};
static const std::string KEY_NETID {"n"};
static const std::string KEY_ISCLIENT {"s"};
static const std::string KEY_Q {"q"};
static const std::string KEY_A {"a"};
static const std::string KEY_REQ_SID {"sid"};
static const std::string KEY_REQ_ID {"id"};
static const std::string KEY_REQ_H {"h"};
static const std::string KEY_REQ_TARGET {"target"};
static const std::string KEY_REQ_QUERY {"q"};
static const std::string KEY_REQ_TOKEN {"token"};
static const std::string KEY_REQ_VALUE_ID {"vid"};
static const std::string KEY_REQ_NODES4 {"n4"};
static const std::string KEY_REQ_NODES6 {"n6"};
static const std::string KEY_REQ_CREATION {"c"};
static const std::string KEY_REQ_ADDRESS {"sa"};
static const std::string KEY_REQ_VALUES {"values"};
static const std::string KEY_REQ_EXPIRED {"exp"};
static const std::string KEY_REQ_REFRESHED {"re"};
static const std::string KEY_REQ_FIELDS {"fileds"};
static const std::string KEY_REQ_WANT {"w"};
static const std::string QUERY_PING {"ping"};
static const std::string QUERY_FIND {"find"};
static const std::string QUERY_GET {"get"};
static const std::string QUERY_PUT {"put"};
static const std::string QUERY_LISTEN {"listen"};
static const std::string QUERY_REFRESH {"refresh"};
Tid unpackTid(const msgpack::object& o) {
switch (o.type) {
case msgpack::type::POSITIVE_INTEGER:
@@ -48,13 +84,13 @@ struct ParsedMessage {
/* target id around which to find nodes */
InfoHash target;
/* transaction id */
Tid tid;
Tid tid {0};
/* tid for packets going through request socket */
Tid socket_id;
Tid socket_id {0};
/* security token */
Blob token;
/* the value id (announce confirmation) */
Value::Id value_id;
Value::Id value_id {0};
/* time when value was first created */
time_point created { time_point::max() };
/* IPv4 nodes in response to a 'find' request */
@@ -78,7 +114,7 @@ struct ParsedMessage {
/* reported address by the distant node */
std::string ua;
SockAddr addr;
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
bool append(const ParsedMessage& block);
bool complete();
@@ -123,63 +159,79 @@ ParsedMessage::complete()
}
void
ParsedMessage::msgpack_unpack(msgpack::object msg)
ParsedMessage::msgpack_unpack(const msgpack::object& msg)
{
auto y = findMapValue(msg, "y");
auto r = findMapValue(msg, "r");
auto u = findMapValue(msg, "u");
auto e = findMapValue(msg, "e");
auto v = findMapValue(msg, "p");
if (msg.type != msgpack::type::MAP) throw msgpack::type_error();
if (auto t = findMapValue(msg, "t"))
tid = unpackTid(*t);
struct ParsedMsg {
msgpack::object* y;
msgpack::object* r;
msgpack::object* u;
msgpack::object* e;
msgpack::object* v;
msgpack::object* a;
std::string q;
} parsed {};
if (auto rv = findMapValue(msg, "v"))
ua = rv->as<std::string>();
if (auto netid = findMapValue(msg, "n"))
network = netid->as<NetId>();
if (auto is_client_v = findMapValue(msg, "s"))
is_client = is_client_v->as<bool>();
std::string q;
if (auto rq = findMapValue(msg, "q")) {
if (rq->type != msgpack::type::STR)
throw msgpack::type_error();
q = rq->as<std::string>();
for (unsigned i = 0; i < msg.via.map.size; i++) {
auto& o = msg.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
continue;
auto key = o.key.as<std::string>();
if (key == KEY_Y)
parsed.y = &o.val;
else if (key == KEY_R)
parsed.r = &o.val;
else if (key == KEY_U)
parsed.u = &o.val;
else if (key == KEY_E)
parsed.e = &o.val;
else if (key == KEY_V)
parsed.v = &o.val;
else if (key == KEY_TID)
tid = unpackTid(o.val);
else if (key == KEY_UA)
ua = o.val.as<std::string>();
else if (key == KEY_NETID)
network = o.val.as<NetId>();
else if (key == KEY_ISCLIENT)
is_client = o.val.as<bool>();
else if (key == KEY_Q)
parsed.q = o.val.as<std::string>();
else if (key == KEY_A)
parsed.a = &o.val;
}
if (e)
if (parsed.e)
type = MessageType::Error;
else if (r)
else if (parsed.r)
type = MessageType::Reply;
else if (v)
else if (parsed.v)
type = MessageType::ValueData;
else if (u)
else if (parsed.u)
type = MessageType::ValueUpdate;
else if (y and y->as<std::string>() != "q")
else if (parsed.y and parsed.y->as<std::string>() != "q")
throw msgpack::type_error();
else if (q == "ping")
else if (parsed.q == QUERY_PING)
type = MessageType::Ping;
else if (q == "find")
else if (parsed.q == QUERY_FIND)
type = MessageType::FindNode;
else if (q == "get")
else if (parsed.q == QUERY_GET)
type = MessageType::GetValues;
else if (q == "listen")
else if (parsed.q == QUERY_LISTEN)
type = MessageType::Listen;
else if (q == "put")
else if (parsed.q == QUERY_PUT)
type = MessageType::AnnounceValue;
else if (q == "refresh")
else if (parsed.q == QUERY_REFRESH)
type = MessageType::Refresh;
else
throw msgpack::type_error();
if (type == MessageType::ValueData) {
if (v->type != msgpack::type::MAP)
if (parsed.v->type != msgpack::type::MAP)
throw msgpack::type_error();
for (size_t i = 0; i < v->via.map.size; ++i) {
auto& vdat = v->via.map.ptr[i];
for (size_t i = 0; i < parsed.v->via.map.size; ++i) {
auto& vdat = parsed.v->via.map.ptr[i];
auto o = findMapValue(vdat.val, "o");
auto d = findMapValue(vdat.val, "d");
if (not o or not d)
@@ -189,70 +241,85 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
return;
}
auto a = findMapValue(msg, "a");
if (!a && !r && !e && !u)
if (!parsed.a && !parsed.r && !parsed.e && !parsed.u)
throw msgpack::type_error();
auto& req = a ? *a : (r ? *r : (u ? *u : *e));
auto& req = parsed.a ? *parsed.a : (parsed.r ? *parsed.r : (parsed.u ? *parsed.u : *parsed.e));
if (e) {
if (e->type != msgpack::type::ARRAY)
if (parsed.e) {
if (parsed.e->type != msgpack::type::ARRAY)
throw msgpack::type_error();
error_code = e->via.array.ptr[0].as<uint16_t>();
error_code = parsed.e->via.array.ptr[0].as<uint16_t>();
}
if (auto t = findMapValue(req, "sid"))
socket_id = unpackTid(*t);
struct ParsedReq {
msgpack::object* values;
msgpack::object* fields;
msgpack::object* sa;
msgpack::object* want;
} parsedReq {};
if (auto rid = findMapValue(req, "id"))
id = {*rid};
for (unsigned i = 0; i < req.via.map.size; i++) {
auto& o = req.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
continue;
auto key = o.key.as<std::string>();
if (key == KEY_REQ_SID)
socket_id = unpackTid(o.val);
else if (key == KEY_REQ_ID)
id = {o.val};
else if (key == KEY_REQ_H)
info_hash = {o.val};
else if (key == KEY_REQ_TARGET)
target = {o.val};
else if (key == KEY_REQ_QUERY)
query.msgpack_unpack(o.val);
else if (key == KEY_REQ_TOKEN)
token = unpackBlob(o.val);
else if (key == KEY_REQ_VALUE_ID)
value_id = o.val.as<Value::Id>();
else if (key == KEY_REQ_NODES4)
nodes4_raw = unpackBlob(o.val);
else if (key == KEY_REQ_NODES6)
nodes6_raw = unpackBlob(o.val);
else if (key == KEY_REQ_ADDRESS)
parsedReq.sa = &o.val;
else if (key == KEY_REQ_CREATION)
created = from_time_t(o.val.as<std::time_t>());
else if (key == KEY_REQ_VALUES)
parsedReq.values = &o.val;
else if (key == KEY_REQ_EXPIRED)
expired_values = o.val.as<decltype(expired_values)>();
else if (key == KEY_REQ_REFRESHED)
refreshed_values = o.val.as<decltype(refreshed_values)>();
else if (key == KEY_REQ_FIELDS)
parsedReq.fields = &o.val;
else if (key == KEY_REQ_WANT)
parsedReq.want = &o.val;
}
if (auto rh = findMapValue(req, "h"))
info_hash = {*rh};
if (auto rtarget = findMapValue(req, "target"))
target = {*rtarget};
if (auto rquery = findMapValue(req, "q"))
query.msgpack_unpack(*rquery);
if (auto otoken = findMapValue(req, "token"))
token = unpackBlob(*otoken);
if (auto vid = findMapValue(req, "vid"))
value_id = vid->as<Value::Id>();
if (auto rnodes4 = findMapValue(req, "n4"))
nodes4_raw = unpackBlob(*rnodes4);
if (auto rnodes6 = findMapValue(req, "n6"))
nodes6_raw = unpackBlob(*rnodes6);
if (auto sa = findMapValue(req, "sa")) {
if (sa->type != msgpack::type::BIN)
if (parsedReq.sa) {
if (parsedReq.sa->type != msgpack::type::BIN)
throw msgpack::type_error();
auto l = sa->via.bin.size;
auto l = parsedReq.sa->via.bin.size;
if (l == sizeof(in_addr)) {
addr.setFamily(AF_INET);
auto& a = addr.getIPv4();
a.sin_port = 0;
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin_addr);
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin_addr);
} else if (l == sizeof(in6_addr)) {
addr.setFamily(AF_INET6);
auto& a = addr.getIPv6();
a.sin6_port = 0;
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin6_addr);
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin6_addr);
}
} else
addr = {};
if (auto rcreated = findMapValue(req, "c"))
created = from_time_t(rcreated->as<std::time_t>());
if (auto rvalues = findMapValue(req, "values")) {
if (rvalues->type != msgpack::type::ARRAY)
if (parsedReq.values) {
if (parsedReq.values->type != msgpack::type::ARRAY)
throw msgpack::type_error();
for (size_t i = 0; i < rvalues->via.array.size; i++) {
auto& packed_v = rvalues->via.array.ptr[i];
for (size_t i = 0; i < parsedReq.values->via.array.size; i++) {
auto& packed_v = parsedReq.values->via.array.ptr[i];
if (packed_v.type == msgpack::type::POSITIVE_INTEGER) {
// Skip oversize values with a small margin for header overhead
if (packed_v.via.u64 > MAX_VALUE_SIZE + 32)
@@ -260,16 +327,16 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
value_parts.emplace(i, std::make_pair(packed_v.via.u64, Blob{}));
} else {
try {
values.emplace_back(std::make_shared<Value>(rvalues->via.array.ptr[i]));
values.emplace_back(std::make_shared<Value>(parsedReq.values->via.array.ptr[i]));
} catch (const std::exception& e) {
//DHT_LOG_WARN("Error reading value: %s", e.what());
}
}
}
} else if (auto raw_fields = findMapValue(req, "fields")) {
if (auto rfields = findMapValue(*raw_fields, "f")) {
} else if (parsedReq.fields) {
if (auto rfields = findMapValue(*parsedReq.fields, "f")) {
auto vfields = rfields->as<std::set<Value::Field>>();
if (auto rvalues = findMapValue(*raw_fields, "v")) {
if (auto rvalues = findMapValue(*parsedReq.fields, "v")) {
if (rvalues->type != msgpack::type::ARRAY)
throw msgpack::type_error();
size_t val_num = rvalues->via.array.size / vfields.size();
@@ -284,18 +351,14 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
} else {
throw msgpack::type_error();
}
} else if (auto raw_fields = findMapValue(req, "exp")) {
expired_values = raw_fields->as<decltype(expired_values)>();
} else if (auto raw_fields = findMapValue(req, "re")) {
refreshed_values = raw_fields->as<decltype(refreshed_values)>();
}
if (auto w = findMapValue(req, "w")) {
if (w->type != msgpack::type::ARRAY)
if (parsedReq.want) {
if (parsedReq.want->type != msgpack::type::ARRAY)
throw msgpack::type_error();
want = 0;
for (unsigned i=0; i<w->via.array.size; i++) {
auto& val = w->via.array.ptr[i];
for (unsigned i=0; i<parsedReq.want->via.array.size; i++) {
auto& val = parsedReq.want->via.array.ptr[i];
try {
auto w = val.as<sa_family_t>();
if (w == AF_INET)
+577
View File
@@ -0,0 +1,577 @@
/*
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@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/>.
*/
#include "peer_discovery.h"
#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
namespace dht {
// Organization-local Scope multicast
constexpr char MULTICAST_ADDRESS_IPV4[12] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[10] = "ff08::101";
class PeerDiscovery::DomainPeerDiscovery
{
public:
DomainPeerDiscovery(sa_family_t domain, in_port_t port);
~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 socketJoinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join() {
if(running_listen_.joinable()) running_listen_.join();
if(running_send_.joinable()) running_send_.join();
}
private:
//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 stop_writefd_ {-1};
SockAddr sockAddrSend_;
//Thread export to be joined
std::thread running_listen_;
std::thread running_send_;
msgpack::sbuffer sbuf_;
std::map<std::string, msgpack::sbuffer> messages_;
std::map<std::string, ServiceDiscoveredCallback> callbackmap_;
/**
* Multicast Socket Initialization, accept IPV4, IPV6
*/
static int initialize_socket(sa_family_t domain);
/**
* Receive messages
*/
std::pair<SockAddr, msgpack::object_handle> recvFrom();
/**
* Listener pack thread loop
*/
void listenerpack_thread();
/**
* Listener Parameters Setup
*/
void listener_setup();
/**
* Sender Parameters Setup
*/
void sender_setup();
/**
* Sender Parameters Setup
*/
void messages_reload();
void stopDiscovery();
void stopPublish();
};
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(sa_family_t domain, in_port_t port)
: domain_(domain), port_(port), sockfd_(initialize_socket(domain))
{
socketJoinMulticast(sockfd_, domain);
listener_setup();
sender_setup();
}
PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
{
stop();
join();
if (sockfd_ != -1)
close(sockfd_);
#ifdef _WIN32
WSACleanup();
#endif
}
int
PeerDiscovery::DomainPeerDiscovery::initialize_socket(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::listener_setup()
{
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::socketJoinMulticast(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;
}
}
}
void
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
std::unique_lock<std::mutex> lck(dmtx_);
callbackmap_[type] = callback;
if (not drunning_) {
if (running_listen_.joinable())
running_listen_.join();
drunning_ = true;
running_listen_ = std::thread(&DomainPeerDiscovery::listenerpack_thread, this);
}
}
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::listenerpack_thread()
{
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];
stop_writefd_ = stopfds_pipe[1];
while (true) {
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
}
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;
for (unsigned i = 0; i < obj.via.map.size; i++) {
auto& o = obj.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
continue;
auto key = o.key.as<std::string>();
ServiceDiscoveredCallback cb;
{
std::lock_guard<std::mutex> lck(dmtx_);
auto callback = callbackmap_.find(key);
if (callback != callbackmap_.end())
cb = callback->second;
}
if (cb)
cb(std::move(o.val), std::move(rcv.first));
}
} catch (const std::exception& e) {
std::cerr << "Error receiving packet: " << e.what() << std::endl;
}
}
}
if (stop_readfd != -1)
close(stop_readfd);
if (stop_writefd_ != -1) {
close(stop_writefd_);
stop_writefd_ = -1;
}
}
void
PeerDiscovery::DomainPeerDiscovery::sender_setup()
{
// Setup sender address
sockAddrSend_.setFamily(domain_);
sockAddrSend_.setAddress(domain_ == AF_INET ? MULTICAST_ADDRESS_IPV4 : MULTICAST_ADDRESS_IPV6);
sockAddrSend_.setPort(port_);
}
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_);
messages_[type] = std::move(pack_buf_c);
messages_reload();
if (not lrunning_) {
if (running_send_.joinable())
running_send_.join();
lrunning_ = true;
running_send_ = 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;
}
});
}
}
bool
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
{
std::lock_guard<std::mutex> lck(dmtx_);
if (callbackmap_.erase(type) > 0) {
if (callbackmap_.empty())
stopDiscovery();
return true;
}
return false;
}
bool
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
{
std::lock_guard<std::mutex> lck(mtx_);
if (messages_.erase(type) > 0) {
if (messages_.empty())
stopPublish();
else
messages_reload();
return true;
}
return false;
}
void
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
{
#ifdef _WIN32
#define write(s, b, f) send((s), (b), (f), 0)
#endif
if (drunning_) {
drunning_ = false;
if (stop_writefd_ != -1) {
if (write(stop_writefd_, "\0", 1) == -1) {
std::cerr << "Can't send stop message: " << strerror(errno) << std::endl;
}
}
}
#ifdef _WIN32
#undef write
#endif
}
void
PeerDiscovery::DomainPeerDiscovery::stopPublish()
{
if (lrunning_) {
lrunning_ = false;
cv_.notify_all();
}
}
void
PeerDiscovery::DomainPeerDiscovery::stop()
{
{
std::unique_lock<std::mutex> lck(dmtx_);
stopDiscovery();
}
{
std::unique_lock<std::mutex> lck(mtx_);
stopPublish();
}
}
void
PeerDiscovery::DomainPeerDiscovery::messages_reload()
{
sbuf_.clear();
msgpack::packer<msgpack::sbuffer> pk(&sbuf_);
pk.pack_map(messages_.size());
for (const auto& m : messages_) {
pk.pack(m.first);
sbuf_.write(m.second.data(), m.second.size());
}
}
PeerDiscovery::PeerDiscovery(in_port_t port)
{
try {
peerDiscovery4_.reset(new DomainPeerDiscovery(AF_INET, port));
} catch(const std::exception& e){
std::cerr << "Can't start peer discovery (IPv4): " << e.what() << std::endl;
}
try {
peerDiscovery6_.reset(new DomainPeerDiscovery(AF_INET6, port));
} catch(const std::exception& e) {
std::cerr << "Can't start peer discovery (IPv6): " << e.what() << std::endl;
}
}
PeerDiscovery::~PeerDiscovery(){}
void
PeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
if(peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if(peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
}
void
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);
} else if (domain == AF_INET6) {
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
}
}
void
PeerDiscovery::stop()
{
if(peerDiscovery4_) peerDiscovery4_->stop();
if(peerDiscovery6_) peerDiscovery6_->stop();
}
bool
PeerDiscovery::stopDiscovery(const std::string &type)
{
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopDiscovery(type);
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopDiscovery(type);
return stopped4 or stopped6;
}
bool
PeerDiscovery::stopPublish(const std::string &type)
{
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopPublish(type);
return stopped4 or stopped6;
}
bool
PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
{
if (domain == AF_INET) {
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
} else if (domain == AF_INET6) {
return peerDiscovery6_ and peerDiscovery6_->stopPublish(type);
}
return false;
}
void
PeerDiscovery::join() {
if(peerDiscovery4_) peerDiscovery4_->join();
if(peerDiscovery6_) peerDiscovery6_->join();
}
}
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -57,6 +57,15 @@ struct Request {
bool pending() const { return state_ == State::PENDING; }
bool over() const { return not pending(); }
State getState() const { return state_; }
char getStateChar() const {
switch (state_) {
case State::PENDING: return 'f';
case State::CANCELLED: return 'c';
case State::EXPIRED: return 'e';
case State::COMPLETED: return 'a';
default: return '?';
}
}
Request(State state = State::PENDING) : state_(state) {}
Request(MessageType type, Tid tid,
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -92,7 +92,7 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
throw std::out_of_range("End of table");
InfoHash id = it->first;
id.setBit(bit, 1);
id.setBit(bit, true);
return id;
}
+83 -22
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -65,7 +65,8 @@ struct Dht::SearchNode {
ValueCache cache;
Sp<Scheduler::Job> cacheExpirationJob {};
Sp<net::Request> req {};
CachedListenStatus(ValueStateCallback&& cb) : cache(std::forward<ValueStateCallback>(cb)) {}
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
CachedListenStatus(CachedListenStatus&&) = default;
CachedListenStatus(const CachedListenStatus&) = delete;
CachedListenStatus& operator=(const CachedListenStatus&) = delete;
@@ -136,7 +137,7 @@ struct Dht::SearchNode {
*
* @return true if we can send get, else false.
*/
bool canGet(time_point now, time_point update, Sp<Query> q = {}) const {
bool canGet(time_point now, time_point update, const Sp<Query>& q) const {
if (node->isExpired())
return false;
@@ -147,9 +148,9 @@ struct Dht::SearchNode {
if (s.second and s.second->pending())
pending = true;
if (s.first and q and q->isSatisfiedBy(*s.first) and s.second) {
if (s.second->pending() and not pending_sq_status)
if (s.second->pending())
pending_sq_status = true;
if (s.second->completed() and not (update > s.second->reply_time) and not completed_sq_status)
else if (s.second->completed() and not (update > s.second->reply_time))
completed_sq_status = true;
if (completed_sq_status and pending_sq_status)
break;
@@ -157,7 +158,7 @@ struct Dht::SearchNode {
}
return (not pending and now > last_get_reply + Node::NODE_EXPIRE_TIME) or
not (hasStartedPagination(q) or completed_sq_status or pending_sq_status);
not (completed_sq_status or pending_sq_status or hasStartedPagination(q));
}
/**
@@ -225,6 +226,13 @@ struct Dht::SearchNode {
}
}
void onListenSynced(const Sp<Query>& q, bool synced = true) {
auto l = listenStatus.find(q);
if (l != listenStatus.end()) {
l->second.cache.onSynced(synced);
}
}
void expireValues(const Sp<Query>& q, Scheduler& scheduler) {
auto l = listenStatus.find(q);
if (l != listenStatus.end()) {
@@ -302,7 +310,7 @@ struct Dht::SearchNode {
return isListening(now, ls);
}
bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status) const {
if (listen_status == listenStatus.end())
if (listen_status == listenStatus.end() or not listen_status->second.req)
return false;
return listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME > now;
}
@@ -320,22 +328,21 @@ struct Dht::SearchNode {
}
/**
* Assumng the node is synced, should a "put" request be sent to this node now ?
* Assuming the node is synced, should a "put" request be sent to this node now ?
*/
time_point getAnnounceTime(Value::Id vid) const {
const auto& ack = acked.find(vid);
const auto& gs = probe_query ? getStatus.find(probe_query) : getStatus.cend();
if ((ack == acked.cend() or not ack->second.first) and (gs == getStatus.cend()
or not gs->second or not gs->second->pending()))
if (ack == acked.cend() or not ack->second.first) {
return time_point::min();
return ((gs != getStatus.cend() and gs->second and gs->second->pending())
or ack == acked.cend() or not ack->second.first or ack->second.first->pending())
? time_point::max()
: ack->second.second - REANNOUNCE_MARGIN;
}
if (ack->second.first->completed()) {
return ack->second.second - REANNOUNCE_MARGIN;
}
return ack->second.first->pending() ? time_point::max() : time_point::min();
}
/**
* Assumng the node is synced, should the "listen" request with Query q be
* 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 {
@@ -378,6 +385,11 @@ struct Dht::Search {
std::multimap<time_point, Get> callbacks {};
/* listeners */
struct SearchListener {
Sp<Query> query;
ValueCallback get_cb;
SyncCallback sync_cb;
};
std::map<size_t, SearchListener> listeners {};
size_t listener_token = 1;
@@ -430,7 +442,8 @@ struct Dht::Search {
*
* @param query The query identifying a 'get' request.
*/
time_point getLastGetTime(Sp<Query> query = {}) const;
time_point getLastGetTime(const Query&) const;
time_point getLastGetTime() const;
/**
* Is this get operation done ?
@@ -475,12 +488,22 @@ struct Dht::Search {
bool isAnnounced(Value::Id id) const;
bool isListening(time_point now) const;
size_t listen(ValueCallback cb, Value::Filter f, const Sp<Query>& q, Scheduler& scheduler) {
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) {
if (not cache.get(f, q, gcb, dcb)) {
const auto& now = scheduler.time();
callbacks.emplace(now, Get { now, f, q, qcb, gcb, dcb });
scheduler.edit(nextSearchStep, now);
}
}
}
size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
//DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb){
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
done = false;
auto token = ++listener_token;
listeners.emplace(token, SearchListener{q, f, vcb});
listeners.emplace(token, SearchListener{q, vcb, scb});
scheduler.edit(nextSearchStep, scheduler.time());
return token;
});
@@ -509,6 +532,35 @@ struct Dht::Search {
scheduler.edit(opExpirationJob, cache.getExpiration());
}
std::vector<Sp<Value>> getPut() const {
std::vector<Sp<Value>> ret;
ret.reserve(announce.size());
for (const auto& a : announce)
ret.push_back(a.value);
return ret;
}
Sp<Value> getPut(Value::Id vid) const {
for (auto& a : announce) {
if (a.value->id == vid)
return a.value;
}
return {};
}
bool cancelPut(Value::Id vid) {
bool canceled {false};
for (auto it = announce.begin(); it != announce.end();) {
if (it->value->id == vid) {
canceled = true;
it = announce.erase(it);
}
else
++it;
}
return canceled;
}
/**
* @return The number of non-good search nodes.
*/
@@ -746,11 +798,20 @@ Dht::Search::isSynced(time_point now) const
}
time_point
Dht::Search::getLastGetTime(Sp<Query> q) const
Dht::Search::getLastGetTime(const Query& q) const
{
time_point last = time_point::min();
for (const auto& g : callbacks)
last = std::max(last, (not q or q->isSatisfiedBy(*g.second.query) ? g.second.start : time_point::min()));
last = std::max(last, (q.isSatisfiedBy(*g.second.query) ? g.second.start : time_point::min()));
return last;
}
time_point
Dht::Search::getLastGetTime() const
{
time_point last = time_point::min();
for (const auto& g : callbacks)
last = std::max(last, g.second.start);
return last;
}
+54 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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>
@@ -54,27 +54,28 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
CERTIFICATE_TYPE,
*certificate_,
1
}, [this](bool ok) {
}, [this, certId](bool ok) {
if (ok)
DHT_LOG.DEBUG("SecureDht: public key announced successfully");
DHT_LOG.d(certId, "SecureDht: public key announced successfully");
}, {}, true);
}
}
SecureDht::~SecureDht()
{}
SecureDht::~SecureDht() = default;
ValueType
SecureDht::secureType(ValueType&& type)
{
type.storePolicy = [this,type](InfoHash id, Sp<Value>& v, const InfoHash& nid, const SockAddr& a) {
if (v->isSigned()) {
if (!v->owner or !v->owner->checkSignature(v->getToSign(), v->signature)) {
DHT_LOG.WARN("Signature verification failed");
if (!v->signatureChecked) {
v->signatureChecked = true;
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
}
if (!v->signatureValid) {
DHT_LOG.w("Signature verification failed");
return false;
}
else
DHT_LOG.WARN("Signature verification succeeded");
}
return type.storePolicy(id, v, nid, a);
};
@@ -82,18 +83,22 @@ SecureDht::secureType(ValueType&& type)
if (!o->isSigned())
return type.editPolicy(id, o, n, nid, a);
if (o->owner != n->owner) {
DHT_LOG.WARN("Edition forbidden: owner changed.");
DHT_LOG.w("Edition forbidden: owner changed.");
return false;
}
if (!o->owner or !o->owner->checkSignature(n->getToSign(), n->signature)) {
DHT_LOG.WARN("Edition forbidden: signature verification failed.");
if (!n->signatureChecked) {
n->signatureChecked = true;
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
}
if (!n->signatureValid) {
DHT_LOG.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.WARN("Edition forbidden: sequence number must be increasing.");
DHT_LOG.w("Edition forbidden: sequence number must be increasing.");
return false;
}
}
@@ -139,7 +144,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
}
InfoHash h = crt->getPublicKey().getId();
if (node == h) {
DHT_LOG.DEBUG("Registering certificate for %s", h.toString().c_str());
DHT_LOG.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));
@@ -147,7 +152,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
it->second = std::move(crt);
return it->second;
} else {
DHT_LOG.DEBUG("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
DHT_LOG.w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
return nullptr;
}
}
@@ -160,11 +165,11 @@ SecureDht::registerCertificate(Sp<crypto::Certificate>& cert)
}
void
SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb)
SecureDht::findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb)
{
Sp<crypto::Certificate> b = getCertificate(node);
if (b && *b) {
DHT_LOG.DEBUG("Using certificate from cache for %s", node.toString().c_str());
DHT_LOG.d("Using certificate from cache for %s", node.toString().c_str());
if (cb)
cb(b);
return;
@@ -172,7 +177,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
if (localQueryMethod_) {
auto res = localQueryMethod_(node);
if (not res.empty()) {
DHT_LOG.DEBUG("Registering certificate from local store for %s", node.toString().c_str());
DHT_LOG.d("Registering certificate from local store for %s", node.toString().c_str());
nodesCertificates_.emplace(node, res.front());
if (cb)
cb(res.front());
@@ -187,7 +192,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
DHT_LOG.DEBUG("Found certificate for %s", node.toString().c_str());
DHT_LOG.d("Found certificate for %s", node.toString().c_str());
if (cb)
cb(cert);
return false;
@@ -201,11 +206,11 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
}
void
SecureDht::findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb)
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
DHT_LOG.DEBUG("Found public key from cache for %s", node.toString().c_str());
DHT_LOG.d("Found public key from cache for %s", node.toString().c_str());
if (cb)
cb(pk);
return;
@@ -229,32 +234,42 @@ SecureDht::checkValue(const Sp<Value>& v)
// Decrypt encrypted values
if (v->isEncrypted()) {
if (not key_) {
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
if (forward_all_) // We are currently a proxy, send messages to clients.
return v;
#endif
return {};
}
if (v->decrypted) {
return v->decryptedValue;
}
v->decrypted = true;
try {
Value decrypted_val (decrypt(*v));
if (decrypted_val.recipient == getId()) {
if (decrypted_val.owner)
nodesPubKeys_[decrypted_val.owner->getId()] = decrypted_val.owner;
return std::make_shared<Value>(std::move(decrypted_val));
v->decryptedValue = std::make_shared<Value>(std::move(decrypted_val));
return v->decryptedValue;
}
// Ignore values belonging to other people
} catch (const std::exception& e) {
DHT_LOG.WARN("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
DHT_LOG.w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
}
}
// Check signed values
else if (v->isSigned()) {
if (v->signatureChecked) {
return v->signatureValid ? v : Sp<Value>{};
}
v->signatureChecked = true;
if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
v->signatureValid = true;
nodesPubKeys_[v->owner->getId()] = v->owner;
return v;
}
else
DHT_LOG.WARN("Signature verification failed for %s", v->toString().c_str());
DHT_LOG.w("Signature verification failed for %s", v->toString().c_str());
}
// Forward normal values
else {
@@ -264,10 +279,12 @@ SecureDht::checkValue(const Sp<Value>& v)
}
ValueCallback
SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
SecureDht::getCallbackFilter(const ValueCallback& cb, Value::Filter&& filter)
{
return [=](const std::vector<Sp<Value>>& values, bool expired) {
std::vector<Sp<Value>> tmpvals {};
if (not filter)
tmpvals.reserve(values.size());
for (const auto& v : values) {
if (auto nv = checkValue(v))
if (not filter or filter(*nv))
@@ -281,10 +298,12 @@ SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
GetCallback
SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
SecureDht::getCallbackFilter(const GetCallback& cb, Value::Filter&& filter)
{
return [=](const std::vector<Sp<Value>>& values) {
std::vector<Sp<Value>> tmpvals {};
if (not filter)
tmpvals.reserve(values.size());
for (const auto& v : values) {
if (auto nv = checkValue(v))
if (not filter or filter(*nv))
@@ -327,19 +346,18 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
// Check if we are already announcing a value
auto p = dht_->getPut(hash, val->id);
if (p && val->seq <= p->seq) {
DHT_LOG.DEBUG("Found previous value being announced.");
val->seq = p->seq + 1;
}
// Check if data already exists on the dht
get(hash,
[val,this] (const std::vector<Sp<Value>>& vals) {
DHT_LOG.DEBUG("Found online previous value being announced.");
DHT_LOG.d("Found online previous value being announced.");
for (const auto& v : vals) {
if (!v->isSigned())
DHT_LOG.ERR("Existing non-signed value seems to exists at this location.");
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.ERR("Existing signed value belonging to someone else seems to exists at this location.");
DHT_LOG.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;
}
@@ -349,24 +367,25 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
sign(*val);
dht_->put(hash, val, callback, time_point::max(), permanent);
},
Value::IdFilter(val->id)
Value::IdFilter(val->id),
std::move(Where().id(val->id))
);
}
void
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
findPublicKey(to, [=](const Sp<const crypto::PublicKey> pk) {
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
DHT_LOG.WARN("Encrypting data for PK: %s", pk->getId().toString().c_str());
DHT_LOG.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.ERR("Error putting encrypted data: %s", e.what());
DHT_LOG.e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
+29 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 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
@@ -90,20 +90,7 @@ struct Storage {
Storage() {}
Storage(time_point t) : maintenance_time(t) {}
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 || defined(_WIN32)
// GCC-bug: remove me when support of GCC < 4.9.2 is abandoned
Storage(Storage&& o) noexcept
: maintenance_time(std::move(o.maintenance_time))
, listeners(std::move(o.listeners))
, local_listeners(std::move(o.local_listeners))
, listener_token(std::move(o.listener_token))
, values(std::move(o.values))
, total_size(std::move(o.total_size)) {}
#else
Storage(Storage&& o) noexcept = default;
#endif
Storage& operator=(Storage&& o) = default;
bool empty() const {
@@ -128,7 +115,7 @@ struct Storage {
return {};
}
std::vector<Sp<Value>> get(Value::Filter f = {}) const {
std::vector<Sp<Value>> get(const Value::Filter& f = {}) const {
std::vector<Sp<Value>> newvals {};
if (not f) newvals.reserve(values.size());
for (auto& v : values) {
@@ -154,15 +141,22 @@ struct Storage {
*
* @param now The reference to now
* @param vid The value id
* @return true if a value storage was updated, false otherwise
* @return time of the next expiration, time_point::max() if no expiration
*/
bool refresh(const time_point& now, const Value::Id& vid) {
time_point refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) {
for (auto& vs : values)
if (vs.data->id == vid) {
vs.created = now;
return true;
vs.expiration = std::max(vs.expiration, now + types.getType(vs.data->type).expiration);
return vs.expiration;
}
return false;
return time_point::max();
}
size_t listen(ValueCallback& cb, Value::Filter& f, const Sp<Query>& q);
void cancelListen(size_t token) {
local_listeners.erase(token);
}
StoreDiff remove(const InfoHash& id, Value::Id);
@@ -178,6 +172,22 @@ private:
};
size_t
Storage::listen(ValueCallback& gcb, Value::Filter& filter, const Sp<Query>& query)
{
if (not empty()) {
std::vector<Sp<Value>> newvals = get(filter);
if (not newvals.empty()) {
if (!gcb(newvals, false))
return 0;
}
}
auto tokenlocal = ++listener_token;
local_listeners.emplace(tokenlocal, LocalListener{query, filter, gcb});
return tokenlocal;
}
std::pair<ValueStorage*, Storage::StoreDiff>
Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, time_point expiration, StorageBucket* sb)
{
+175
View File
@@ -0,0 +1,175 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: 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 <http://www.gnu.org/licenses/>.
*/
#include "thread_pool.h"
#include <atomic>
#include <thread>
#include <iostream>
#include <ciso646> // fix windows compiler bug
namespace dht {
constexpr const size_t IO_THREADS_MAX {64};
struct ThreadPool::ThreadState
{
std::thread thread {};
std::atomic_bool run {true};
};
ThreadPool&
ThreadPool::computation()
{
static ThreadPool pool;
return pool;
}
ThreadPool&
ThreadPool::io()
{
static ThreadPool pool(IO_THREADS_MAX);
return pool;
}
ThreadPool::ThreadPool(size_t maxThreads) : maxThreads_(maxThreads)
{
threads_.reserve(maxThreads_);
}
ThreadPool::ThreadPool()
: ThreadPool(std::max<size_t>(std::thread::hardware_concurrency(), 4))
{}
ThreadPool::~ThreadPool()
{
join();
}
void
ThreadPool::run(std::function<void()>&& cb)
{
std::unique_lock<std::mutex> l(lock_);
if (not running_) return;
// launch new thread if necessary
if (not readyThreads_ && threads_.size() < maxThreads_) {
threads_.emplace_back(new ThreadState());
auto& t = *threads_.back();
t.thread = std::thread([&]() {
while (t.run) {
std::function<void()> task;
// pick task from queue
{
std::unique_lock<std::mutex> l(lock_);
readyThreads_++;
cv_.wait(l, [&](){
return not t.run or not tasks_.empty();
});
readyThreads_--;
if (not t.run)
break;
task = std::move(tasks_.front());
tasks_.pop();
}
// run task
try {
if (task)
task();
} catch (const std::exception& e) {
// LOG_ERR("Exception running task: %s", e.what());
std::cerr << "Exception running task: " << e.what() << std::endl;
}
}
});
}
// push task to queue
tasks_.emplace(std::move(cb));
// notify thread
l.unlock();
cv_.notify_one();
}
void
ThreadPool::stop()
{
{
std::lock_guard<std::mutex> l(lock_);
running_ = false;
}
for (auto& t : threads_)
t->run = false;
cv_.notify_all();
}
void
ThreadPool::join()
{
stop();
for (auto& t : threads_)
t->thread.join();
threads_.clear();
}
void
Executor::run(std::function<void()>&& task)
{
std::lock_guard<std::mutex> l(lock_);
if (current_ < maxConcurrent_) {
run_(std::move(task));
} else {
tasks_.emplace(std::move(task));
}
}
void
Executor::run_(std::function<void()>&& task)
{
current_++;
std::weak_ptr<Executor> w = shared_from_this();
threadPool_.get().run([w,task] {
try {
task();
} catch (const std::exception& e) {
std::cerr << "Exception running task: " << e.what() << std::endl;
}
if (auto sthis = w.lock()) {
auto& this_ = *sthis;
std::lock_guard<std::mutex> l(this_.lock_);
this_.current_--;
this_.schedule();
}
});
}
void
Executor::schedule()
{
if (not tasks_.empty() and current_ < maxConcurrent_) {
run_(std::move(tasks_.front()));
tasks_.pop();
}
}
}
+50 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -16,6 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "utils.h"
#include "sockaddr.h"
#include "default_types.h"
@@ -25,10 +29,18 @@
#define IN_IS_ADDR_UNSPECIFIED(a) (((long int) (a)->s_addr) == 0x00000000)
#endif /* IN_IS_ADDR_UNSPECIFIED */
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION "(unknown version)"
#endif
namespace dht {
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
const char* version() {
return PACKAGE_VERSION;
}
std::pair<std::string, std::string>
splitPort(const std::string& s) {
if (s.empty())
@@ -73,6 +85,24 @@ SockAddr::resolve(const std::string& host, const std::string& service)
return ips;
}
void
SockAddr::setAddress(const char* address)
{
auto family = getFamily();
void* addr = nullptr;
switch (family) {
case AF_INET:
addr = &getIPv4().sin_addr;
break;
case AF_INET6:
addr = &getIPv6().sin6_addr;
break;
default:
throw std::runtime_error("Unknown address family");
}
if (inet_pton(family, address, addr) <= 0)
throw std::runtime_error(std::string("Can't parse IP address: ") + strerror(errno));
}
std::string
print_addr(const sockaddr* sa, socklen_t slen)
@@ -80,7 +110,7 @@ print_addr(const sockaddr* sa, socklen_t slen)
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
std::stringstream out;
if (!getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
if (sa->sa_family == AF_INET6)
out << "[" << hbuf << "]";
else
@@ -171,10 +201,10 @@ SockAddr::isMappedIPv4() const
}
SockAddr
SockAddr::getMappedIPv4() const
SockAddr::getMappedIPv4()
{
if (not isMappedIPv4())
return *this;
return std::move(*this);
SockAddr ret;
ret.setFamily(AF_INET);
ret.setPort(getPort());
@@ -185,6 +215,22 @@ SockAddr::getMappedIPv4() const
return ret;
}
SockAddr
SockAddr::getMappedIPv6()
{
auto family = getFamily();
if (family != AF_INET)
return std::move(*this);
SockAddr ret;
ret.setFamily(AF_INET6);
ret.setPort(getPort());
auto addr4 = reinterpret_cast<const uint8_t*>(&getIPv4().sin_addr);
auto addr6 = reinterpret_cast<uint8_t*>(&ret.getIPv6().sin6_addr);
std::copy(MAPPED_IPV4_PREFIX.begin(), MAPPED_IPV4_PREFIX.end(), addr6);
std::copy_n(addr4, sizeof(in_addr), addr6 + MAPPED_IPV4_PREFIX.size());
return ret;
}
bool operator==(const SockAddr& a, const SockAddr& b) {
return a.equals(b);
}
+19 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -22,9 +22,9 @@
#include "default_types.h"
#include "securedht.h" // print certificate ID
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
#include "base64.h"
#endif //OPENDHT_PROXY_SERVER
#endif
namespace dht {
@@ -54,17 +54,19 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
s << IpServiceAnnouncement(v.data);
} else if (v.type == CERTIFICATE_TYPE.id) {
s << "Certificate";
#ifdef OPENDHT_LOG_CRT_ID
try {
InfoHash h = crypto::Certificate(v.data).getPublicKey().getId();
auto h = crypto::Certificate(v.data).getPublicKey().getLongId();
s << " with ID " << h;
} catch (const std::exception& e) {
s << " (invalid)";
}
#endif
} else {
s << "Data (type: " << v.type << " ): ";
s << std::hex;
for (size_t i=0; i<v.data.size(); i++)
s << std::setfill('0') << std::setw(2) << (unsigned)v.data[i];
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
}
}
@@ -76,7 +78,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
const ValueType ValueType::USER_DATA = {0, "User Data"};
bool
ValueType::DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
{
return v->size() <= MAX_VALUE_SIZE;
}
@@ -172,7 +174,7 @@ Value::msgpack_unpack_body(const msgpack::object& o)
}
}
#if OPENDHT_PROXY_SERVER || OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_JSONCPP
Value::Value(Json::Value& json)
{
id = Value::Id(unpackId(json, "id"));
@@ -248,7 +250,7 @@ unpackId(const Json::Value& json, const std::string& key) {
} catch (...) {}
return ret;
}
#endif //OPENDHT_PROXY_SERVER
#endif
bool
FieldValue::operator==(const FieldValue& vfd) const
@@ -286,11 +288,11 @@ FieldValue::getLocalFilter() const
case Value::Field::UserType:
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
default:
return Value::AllFilter();
return {};
}
}
FieldValueIndex::FieldValueIndex(const Value& v, Select s)
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
{
auto selection = s.getSelection();
if (not selection.empty()) {
@@ -397,8 +399,8 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
}
void trim_str(std::string& str) {
auto first = std::min(str.size(), str.find_first_not_of(" "));
auto last = std::min(str.size(), str.find_last_not_of(" "));
auto first = std::min(str.size(), str.find_first_not_of(' '));
auto last = std::min(str.size(), str.find_last_not_of(' '));
str = str.substr(first, last - first + 1);
}
@@ -495,8 +497,7 @@ template <typename T>
bool subset(std::vector<T> fds, std::vector<T> qfds)
{
for (auto& fd : fds) {
auto correspondance = std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; });
if (correspondance == qfds.end())
if (std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; }) == qfds.end())
return false;
}
return true;
@@ -504,10 +505,9 @@ bool subset(std::vector<T> fds, std::vector<T> qfds)
bool Select::isSatisfiedBy(const Select& os) const {
/* empty, means all values are selected. */
if (fieldSelection_.empty() and not os.fieldSelection_.empty())
return false;
else
return subset(fieldSelection_, os.fieldSelection_);
return fieldSelection_.empty() ?
os.fieldSelection_.empty() :
subset(fieldSelection_, os.fieldSelection_);
}
bool Where::isSatisfiedBy(const Where& ow) const {
+30 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 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,19 +22,32 @@
namespace dht {
using ValueStateCallback = std::function<void(const std::vector<Sp<Value>>&, bool)>;
enum class ListenSyncStatus { ADDED, SYNCED, UNSYNCED, REMOVED };
using SyncCallback = std::function<void(ListenSyncStatus)>;
using CallbackQueue = std::list<std::function<void()>>;
class ValueCache {
public:
ValueCache(ValueStateCallback&& cb) : callback(std::forward<ValueStateCallback>(cb)) {}
ValueCache(ValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)) {
ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {})
: callback(std::forward<ValueStateCallback>(cb)), syncCallback(std::move(scb))
{
if (syncCallback)
syncCallback(ListenSyncStatus::ADDED);
}
ValueCache(ValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)), syncCallback(std::move(o.syncCallback)) {
o.callback = {};
o.syncCallback = {};
}
~ValueCache() {
auto q = clear();
for (auto& cb: q)
cb();
if (syncCallback) {
if (status == ListenSyncStatus::SYNCED)
syncCallback(ListenSyncStatus::UNSYNCED);
syncCallback(ListenSyncStatus::REMOVED);
}
}
CallbackQueue clear() {
@@ -66,7 +79,7 @@ public:
CallbackQueue expireValues(const time_point& now, time_point& next) {
std::vector<Sp<Value>> expired_values;
for (auto it = values.begin(); it != values.end();) {
if (it->second.expiration < now) {
if (it->second.expiration <= now) {
expired_values.emplace_back(std::move(it->second.data));
it = values.erase(it);
} else {
@@ -74,7 +87,7 @@ public:
++it;
}
}
while (values.size() >= MAX_VALUES) {
while (values.size() > MAX_VALUES) {
// too many values, remove oldest values
time_point oldest_creation = time_point::max();
auto oldest_value = values.end();
@@ -120,6 +133,15 @@ public:
return ret;
}
void onSynced(bool synced) {
auto newStatus = synced ? ListenSyncStatus::SYNCED : ListenSyncStatus::UNSYNCED;
if (status != newStatus) {
status = newStatus;
if (syncCallback)
syncCallback(newStatus);
}
}
private:
// prevent copy
ValueCache(const ValueCache&) = delete;
@@ -127,7 +149,7 @@ private:
ValueCache& operator=(ValueCache&&) = delete;
/* The maximum number of values we store in the cache. */
static constexpr unsigned MAX_VALUES {1024};
static constexpr unsigned MAX_VALUES {4096};
struct CacheValueStorage {
Sp<Value> data {};
@@ -141,6 +163,8 @@ private:
std::map<Value::Id, CacheValueStorage> values;
ValueStateCallback callback;
SyncCallback syncCallback;
ListenSyncStatus status {ListenSyncStatus::UNSYNCED};
CallbackQueue addValues(const std::vector<Sp<Value>>& new_values, const TypeStore& types, const time_point& now) {
std::vector<Sp<Value>> nvals;
+2 -2
View File
@@ -3,7 +3,7 @@ bin_PROGRAMS = opendht_unit_tests
AM_CPPFLAGS = -I../include
nobase_include_HEADERS = infohashtester.h dhtrunnertester.h
opendht_unit_tests_SOURCES = tests_runner.cpp infohashtester.cpp dhtrunnertester.cpp
nobase_include_HEADERS = infohashtester.h valuetester.h cryptotester.h dhtrunnertester.h dhtproxytester.h
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp valuetester.cpp dhtrunnertester.cpp dhtproxytester.cpp
opendht_unit_tests_LDFLAGS = -lopendht -lcppunit -L@top_builddir@/src/.libs @GnuTLS_LIBS@
endif
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: 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/>.
*/
#include "cryptotester.h"
#include "opendht/crypto.h"
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTester);
void
CryptoTester::setUp() {
}
void
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);
// check signature
CPPUNIT_ASSERT(public_key.checkSignature(data, signature));
// encrypt data
std::vector<uint8_t> encrypted = public_key.encrypt(data);
std::vector<uint8_t> decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data == decrypted);
}
void
CryptoTester::testCertificateRevocation()
{
auto ca1 = dht::crypto::generateIdentity("ca1");
auto account1 = dht::crypto::generateIdentity("acc1", ca1, 4096, true);
auto device11 = dht::crypto::generateIdentity("dev11", account1);
auto device12 = dht::crypto::generateIdentity("dev12", account1);
dht::crypto::TrustList list;
list.add(*ca1.second);
auto v = list.verify(*account1.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
list.add(*account1.second);
v = list.verify(*device11.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
v = list.verify(*device12.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
auto ca2 = dht::crypto::generateIdentity("ca2");
auto account2 = dht::crypto::generateIdentity("acc2", ca2, 4096, true);
auto device2 = dht::crypto::generateIdentity("dev2", account2);
v = list.verify(*device2.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), !v);
account1.second->revoke(*account1.first, *device11.second);
dht::crypto::TrustList list2;
list2.add(*account1.second);
v = list2.verify(*device11.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), !v);
v = list2.verify(*device12.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::testCertificateRequest()
{
// Generate CA
auto ca = dht::crypto::generateIdentity("Test CA");
// Generate signed request
auto deviceKey = dht::crypto::PrivateKey::generate();
auto request = dht::crypto::CertificateRequest();
request.setName("Test Device");
request.sign(deviceKey);
// Export/import request
auto importedRequest = dht::crypto::CertificateRequest(request.pack());
CPPUNIT_ASSERT(importedRequest.verify());
// Generate/sign certificate from request
auto signedCert = dht::crypto::Certificate::generate(request, ca);
CPPUNIT_ASSERT_EQUAL(ca.second->getName(), signedCert.getIssuerName());
CPPUNIT_ASSERT_EQUAL(request.getName(), signedCert.getName());
// Check generated certificate
dht::crypto::TrustList list;
list.add(*ca.second);
auto v = list.verify(signedCert);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::tearDown() {
}
} // namespace test
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: 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/>.
*/
#pragma once
// cppunit
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
namespace test {
class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CryptoTester);
CPPUNIT_TEST(testSignatureEncryption);
CPPUNIT_TEST(testCertificateRevocation);
CPPUNIT_TEST(testCertificateRequest);
CPPUNIT_TEST_SUITE_END();
public:
/**
* Method automatically called before each test by CppUnit
*/
void setUp();
/**
* Method automatically called after each test CppUnit
*/
void tearDown();
/**
* Test data signature, encryption and decryption
*/
void testSignatureEncryption();
/**
* Test certificate generation, validation and revocation
*/
void testCertificateRevocation();
/**
* Test certificate requests
*/
void testCertificateRequest();
};
} // namespace test
+199
View File
@@ -0,0 +1,199 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@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/>.
*/
#include "dhtproxytester.h"
// std
#include <iostream>
#include <string>
#include <chrono>
#include <condition_variable>
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(DhtProxyTester);
void
DhtProxyTester::setUp() {
logger = dht::log::getStdLogger();
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
nodeProxy = std::make_shared<dht::DhtRunner>();
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
nodeProxy->bootstrap(nodePeer.getBound());
serverProxy = std::unique_ptr<dht::DhtProxyServer>(new dht::DhtProxyServer(
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
nodeClient = std::make_shared<dht::DhtRunner>();
nodeClient->run(0, /*identity*/{}, /*threaded*/true);
nodeClient->bootstrap(nodePeer.getBound());
nodeClient->setProxyServer("127.0.0.1:8080");
nodeClient->enableProxy(true); // creates DhtProxyClient
}
void
DhtProxyTester::tearDown() {
logger->d("[tester:proxy] stopping peer node");
nodePeer.join();
nodeClient->join();
logger->d("[tester:proxy] stopping proxy server");
serverProxy->stop();
serverProxy = nullptr;
logger->d("[tester:proxy] stopping proxy node");
nodeProxy->join();
}
void
DhtProxyTester::testGetPut() {
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
auto key = dht::InfoHash::get("GLaDOs");
dht::Value val {"Hey! It's been a long time. How have you been?"};
auto val_data = val.data;
{
std::unique_lock<std::mutex> lk(cv_m);
nodePeer.put(key, std::move(val), [&](bool) {
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
}
auto vals = nodeClient->get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtProxyTester::testListen() {
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
auto key = dht::InfoHash::get("GLaDOs");
bool done = false;
// If a peer send a value, the listen operation from the client
// should retrieve this value
dht::Value firstVal {"Hey! It's been a long time. How have you been?"};
auto firstVal_data = firstVal.data;
nodePeer.put(key, std::move(firstVal), [&](bool ok) {
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
std::vector<dht::Blob> values;
auto token = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
for (const auto& value : v)
values.emplace_back(value->data);
done = true;
cv.notify_all();
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
// Here values should contains 1 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 1);
CPPUNIT_ASSERT(values.front() == firstVal_data);
// And the listen should retrieve futures values
// All values
dht::Value secondVal {"You're a monster"};
auto secondVal_data = secondVal.data;
nodePeer.put(key, std::move(secondVal));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
nodeClient->cancelListen(key, std::move(token));
// Here values should contains 2 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 2);
CPPUNIT_ASSERT(values.back() == secondVal_data);
}
void
DhtProxyTester::testResubscribeGetValues() {
nodeClient->setPushNotificationToken("atlas");
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
auto key = dht::InfoHash::get("GLaDOs");
// If a peer send a value, the listen operation from the client
// should retrieve this value
dht::Value firstVal {"Hey! It's been a long time. How have you been?"};
auto firstVal_data = firstVal.data;
nodePeer.put(key, std::move(firstVal), [&](bool) {
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
// Send a first subscribe, the value is sent via a push notification
// So ignore values here.
nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
return true;
});
cv.wait_for(lk, std::chrono::seconds(1));
// Reboot node (to avoid cache)
nodeClient->join();
nodeClient->run(0, {}, true);
nodeClient->bootstrap(nodePeer.getBound());
nodeClient->setProxyServer("127.0.0.1:8080");
nodeClient->enableProxy(true);
nodeClient->setPushNotificationToken("atlas");
// For the second subscribe, the proxy will return the value in the body
auto values = std::vector<dht::Blob>();
auto ftoken = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
for (const auto& value : v)
values.emplace_back(value->data);
done = true;
cv.notify_all();
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
auto token = ftoken.get();
CPPUNIT_ASSERT(token);
nodeClient->cancelListen(key, token);
// Here values should still contains 1 values
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
CPPUNIT_ASSERT(firstVal_data == values.front());
}
} // namespace test
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 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/>.
*/
#pragma once
// cppunit
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <opendht/dhtrunner.h>
#include <opendht/dht_proxy_server.h>
#include <opendht/log.h>
namespace test {
class DhtProxyTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DhtProxyTester);
CPPUNIT_TEST(testGetPut);
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testResubscribeGetValues);
CPPUNIT_TEST_SUITE_END();
public:
/**
* Method automatically called before each test by CppUnit
* Init nodes
*/
void setUp();
/**
* Method automatically called after each test CppUnit
*/
void tearDown();
/**
* Test get and put methods
*/
void testGetPut();
/**
* Test listen
*/
void testListen();
/**
* When a proxy redo a subscribe on the proxy
* it should retrieve existant values
*/
void testResubscribeGetValues();
private:
dht::DhtRunner nodePeer;
std::shared_ptr<dht::DhtRunner> nodeClient;
std::shared_ptr<dht::DhtRunner> nodeProxy;
std::unique_ptr<dht::DhtProxyServer> serverProxy;
dht::DhtRunner::Config config {};
std::shared_ptr<dht::Logger> logger {};
};
} // namespace test
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff. Show more