Compare commits

...
314 Commits
Author SHA1 Message Date
Adrien Béraud a222e30428 update to version 1.3.0 2017-01-17 16:44:02 -05:00
Adrien Béraud bd822fce19 dht: don't stop node insertion on expired search 2017-01-17 16:43:32 -05:00
Adrien Béraud cabe9dbeb5 dht: declare StorageBucket as class 2017-01-16 17:53:21 -05:00
Adrien Béraud 99b7a07350 sockaddr: make ipCmp comparator const 2017-01-16 17:51:59 -05:00
Adrien Béraud 756e0bd3d8 dht: cleanup paginate
Reduce indentation level by 4,
add code documentation,
remain under 120 chars wide.
2017-01-15 19:02:15 -05:00
Adrien Béraud 9b0ce12b5f Update README.md 2017-01-15 02:18:37 -05:00
Adrien Béraud e29c2df002 Merge pull request #166 from sim590/license-notice
update license notice (2017)
2017-01-15 02:15:10 -05:00
Simon Désaulniers b03a8b5b50 update license notice (2017) 2017-01-13 17:27:29 -05:00
Adrien Béraud 32f5175d68 dht: expire storage just on time 2017-01-13 16:06:46 -05:00
Adrien Béraud 7d3a54db57 dht: storage rate limiting 2017-01-13 16:06:46 -05:00
Adrien Béraud 3fb7c2acfe Merge pull request #165 from atraczyk/master
msvc: change contrib repo sources
2017-01-11 14:48:56 -05:00
atraczyk bce5d35b51 msvc: change contrib repo sources 2017-01-11 14:37:22 -05:00
Adrien Béraud b6dca5ccd6 dht: use new NodeStats structure to provide stats 2017-01-10 23:34:56 -05:00
Adrien Béraud 23b2712400 dht: use SHA265 instead of SHA512 for the op token
The op token is renewed regularly (around every 30 minutes),
so SHA256 provides enough security for this non-sensitive token.
SHA256 takes 32 bytes instead of 64 bytes for SHA512,
and the token is included in every listen requests,
renewed every 30 seconds, and every answer to get.
In the context of limited bandwith usage, using SHA256 seems more appropriate.
This change is backward and forward compatible.
2017-01-10 23:34:56 -05:00
Adrien Béraud 63bec73885 default types: make TrustRequest a map, add confirm field 2017-01-10 14:24:42 -05:00
Simon Désaulniers af5e0c8982 node: remove expired flag when a node reaches us 2017-01-09 14:40:42 -05:00
Adrien Béraud 5a7c8753e1 python/tools: use asyncio in pingpong test 2017-01-09 14:40:06 -05:00
Adrien Béraud 19fdec96ca dht: remove getStatus with get 2017-01-09 14:38:51 -05:00
Adrien Béraud 2208a06232 dht: clear acked with announce
Clear the search node acked when clearing
the corresponding announce, after checking
the announce status for all announces.
2017-01-09 00:06:54 -05:00
Adrien Béraud 2cfcaf3909 Merge pull request #164 from sim590/connectivity-changes
routing_table: complete connecting state resolution
2017-01-04 14:04:37 -05:00
Simon Désaulniers 620868b5d6 routing_table: complete connecting state resolution
After a connectivity change, the DHT would enter the "connecting" state in order
to try to resolve good nodes. However, the previous algorithm would
probabilistically increase time for completion each time a node would fail to
resolve. We now avoid this by prioritizing non-expired nodes in the process.
Also, a subtle error would sensibly stop the process for 30 minutes due to using
the Node::NODE_EXPIRE_TIME constant instead of Node::MAX_RESPONSE_TIME.
2017-01-03 17:48:40 -05:00
Adrien Béraud e7295bac7b crypto: prevent signing certificates with a non-CA certificate 2017-01-02 16:16:28 -05:00
Adrien Béraud 38aa86de2a crypto/crl: add getIssuerName, getIssuerUID 2016-12-29 11:19:27 -05:00
Adrien Béraud fdf476a3f3 cmake: generate opendhtConfigVersion.cmake 2016-12-29 11:18:45 -05:00
Adrien Béraud 22f27a6cc0 cmake: generate opendhtConfig.cmake 2016-12-28 18:19:16 -05:00
Adrien Béraud c72ea8ce77 tools/scanner: don't use a certificate 2016-12-09 02:41:40 -05:00
Adrien Béraud ea168353b9 tools/scanner: use urllib3 streaming 2016-12-09 02:41:12 -05:00
Adrien Béraud 79b9c4838e Merge pull request #161 from savoirfairelinux/yomgui1-patch-1
remove InfoHash::toCString()
2016-12-06 18:35:56 -05:00
Guillaume Roguez d6e86ebcc9 remove InfoHash::toCString()
Implementation of InfoHash::toCString() is broken
2016-12-06 18:28:14 -05:00
Adrien Béraud 197aaa47f0 crypto: prevent duplicate CRLs, reimport after signing 2016-12-06 16:59:54 -05:00
Adrien Béraud ad234004aa crypto: store CRLs in a set 2016-12-05 15:43:00 -05:00
Adrien Béraud a88e6a4c5f crypto: make CRL default expiration same as certificate 2016-12-02 12:59:03 -05:00
Adrien Béraud c776dad96f crypto: add Certificate::getExpiration() 2016-12-02 12:58:10 -05:00
Adrien Béraud 31fedd529b crypto: add CRL msgpack serialization 2016-12-01 18:42:26 -05:00
Adrien Béraud e9adff9dc5 crypto: add CRL move operator, export as DER 2016-11-30 17:30:09 -05:00
Adrien Béraud bfd58a204b crypto: add CRL import/export methods 2016-11-30 16:31:29 -05:00
Adrien Béraud 867bcf1514 crypto: add EC key generation 2016-11-29 18:04:25 -05:00
Adrien Béraud fb882ee440 crypto: add revocation list 2016-11-29 18:03:49 -05:00
Adrien Béraud 215d3d2847 http server: add cmd arguments 2016-11-29 13:31:40 -05:00
Adrien Béraud 43a345ba0c python: add HTTP server to access the DHT 2016-11-29 12:08:33 -05:00
Adrien Béraud f73f5e2798 log: cosmetics 2016-11-29 01:27:42 -05:00
Istvan 3724670fcc Log.cpp added to src/MakeFile.am 2016-11-29 00:50:47 -05:00
Istvan e7db64bd74 Log functions are moved to log.cpp
Log functions are moved to the log.cpp
in order to avoid multiple definitions
of the logger functions.
2016-11-29 00:50:47 -05:00
Adrien Béraud 9c29b8a29e Merge pull request #160 from sim590/fix-include-dep
buildtools: add def.h to include files
2016-11-28 01:49:30 -05:00
Adrien Béraud c22f0e4d43 Update Makefile.am 2016-11-28 01:48:26 -05:00
Adrien Béraud 4e2b11c24c Update CMakeLists.txt 2016-11-28 01:47:33 -05:00
Simon Désaulniers 8c34e927ea buildtools: add def.h to include files 2016-11-27 23:28:23 -05:00
Adrien Béraud 8a5de47aa0 hide symbols by default (#140) 2016-11-23 18:27:24 -05:00
Adrien Béraud 7f84c1e397 utils: remove useless definitions 2016-11-23 15:12:37 -05:00
Adrien Béraud 65c915fd9d value: print hex value data contiguously 2016-11-23 11:01:14 -05:00
Adrien Béraud 0fd4f73ab1 network monitor: access proper dictionary key 2016-11-23 11:00:11 -05:00
Adrien Béraud 01117567b1 cmake: adapt pkg-config paths to GNUInstallDirs 2016-11-22 10:43:01 -05:00
Adrien Béraud d68cc5cf40 Merge pull request #156 from sim590/cython-robust-check
autoconf: robustly check for cython3
2016-11-21 15:10:40 -05:00
Simon Désaulniers 6db16be2fa autoconf: robustly check for cython3 2016-11-14 21:07:36 -05:00
Adrien Béraud 5166b1add9 tools: add network monitor
The network monitor allows to regularly
check the status of an OpenDHT network,
by performing listen and put operations at
random places on the DHT.

This first version exit with status code 1
if the test fails.
2016-11-10 01:03:29 -05:00
Adrien Béraud 9fadcc907c python: add default port for bootstrap 2016-11-10 00:58:35 -05:00
Adrien Béraud 42171efc3f dht: send values to all sockets for a node
We used to send values once to a given node,
however the receiving node may have canceled
or dropped the request since then,
so we now send the values for every socket and
the optimization will happen on the sending side.
2016-11-09 21:53:43 -05:00
Adrien Béraud 206f12648f Merge pull request #155 from aviau/patch-1
Multi-Arch support
2016-11-09 13:10:08 -05:00
Alexandre Viau ecd0573c4d Multi-Arch support 2016-11-09 11:30:17 -05:00
Simon Désaulniers 2d9f6241a9 net: don't close socket on listen renew 2016-11-08 16:07:15 -05:00
Adrien Béraud 77ee50f5a6 Merge pull request #154 from savoirfairelinux/c_str
infohash: add helper to C string format conversion
2016-11-08 15:48:05 -05:00
Guillaume Roguez 297c37e609 infohash: add helper to C string format conversion
This const void* convertion method helps a lot with programs
that need to print the hash with a printf() like function.
2016-11-08 15:26:13 -05:00
Simon Désaulniers 9bb1ab43eb net.h: moved to include/opendht/ 2016-11-08 14:52:09 -05:00
Adrien Béraud cd36b13c30 dht: prevent infinite loop in expireStorage() 2016-11-07 16:56:08 -05:00
Adrien Béraud 5d63084627 Merge pull request #152 from sim590/listen-consistency
Listen consistency
2016-11-07 10:33:05 -05:00
Simon Désaulniers ab7d1d6582 dht,net: introduce socket, support multiple listen
Since the initial implementation of listen operation, multiple listen requests
from a single node on a same hash was not possible without singular
inconsistencies. The flaw was coming from the fact that nodes receiving listen
request could not differentiate between listen refresh request and a new
independent listen request.

This patch introduces the new net::Socket structure which in time will enable
remote nodes to send update for a storage while differentiating between
concurrent listen requests. A socket has a unique identifier which consists of a
transaction id as defined in the OpenDHT protocol.
2016-11-07 06:44:15 -05:00
Simon Désaulniers 77ea6d8c2f net: create net namespace, moving relevant structs 2016-11-05 19:29:00 -04:00
Simon Désaulniers b5cd629160 dht: callback if no storage maintenance 2016-11-04 09:15:10 -04:00
Adrien Béraud 39467c8b71 tools: add python cluster runner commands 2016-11-02 02:32:06 -04:00
Adrien Béraud 87740e3b38 tools: add python node cluster runner 2016-11-01 03:14:26 -04:00
Adrien Béraud 19848a9b72 python: encode log file name 2016-11-01 03:13:56 -04:00
Adrien Béraud 36e9998fe2 scanner: use urllib3 2016-11-01 03:13:56 -04:00
Adrien Béraud b2529c241e log: flush on new line 2016-11-01 03:13:56 -04:00
Adrien Béraud 83c47037d2 dht: remove unimplemented declaration 2016-11-01 03:13:56 -04:00
Adrien Béraud 125b6f9236 dht: make storage maintenance optional, default disabled 2016-10-31 14:43:56 -04:00
Adrien Béraud e260ba6b78 infohash: remove misused restrict 2016-10-31 12:35:50 -04:00
Simon Désaulniers eafb934e85 bump version to 1.2.1 2016-10-28 18:49:09 -04:00
Adrien Béraud c3d3da20f6 Merge pull request #146 from sim590/permanent-put-enhancement
dht: make reannounce margin bigger, safer
2016-10-28 16:24:07 -04:00
Adrien Béraud 6036ccdbaa dht: try inserting new nodes smarter (#150)
Attempt closest search and nearby searches
until we are too far instead of trying every
search.
2016-10-28 15:46:27 -04:00
Simon Désaulniers 9404a4d069 dht: make reannounce margin bigger, safer
Reannouncing margin going from 5 seconds to 10 seconds.
2016-10-28 15:24:09 -04:00
Adrien Béraud 274621dcec dht: add searches(sa_family) 2016-10-27 18:12:05 -04:00
Adrien Béraud 2ab756906d dht: getSearchLog for a specific search 2016-10-27 16:51:21 -04:00
Adrien Béraud 2b3f63443f dht: maintain each storage independently
Schedule every storage maintenance independently,
to improve performance when there are a lot of storages.
2016-10-27 14:21:52 -04:00
Adrien Béraud c71f960948 python: add ping-pong simple test 2016-10-26 18:07:06 -04:00
Adrien Béraud 9d3514e087 dhtrunner: don't run ops if disconnected and bootstraping 2016-10-26 17:50:30 -04:00
Adrien Béraud 6703e039b1 network_engine: deserialize proper number of fields 2016-10-26 17:50:30 -04:00
Adrien Béraud 29b81750ad Merge pull request #148 from atraczyk/master
bump visual studio support
2016-10-26 12:48:51 -04:00
atraczyk d6fff53f6b bump visual studio support 2016-10-26 10:28:05 -04:00
Simon Désaulniers 7ee6281426 log: display time before each line in log 2016-10-25 16:40:48 -04:00
Adrien Béraud 28a5740c37 argon2: bump source 2016-10-25 16:40:48 -04:00
Adrien Béraud 09a3332cf0 Merge pull request #147 from savoirfairelinux/feature/log_filter
log: add filters
2016-10-24 16:55:23 -04:00
Adrien Béraud f584c4849b dht: unify creation date normalisation 2016-10-24 02:09:38 -04:00
Adrien Béraud e3663c995a log: add storage filter 2016-10-24 02:09:38 -04:00
Adrien Béraud 1d62b3ca64 log: add InfoHash filter
* filter log entries with new method setLogFilter
* filter by node id, search or infohash
* add optional parameter to 'log' in dhtnode
2016-10-24 02:09:38 -04:00
Adrien Béraud 3af04a4259 securedht: use default max expiration for putSigned 2016-10-23 17:23:39 -04:00
Adrien Béraud 78d98822a5 securedht: use default max expiration for putEncrypted 2016-10-23 16:47:37 -04:00
Adrien Béraud 8c04ddc66b dht use proper value type to compute expiration 2016-10-23 14:58:15 -04:00
Adrien Béraud 5277b8d23e dht: storage refresh returns bool 2016-10-23 03:23:17 -04:00
Simon Désaulniers 86fea49178 doc: add pdf compiled of tex file 2016-10-21 19:00:08 -04:00
Simon Désaulniers 5b1242f786 bump version
* several clang related bug fixes;
* connectivity changes related enhancements;
* new "refresh" protocol primitive (not exposed to API);
* "permanent put" operation fixes/enhancements;
* fixed general efficiency issues;
2016-10-21 18:56:45 -04:00
Simon Désaulniers a8cfdbe762 doc: add connectivity loss search analysis tex file 2016-10-21 18:07:11 -04:00
Adrien Béraud 70b1ebae0b dht: fix scheduler job edition on clang 2016-10-21 17:44:39 -04:00
Adrien Béraud 9dc6004329 network engine: cancel request when clearing listen status 2016-10-19 13:58:18 -04:00
Adrien Béraud d4bd17a2dc dhtrunner: use a second condition variable for bootstrap 2016-10-19 13:34:33 -04:00
Simon Désaulniers 6c73e5fa5c dht: less cases clear values, storage maintenance 2016-10-19 11:53:47 -04:00
Simon Désaulniers 24edfb8eaf dht: uniformly sync SearchNodes reannouncing
Historically, the next announce timing was based on the last acknowledgement
received from a SearchNode. This behavior was invalid since the 'refresh'
operation. In fact, for a given value that was "refreshed", its creation time
would differ from the announcer's info. Therefor, all search node's
reannouncing timings would differ, hence causing inconsistency on the network.
2016-10-19 11:53:47 -04:00
Adrien Béraud 4ef5a2216e dht: revert to previous onNewNode behavior 2016-10-19 01:27:19 -04:00
Adrien Béraud 0d646eb244 network engine: log cleanup 2016-10-19 01:01:51 -04:00
Adrien Béraud 757fea37f3 Merge pull request #142 from sim590/fix-permanent-put-time-info
dht: appropriate time info in permanent put ops
2016-10-18 14:26:21 -04:00
Simon Désaulniers 09e41cc9f2 dht: appropriate time info in permanent put ops 2016-10-18 14:20:43 -04:00
Adrien Béraud 71ad92e286 dht: log cleanup 2016-10-17 17:55:22 -04:00
Adrien Béraud d4f3d3aa98 dht: add missing iterator 2016-10-17 17:14:30 -04:00
Simon Désaulniers c0612a1b2c dht: use "refresh" operation for permanent put 2016-10-17 11:56:54 -04:00
Simon Désaulniers 6743cbbf50 dht: introduce "refresh" operation
This operation requests a node to refresh a value's time_point information of
its lifetime begining. This is intended to fix the *permanent put* operation
which has been having syncing issues since the introduction of an enhanced and
lighter put operation.
2016-10-17 11:56:54 -04:00
Adrien Béraud da1bdf9d4c dht: retry nodes more aggressively in case of failure 2016-10-16 22:36:52 -04:00
Adrien Béraud 96da4cd85d build: make logs optional at build time 2016-10-16 22:36:42 -04:00
Adrien Béraud f233340cb2 node: clear reply_time on reset 2016-10-16 22:36:36 -04:00
Adrien Béraud cfb817d37f dht: add buckets() utility 2016-10-16 22:36:30 -04:00
Adrien Béraud 9440c03048 dht: log cleanup 2016-10-16 22:36:24 -04:00
Adrien Béraud aa611bde50 network engine: cleanup 2016-10-15 20:07:37 -04:00
Adrien Béraud 7af856508e dht: make connectivityChanged family dependent 2016-10-15 19:13:15 -04:00
Adrien Béraud aaed64039a dht: fix compilation on clang 2016-10-12 15:02:02 -04:00
Adrien Béraud 7c5e8c3234 sockaddr: add missing include for Win32 2016-10-12 14:38:39 -04:00
Adrien Béraud a56bf3f115 dhtrunner: handle null callback in pingNode 2016-10-12 13:25:00 -04:00
Adrien Béraud 2d2fa9cfa9 OpenDHT 1.1.0
* automatic connection loss recovery
* dhtrunner: asynchronous DNS lookup for bootstrap
* handle values up to 64k
* better support for large values on macOS
* dht: add callback to pingNode
* fix compilation with recent clang versions
2016-10-11 17:36:12 -04:00
Adrien Béraud 9f11930f3d fix compilation on latest clang 2016-10-11 16:34:40 -04:00
Adrien Béraud 013b1dfe2e Merge pull request #138 from sim590/connectivity-changes-detect
search: detect connectivity changes
2016-10-11 16:01:59 -04:00
Simon Désaulniers 733f699ff2 search: detect connectivity changes
The number of bad nodes is limited in order to help determine presence of
connectivity changes. See https://github.com/savoirfairelinux/opendht/issues/137
for details.

According to the tables, 25 is a good average value for big networks. If the
network is small, normal search expiration process will handle the situation.
2016-10-11 15:54:37 -04:00
Adrien Béraud a366d502a2 fix compilation on latest clang 2016-10-11 15:50:49 -04:00
Adrien Béraud eed8ffc792 Merge pull request #139 from savoirfairelinux/recover-from-network-changes
dhtrunner: recover from network changes
2016-10-11 11:57:31 -04:00
Adrien Béraud 998547e1a1 Merge pull request #136 from savoirfairelinux/feature/value_fragment
network: transmit large values in multiple packets
2016-10-11 11:57:18 -04:00
Simon Désaulniers 8567b7ad84 network_engine: expire requests when clearing NE
This is to prevent any thread relying on network_engine's callback to block
forever just like the Dht::sendPing's callback.
2016-10-10 01:51:26 -04:00
Adrien Béraud 64118404fe dhtrunner: recover from network changes
Using a list of bootstrap nodes, we recover from network loss by pinging those
nodes continuously until connected.
Written with Simon Désaulniers.
2016-10-10 01:51:26 -04:00
Simon Désaulniers bb74dc846c dht/dhtrunner: enable callback for pingNode 2016-10-10 00:23:53 -04:00
Adrien Béraud 659d893dee network: transmit large values in multiple packets 2016-10-09 16:22:33 -04:00
Simon Désaulniers e3f371c2d8 bump version 2016-10-06 08:27:00 -04:00
Adrien Béraud f53c7a6785 dht: keep track of storage usage in maintainStorage 2016-10-04 03:09:00 -04:00
Adrien Béraud 261c193b50 Merge pull request #133 from sim590/sync-enhancements
dht: bug fixes, timing computation enhancements
2016-09-24 19:07:05 -04:00
Simon Désaulniers dc0b650aa3 dht: make sure we are synced before sending put 2016-09-23 19:27:59 -04:00
Simon Désaulniers 87cf6faedd dht/node: don't allow more than 3 auth errors 2016-09-23 19:27:59 -04:00
Simon Désaulniers ca6aa6706d dht/value: make 'find_node' queries satisfied by any queries
'find_node' requests don't ask for values. Then, the idea of a Query makes less
sense, but since we still need those to map status to network engine requests,
we introduce dummy queries which with the field Query::none. Those queries will
then only serve as key to network engine's requests.
2016-09-23 19:27:58 -04:00
Simon Désaulniers 16e55416a6 network_engine: fix bug token not sent for listen 2016-09-23 19:27:58 -04:00
Simon Désaulniers 3e24058175 dht: fix SearchNode's getListenTime computation
When no listen request have been sent yet, getListenTime should tell it's okay
to send pending listen request.
2016-09-23 19:27:55 -04:00
Simon Désaulniers d1c2b20b28 dht: canGet must allow sending when no token 2016-09-23 13:48:04 -04:00
Adrien Béraud ccd0cbd8f2 add per IP rate limiting (#131) 2016-09-21 15:44:20 -04:00
Adrien Béraud e5213674e3 value: fix compilation on older clang 2016-09-20 17:02:29 -04:00
Adrien Béraud b9cc848810 cmake: remove OPENDHT_DEBUG flag
Replace with -DCMAKE_BUILD_TYPE=Debug
2016-09-20 00:04:39 -04:00
Adrien Béraud 65bdfaf22b autotools: fix 'make dist' 2016-09-18 13:55:14 -04:00
Adrien Béraud de31d836b4 Merge pull request #132 from savoirfairelinux/feature/map_storage
dht: use a map for storage
2016-09-18 13:02:03 -04:00
Adrien Béraud 25b339956e tools: gnutls cleanup 2016-09-16 01:43:58 -04:00
Adrien Béraud 23bb6e7a45 dht: use a map for storage 2016-09-16 01:29:33 -04:00
Adrien Béraud b44f7ec653 Merge pull request #130 from savoirfairelinux/feature/sockaddr
introduce SockAddr to store IP addresses
2016-09-15 23:46:57 -04:00
Adrien Béraud 6d38c18572 introduce SockAddr to store IP addresses 2016-09-15 01:38:26 -04:00
Simon Désaulniers 8eaf78bfe2 bump version 2016-09-14 19:06:51 -04:00
Simon Désaulniers dc836b38a6 build: use -pedantic-errors flag in autotools 2016-09-14 19:06:20 -04:00
Adrien Béraud b01f8d079b Merge pull request #128 from sim590/concurrent-queries
[dht] concurrent queries
2016-09-14 18:12:47 -04:00
Simon Désaulniers 6f7ac21a85 dht: refactor code, terminating a Search (isDone)
More code encapsulated in objects method is better for keeping consistent
behavior.
2016-09-14 18:06:25 -04:00
Simon Désaulniers 7c5db84f33 dht: take multiple queries into account
The code preceding this would just not take multiple concurrent queries for a
same search into account. This is a bug fix for a bad behavior since the
queries.
2016-09-14 18:06:23 -04:00
Simon Désaulniers 4fecb2066b dht: SearchNode::canGet criteria using 'update'
The criteria has been rewritten (again) exploiting the idea behind the parameter
'update' to take into account the case where we have new distinct requests to
send, then bypass some checks.
2016-09-14 18:06:12 -04:00
Adrien Béraud eabdddcfb3 dht: fix warnings 2016-09-08 18:02:17 -04:00
Adrien Béraud ceab27d723 value: optimize chainAll for empty filters 2016-09-08 17:22:34 -04:00
Adrien Béraud a9cc669a95 dht: clarify code 2016-09-08 15:52:18 -04:00
Simon Désaulniers 927c835b8f dht: call all announce callback appropriately 2016-09-08 12:24:35 -04:00
Simon Désaulniers 5415eaaf60 dht: consider probe query in announce time 2016-09-08 12:24:35 -04:00
Simon Désaulniers ec587f9b58 dht: make sure search can be flagged "done" 2016-09-08 12:24:35 -04:00
Simon Désaulniers babfed73f3 dht: use SearchNode::acked for next announce time 2016-09-08 12:24:35 -04:00
Simon Désaulniers 2c0ce576e3 dht: enable data persistence 2016-09-08 12:24:35 -04:00
Simon Désaulniers 8f2cc937c5 dht: introduce light put
The 'put' operation will now first check if nodes already store the value we
have to announce. If so, we don't announce it to that node.
2016-09-08 12:24:35 -04:00
Adrien Béraud c9f6567128 Merge pull request #127 from sim590/insert-node-export-fix
dht: Dht::insertNode has to really insert
2016-09-07 16:43:28 -04:00
Simon Désaulniers d60672e8ba dht: remove unnecessary return value 2016-09-07 16:15:06 -04:00
Simon Désaulniers fd4cce4883 NetworkEngine: insertNode tells routing table 2016-09-07 15:54:16 -04:00
Adrien Béraud df15d3d48e Merge pull request #126 from savoirfairelinux/wip/crypto
crypto: drop support for GnuTLS < 3.3
2016-09-07 00:10:36 -04:00
Adrien Béraud 76fd216386 crypto: drop support for GnuTLS < 3.3 2016-09-06 17:18:16 -04:00
Adrien Béraud 48735aad94 build/cmake: use proper indentation 2016-09-06 17:16:33 -04:00
Adrien Béraud 91a1471de5 build/autotools: fix build flags 2016-09-06 17:16:33 -04:00
Adrien Béraud 047ba76ff1 Merge pull request #125 from savoirfairelinux/wip/crypto
crypto: add length parameters
2016-09-06 13:50:38 -04:00
Adrien Béraud e57eb63c87 securedht: don't complain about certificate announcement 2016-09-06 12:06:30 -04:00
Adrien Béraud 8461f4018d crypto: avoid using std::to_string 2016-09-06 12:06:30 -04:00
Adrien Béraud c33c2e7e95 crypto: add key, hash length parameters 2016-09-06 12:06:30 -04:00
Adrien Béraud e5a9a2af4c Merge pull request #124 from aberaud/master
dht: fail pending operations before clearing them
2016-09-06 10:49:33 -04:00
Adrien Béraud 7919ca8de1 dht: fail pending operations before clearing them 2016-09-02 14:30:08 -04:00
Adrien Béraud 00ef660952 dht: hide more internal structures 2016-09-02 14:30:08 -04:00
Adrien Béraud 862a03713b opendht: version 1.0
* add Prefix Hash Tree (PHT) for data indexation (Nicolas Reynaud, Simon Désaulniers)
* add Queries (Simon Désaulniers)
* add long-term data persistance (Simon Désaulniers)
* add data pagination (Simon Désaulniers)
* reduced bandwith usage
2016-09-01 18:02:23 -04:00
Adrien Béraud 89d0d2f109 pht: fix compilation with pedantic 2016-09-01 18:02:23 -04:00
Adrien Béraud 3283e34dcf pht: rebase over queries 2016-09-01 18:02:23 -04:00
kaldoran 34c6b264df Add filter of duplicate value 2016-09-01 18:02:23 -04:00
kaldoran 2d8fe502f2 Fix print of the lookup output 2016-09-01 18:02:23 -04:00
kaldoran 73df308250 Adding ZCurve algorithm 2016-09-01 18:02:23 -04:00
kaldoran cdca40cb59 Rework prefix [add flags] and prepare prefix 2016-09-01 18:02:23 -04:00
kaldoran 2a3c301314 dht: Fix get and put at the same time on a same node
When the put is performed just after a get, then the get will not include the value which was in the put.
2016-09-01 18:02:23 -04:00
kaldoran 6f4923da2e dht: fix some typo 2016-09-01 18:02:23 -04:00
kaldoran ae26a2b39a Update of algorithm, by using new feature of api 2016-09-01 18:02:23 -04:00
kaldoran 48c40c8a27 pht: correction on the algorithm of complet node splitting 2016-09-01 18:02:23 -04:00
kaldoran a4a4eee495 pht: introduction of complet node splitting 2016-09-01 18:02:23 -04:00
kaldoran d185428d1d [Python] Draw benchmark graph in a better way #104 2016-09-01 18:02:23 -04:00
kaldoran 6855aaa6f4 Correction of error on SwapBit 2016-09-01 18:02:23 -04:00
kaldoran 2aee4f418f Correction of the size of the prefix, now size does not include the size of the padding 2016-09-01 18:02:23 -04:00
kaldoran 95aef01a59 Pht : Fix out of range in isActiveBit function 2016-09-01 18:02:23 -04:00
kaldoran d2ccde4859 pht: bit padding when the key is too short 2016-09-01 18:02:23 -04:00
Simon Désaulniers 7ab64ea0e6 pht: validKey must check for key field value len 2016-09-01 18:02:23 -04:00
Simon Désaulniers fe1b8b88e1 pht: provide simpler lookup callback
From a user point of view, the structure Prefix doesn't make sense really. It's
better to provide a simpler callback function signature for the user then.
2016-09-01 18:02:23 -04:00
Simon Désaulniers b6832869b1 pht: moved some defs in cpp file 2016-09-01 18:02:23 -04:00
Simon Désaulniers 6da8d39a0e python: update cython wrapper and python benchmark
API changed when the keys pec was added. This commit updates python code
according to the new API.
2016-09-01 18:02:23 -04:00
Simon Désaulniers f8cf1316ad pht: add key spec, handling maximum prefix length
This commit adds the new KeySpec in the Pht constructor signature so that all
keys used inside a same PHT structure have the same maximal length.
2016-09-01 18:02:23 -04:00
Simon Désaulniers 736606a845 pht: a Key is rather map str:Blob not str:Prefix 2016-09-01 18:02:23 -04:00
Simon Désaulniers cba240e15e pht: fix invalid comparison, inexact match lookup 2016-09-01 18:02:23 -04:00
Adrien Béraud eb90fffb5e update for API changes 2016-09-01 18:02:23 -04:00
kaldoran 041e280bde benchmark: timing pht insert operations 2016-09-01 18:02:23 -04:00
kaldoran 33fae1cb66 pht: add prefix cache 2016-09-01 18:02:23 -04:00
Simon Désaulniers 4e8408e225 python: lock before launching pht insert in test 2016-09-01 18:02:23 -04:00
Simon Désaulniers e85a423f6a Revert "[Bug] Correction of function commonBits" 2016-09-01 18:02:23 -04:00
kaldoran 532cb40665 Correction of error on commonBits 2016-09-01 18:02:23 -04:00
kaldoran dd58b0497e Correction of prefix, sometime some bit remain at they default value 2016-09-01 18:02:23 -04:00
Kaldoran cc070c80ba Fix the autotool Makefile, missing pht include
Fix indentation for pull request #37

Fix include error, and use only needed file in pht

Fix implementation of function in pht
2016-09-01 18:02:23 -04:00
Simon Désaulniers e332dae576 python: insert test show entries for each prefix 2016-09-01 18:02:23 -04:00
Simon Désaulniers 727fd4e98b fix typo in tests 2016-09-01 18:02:23 -04:00
Simon Désaulniers 5a5f7012d8 add pht insert test 2016-09-01 18:02:23 -04:00
Simon Désaulniers 5a239cddf7 pht: fix insert always to root bug
This makes the pht node recover all indexed data on a DHT node (maximum
MAX_NODE_ENTRY_COUNT per node) so that the pht node can be aware if it has to
split its data in the leaf.
2016-09-01 18:02:23 -04:00
Simon Désaulniers c4928553ba python: fix successive deref on cython object 2016-09-01 18:02:23 -04:00
Simon Désaulniers 48b0cff08e pht: fix multiple DoneCallBack calls 2016-09-01 18:02:23 -04:00
Simon Désaulniers c8fcffbe6b fix possible out of range error in Prefix ctor 2016-09-01 18:02:23 -04:00
Simon Désaulniers 63c4eeb9c9 cover empty leaf case in inexact match lookup
In case this is inexact match lookup and we end up on an empty leaf (diffrent
than the root), the search goes on in the leaf's sibling subtree.
2016-09-01 18:02:23 -04:00
Simon Désaulniers d45f777099 pht tools 2016-09-01 18:02:23 -04:00
Simon Désaulniers 9c4035dd8f add inexact match lookup
This is meant to enable random lookup queries.
2016-09-01 18:02:23 -04:00
Simon Désaulniers acc2b71c86 base pht indexation 2016-09-01 18:02:23 -04:00
Nicolas 09d849c93d Update README.md 2016-09-01 17:46:04 -04:00
Nicolas 1be1ad88c6 Update README.md 2016-09-01 17:43:10 -04:00
Nicolas 8ecaf25339 Move logo in the right position 2016-09-01 17:41:33 -04:00
Adrien Béraud 7a6dce4727 securedht: don't complain about certificate announcement (reverted from commit 85a9dbafc6) 2016-09-01 17:12:28 -04:00
Adrien Béraud b357ffb0e6 add logo 2016-09-01 17:10:59 -04:00
Adrien Béraud 517bd5f22b opendht: add logo 2016-09-01 12:49:26 -04:00
Adrien Béraud d1d0a67d35 dht: fix public address sorting 2016-09-01 12:46:39 -04:00
Adrien Béraud 85a9dbafc6 securedht: don't complain about certificate announcement 2016-09-01 12:46:39 -04:00
Nicolas 79390f72fa Merge pull request #121 from sim590/benchmark-msgpack-ipc
[benchmark] new msgpack ipc
2016-08-31 16:25:21 -04:00
Simon Désaulniers b7a37dd771 benchmark: msgpack with callback based IPC 2016-08-31 15:47:05 -04:00
Simon Désaulniers b24d1ccc8b benchmark: removing anormal behavior from normal test 2016-08-31 15:37:30 -04:00
Simon Désaulniers 4f53e10e7e benchmark: enable traffic_plot for "delete" test 2016-08-31 15:37:30 -04:00
Simon Désaulniers a608ad3cf6 benchmark: send new distinct values during test
During totallyNormalTest, an initial set of values would be put on the dht.
Then, random values from this same set would be put over time, but since values
would already be there, no put were really made.
2016-08-31 15:37:29 -04:00
Simon Désaulniers a135f81073 benchmark: create function for displaying plot 2016-08-31 15:37:15 -04:00
Nicolas 2da48557ff Merge pull request #120 from sim590/fix-timing-loops
dht: send find_node before sending 'listen'.
2016-08-30 16:14:22 -04:00
Simon Désaulniers 73686debaf dht: before sending 'listen', send find_node
Since pagination, a bug was making the listen feature unusable running in
infinite loop. This also makes more sense than sending 'get' since the listen
request is paired with a Query defining the values that have to be fetched.
2016-08-30 15:51:50 -04:00
Adrien Béraud 97950621cd crypto: check max data size for sign 2016-08-25 00:42:50 -04:00
Adrien Béraud b3401828e4 dht: set "connecting" state when waiting for a ping 2016-08-25 00:42:50 -04:00
Nicolas 0a7d4a68b3 Merge pull request #119 from sim590/find-node-timings
dht: cover bad cases in SearchNode::canGet
2016-08-22 19:16:19 -04:00
Simon Désaulniers 8d7deffa6a dht: properly find pending satisfying query
In SearchNode::canGet, we don't send a 'get' request to a search node if a
satisfying query for the query we want to send is already pending. This patch
honors this behavior.
2016-08-22 18:45:29 -04:00
Simon Désaulniers 669c08210e dht: erase find node request status when done
This was memory leak and produced inconsistency in SearchNode::canGet timings.
2016-08-22 18:26:53 -04:00
Adrien Béraud 27a3231a55 argon2: bump source 2016-08-18 10:10:03 -04:00
Seva Ivanov 86ce695939 cython: change shared_ptr invocation to libcpp.memory 2016-08-16 10:27:34 -04:00
Adrien Béraud 2759a136df infohash: add istream operator overload 2016-08-16 10:27:31 -04:00
Adrien Béraud 690682408b build with -pedantic-errors, fix pedantic build errors 2016-08-16 10:26:44 -04:00
Nicolas bfdb8a24e9 Merge pull request #113 from sim590/value-pagination-fix
dht: value pagination fix
2016-08-15 19:35:33 -04:00
Simon Désaulniers e9bf042ac5 dht: document SearchNode::canGet 2016-08-15 13:44:52 -04:00
Simon Désaulniers 5aab3078c8 dht: properly handle pagination timings 2016-08-15 12:13:16 -04:00
Simon Désaulniers 1ac5840bb1 dht: let nodes expire properly
The line with `srn->getStatus[query]->setExpired()` in searchNodeGetExpired was
messign with the node expiration process.
2016-08-14 22:08:52 -04:00
Simon Désaulniers 426b3d6834 dht: pagination queries should be in SearchNode
Pagination queries must to be kept in seperate list per node. Otherwise, two
searches could be blocking each others or generating unwanted behavior.
2016-08-11 12:27:04 -04:00
Nicolas 97b573c182 Merge pull request #110 from sim590/value-pagination
dht: Value pagination using queries
2016-08-09 17:27:00 -04:00
Simon Désaulniers 5c41cbb964 dht: value pagination
Instead of literally asking to a node all values for givent `h`, we first ask
for all ids the node has. Then, we concurently and individually ask for each
values that match each id we recovered in our first request.
2016-08-09 15:43:55 -04:00
Simon Désaulniers e192e3beaf better indentation and comments 2016-08-09 15:42:05 -04:00
Adrien Béraud 5dacb50d63 Merge pull request #108 from sim590/search-refill-from-cache
dht: unify bootstrapSearch and refill method using node cache
2016-08-09 14:41:23 -04:00
Adrien Béraud 86d837b5a9 Merge pull request #106 from sim590/get-timings
[dht] rework get timings after queries in master
2016-08-09 14:23:13 -04:00
Adrien Béraud 6454a6dc3f Merge pull request #109 from kaldoran/fix_put-get
dht: Fix, get does not include the put value if its performed just after it.
2016-08-08 18:10:05 -04:00
kaldoran bbd1200ad7 dht: Fix get and put at the same time on a same node
When the put is performed just after a get, then the get will not include the value which was in the put.
2016-08-08 17:50:56 -04:00
Adrien Béraud aa59242843 readme: add IRC link 2016-08-07 00:13:18 -04:00
Simon Désaulniers c04ede4909 dht: unify bootstrapSearch and refill method
Since bootstrapSearch was rewritten to use the node cache, it made it clear that
refill should be rewritten as such. However, then bootstrapSearch becomes
irrelevant.

An enhancement to refill is that it will let insertNode review its whole list
of nodes and then let it insert nodes up to SEARCH_NODES nodes. The previous
method would not garantee this behavior since, most of the times, it would pass
less than SEARCH_NODES nodes to insertNode.
2016-08-06 21:14:17 -04:00
Adrien Béraud a1eaf2e83c Merge pull request #107 from sim590/minor-search-refactor
dht: more accurate name for requested nodes count
2016-08-05 23:03:25 -04:00
Simon Désaulniers a21d4d4adc queries: fix deserialization bug
Only the first two entries of the array would be accessed in a consistent way.
Therefor, only the two first field value index would be returned.
2016-08-05 21:20:58 -04:00
Simon Désaulniers f0a92d999c dht: more accurate name for requested nodes count
The number of currently requested nodes, formerly named currentGetRequests, was
renamed since it was not accurately describing the behavior. The number we are
counting is not the number of 'get' requests, but rather the number of nodes
being requested simultaneously.
2016-08-05 21:19:46 -04:00
Simon Désaulniers 28a3498a69 dht: fixing timing in SearchNode::canGet
When a 'get' request associated with a certain 'query' has been sent, we don't
want to send it again, i.e. we don't care if it's pending or not as soon as it
has been sent.
2016-08-05 21:17:58 -04:00
Simon Désaulniers 7eb5d892f1 search: isDone computes using Request interface
There's no need to compute with time since the network engine gives us the
information we need.
2016-08-05 21:17:11 -04:00
Simon Désaulniers f6cd79952c node_cache: fix bad condition in getCachedNodes 2016-08-05 13:07:14 -04:00
Adrien Béraud 9c1a0ae27f freenode: fix typo 2016-08-05 10:23:08 -04:00
Simon Désaulniers 29c1a955d0 readme: add freenode irc opendht channel 2016-08-04 18:33:56 -04:00
Nicolas b366432a8a Merge pull request #103 from sim590/sendlisten-loop
dht: fix sendListen loop bug
2016-08-04 10:25:22 -04:00
Simon Désaulniers af8bfdc1c1 dht: fix sendListen loop bug
Each time a 'listen' request is sent to the network engine, we track this
request in the upper layer with a map<shared_ptr<Query>, shared_ptr<Request>>.
At some point, this map has to be maintained or totally cleared. However, it was
done wrong, hence the sendListen loop. Clearing a pair <Query, Request> has to
be done when the API user cancels a 'listen' operation.
2016-08-03 18:49:37 -04:00
Simon Désaulniers 88040ad467 dht: display debug info according to query impact 2016-08-03 18:49:10 -04:00
Simon Désaulniers a35e67bcdf Merge pull request #101 from kaldoran/optimize_search
dht: bootstrap from node cache instead of routing table
2016-08-03 15:31:07 -04:00
kaldoran df3317a5b2 dht: bootstrap from cache instead of routing table 2016-08-03 10:04:02 -04:00
kaldoran 33f95c00a9 NodeCache: getNode takes bool not int
Since this was old code which use int as bool I edit that for a bool [and change related code]
2016-08-02 18:57:20 -04:00
Adrien Béraud 7383505dcc value: increase max value size to 16KiB 2016-08-01 10:47:21 -04:00
Adrien Béraud 2c9a29af0e docker: add python, lto, msgpack 2.0 2016-08-01 01:18:37 -04:00
Adrien Béraud 5847273b79 travis: add llvm docker build 2016-07-29 21:37:43 -04:00
Adrien Béraud 98204991ec travis with docker 2016-07-29 21:37:43 -04:00
Adrien Béraud b8e10bfe15 const shared_ptr 2016-07-29 21:37:07 -04:00
Adrien Béraud 132fe66699 dhtnode: cleanup 2016-07-29 15:49:43 -04:00
Adrien Béraud a28fc4dfb1 tools: remove optional arguments 2016-07-29 15:39:50 -04:00
Nicolas 7721aa5643 api: Add value creation timepoint (#97) 2016-07-28 17:03:11 -04:00
Nicolas 68707aff17 dht: prevent outdated store of value 2016-07-28 16:58:04 -04:00
Adrien Béraud 3ecbc9adff Merge pull request #95 from sim590/consistent-so-versionning
autotools: versionning consistent with CMake
2016-07-25 17:09:56 -04:00
Simon Désaulniers b5a7a0ca31 autotools: versionning consistent with CMake 2016-07-25 17:03:57 -04:00
Nicolas 2362db8528 Merge pull request #94 from sim590/storage-unique-ptr
dht: make main store a vector<unique_ptr<Storage>>
2016-07-22 17:02:21 -04:00
Simon Désaulniers 62835bdc54 dht: make main store a vector<unique_ptr<Storage>>
Since the elements inside are going to be moved constantly during the life of
the node, this design is better. Also, it works around a crash when the store is
resized (elements inside moved) at some point (always happenned the 3rd time)
for some reason. This bug was known when compiled with LLVM >7.3.0 (>clang-703.0.31).
2016-07-22 16:57:46 -04:00
Nicolas fe1cf209f1 Merge pull request #93 from sim590/select-consistency
dht: return consistent query from local storage
2016-07-19 16:47:44 -04:00
Simon Désaulniers 2f72563b1f dht: return consistent query from local storage
When querying from local storage with SELECT f, a FieldValueIndex with empty
fields was returned without considering the SELECT statement requiring only a
field "f".
2016-07-19 15:52:21 -04:00
Simon Désaulniers 0d754d6ca8 doc: clarify dhtnode usage 2016-07-19 14:00:34 -04:00
Simon Désaulniers f474f6499b value: missing return, errors on non-gcc
Gcc understands the syntax without return value, but this confuses other
compilers.
2016-07-18 14:18:37 -04:00
Adrien Béraud 97baacf609 Merge pull request #79 from sim590/queries
[DHT] Queries: remote values filtering
2016-07-11 20:23:15 +02:00
Simon Désaulniers 0fa8cfdb71 tools: enable queries in dhtnode 2016-07-10 19:26:13 +02:00
Simon Désaulniers 78c7cae7e9 dhtrunner: add query in dhtrunner API 2016-07-10 19:26:13 +02:00
Simon Désaulniers a4834efd37 dht: use queries in dht 2016-07-10 19:26:13 +02:00
Simon Désaulniers 07e4435a07 value: add Query relevant structures 2016-07-10 19:26:04 +02:00
zorun 9f93771771 doc: Fix install path of man page (#90)
Man pages go in /usr/share/man

  http://www.pathname.com/fhs/pub/fhs-2.3.html#USRSHAREMANMANUALPAGES
2016-07-02 14:32:43 +02:00
Simon Désaulniers a533807fcf doc: add missing CMakeLists.txt 2016-07-02 01:20:46 +02:00
Simon Désaulniers 49129ec1b2 tools: specify optional arg syntax -o[ARG] 2016-06-30 01:33:14 +02:00
Simon Désaulniers 803354552f build-tools: distribute dhtnode.1 manpage 2016-06-30 00:58:04 +02:00
Simon Désaulniers fa6c365679 doc: fix typos in dhtnode manpage 2016-06-29 20:57:30 +02:00
Adrien Béraud 6ac1ae3527 Merge pull request #84 from sim590/dhtnode-user-experience
[dhtnode] user experience
2016-06-28 14:55:27 -04:00
Simon Désaulniers 29834b714e dhtnode: manpage and add all options in help text 2016-06-28 18:51:40 +02:00
Simon Désaulniers bba27adf4d dhtnode: fix getopt optional arg parsing 2016-06-27 21:14:54 +02:00
Simon Désaulniers e3a280d7a9 Merge pull request #82 from aviau/typos
fixed typos
2016-06-27 19:46:17 +02:00
aviau 63f1a736f4 fixed typos 2016-06-27 19:33:52 +02:00
Simon Désaulniers 0f8720c433 Merge pull request #80 from aviau/powerful
readme: fix typo s/powerfull/powerful/
2016-06-27 15:39:55 +02:00
aviau 7a6263b940 typo: powerfull ->powerful 2016-06-27 15:29:35 +02:00
Adrien Béraud b09e3df2e2 add network id to distinguish different networks 2016-06-21 03:06:47 -04:00
Adrien Béraud 041a9e0e7f Clarify GPLv3 "or any later version" licence 2016-06-20 11:47:21 -04:00
106 changed files with 11298 additions and 2716 deletions

No files matched your search

+10
View File
@@ -45,3 +45,13 @@ Makefile.in
# KDevelop
.kdev4/
*.kdev4
# Python
*.pyc
# git backup files
*.orig
# vim swap files
*.swp
*.swo
+5 -31
View File
@@ -1,44 +1,18 @@
sudo: false
sudo: required
services:
- docker
language: cpp
compiler:
- gcc
- clang
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- g++-6
- libgnutls28-dev
- cmake
before_install:
- if [ $TRAVIS_OS_NAME == linux ] && [ $CXX == g++ ]; then export CXX=/usr/bin/g++-6 && export CC=/usr/bin/gcc-6; fi
- if [ $TRAVIS_OS_NAME == linux ]; then git clone https://github.com/msgpack/msgpack-c.git; fi
- if [ $TRAVIS_OS_NAME == linux ]; then cd msgpack-c && git checkout cpp-1.2.0 && mkdir build && mkdir -p $HOME/usr && cd build; fi
- if [ $TRAVIS_OS_NAME == linux ]; then cmake -DCMAKE_INSTALL_PREFIX=$HOME/usr -DMSGPACK_CXX11=ON -DMSGPACK_BUILD_EXAMPLES=OFF .. && make -j && make install && cd ../.. && pwd; fi
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install llvm36 && brew install msgpack && brew install gnutls && brew link --force llvm36; fi
before_script:
- if [ $TRAVIS_OS_NAME == linux ]; then travis_retry ./autogen.sh && ./configure --prefix=$HOME/usr; fi
- if [ $TRAVIS_OS_NAME == osx ]; then travis_retry ./autogen.sh && ./configure; fi
- docker pull aberaud/opendht-deps
- docker pull aberaud/opendht-deps-llvm
script:
- make -j
- docker build -f docker/DockerfileTravis .
- docker build -f docker/DockerfileTravisLlvm .
notifications:
email:
- adrien.beraud@savoirfairelinux.com
env:
- LANG="en_US.UTF-8"
os:
- osx
+47 -27
View File
@@ -1,43 +1,52 @@
cmake_minimum_required (VERSION 2.8.6)
project (opendht)
set (opendht_VERSION_MAJOR 0)
set (opendht_VERSION_MINOR 6.1)
set (opendht_VERSION_MAJOR 1)
set (opendht_VERSION_MINOR 3.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(GNUInstallDirs)
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix "\${prefix}")
set (libdir "\${exec_prefix}/lib")
set (includedir "\${prefix}/include")
set (libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
set (includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
option (OPENDHT_DEBUG "Build with debug flags" OFF)
option (OPENDHT_STATIC "Build static library" ON)
option (OPENDHT_SHARED "Build shared library" ON)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_LOG "Build with logs" ON)
option (OPENDHT_PYTHON "Build Python bindings" OFF)
option (OPENDHT_TOOLS "Build DHT tools" ON)
option (OPENDHT_LTO "Build with LTO" OFF)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (OPENDHT_LTO)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fuse-linker-plugin")
if (CMAKE_COMPILER_IS_GNUCC)
SET (CMAKE_AR "gcc-ar")
SET (CMAKE_NM "gcc-nm")
SET (CMAKE_RANLIB "gcc-ranlib")
endif ()
endif ()
find_package (GnuTLS 3.1 REQUIRED)
find_package (GnuTLS 3.3 REQUIRED)
find_package (Msgpack 1.2 REQUIRED)
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
if (OPENDHT_LOG)
add_definitions(-DOPENDHT_LOG=true)
else ()
add_definitions(-DOPENDHT_LOG=false)
endif()
if (OPENDHT_LTO)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
if (CMAKE_COMPILER_IS_GNUCC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-linker-plugin")
set (CMAKE_AR "gcc-ar")
set (CMAKE_NM "gcc-nm")
set (CMAKE_RANLIB "gcc-ranlib")
endif ()
endif ()
list (APPEND opendht_SOURCES
src/utils.cpp
src/infohash.cpp
@@ -58,10 +67,14 @@ list (APPEND opendht_SOURCES
src/argon2/thread.c
src/argon2/encoding.c
src/argon2/ref.c
src/indexation/pht.cpp
src/log.cpp
)
list (APPEND opendht_HEADERS
include/opendht/def.h
include/opendht/utils.h
include/opendht/sockaddr.h
include/opendht/rng.h
include/opendht/crypto.h
include/opendht/infohash.h
@@ -73,10 +86,14 @@ list (APPEND opendht_HEADERS
include/opendht/routing_table.h
include/opendht/node_cache.h
include/opendht/network_engine.h
include/opendht/net.h
include/opendht/scheduler.h
include/opendht/rate_limiter.h
include/opendht/securedht.h
include/opendht/log.h
include/opendht/log_enable.h
include/opendht.h
include/opendht/indexation/pht.h
)
configure_file (
@@ -92,12 +109,6 @@ include_directories (
${CMAKE_CURRENT_BINARY_DIR}/include/
)
if (OPENDHT_DEBUG)
set(CMAKE_BUILD_TYPE Debug)
else ()
set(CMAKE_BUILD_TYPE Release)
endif ()
if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR lib)
endif ()
@@ -112,7 +123,7 @@ if (OPENDHT_STATIC)
target_link_libraries(opendht-static -flto -fuse-linker-plugin)
endif ()
target_link_libraries(opendht-static gnutls nettle)
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR})
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
if (OPENDHT_SHARED)
@@ -122,20 +133,29 @@ 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 -flto -fuse-linker-plugin)
endif ()
target_link_libraries(opendht gnutls nettle)
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR})
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
if (OPENDHT_TOOLS)
add_subdirectory(tools)
endif ()
add_subdirectory(doc)
if (OPENDHT_PYTHON)
add_subdirectory(python)
endif ()
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
VERSION ${opendht_VERSION}
COMPATIBILITY AnyNewerVersion
)
install (DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX})
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE opendhtConfig.cmake)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
+162
View File
@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}</ProjectGuid>
<RootNamespace>argon</RootNamespace>
<WindowsTargetPlatformVersion>8.1</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32_NATIVE;WIN32_LEAN_AND_MEAN;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\src\argon2\argon2.c" />
<ClCompile Include="..\src\argon2\core.c" />
<ClCompile Include="..\src\argon2\encoding.c" />
<ClCompile Include="..\src\argon2\opt.c" />
<ClCompile Include="..\src\argon2\ref.c" />
<ClCompile Include="..\src\argon2\thread.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\argon2\argon2.h" />
<ClInclude Include="..\src\argon2\core.h" />
<ClInclude Include="..\src\argon2\encoding.h" />
<ClInclude Include="..\src\argon2\opt.h" />
<ClInclude Include="..\src\argon2\ref.h" />
<ClInclude Include="..\src\argon2\thread.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+151
View File
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}</ProjectGuid>
<RootNamespace>blake</RootNamespace>
<WindowsTargetPlatformVersion>8.1</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.lib</TargetExt>
<OutDir>$(ProjectDir)..\..\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\src\argon2\blake2\blake2b.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\argon2\blake2\blake2-impl.h" />
<ClInclude Include="..\src\argon2\blake2\blake2.h" />
<ClInclude Include="..\src\argon2\blake2\blamka-round-opt.h" />
<ClInclude Include="..\src\argon2\blake2\blamka-round-ref.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+166
View File
@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}</ProjectGuid>
<RootNamespace>dhtchat</RootNamespace>
<WindowsTargetPlatformVersion>8.1</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtchat.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+166
View File
@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}</ProjectGuid>
<RootNamespace>dhtnode</RootNamespace>
<WindowsTargetPlatformVersion>8.1</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtnode.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+166
View File
@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{78443BCD-4689-4007-A246-F8F34B27F561}</ProjectGuid>
<RootNamespace>dhtscanner</RootNamespace>
<WindowsTargetPlatformVersion>8.1</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</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>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
<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>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\tools\dhtscanner.cpp" />
<ClCompile Include="wingetopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tools\tools_common.h" />
<ClInclude Include="wingetopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+221
View File
@@ -0,0 +1,221 @@
--- /dev/null
+++ b/msgpack_vc8.vcxproj
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>MessagePack</ProjectName>
+ <ProjectGuid>{122A2EA4-B283-4241-9655-786DE78283B2}</ProjectGuid>
+ <RootNamespace>MessagePack</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(ProjectDir)..\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <TargetName>msgpackd</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>msgpackd</TargetName>
+ <OutDir>$(ProjectDir)..\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(ProjectDir)..\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <TargetName>msgpack</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>msgpack</TargetName>
+ <OutDir>$(ProjectDir)..\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>StackFrameRuntimeCheck</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
+ </Lib>
+ <PostBuildEvent>
+ <Command>mkdir $(OutDir)\include
+
+mkdir $(OutDir)\include\msgpack
+
+copy include\*.h $(OutDir)\include\
+
+copy include\*.hpp $(OutDir)\include\
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>StackFrameRuntimeCheck</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
+ </Lib>
+ <PostBuildEvent>
+ <Command>mkdir $(OutDir)\include
+
+mkdir $(OutDir)\include\msgpack
+
+copy include\*.h $(OutDir)\include\
+
+copy include\*.hpp $(OutDir)\include\
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32_NATIVE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
+ <LinkTimeCodeGeneration />
+ </Lib>
+ <PostBuildEvent>
+ <Command>mkdir $(OutDir)\include
+
+mkdir $(OutDir)\include\msgpack
+
+copy include\*.h $(OutDir)\include\
+
+copy include\*.hpp $(OutDir)\include\
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>MSGPACK_USE_CPP03;WIN32_NATIVE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
+ <LinkTimeCodeGeneration />
+ </Lib>
+ <PostBuildEvent>
+ <Command>mkdir $(OutDir)\include
+
+mkdir $(OutDir)\include\msgpack
+
+copy include\*.h $(OutDir)\include\
+
+copy include\*.hpp $(OutDir)\include\
+xcopy /S /Y include\msgpack\*.h $(OutDir)\include\msgpack
+xcopy /S /Y include\msgpack\*.hpp $(OutDir)\include\msgpack
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\objectc.c" />
+ <ClCompile Include="src\unpack.c" />
+ <ClCompile Include="src\version.c" />
+ <ClCompile Include="src\vrefbuffer.c" />
+ <ClCompile Include="src\zone.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="include\msgpack.hpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--
2.8.1.windows.1
+12
View File
@@ -24,6 +24,7 @@
<ClCompile Include="..\src\default_types.cpp" />
<ClCompile Include="..\src\dht.cpp" />
<ClCompile Include="..\src\dhtrunner.cpp" />
<ClCompile Include="..\src\indexation\pht.cpp" />
<ClCompile Include="..\src\infohash.cpp" />
<ClCompile Include="..\src\network_engine.cpp" />
<ClCompile Include="..\src\node.cpp" />
@@ -40,11 +41,14 @@
<ClInclude Include="..\include\opendht\default_types.h" />
<ClInclude Include="..\include\opendht\dht.h" />
<ClInclude Include="..\include\opendht\dhtrunner.h" />
<ClInclude Include="..\include\opendht\indexation\pht.h" />
<ClInclude Include="..\include\opendht\infohash.h" />
<ClInclude Include="..\include\opendht\log.h" />
<ClInclude Include="..\include\opendht\log_enable.h" />
<ClInclude Include="..\include\opendht\network_engine.h" />
<ClInclude Include="..\include\opendht\node.h" />
<ClInclude Include="..\include\opendht\node_cache.h" />
<ClInclude Include="..\include\opendht\rate_limiter.h" />
<ClInclude Include="..\include\opendht\request.h" />
<ClInclude Include="..\include\opendht\rng.h" />
<ClInclude Include="..\include\opendht\routing_table.h" />
@@ -135,6 +139,8 @@
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
@@ -155,6 +161,8 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
@@ -182,6 +190,8 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
@@ -210,6 +220,8 @@ copy ..\include\opendht.h $(OutDir)\include\</Command>
<PostBuildEvent>
<Command>mkdir $(OutDir)\include
mkdir $(OutDir)\include\opendht
mkdir $(OutDir)\include\opendht\indexation
copy ..\include\opendht\indexation\*.h $(OutDir)\include\opendht\indexation
copy ..\include\opendht\*.h $(OutDir)\include\opendht
copy ..\include\opendht.h $(OutDir)\include\</Command>
</PostBuildEvent>
+177 -7
View File
@@ -1,10 +1,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opendht", "opendht.vcxproj", "{711397CE-E5D5-467D-9457-8716C047E50C}"
ProjectSection(ProjectDependencies) = postProject
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA} = {2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
{122A2EA4-B283-4241-9655-786DE78283B2} = {122A2EA4-B283-4241-9655-786DE78283B2}
{6F610EE8-7F59-4191-AB88-F63843267C02} = {6F610EE8-7F59-4191-AB88-F63843267C02}
@@ -12,9 +13,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opendht", "opendht.vcxproj"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{71A1A9EC-1104-4335-A87E-AF8749FD5B34}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgmp", "..\..\gmp\MSVC\libgmp.vcxproj", "{02B94302-23D6-43EF-8865-95CDE99D5DC2}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgmp", "..\..\gmp\SMP\libgmp.vcxproj", "{02B94302-23D6-43EF-8865-95CDE99D5DC2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgnutls", "..\..\gnutls\MSVC\libgnutls.vcxproj", "{6F610EE8-7F59-4191-AB88-F63843267C02}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgnutls", "..\..\gnutls\SMP\libgnutls.vcxproj", "{6F610EE8-7F59-4191-AB88-F63843267C02}"
ProjectSection(ProjectDependencies) = postProject
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {070FEF2B-0C3F-4F33-9D3C-53C7330BF518}
@@ -23,19 +24,43 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgnutls", "..\..\gnutls\M
{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B} = {CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libiconv", "..\..\libiconv\MSVC\libiconv.vcxproj", "{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libiconv", "..\..\libiconv\SMP\libiconv.vcxproj", "{CB8BB76F-D3FF-434E-A85E-7FFC0893EC9B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhogweed", "..\..\nettle\MSVC\libhogweed.vcxproj", "{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libhogweed", "..\..\nettle\SMP\libhogweed.vcxproj", "{200F3D3C-8B84-46D8-953A-6C0EBD283B5C}"
ProjectSection(ProjectDependencies) = postProject
{02B94302-23D6-43EF-8865-95CDE99D5DC2} = {02B94302-23D6-43EF-8865-95CDE99D5DC2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnettle", "..\..\nettle\MSVC\libnettle.vcxproj", "{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnettle", "..\..\nettle\SMP\libnettle.vcxproj", "{070FEF2B-0C3F-4F33-9D3C-53C7330BF518}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzlib", "..\..\zlib\MSVC\libzlib.vcxproj", "{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzlib", "..\..\zlib\SMP\libzlib.vcxproj", "{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MessagePack", "..\..\msgpack-c\msgpack_vc8.vcxproj", "{122A2EA4-B283-4241-9655-786DE78283B2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "argon", "argon.vcxproj", "{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}"
ProjectSection(ProjectDependencies) = postProject
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6} = {36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blake", "blake.vcxproj", "{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{296E2989-CF09-43AC-BBD2-BCF1A4B56D07}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtnode", "dhtnode.vcxproj", "{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}"
ProjectSection(ProjectDependencies) = postProject
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtscanner", "dhtscanner.vcxproj", "{78443BCD-4689-4007-A246-F8F34B27F561}"
ProjectSection(ProjectDependencies) = postProject
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dhtchat", "dhtchat.vcxproj", "{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}"
ProjectSection(ProjectDependencies) = postProject
{711397CE-E5D5-467D-9457-8716C047E50C} = {711397CE-E5D5-467D-9457-8716C047E50C}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -276,6 +301,146 @@ Global
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x64.Build.0 = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{122A2EA4-B283-4241-9655-786DE78283B2}.ReleaseLTO|x86.Build.0 = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x64.ActiveCfg = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x64.Build.0 = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x86.ActiveCfg = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Debug|x86.Build.0 = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x64.ActiveCfg = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x64.Build.0 = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x86.ActiveCfg = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLL|x86.Build.0 = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x64.ActiveCfg = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x64.Build.0 = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x86.ActiveCfg = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.Release|x86.Build.0 = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x64.ActiveCfg = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x64.Build.0 = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLL|x86.Build.0 = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x64.ActiveCfg = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x64.Build.0 = Release|x64
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA}.ReleaseLTO|x86.Build.0 = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x64.ActiveCfg = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x64.Build.0 = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x86.ActiveCfg = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Debug|x86.Build.0 = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x64.ActiveCfg = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x64.Build.0 = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x86.ActiveCfg = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLL|x86.Build.0 = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x64.ActiveCfg = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x64.Build.0 = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x86.ActiveCfg = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.Release|x86.Build.0 = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x64.ActiveCfg = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x64.Build.0 = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLL|x86.Build.0 = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x64.ActiveCfg = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x64.Build.0 = Release|x64
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6}.ReleaseLTO|x86.Build.0 = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x64.ActiveCfg = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x64.Build.0 = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x86.ActiveCfg = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Debug|x86.Build.0 = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x64.ActiveCfg = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x64.Build.0 = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x86.ActiveCfg = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLL|x86.Build.0 = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x64.ActiveCfg = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x64.Build.0 = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x86.ActiveCfg = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.Release|x86.Build.0 = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x64.ActiveCfg = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x64.Build.0 = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLL|x86.Build.0 = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x64.ActiveCfg = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x64.Build.0 = Release|x64
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5}.ReleaseLTO|x86.Build.0 = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x64.ActiveCfg = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x64.Build.0 = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x86.ActiveCfg = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.Debug|x86.Build.0 = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x64.ActiveCfg = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x64.Build.0 = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x86.ActiveCfg = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLL|x86.Build.0 = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x64.ActiveCfg = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x64.Build.0 = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x86.ActiveCfg = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.Release|x86.Build.0 = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x64.ActiveCfg = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x64.Build.0 = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLL|x86.Build.0 = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x64.ActiveCfg = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x64.Build.0 = Release|x64
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{78443BCD-4689-4007-A246-F8F34B27F561}.ReleaseLTO|x86.Build.0 = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x64.ActiveCfg = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x64.Build.0 = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x86.ActiveCfg = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Debug|x86.Build.0 = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x64.ActiveCfg = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x64.Build.0 = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x86.ActiveCfg = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLL|x86.Build.0 = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x64.ActiveCfg = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x64.Build.0 = Debug|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x86.ActiveCfg = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.DebugDLLStaticDeps|x86.Build.0 = Debug|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x64.ActiveCfg = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x64.Build.0 = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x86.ActiveCfg = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.Release|x86.Build.0 = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x64.ActiveCfg = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x64.Build.0 = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x86.ActiveCfg = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLL|x86.Build.0 = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x64.ActiveCfg = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x64.Build.0 = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x86.ActiveCfg = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseDLLStaticDeps|x86.Build.0 = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x64.ActiveCfg = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x64.Build.0 = Release|x64
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x86.ActiveCfg = Release|Win32
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA}.ReleaseLTO|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -288,5 +453,10 @@ Global
{070FEF2B-0C3F-4F33-9D3C-53C7330BF518} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{122A2EA4-B283-4241-9655-786DE78283B2} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{2B85EA05-086B-4DF6-A140-DF52BDAEEEEA} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{36A40B5B-FBAD-4830-9F74-7B4E5788B7A6} = {71A1A9EC-1104-4335-A87E-AF8749FD5B34}
{BF92AECF-AA1D-4B05-9D00-0247E92A24B5} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
{78443BCD-4689-4007-A246-F8F34B27F561} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
{8BE7F14D-B227-4D54-9105-7E5473F2D0BA} = {296E2989-CF09-43AC-BBD2-BCF1A4B56D07}
EndGlobalSection
EndGlobal
+13 -5
View File
@@ -1,12 +1,11 @@
@ECHO OFF
SETLOCAL EnableDelayedExpansion
SET UPSTREAMURL=https://github.com/atraczyk
SET UPSTREAMURL=https://github.com/ShiftMediaProject
SET DEPENDENCIES=( ^
gmp, ^
gnutls, ^
nettle, ^
msgpack-c ^
nettle ^
)
SET PASSDEPENDENCIES=%~1
@@ -24,6 +23,15 @@ IF %ERRORLEVEL% EQU 128 (
SET CURRDIR=%~dp1
cd ..\..
set MSGPACK_VERSION=1df97bc37b363a340c5ad06c5cbcc53310aaff80
set MSGPACK_URL="https://github.com/msgpack/msgpack-c.git"
ECHO Cloning msgpack-c...
git clone %MSGPACK_URL% --quiet
cd msgpack-c
git checkout %MSGPACK_VERSION%
git apply --reject --whitespace=fix ..\opendht\MSVC\msgpack-msvc.patch
cd ..
FOR %%I IN %DEPENDENCIES% DO (
ECHO !PASSDEPENDENCIES! | FINDSTR /C:"%%I" >NUL 2>&1 || (
CALL :cloneOrUpdateRepo "%%I" )
@@ -46,10 +54,10 @@ IF NOT EXIST "%REPONAME%" (
SET PASSDEPENDENCIES=%PASSDEPENDENCIES% %REPONAME%
IF EXIST "%REPONAME%\MSVC\project_get_dependencies.bat" (
IF EXIST "%REPONAME%\SMP\project_get_dependencies.bat" (
ECHO %REPONAME%: Found additional dependencies...
ECHO.
cd %REPONAME%\MSVC
cd %REPONAME%\SMP
project_get_dependencies.bat "!PASSDEPENDENCIES!" || GOTO exitOnError
cd ..\..
)
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#ifndef __STRICT_ANSI__
#include <stdlib.h>
#include <process.h>
#include <direct.h>
#include <fcntl.h>
#define R_OK 4
#define W_OK 2
#define F_OK 0
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#define srandom srand
#define random rand
#define inline __inline
typedef int mode_t;
#include <BaseTsd.h>
#endif
+971
View File
@@ -0,0 +1,971 @@
/* Getopt for Microsoft C
This code is a modification of the Free Software Foundation, Inc.
Getopt library for parsing command line argument the purpose was
to provide a Microsoft Visual C friendly derivative. This code
provides functionality for both Unicode and Multibyte builds.
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
Version: 1.0
Comment: Supports getopt, getopt_long, and getopt_long_only
and POSIXLY_CORRECT environment flag
License: LGPL
Revisions:
02/03/2011 - Ludvik Jerabek - Initial Release
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
**DISCLAIMER**
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include "wingetopt.h"
#ifdef __cplusplus
#define _GETOPT_THROW throw()
#else
#define _GETOPT_THROW
#endif
int optind = 1;
int opterr = 1;
int optopt = '?';
enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
//
//
// Ansi structures and functions follow
//
//
static struct _getopt_data_a
{
int optind;
int opterr;
int optopt;
char *optarg;
int __initialized;
char *__nextchar;
enum ENUM_ORDERING __ordering;
int __posixly_correct;
int __first_nonopt;
int __last_nonopt;
} getopt_data_a;
char *optarg_a;
static void exchange_a(char **argv, struct _getopt_data_a *d)
{
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
char *tem;
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
int len = middle - bottom;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else
{
int len = top - middle;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
{
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
if (optstring[0] == '-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (d->__posixly_correct)
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
return optstring;
}
int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
{
if (d->optind == 0)
d->optind = 1;
optstring = _getopt_initialize_a (optstring, d, posixly_correct);
d->__initialized = 1;
}
else if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
if (optstring[0] == ':')
print_errors = 0;
if (d->__nextchar == NULL || *d->__nextchar == '\0')
{
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a ((char **) argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !strcmp(argv[d->optind], "--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_a((char **) argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc)
{
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
}
if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
{
char *nameend;
unsigned int namelen;
const struct option_a *p;
const struct option_a *pfound = NULL;
struct option_list
{
const struct option_a *p;
struct option_list *next;
} *ambig_list = NULL;
int exact = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
namelen = (unsigned int)(nameend - d->__nextchar);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp(p->name, d->__nextchar, namelen))
{
if (namelen == (unsigned int)strlen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
{
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
newp->p = p;
newp->next = ambig_list;
ambig_list = newp;
}
}
if (ambig_list != NULL && !exact)
{
if (print_errors)
{
struct option_list first;
first.p = pfound;
first.next = ambig_list;
ambig_list = &first;
fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
do
{
fprintf (stderr, " '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
fputc ('\n', stderr);
}
d->__nextchar += strlen(d->__nextchar);
d->optind++;
d->optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
d->optind++;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
if (argv[d->optind - 1][1] == '-')
{
fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
}
else
{
fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
}
}
d->__nextchar += strlen(d->__nextchar);
d->optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
d->optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
d->__nextchar += strlen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
{
if (print_errors)
{
if (argv[d->optind][1] == '-')
{
fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
}
else
{
fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
}
}
d->__nextchar = (char *)"";
d->optind++;
d->optopt = 0;
return '?';
}
}
{
char c = *d->__nextchar++;
char *temp = (char*)strchr(optstring, c);
if (*d->__nextchar == '\0')
++d->optind;
if (temp == NULL || c == ':' || c == ';')
{
if (print_errors)
{
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
}
d->optopt = c;
return '?';
}
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option_a *p;
const struct option_a *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
if (longopts == NULL)
goto no_longs;
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
d->optarg = argv[d->optind++];
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
}
d->__nextchar += strlen(d->__nextchar);
d->optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += strlen(d->__nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
else
d->optarg = NULL;
d->__nextchar += strlen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
no_longs:
d->__nextchar = NULL;
return 'W';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
if (*d->__nextchar != '\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
{
int result;
getopt_data_a.optind = optind;
getopt_data_a.opterr = opterr;
result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
optind = getopt_data_a.optind;
optarg_a = getopt_data_a.optarg;
optopt = getopt_data_a.optopt;
return result;
}
int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
}
int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
{
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
}
int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
{
return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
}
//
//
// Unicode Structures and Functions
//
//
static struct _getopt_data_w
{
int optind;
int opterr;
int optopt;
wchar_t *optarg;
int __initialized;
wchar_t *__nextchar;
enum ENUM_ORDERING __ordering;
int __posixly_correct;
int __first_nonopt;
int __last_nonopt;
} getopt_data_w;
wchar_t *optarg_w;
static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
{
int bottom = d->__first_nonopt;
int middle = d->__last_nonopt;
int top = d->optind;
wchar_t *tem;
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
int len = middle - bottom;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
top -= len;
}
else
{
int len = top - middle;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
bottom += len;
}
}
d->__first_nonopt += (d->optind - d->__last_nonopt);
d->__last_nonopt = d->optind;
}
static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
{
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
if (optstring[0] == L'-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == L'+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (d->__posixly_correct)
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
return optstring;
}
int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
{
if (d->optind == 0)
d->optind = 1;
optstring = _getopt_initialize_w (optstring, d, posixly_correct);
d->__initialized = 1;
}
else if (optstring[0] == L'-' || optstring[0] == L'+')
optstring++;
if (optstring[0] == L':')
print_errors = 0;
if (d->__nextchar == NULL || *d->__nextchar == L'\0')
{
if (d->__last_nonopt > d->optind)
d->__last_nonopt = d->optind;
if (d->__first_nonopt > d->optind)
d->__first_nonopt = d->optind;
if (d->__ordering == PERMUTE)
{
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w((wchar_t **) argv, d);
else if (d->__last_nonopt != d->optind)
d->__first_nonopt = d->optind;
while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
d->optind++;
d->__last_nonopt = d->optind;
}
if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
{
d->optind++;
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
exchange_w((wchar_t **) argv, d);
else if (d->__first_nonopt == d->__last_nonopt)
d->__first_nonopt = d->optind;
d->__last_nonopt = argc;
d->optind = argc;
}
if (d->optind == argc)
{
if (d->__first_nonopt != d->__last_nonopt)
d->optind = d->__first_nonopt;
return -1;
}
if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
{
if (d->__ordering == REQUIRE_ORDER)
return -1;
d->optarg = argv[d->optind++];
return 1;
}
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
}
if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
{
wchar_t *nameend;
unsigned int namelen;
const struct option_w *p;
const struct option_w *pfound = NULL;
struct option_list
{
const struct option_w *p;
struct option_list *next;
} *ambig_list = NULL;
int exact = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
namelen = (unsigned int)(nameend - d->__nextchar);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!wcsncmp(p->name, d->__nextchar, namelen))
{
if (namelen == (unsigned int)wcslen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
{
struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
newp->p = p;
newp->next = ambig_list;
ambig_list = newp;
}
}
if (ambig_list != NULL && !exact)
{
if (print_errors)
{
struct option_list first;
first.p = pfound;
first.next = ambig_list;
ambig_list = &first;
fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
do
{
fwprintf (stderr, L" '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
fputwc (L'\n', stderr);
}
d->__nextchar += wcslen(d->__nextchar);
d->optind++;
d->optopt = 0;
return L'?';
}
if (pfound != NULL)
{
option_index = indfound;
d->optind++;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
if (argv[d->optind - 1][1] == L'-')
{
fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
}
else
{
fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
}
}
d->__nextchar += wcslen(d->__nextchar);
d->optopt = pfound->val;
return L'?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
d->optopt = pfound->val;
return optstring[0] == L':' ? L':' : L'?';
}
}
d->__nextchar += wcslen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
{
if (print_errors)
{
if (argv[d->optind][1] == L'-')
{
fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
}
else
{
fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
}
}
d->__nextchar = (wchar_t *)L"";
d->optind++;
d->optopt = 0;
return L'?';
}
}
{
wchar_t c = *d->__nextchar++;
wchar_t *temp = (wchar_t*)wcschr(optstring, c);
if (*d->__nextchar == L'\0')
++d->optind;
if (temp == NULL || c == L':' || c == L';')
{
if (print_errors)
{
fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
}
d->optopt = c;
return L'?';
}
if (temp[0] == L'W' && temp[1] == L';')
{
wchar_t *nameend;
const struct option_w *p;
const struct option_w *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
if (longopts == NULL)
goto no_longs;
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
return c;
}
else
d->optarg = argv[d->optind++];
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
{
if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
}
d->__nextchar += wcslen(d->__nextchar);
d->optind++;
return L'?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
if (pfound->has_arg)
d->optarg = nameend + 1;
else
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
return L'?';
}
}
else if (pfound->has_arg == 1)
{
if (d->optind < argc)
d->optarg = argv[d->optind++];
else
{
if (print_errors)
{
fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
}
d->__nextchar += wcslen(d->__nextchar);
return optstring[0] == L':' ? L':' : L'?';
}
}
else
d->optarg = NULL;
d->__nextchar += wcslen(d->__nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
no_longs:
d->__nextchar = NULL;
return L'W';
}
if (temp[1] == L':')
{
if (temp[2] == L':')
{
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else
d->optarg = NULL;
d->__nextchar = NULL;
}
else
{
if (*d->__nextchar != L'\0')
{
d->optarg = d->__nextchar;
d->optind++;
}
else if (d->optind == argc)
{
if (print_errors)
{
fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
}
d->optopt = c;
if (optstring[0] == L':')
c = L':';
else
c = L'?';
}
else
d->optarg = argv[d->optind++];
d->__nextchar = NULL;
}
}
return c;
}
}
int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
{
int result;
getopt_data_w.optind = optind;
getopt_data_w.opterr = opterr;
result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct);
optind = getopt_data_w.optind;
optarg_w = getopt_data_w.optarg;
optopt = getopt_data_w.optopt;
return result;
}
int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0);
}
int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0);
}
int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
{
return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0);
}
int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
{
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0);
}
int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
{
return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0);
}
+97
View File
@@ -0,0 +1,97 @@
#ifndef __WINGETOPT_H_
#define __WINGETOPT_H_
#ifdef _GETOPT_API
#undef _GETOPT_API
#endif
#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
#error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
#elif defined(STATIC_GETOPT)
#define _GETOPT_API
#elif defined(EXPORTS_GETOPT)
#define _GETOPT_API __declspec(dllexport)
#else
#define _GETOPT_API __declspec(dllimport)
#endif
// Change behavior for C\C++
#ifdef __cplusplus
#define _BEGIN_EXTERN_C extern "C" {
#define _END_EXTERN_C }
#define _GETOPT_THROW throw()
#else
#define _BEGIN_EXTERN_C
#define _END_EXTERN_C
#define _GETOPT_THROW
#endif
// Standard GNU options
#define null_argument 0 /*Argument Null*/
#define no_argument 0 /*Argument Switch Only*/
#define required_argument 1 /*Argument Required*/
#define optional_argument 2 /*Argument Optional*/
// Shorter Options
#define ARG_NULL 0 /*Argument Null*/
#define ARG_NONE 0 /*Argument Switch Only*/
#define ARG_REQ 1 /*Argument Required*/
#define ARG_OPT 2 /*Argument Optional*/
#include <string.h>
#include <wchar.h>
_BEGIN_EXTERN_C
extern _GETOPT_API int optind;
extern _GETOPT_API int opterr;
extern _GETOPT_API int optopt;
// Ansi
struct option_a
{
const char* name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API char *optarg_a;
extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
// Unicode
struct option_w
{
const wchar_t* name;
int has_arg;
int *flag;
int val;
};
extern _GETOPT_API wchar_t *optarg_w;
extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
_END_EXTERN_C
#undef _BEGIN_EXTERN_C
#undef _END_EXTERN_C
#undef _GETOPT_THROW
#undef _GETOPT_API
#ifdef _UNICODE
#define getopt getopt_w
#define getopt_long getopt_long_w
#define getopt_long_only getopt_long_only_w
#define option option_w
#define optarg optarg_w
#else
#define getopt getopt_a
#define getopt_long getopt_long_a
#define getopt_long_only getopt_long_only_a
#define option option_a
#define optarg optarg_a
#endif
#endif // __WINGETOPT_H_
+1 -3
View File
@@ -10,15 +10,13 @@ if USE_CYTHON
SUBDIRS += python
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
DOC_FILES = \
README.md \
LICENSE
COPYING
EXTRA_DIST = \
$(DOC_FILES)
+23 -16
View File
@@ -1,16 +1,19 @@
OpenDHT
===
<img src="https://raw.githubusercontent.com/savoirfairelinux/opendht/master/resources/opendht_logo_512.png" width="100" align="right">
<br>
<h1 style="margin-top:10px">
<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 originally based on https://github.com/jech/dht by Juliusz Chroboczek.
* Light and fast C++11 Kademlia DHT library.
* Distributed shared key->value data-store
* Clean and powerfull distributed map API with storage of arbitrary binary values of up to 56 KB.
* Clean and powerful distributed map API with storage of arbitrary binary values of up to 56 KB.
* Optional public key cryptography layer providing data signature and encryption (using GnuTLS).
* IPv4 and IPv6 support.
* Python binding.
Documentation
-
## Documentation
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
#### How-to build and install
@@ -22,8 +25,7 @@ Build instructions : <https://github.com/savoirfairelinux/opendht/wiki/Build-the
g++ main.cpp -std=c++11 -lopendht -lgnutls
```
Examples
-
## 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.
@@ -85,22 +87,27 @@ for r in results:
print(r)
```
Dependencies
-
## Dependencies
- msgpack-c 1.2+, used for data serialization.
- GnuTLS 3.1+, used for cryptographic operations.
- GnuTLS 3.3+, used for cryptographic operations.
- Nettle 2.4+, a GnuTLS dependency for crypto.
- Build tested with GCC 4.8+ (GNU/Linux, Android, Windows with MinGW), Clang/LLVM (Linux, OS X).
- Build tested with Microsoft Visual Studio 2015
Licence
-
Copyright (C) 2014-2016 Savoir-faire Linux Inc.
## Contact
Licenced under the GNU General Public License version 3 (see COPYING for the full licence).
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## Licence
Copyright (C) 2014-2017 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.
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.
See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 licence.
This project is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
Donations
-
## Donations
We gratefully accept Bitcoin donations to support OpenDHT development at: `bitcoin:3EykSd1An888efq4Bq3KaV3hJ3JQ4FPnwm`.
+27 -8
View File
@@ -1,23 +1,42 @@
AC_INIT(opendht, 0.6.1)
dnl define macros
m4_define([opendht_major_version], 1)
m4_define([opendht_minor_version], 3)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
AC_INIT(opendht, [opendht_version])
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AC_SUBST(OPENDHT_MAJOR_VERSION, opendht_major_version)
AC_SUBST(OPENDHT_MINOR_VERSION, opendht_minor_version)
AC_SUBST(OPENDHT_PATCH_VERSION, opendht_patch_version)
AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Build in debug mode, adds stricter warnings, disables optimization]))
AS_IF([test "x$enable_debug" = "xyes"],
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0"],
[CXXFLAGS="${CXXFLAGS} -O3"])
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0 -pedantic-errors"],
[CXXFLAGS="${CXXFLAGS} -O3 -pedantic-errors"])
AC_PROG_CXX
AM_PROG_AR
dnl Check for logs
AC_ARG_ENABLE([logs], [AS_HELP_STRING([--disable-logs], [Disble DHT logs])])
AS_IF([test "x$enable_logs" != "xno"], [
AC_DEFINE([OPENDHT_LOG], [true], [Define if DHT logs are enabled])
], [
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled])
])
dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
AS_IF([test -z "$DOXYGEN"], [AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])])
])
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
@@ -26,8 +45,8 @@ AC_ARG_ENABLE([python], [AS_HELP_STRING([--disable-python], [Disble python bindi
AS_IF([test "x$enable_python" != "xno"], [
AM_PATH_PYTHON([3.3],, [:])
AS_IF([test -n "$PYTHON"],[
AC_CHECK_PROGS([CYTHON], [cython3])
AS_IF([test -z "$CYTHON"],[AC_MSG_WARN([Cython not found - continuing without python support])])
echo 'import Cython' | $PYTHON
AS_IF([test $? == 0],[CYTHON=yes],[AC_MSG_WARN([Cython not found - continuing without python support])])
AC_CHECK_PROGS([PIP], [pip3])
AS_IF([test -z "$PIP"],[AC_MSG_WARN([pip not found - continuing without python uninstall support])])
])
@@ -76,7 +95,7 @@ AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.1])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
@@ -88,7 +107,7 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])])
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
dnl Configure setup.py if we build the python module
AM_COND_IF([USE_CYTHON], [
+3
View File
@@ -0,0 +1,3 @@
if (OPENDHT_TOOLS)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dhtnode.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
endif ()
+4
View File
@@ -1,3 +1,6 @@
dist_man1_MANS = dhtnode.1
if HAVE_DOXYGEN
doxyfile.stamp:
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
@@ -7,3 +10,4 @@ CLEANFILES = doxyfile.stamp
all-local: doxyfile.stamp
clean-local:
rm -rf $(top_srcdir)/doc/man $(top_srcdir)/doc/html
endif
Binary file not shown.
@@ -0,0 +1,142 @@
\documentclass[11pt]{article}
\usepackage[utf8x]{inputenc}
\usepackage[top=2cm,bottom=2cm]{geometry}
\usepackage{forloop}
\newcounter{counter}
% maths
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{mathrsfs}
\usepackage{shadethm}
\usepackage{amsthm}
\newshadetheorem{shadeDef}{Definition}[section]
\newtheorem{remark}{Remark}[section]
\renewcommand{\P}{\mathbb{P}}
\usepackage{float}
\usepackage{booktabs}
\setlength{\parindent}{0ex}
\setlength{\parskip}{0.5em}
\begin{document}
\title{Annex 1: Probabilistic analysis of connectivity changes}
\author{Adrien Béraud, Simon Désaulniers, Guillaume Roguez}
\maketitle
\pagestyle{empty}
\begin{shadeDef}
A node flagged as \emph{``expired''} by a node $n$ is a node which has not responded to any
of $n$'s last three requests.
\end{shadeDef}
\begin{remark}
An expired node will not be contacted before 10 minutes from its expiration time.
\end{remark}
Let $N$ the DHT network, $n_0\in N$, a given node and the following probabilistic events:
\begin{itemize}
\item $A$: $\forall n \in N$ $n$ is unreachable by $n_0$, \emph{i.e.} $n_0$ lost connection
with $N$;
\item $B$: $S\subset N$, the nodes unreachable by $n_0$ with $k={|S|\over|N|}$;
\item $C$: $m \le |N|$ nodes are flagged as ``expired''.
\end{itemize}
We are interested in knowing $\P(A|C)$, \emph{i.e.} the probability of the event where $A$ occurs
prior to $C$. From the above, we immediately get
$$\left\{
\begin{array}{ll}
\P(C|A) & = 1\\
\P(A) + \P(B) & = 1
\end{array}
\right.$$
Also, the event $A|C$ can be abstracted as the urn problem of draw without replacement. Then,
$$\P(C|B) = \prod_{i=0}^m \left[k|N| - i \over |N|\right] = \prod_{i=0}^m \left[k - { i \over |N| }\right]$$
Furthermore, using Bayes' theroem we have
\begin{align*}
\P(A|C) & = { \P(C|A)\P(A) \over \P(C|A)\P(A) + \P(C|B)\P(B)}\\
& = { \P(A) \over \P(A) + \P(C|B)\P(B) }\\
& = { \P(A) \over \P(A) + \P(C|B)\left[1 - \P(A)\right] }\\
\Rightarrow \forloop{counter}{0}{\value{counter} < 5}{\qquad}\quad \P(A) & =
\P(A|C)\left[\P(A) + \P(C|B)\left(1 - \P(A)\right) \right] \\
\Rightarrow \forloop{counter}{0}{\value{counter} < 2}{\qquad}\;\:\, \P(A)\left[{ 1 \over \P(A|C)} - 1\right] & =
\P(C|B)\left(1 - \P(A)\right) \\
\end{align*}
Finally,
\begin{equation}
\label{eq:final}
\left[{\P(A) \over 1 - \P(A)}\right]\left[{ 1 \over \P(A|C)} - 1\right] =
\prod_{i=0}^m \left[k - { i \over |N| }\right]
\end{equation}
From \eqref{eq:final}, we may set a plausible configuration $\{\P(A),\P(A|C),k,|N|\}$ letting us
produce results such as in table \ref{tbl:k_1_2}, \ref{tbl:k_2_3} and \ref{tbl:k_3_4}.
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {1 \over 2}$}
\label{tbl:k_1_2}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 1 & 1 & 1 & 1\\
$2^2$ & 2 & 2 & 2 & 2\\
$2^3$ & 4 & 4 & 4 & 4\\
$2^4$ & 5 & 6 & 7 & 8\\
$2^5$ & 5 & 7 & 9 & 10\\
$2^6$ & 6 & 9 & 11 & 13\\
$2^7$ & 6 & 9 & 12 & 14\\
$2^8$ & 7 & 10 & 13 & 16\\
$2^9$ & 7 & 10 & 13 & 16\\
$2^{10}$ & 7 & 10 & 13 & 17\\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {2 \over 3}$}
\label{tbl:k_2_3}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 2 & 2 & 2 & 2\\
$2^2$ & 3 & 3 & 4 & 4\\
$2^3$ & 5 & 5 & 6 & 8\\
$2^4$ & 6 & 8 & 9 & 10\\
$2^5$ & 8 & 10 & 12 & 14\\
$2^6$ & 9 & 13 & 16 & 18\\
$2^7$ & 11 & 15 & 18 & 22\\
$2^8$ & 11 & 16 & 21 & 25\\
$2^9$ & 12 & 17 & 22 & 27\\
$2^{10}$ & 12 & 18 & 23 & 28\\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{The values for $m$ assuming $\P(A|C) \ge 0.95,\, k = {3 \over 4}$}
\label{tbl:k_3_4}
\begin{tabular}{lcccc}
\toprule
$|N| \diagdown \P(A)$ & ${1 \over 10 }$ & ${1 \over 100 }$ & ${1 \over 1000 }$ & ${1 \over 10000 }$\\
\midrule
$2^0$ & 1 & 1 & 1 & 1\\
$2^1$ & 2 & 2 & 2 & 2\\
$2^2$ & 3 & 3 & 3 & 3\\
$2^3$ & 5 & 6 & 6 & 6\\
$2^4$ & 7 & 9 & 10 & 11\\
$2^5$ & 10 & 12 & 14 & 16\\
$2^6$ & 12 & 16 & 19 & 22\\
$2^7$ & 14 & 19 & 23 & 27\\
$2^8$ & 15 & 21 & 27 & 32\\
$2^9$ & 16 & 23 & 30 & 36\\
$2^{10}$ & 17 & 24 & 31 & 38\\
\bottomrule
\end{tabular}
\end{table}
\end{document}
+87
View File
@@ -0,0 +1,87 @@
.TH DHTNODE 1 2016-07-29
.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]]
.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:
.EE
h, help Print this help message.
q, quit Quit the program.
log Start/stop printing DHT logs.
Node information:
ll Print basic information and stats about the current node.
ls Print basic information about current searches.
ld Print basic information about currenty stored values on this node.
lr Print the full current routing table of this node
Operations on the DHT:
b ip:port Ping potential node at given IP address/port.
g [key] Get values at [key].
l [key] Listen for value changes at [key].
p [key] [str] Put string value at [key].
s [key] [str] Put string value at [key], signed with our generated
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
Prints some help.
.TP
\fB-v\fP
Enable the verbose mode (log to stdout by default)
.TP
\fB-l\fP \fIlog_file\fP
Write log to file instead of stdout
.TP
\fB-i\fP
Generate cryptographic identity for the node.
.TP
\fB-d\fP
Run the program in daemon mode (will fork in the background).
.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.
.TP
\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.
.SH AUTHORS
.TP
Program written by
.IP \(bu
.\}
Adrien Béraud <adrien.beraud@savoirfairelinux.com>
.TP
Man page written by
.IP \(bu
.\}
Simon Désaulniers <sim.desaulniers@gmail.com>
+6
View File
@@ -0,0 +1,6 @@
FROM aberaud/opendht-deps
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+9
View File
@@ -0,0 +1,9 @@
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 libgnutls-dev cython3 python3-dev python3-setuptools && apt-get clean
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.0.0/msgpack-2.0.0.tar.gz \
&& tar -xzf msgpack-2.0.0.tar.gz \
&& cd msgpack-2.0.0 && 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.0.0 msgpack-2.0.0.tar.gz
+13
View File
@@ -0,0 +1,13 @@
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 libgnutls-dev cython3 python3-dev python3-setuptools \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
ENV CXX c++
RUN wget https://github.com/msgpack/msgpack-c/releases/download/cpp-2.0.0/msgpack-2.0.0.tar.gz \
&& tar -xzf msgpack-2.0.0.tar.gz \
&& cd msgpack-2.0.0 && 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.0.0 msgpack-2.0.0.tar.gz
+6
View File
@@ -0,0 +1,6 @@
FROM aberaud/opendht-deps-llvm
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+6
View File
@@ -0,0 +1,6 @@
FROM aberaud/opendht-deps
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On .. && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+6
View File
@@ -0,0 +1,6 @@
FROM aberaud/opendht-deps-llvm
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On .. && make -j8 && make install \
&& cd ../.. && rm -rf opendht
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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,3 +22,4 @@
#include "opendht/dhtrunner.h"
#include "opendht/log.h"
#include "opendht/default_types.h"
#include "opendht/indexation/pht.h"
+48 -13
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -30,25 +31,60 @@ namespace dht {
struct Node;
/**
* Current status of a DHT node.
*/
enum class NodeStatus {
Disconnected, // 0 nodes
Connecting, // 1+ nodes
Connected // 1+ good nodes
};
struct Config {
InfoHash node_id;
bool is_bootstrap;
struct OPENDHT_PUBLIC NodeStats {
unsigned good_nodes,
dubious_nodes,
cached_nodes,
incoming_nodes;
unsigned table_depth;
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
std::string toString() const;
};
struct SecureDhtConfig
/**
* Dht configuration.
*/
struct OPENDHT_PUBLIC Config {
/** DHT 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;
/** For testing purposes only, enables bootstrap mode */
bool is_bootstrap;
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
bool maintain_storage;
};
/**
* SecureDht configuration.
*/
struct OPENDHT_PUBLIC SecureDhtConfig
{
Config node_config;
crypto::Identity id;
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
using ValuesExport = std::pair<InfoHash, Blob>;
using QueryCallback = std::function<bool(const std::vector<std::shared_ptr<FieldValueIndex>>& fields)>;
using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values)>;
using GetCallbackSimple = std::function<bool(std::shared_ptr<Value> value)>;
using ShutdownCallback = std::function<void()>;
@@ -57,20 +93,19 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
GetCallback bindGetCb(GetCallbackSimple cb);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(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);
typedef void (*ShutdownCallbackRaw)(void *user_data);
typedef void (*DoneCallbackSimpleRaw)(bool, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
DoneCallback bindDoneCb(DoneCallbackSimple donecb);
DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(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);
}
+109 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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 @@ extern "C" {
namespace dht {
namespace crypto {
class CryptoException : public std::runtime_error {
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
public:
CryptoException(const std::string& str) : std::runtime_error(str) {};
};
@@ -46,20 +46,21 @@ class CryptoException : public std::runtime_error {
/**
* Exception thrown when a decryption error happened.
*/
class DecryptError : public CryptoException {
class OPENDHT_PUBLIC DecryptError : public CryptoException {
public:
DecryptError(const std::string& str = "") : CryptoException(str) {};
};
struct PrivateKey;
struct Certificate;
class RevocationList;
using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
/**
* A public key.
*/
struct PublicKey
struct OPENDHT_PUBLIC PublicKey
{
PublicKey() {}
@@ -109,7 +110,7 @@ private:
/**
* A private key, including the corresponding public key.
*/
struct PrivateKey
struct OPENDHT_PUBLIC PrivateKey
{
PrivateKey();
//PrivateKey(gnutls_privkey_t k) : key(k) {}
@@ -148,6 +149,7 @@ struct PrivateKey
* Recommended values: 4096, 8192
*/
static PrivateKey generate(unsigned key_length = 4096);
static PrivateKey generateEC();
gnutls_privkey_t key {};
gnutls_x509_privkey_t x509_key {};
@@ -159,7 +161,77 @@ private:
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
};
struct Certificate {
class OPENDHT_PUBLIC RevocationList
{
using clock = std::chrono::system_clock;
using time_point = clock::time_point;
using duration = clock::duration;
public:
RevocationList();
RevocationList(const Blob& b);
RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
~RevocationList();
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
void pack(Blob& b) const;
void unpack(const uint8_t* dat, size_t dat_size);
Blob getPacked() const {
Blob b;
pack(b);
return b;
}
template <typename Packer>
void msgpack_pack(Packer& p) const
{
Blob b = getPacked();
p.pack_bin(b.size());
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(msgpack::object o);
void revoke(const Certificate& crt, time_point t = time_point::min());
bool isRevoked(const Certificate& crt) const;
/**
* Sign this revocation list using provided key and certificate.
* Validity_period sets the duration until next update (default to no next update).
*/
void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
void sign(const Identity& id) { sign(*id.first, *id.second); }
bool isSignedBy(const Certificate& issuer) const;
std::string toString() const;
/**
* Read the CRL number extension field.
*/
Blob getNumber() const;
/** Read CRL issuer Common Name (CN) */
std::string getIssuerName() const;
/** Read CRL issuer User ID (UID) */
std::string getIssuerUID() const;
time_point getUpdateTime() const;
time_point getNextUpdateTime() const;
gnutls_x509_crl_t get() { return crl; }
private:
gnutls_x509_crl_t crl {};
RevocationList(const RevocationList&) = delete;
RevocationList& operator=(const RevocationList&) = delete;
};
struct OPENDHT_PUBLIC Certificate {
Certificate() {}
/**
@@ -296,6 +368,8 @@ struct Certificate {
/** Read certificate alternative names */
std::vector<std::pair<NameType, std::string>> getAltNames() const;
std::chrono::system_clock::time_point getExpiration() const;
/**
* Returns true if the certificate is marked as a Certificate Authority.
*/
@@ -307,6 +381,13 @@ struct Certificate {
*/
std::string toString(bool chain = true) const;
std::string print() const;
void revoke(const PrivateKey&, const Certificate&);
std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
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);
gnutls_x509_crt_t cert {};
@@ -314,6 +395,14 @@ struct Certificate {
private:
Certificate(const Certificate&) = delete;
Certificate& operator=(const Certificate&) = delete;
struct crlNumberCmp {
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
return lhs->getNumber() < rhs->getNumber();
}
};
std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
};
@@ -324,14 +413,19 @@ private:
* If not set, the generated certificate will be a self-signed CA.
* @param key_length stength of the generated private key (bits).
*/
Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
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);
/**
* SHA512
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
* Attempts to choose an hash function with
* output size of at least hash_length bytes, Current implementation
* will use SHA1 for hash_length up to 20 bytes,
* will use SHA256 for hash_length up to 32 bytes,
* will use SHA512 for hash_length of 33 bytes and more.
*/
Blob hash(const Blob& data);
OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
/**
* Generates an encryption key from a text password,
@@ -340,19 +434,19 @@ Blob hash(const Blob& data);
* that can be transmitted in clear, and will be generated if
* not provided (32 bytes).
*/
Blob stretchKey(const std::string& password, Blob& salt);
OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
/**
* AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
*/
Blob aesEncrypt(const Blob& data, const Blob& key);
Blob aesEncrypt(const Blob& data, const std::string& password);
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
/**
* AES-GCM decryption.
*/
Blob aesDecrypt(const Blob& data, const Blob& key);
Blob aesDecrypt(const Blob& data, const std::string& password);
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
}
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
#define OPENDTH_IMPORT __declspec(dllimport)
#define OPENDHT_EXPORT __declspec(dllexport)
#define OPENDHT_HIDDEN
#else
#define OPENDTH_IMPORT __attribute__ ((visibility ("default")))
#define OPENDHT_EXPORT __attribute__ ((visibility ("default")))
#define OPENDHT_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
// Now we use the generic helper definitions above to define OPENDHT_PUBLIC and OPENDHT_LOCAL.
// OPENDHT_PUBLIC is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
// OPENDHT_LOCAL is used for non-api symbols.
#ifdef opendht_EXPORTS // defined if OpenDHT is compiled as a shared library
#ifdef OPENDHT_BUILD // defined if we are building the OpenDHT shared library (instead of using it)
#define OPENDHT_PUBLIC OPENDHT_EXPORT
#else
#define OPENDHT_PUBLIC OPENDTH_IMPORT
#endif // OPENDHT_BUILD
#define OPENDHT_LOCAL OPENDHT_HIDDEN
#else // opendht_EXPORTS is not defined: this means OpenDHT is a static lib.
#define OPENDHT_PUBLIC
#define OPENDHT_LOCAL
#endif // opendht_EXPORTS
+18 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,8 @@
#include "value.h"
MSGPACK_ADD_ENUM(dht::Value::Field)
namespace dht {
enum class ImStatus : uint8_t {
NONE = 0,
@@ -29,11 +31,11 @@ enum class ImStatus : uint8_t {
READ
};
}
MSGPACK_ADD_ENUM(dht::ImStatus);
MSGPACK_ADD_ENUM(dht::ImStatus)
namespace dht {
class DhtMessage : public Value::Serializable<DhtMessage>
class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
{
public:
static const ValueType TYPE;
@@ -55,11 +57,11 @@ public:
std::string service;
Blob data;
MSGPACK_DEFINE(service, data);
MSGPACK_DEFINE(service, data)
};
template <typename T>
class SignedValue : public Value::Serializable<T>
class OPENDHT_PUBLIC SignedValue : public Value::Serializable<T>
{
private:
using BaseClass = Value::Serializable<T>;
@@ -79,7 +81,7 @@ public:
};
template <typename T>
class EncryptedValue : public SignedValue<T>
class OPENDHT_PUBLIC EncryptedValue : public SignedValue<T>
{
public:
using BaseClass = SignedValue<T>;
@@ -103,7 +105,7 @@ public:
class ImMessage : public SignedValue<ImMessage>
class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage>
{
private:
using BaseClass = SignedValue<ImMessage>;
@@ -126,10 +128,10 @@ public:
long date {0};
ImStatus status {ImStatus::NONE};
MSGPACK_DEFINE_MAP(id, msg, date, status);
MSGPACK_DEFINE_MAP(id, msg, date, status)
};
class TrustRequest : public EncryptedValue<TrustRequest>
class OPENDHT_PUBLIC TrustRequest : public EncryptedValue<TrustRequest>
{
private:
using BaseClass = EncryptedValue<TrustRequest>;
@@ -147,10 +149,11 @@ public:
std::string service;
Blob payload;
MSGPACK_DEFINE(service, payload);
bool confirm {false};
MSGPACK_DEFINE_MAP(service, payload, confirm)
};
class IceCandidates : public EncryptedValue<IceCandidates>
class OPENDHT_PUBLIC IceCandidates : public EncryptedValue<IceCandidates>
{
private:
using BaseClass = EncryptedValue<IceCandidates>;
@@ -175,7 +178,7 @@ public:
pk.pack_bin_body((const char*)ice_data.data(), ice_data.size());
#else
// hack for backward compatibility with old opendht compiled with msgpack 1.0
// remove when enough people have moved to new versions
// remove when enough people have moved to new versions
pk.pack_array(ice_data.size());
for (uint8_t b : ice_data)
pk.pack(b);
@@ -196,7 +199,7 @@ public:
/* "Peer" announcement
*/
class IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
class OPENDHT_PUBLIC IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
{
private:
using BaseClass = Value::Serializable<IpServiceAnnouncement>;
@@ -271,8 +274,8 @@ private:
};
extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
}
+218 -137
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -14,11 +14,9 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "infohash.h"
@@ -28,15 +26,13 @@
#include "scheduler.h"
#include "routing_table.h"
#include "callbacks.h"
#include "log_enable.h"
#include <string>
#include <array>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <functional>
#include <algorithm>
#include <memory>
#ifdef _WIN32
@@ -45,7 +41,9 @@
namespace dht {
namespace net {
struct Request;
} /* namespace net */
/**
* Main Dht class.
@@ -54,7 +52,7 @@ struct Request;
* Must be given open UDP sockets and ::periodic must be
* called regularly.
*/
class Dht {
class OPENDHT_PUBLIC Dht {
public:
// [[deprecated]]
@@ -104,6 +102,13 @@ public:
*/
void setLoggers(LogMethod error = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f) {
DHT_LOG.setFilter(f);
}
virtual void registerType(const ValueType& type) {
types[type.id] = type;
}
@@ -117,14 +122,20 @@ public:
* The node is not pinged, so this should be
* used to bootstrap efficiently from previously known nodes.
*/
bool insertNode(const InfoHash& id, const sockaddr*, socklen_t);
bool insertNode(const NodeExport& n) {
return insertNode(n.id, reinterpret_cast<const sockaddr*>(&n.ss), n.sslen);
void insertNode(const InfoHash& id, const SockAddr&);
void insertNode(const InfoHash& id, const sockaddr* sa, socklen_t salen) {
insertNode(id, SockAddr(sa, salen));
}
void insertNode(const NodeExport& n) {
insertNode(n.id, SockAddr(n.ss, n.sslen));
}
int pingNode(const sockaddr*, socklen_t);
void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
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&);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
return periodic(buf, buflen, SockAddr(from, fromlen));
}
/**
* Get a value by searching on all available protocols (IPv4, IPv6),
@@ -133,18 +144,32 @@ public:
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param donecb a function called when the operation is complete.
cb and donecb won't be called again afterward.
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={});
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}) {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
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 = {}) {
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={}) {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) {
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={}) {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/**
* Similar to Dht::get, but sends a Query to filter data remotely.
* @param key the key for which to query data for.
* @param cb a function called when new values are found on the network.
* It should return false to stop the operation.
* @param donecb a function called when the operation is complete.
cb and donecb won't be called again afterward.
* @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 = {}) {
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
}
/**
@@ -158,14 +183,10 @@ public:
std::shared_ptr<Value> getLocalById(const InfoHash& key, Value::Id vid) const;
/**
* Announce a value on all available protocols (IPv4, IPv6), and
* automatically re-announce when it's about to expire.
* Announce a value on all available protocols (IPv4, IPv6).
*
* The operation will start as soon as the node is connected to the network.
* The done callback will be called once, when the first announce succeeds, or fails.
*
* A "put" operation will never end by itself because the value will need to be
* reannounced on a regular basis.
* User can call #cancelPut(InfoHash, Value::Id) to cancel a put operation.
*/
void put(const InfoHash& key,
std::shared_ptr<Value>,
@@ -221,9 +242,9 @@ public:
*
* @return a token to cancel the listener later.
*/
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={});
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}) {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f));
virtual size_t listen(const InfoHash&, GetCallback, Value::Filter&&={}, Where&& w = {});
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));
}
virtual bool cancelListen(const InfoHash&, size_t token);
@@ -233,7 +254,12 @@ public:
* 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();
void connectivityChanged(sa_family_t);
void connectivityChanged() {
reported_addr.clear();
connectivityChanged(AF_INET);
connectivityChanged(AF_INET6);
}
/**
* Get the list of good nodes for local storage saving purposes
@@ -244,11 +270,14 @@ public:
std::vector<ValuesExport> exportValues() const;
void importValues(const std::vector<ValuesExport>&);
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return,
unsigned *incoming_return) const;
NodeStats getNodesStats(sa_family_t af) const;
std::string getStorageLog() const;
std::string getStorageLog(const InfoHash&) const;
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;
void dumpTables() const;
std::vector<unsigned> getNodeMessageStats(bool in = false) {
@@ -270,10 +299,12 @@ public:
return {total_store_size, total_values};
}
std::vector<Address> getPublicAddress(sa_family_t family = 0);
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0);
protected:
Logger DHT_LOG;
bool logFilerEnable_ {};
InfoHash logFiler_ {};
private:
@@ -282,8 +313,18 @@ private:
the target 8 turn out to be dead. */
static constexpr unsigned SEARCH_NODES {14};
/* Concurrent requests during a search */
static constexpr unsigned SEARCH_REQUESTS {4};
/* The number of bad nodes is limited in order to help determine
* presence of connectivity changes. See
* https://github.com/savoirfairelinux/opendht/issues/137 for details.
*
* According to the tables, 25 is a good average value for big networks. If
* the network is small, normal search expiration process will handle the
* situation.
* */
static constexpr unsigned SEARCH_MAX_BAD_NODES {25};
/* Concurrent search nodes requested count */
static constexpr unsigned MAX_REQUESTED_SEARCH_NODES {4};
/* Number of listening nodes */
static constexpr unsigned LISTEN_NODES {4};
@@ -305,69 +346,19 @@ private:
/* Timeout for listen */
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {5};
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
static constexpr size_t TOKEN_SIZE {64};
static constexpr size_t TOKEN_SIZE {32};
// internal structures
struct SearchNode;
/**
* A single "get" operation data
*/
struct Get {
time_point start;
Value::Filter filter;
GetCallback get_cb;
DoneCallback done_cb;
};
/**
* A single "put" operation data
*/
struct Announce {
bool permanent;
std::shared_ptr<Value> value;
time_point created;
DoneCallback callback;
};
/**
* A single "listen" operation data
*/
struct LocalListener {
Value::Filter filter;
GetCallback get_cb;
};
/**
* A search is a list of the nodes we think are responsible
* for storing values for a given hash.
*/
struct Get;
struct Announce;
struct LocalListener;
struct Search;
struct ValueStorage {
std::shared_ptr<Value> data {};
time_point time {};
ValueStorage() {}
ValueStorage(const std::shared_ptr<Value>& v, time_point t) : data(v), time(t) {}
};
/**
* Foreign nodes asking for updates about an InfoHash.
*/
struct Listener {
size_t rid {};
time_point time {};
/*constexpr*/ Listener(size_t rid, time_point t) : rid(rid), time(t) {}
void refresh(size_t tid, time_point t) {
rid = tid;
time = t;
}
};
struct ValueStorage;
class StorageBucket;
struct Listener;
struct Storage;
// prevent copy
@@ -387,18 +378,21 @@ private:
// 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 buckets {};
RoutingTable buckets4 {};
RoutingTable buckets6 {};
std::vector<Storage> store;
std::map<InfoHash, Storage> store;
std::map<SockAddr, StorageBucket, SockAddr::ipCmp> store_quota;
size_t total_values {0};
size_t total_store_size {0};
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
std::map<InfoHash, std::shared_ptr<Search>> searches4 {};
std::map<InfoHash, std::shared_ptr<Search>> searches6 {};
using SearchMap = std::map<InfoHash, std::shared_ptr<Search>>;
SearchMap searches4 {};
SearchMap searches6 {};
uint16_t search_id {0};
// map a global listen token to IPv4, IPv6 specific listen tokens.
@@ -407,13 +401,16 @@ private:
size_t listener_token {1};
// timing
Scheduler scheduler {};
Scheduler scheduler;
std::shared_ptr<Scheduler::Job> nextNodesConfirmation {};
std::shared_ptr<Scheduler::Job> nextStorageMaintenance {};
time_point mybucket_grow_time {time_point::min()}, mybucket6_grow_time {time_point::min()};
NetworkEngine network_engine;
net::NetworkEngine network_engine;
unsigned pending_pings4 {0};
unsigned pending_pings6 {0};
using ReportedAddr = std::pair<unsigned, Address>;
using ReportedAddr = std::pair<unsigned, SockAddr>;
std::vector<ReportedAddr> reported_addr;
void rotateSecrets();
@@ -421,32 +418,36 @@ private:
Blob makeToken(const sockaddr *sa, bool old) const;
bool tokenMatch(const Blob& token, const sockaddr *sa) const;
void reportedAddr(const sockaddr *sa, socklen_t sa_len);
void reportedAddr(const SockAddr&);
// Storage
decltype(Dht::store)::iterator findStorage(const InfoHash& id);
decltype(Dht::store)::const_iterator findStorage(const InfoHash& id) const;
void storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, size_t tid, Query&& = {});
bool storageStore(const InfoHash& id, const std::shared_ptr<Value>& value, time_point created, const SockAddr* sa = nullptr);
void expireStore();
void expireStorage(InfoHash h);
void expireStore(decltype(store)::iterator);
void storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, size_t tid);
bool storageStore(const InfoHash& id, const std::shared_ptr<Value>& value, time_point created);
void expireStorage();
void storageChanged(Storage& st, ValueStorage&);
void storageChanged(const InfoHash& id, Storage& st, ValueStorage&);
std::string printStorageLog(const decltype(store)::value_type&) const;
void printStorageQuota(std::ostream& out, const decltype(store_quota)::value_type& ip) const;
/**
* For a given storage, if values don't belong there anymore because this
* node is too far from the target, values are sent to the appropriate
* nodes.
*/
void dataPersistence();
size_t maintainStorage(InfoHash id, bool force=false, DoneCallback donecb=nullptr);
void dataPersistence(InfoHash id);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
// 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 = buckets.findBucket(id);
return b == buckets.end() ? nullptr : &(*b);
b = buckets4.findBucket(id);
return b == buckets4.end() ? nullptr : &(*b);
case AF_INET6:
b = buckets6.findBucket(id);
return b == buckets6.end() ? nullptr : &(*b);
@@ -471,52 +472,132 @@ private:
// Searches
/**
* Low-level method that will perform a search on the DHT for the
* specified infohash (id), using the specified IP version (IPv4 or IPv6).
* The values can be filtered by an arbitrary provided filter.
*/
std::shared_ptr<Search> search(const InfoHash& id, sa_family_t af, GetCallback = nullptr, DoneCallback = nullptr, Value::Filter = Value::AllFilter());
void announce(const InfoHash& id, sa_family_t af, std::shared_ptr<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
size_t listenTo(const InfoHash& id, sa_family_t af, GetCallback cb, Value::Filter f = Value::AllFilter());
inline SearchMap& searches(sa_family_t af) { return af == AF_INET ? searches4 : searches6; }
inline const SearchMap& searches(sa_family_t af) const { return af == AF_INET ? searches4 : searches6; }
void bootstrapSearch(Search& sr);
Search *findSearch(unsigned short tid, sa_family_t af);
/**
* Low-level method that will perform a search on the DHT for the specified
* infohash (id), using the specified IP version (IPv4 or IPv6).
*/
std::shared_ptr<Search> search(const InfoHash& id, sa_family_t af, GetCallback = {}, QueryCallback = {}, DoneCallback = {}, Value::Filter = {}, Query q = {});
void announce(const InfoHash& id, sa_family_t af, std::shared_ptr<Value> value, DoneCallback callback, time_point created=time_point::max(), bool permanent = false);
size_t listenTo(const InfoHash& id, sa_family_t af, GetCallback cb, Value::Filter f = Value::AllFilter(), const std::shared_ptr<Query>& q = {});
/**
* Refill the search with good nodes if possible.
*
* @param sr The search to refill.
*
* @return the number inserted nodes.
*/
unsigned refill(Search& sr);
void expireSearches();
void confirmNodes();
void expire();
/**
* Generic function to execute when a 'get' request has completed.
*
* @param status The request passed by the network engine.
* @param answer The answer from the network engine.
* @param ws A weak pointer to the search concerned by the request.
* @param query The query sent to the node.
*/
void searchNodeGetDone(const net::Request& status,
net::NetworkEngine::RequestAnswer&& answer,
std::weak_ptr<Search> ws,
std::shared_ptr<Query> query);
/**
* Generic function to execute when a 'get' request expires.
*
* @param status The request passed by the network engine.
* @param over Whether we're done to try sending the request to the node
* or not. This lets us mark a node as candidate.
* @param ws A weak pointer to the search concerned by the request.
* @param query The query sent to the node.
*/
void searchNodeGetExpired(const net::Request& status, bool over, std::weak_ptr<Search> ws, std::shared_ptr<Query> query);
/**
* This method recovers sends individual request for values per id.
*
* @param ws A weak pointer to the Search.
* @param query The initial query passed through the API.
* @param n The node to which send the requests.
*/
void paginate(std::weak_ptr<Search> ws, std::shared_ptr<Query> query, SearchNode* n);
/**
* If update is true, this method will also send message to synced but non-updated search nodes.
*/
SearchNode* searchSendGetValues(std::shared_ptr<Search> sr, SearchNode *n = nullptr, bool update = true);
/**
* Forwards an 'announce' request for a list of nodes to the network engine.
*
* @param sr The search for which we want to announce a value.
* @param announce The 'announce' structure.
*/
void searchSendAnnounceValue(const std::shared_ptr<Search>& sr);
/**
* Main process of a Search's operations. This function will demand the
* network engine to send requests packets for all pending operations
* ('get', 'put' and 'listen').
*
* @param sr The search to execute its operations.
*/
void searchStep(std::shared_ptr<Search> sr);
void dumpSearch(const Search& sr, std::ostream& out) const;
bool neighbourhoodMaintenance(RoutingTable&);
void processMessage(const uint8_t *buf, size_t buflen, const sockaddr *from, socklen_t fromlen);
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr&);
void onError(std::shared_ptr<Request> node, DhtProtocolException e);
void onError(std::shared_ptr<net::Request> node, net::DhtProtocolException e);
/* when our address is reported by a distant peer. */
void onReportedAddr(const InfoHash& id, sockaddr* sa , socklen_t salen);
void onReportedAddr(const InfoHash& id, const SockAddr&);
/* when we receive a ping request */
NetworkEngine::RequestAnswer onPing(std::shared_ptr<Node> node);
net::NetworkEngine::RequestAnswer onPing(std::shared_ptr<Node> node);
/* when we receive a "find node" request */
NetworkEngine::RequestAnswer onFindNode(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
void onFindNodeDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
net::NetworkEngine::RequestAnswer onFindNode(std::shared_ptr<Node> node, const InfoHash& hash, want_t want);
void onFindNodeDone(const std::shared_ptr<Node>& status,
net::NetworkEngine::RequestAnswer& a,
std::shared_ptr<Search> sr);
/* when we receive a "get values" request */
NetworkEngine::RequestAnswer onGetValues(std::shared_ptr<Node> node, InfoHash& hash, want_t want);
void onGetValuesDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search> sr);
net::NetworkEngine::RequestAnswer onGetValues(std::shared_ptr<Node> node,
const InfoHash& hash,
want_t want,
const Query& q);
void onGetValuesDone(const std::shared_ptr<Node>& status,
net::NetworkEngine::RequestAnswer& a,
std::shared_ptr<Search>& sr,
const std::shared_ptr<Query>& orig_query);
/* when we receive a listen request */
NetworkEngine::RequestAnswer onListen(std::shared_ptr<Node> node, InfoHash& hash, Blob& token, size_t rid);
void onListenDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
net::NetworkEngine::RequestAnswer onListen(std::shared_ptr<Node> node,
const InfoHash& hash,
const Blob& token,
size_t socket_id,
const Query& query);
void onListenDone(const std::shared_ptr<Node>& status,
net::NetworkEngine::RequestAnswer& a,
std::shared_ptr<Search>& sr);
/* when we receive an announce request */
NetworkEngine::RequestAnswer onAnnounce(std::shared_ptr<Node> node,
InfoHash& hash, Blob& token, std::vector<std::shared_ptr<Value>> v, time_point created);
void onAnnounceDone(const Request& status, NetworkEngine::RequestAnswer& a, std::shared_ptr<Search>& sr);
net::NetworkEngine::RequestAnswer onAnnounce(std::shared_ptr<Node> node,
const InfoHash& hash,
const Blob& token,
const std::vector<std::shared_ptr<Value>>& v,
const time_point& created);
net::NetworkEngine::RequestAnswer onRefresh(std::shared_ptr<Node> node,
const InfoHash& hash,
const Blob& token,
const Value::Id& vid);
void onAnnounceDone(const std::shared_ptr<Node>& status,
net::NetworkEngine::RequestAnswer& a,
std::shared_ptr<Search>& sr);
};
}
+97 -39
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -24,6 +24,9 @@
#include "infohash.h"
#include "value.h"
#include "callbacks.h"
#include "sockaddr.h"
#include "log_enable.h"
#include "def.h"
#include <thread>
#include <mutex>
@@ -46,7 +49,7 @@ struct SecureDhtConfig;
* either wait for (expectedly frequent) calls to ::loop() or start an internal
* thread that will update the DHT when appropriate.
*/
class DhtRunner {
class OPENDHT_PUBLIC DhtRunner {
public:
typedef std::function<void(NodeStatus, NodeStatus)> StatusCallback;
@@ -54,20 +57,20 @@ public:
DhtRunner();
virtual ~DhtRunner();
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter()) {
get(id, bindGetCb(cb), donecb, f);
void get(InfoHash id, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
}
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter()) {
get(id, bindGetCb(cb), donecb, f);
void get(InfoHash id, GetCallbackSimple cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
get(id, bindGetCb(cb), donecb, f, w);
}
void get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f={});
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()) {
get(id, cb, bindDoneCb(donecb), f);
void get(InfoHash id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter f = Value::AllFilter(), Where w = {}) {
get(id, cb, bindDoneCb(donecb), f, w);
}
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter());
void get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb={}, Value::Filter f = Value::AllFilter(), Where w = {});
template <class T>
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
@@ -96,7 +99,7 @@ public:
getFilterSet<T>());
}
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter()) {
std::future<std::vector<std::shared_ptr<dht::Value>>> get(InfoHash key, Value::Filter f = Value::AllFilter(), 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) {
@@ -105,7 +108,7 @@ public:
}, [=](bool) {
p->set_value(std::move(*values));
},
f);
f, w);
return p->get_future();
}
@@ -122,10 +125,15 @@ public:
return p->get_future();
}
std::future<size_t> listen(InfoHash key, GetCallback vcb, Value::Filter f = Value::AllFilter());
std::future<size_t> listen(const std::string& key, GetCallback vcb, Value::Filter f = Value::AllFilter());
std::future<size_t> listen(InfoHash key, GetCallbackSimple cb, Value::Filter f = Value::AllFilter()) {
return listen(key, bindGetCb(cb), f);
void query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb = {}, Query q = {});
void query(const InfoHash& hash, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query q = {}) {
query(hash, cb, bindDoneCb(done_cb), q);
}
std::future<size_t> listen(InfoHash key, GetCallback vcb, Value::Filter f = Value::AllFilter(), 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 = {}) {
return listen(key, bindGetCb(cb), f, w);
}
template <class T>
@@ -137,7 +145,7 @@ public:
getFilterSet<T>());
}
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter())
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = Value::AllFilter(), Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
for (const auto& v : vals) {
@@ -150,22 +158,22 @@ public:
}
return true;
},
getFilterSet<T>(f));
getFilterSet<T>(f), w);
}
void cancelListen(InfoHash h, size_t token);
void cancelListen(InfoHash h, std::shared_future<size_t> token);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
put(hash, value, bindDoneCb(cb), permanent);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
void put(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
put(hash, value, bindDoneCb(cb), created, permanent);
}
void put(InfoHash hash, Value&& value, DoneCallback cb={}, bool permanent = false);
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
put(hash, std::forward<Value>(value), bindDoneCb(cb), permanent);
void put(InfoHash hash, Value&& value, DoneCallback cb={}, time_point created=time_point::max(), bool permanent = false);
void put(InfoHash hash, Value&& value, DoneCallbackSimple cb, time_point created=time_point::max(), bool permanent = false) {
put(hash, std::forward<Value>(value), bindDoneCb(cb), created, permanent);
}
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, bool permanent = false);
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, time_point created=time_point::max(), bool permanent = false);
void cancelPut(const InfoHash& h, const Value::Id& id);
@@ -191,10 +199,31 @@ public:
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
void bootstrap(const char* host, const char* service);
void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
/**
* 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 std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb={});
/**
* 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 std::vector<NodeExport>& nodes);
/**
* Add host:service to bootstrap nodes, and ping this node.
* DNS resolution is performed asynchronously.
* When disconnected, all bootstrap nodes added with this method will be tried regularly until connection
* to the DHT network is established.
*/
void bootstrap(const std::string& host, const std::string& service);
/**
* Clear the list of bootstrap added using bootstrap(const std::string&, const std::string&).
*/
void clearBootstrap();
/**
* Inform the DHT of lower-layer connectivity changes.
* This will cause the DHT to assume an IP address change.
@@ -212,7 +241,7 @@ public:
* Returns the currently bound address.
* @param f: address family of the bound address to retreive.
*/
const Address& getBound(sa_family_t f = AF_INET) const {
const SockAddr& getBound(sa_family_t f = AF_INET) const {
return (f == AF_INET) ? bound4 : bound6;
}
@@ -234,6 +263,11 @@ public:
void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f = {});
void registerType(const ValueType& type);
void importValues(const std::vector<ValuesExport>& values);
@@ -242,14 +276,17 @@ public:
return running;
}
int getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
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;
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
std::string getStorageLog() const;
std::string getStorageLog(const InfoHash&) const;
std::string getRoutingTablesLog(sa_family_t af) const;
std::string getSearchesLog(sa_family_t af = 0) const;
std::vector<Address> getPublicAddress(sa_family_t af = 0);
std::vector<std::string> getPublicAddressStr(sa_family_t af = 0);
std::string getSearchesLog(sa_family_t af = AF_UNSPEC) const;
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
std::vector<SockAddr> getPublicAddress(sa_family_t af = AF_UNSPEC);
std::vector<std::string> getPublicAddressStr(sa_family_t af = AF_UNSPEC);
// securedht methods
@@ -268,12 +305,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, const crypto::Identity identity, bool threaded = false, bool is_bootstrap = false) {
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, NetId network = 0) {
run(port, {
/*.dht_config = */{
/*.node_config = */{
/*.node_id = */{},
/*.is_bootstrap = */is_bootstrap
/*.network = */network,
/*.is_bootstrap = */false,
/*.maintain_storage*/false
},
/*.id = */identity
},
@@ -324,11 +363,20 @@ public:
void join();
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
/**
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
* thread and then queue ping requests. This list should contain reliable
* nodes so that the DHT node can recover quickly from losing connection
* with the network.
*/
void tryBootstrapContinuously();
void doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDhtConfig config);
time_point loop_();
static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const char* host, const char* service);
static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const std::string& host, const std::string& service);
NodeStatus getStatus() const {
return std::max(status4, status6);
@@ -341,7 +389,17 @@ private:
std::thread rcv_thread {};
std::mutex sock_mtx {};
std::vector<std::pair<Blob, std::pair<sockaddr_storage, socklen_t>>> rcv {};
std::vector<std::pair<Blob, SockAddr>> rcv {};
/** true if currently actively boostraping */
std::atomic_bool bootstraping {false};
/* bootstrap nodes given as (host, service) pairs */
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 {};
std::queue<std::function<void(SecureDht&)>> pending_ops_prio {};
std::queue<std::function<void(SecureDht&)>> pending_ops {};
@@ -353,8 +411,8 @@ private:
status6 {NodeStatus::Disconnected};
StatusCallback statusCb {nullptr};
Address bound4 {};
Address bound6 {};
SockAddr bound4 {};
SockAddr bound6 {};
};
}
+534
View File
@@ -0,0 +1,534 @@
/*
* Copyright (C) 2014-2017 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>
*
* 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 <string>
#include <vector>
#include <memory>
#include <map>
#include <functional>
#include <stdexcept>
#include <bitset>
#include <iostream>
#include <sstream>
#include "../value.h"
#include "../dhtrunner.h"
#include "../infohash.h"
namespace dht {
namespace indexation {
/*!
* @class Prefix
* @brief A blob structure which prefixes a Key in the PHT.
* @details
* Since the PHT structure is a "trie", every node in this structure have a
* label which is defined by the path from the root of the trie to the node. If
* the node in question is a leaf, *the label is a prefix of all the keys
* contained in the leaf*.
*/
struct OPENDHT_PUBLIC Prefix {
Prefix() {}
Prefix(InfoHash h) : size_(h.size() * 8), content_(h.begin(), h.end()) { }
Prefix(const Blob& d, const Blob& f={}) : size_(d.size()*8), flags_(f), content_(d) { }
Prefix(const Prefix& p, size_t first) :
size_(std::min(first, p.content_.size()*8)),
content_(Blob(p.content_.begin(), p.content_.begin()+size_/8))
{
auto rem = size_ % 8;
if ( not p.flags_.empty() ) {
flags_ = Blob(p.flags_.begin(), p.flags_.begin()+size_/8);
if (rem)
flags_.push_back(p.flags_[size_/8] & (0xFF << (8 - rem)));
}
if (rem)
content_.push_back(p.content_[size_/8] & (0xFF << (8 - rem)));
}
/**
* Get a sub prefix of the Prefix
*
* @param len lenght of the prefix to get, could be negative
* if len is negativ then you will get the prefix
* of size of the previous prefix minus len
*
* @return Sub-prefix of size len or if len is negative sub-prefix of size
* of prefix minus len
*
* @throw out_of_range if len is larger than size of the content
*/
Prefix getPrefix(ssize_t len) const {
if ((size_t)std::abs(len) >= content_.size() * 8)
throw std::out_of_range("len larger than prefix size.");
if (len < 0)
len += size_;
return Prefix(*this, len);
}
/**
* Flags are considered as active if flag is empty or if the flag
* at pos 'pos' is active
ee *
* @see isActiveBit in private function
*/
bool isFlagActive(size_t pos) const {
return flags_.empty() or isActiveBit(flags_, pos);
}
/**
* @see isActiveBit in private function
*/
bool isContentBitActive(size_t pos) const {
return isActiveBit(content_, pos);
}
Prefix getFullSize() { return Prefix(*this, content_.size()*8); }
/**
* This methods gets the prefix of its sibling in the PHT structure.
*
* @return The prefix of this sibling.
*/
Prefix getSibling() const {
Prefix copy = *this;
if ( size_ )
copy.swapContentBit(size_ - 1);
return copy;
}
InfoHash hash() const {
Blob copy(content_);
copy.push_back(size_);
return InfoHash::get(copy);
}
/**
* This method count total of bit in common between 2 prefix
*
* @param p1 first prefix to compared
* @param p2 second prefix to compared
* @return Lenght of the larger common prefix between both
*/
static inline unsigned commonBits(const Prefix& p1, const Prefix& p2) {
unsigned i, j;
uint8_t x;
auto longest_prefix_size = std::min(p1.size_, p2.size_);
for (i = 0; i < longest_prefix_size; i++) {
if (p1.content_.data()[i] != p2.content_.data()[i]
or not p1.isFlagActive(i)
or not p2.isFlagActive(i) ) {
break;
}
}
if (i == longest_prefix_size)
return 8*longest_prefix_size;
x = p1.content_.data()[i] ^ p2.content_.data()[i];
j = 0;
while ((x & 0x80) == 0) {
x <<= 1;
j++;
}
return 8 * i + j;
}
/**
* @see doc of swap private function
*/
void swapContentBit(size_t bit) {
swapBit(content_, bit);
}
/**
* @see doc of swap private function
*/
void swapFlagBit(size_t bit) {
swapBit(flags_, bit);
}
/**
* @see doc of addPadding private function
*/
void addPaddingContent(size_t size) {
content_ = addPadding(content_, size);
}
void updateFlags() {
/* Fill first known bit */
auto csize = size_ - flags_.size() * 8;
while(csize >= 8) {
flags_.push_back(0xFF);
csize -= 8;
}
/* if needed fill remaining bit */
if ( csize )
flags_.push_back(0xFF << (8 - csize));
/* Complet vector space missing */
for ( auto i = flags_.size(); i < content_.size(); i++ )
flags_.push_back(0xFF);
}
std::string toString() const;
size_t size_ {0};
/* Will contain flags according to content_.
If flags_[i] == 0, then content_[i] is unknown
else if flags_[i] == 1, then content_[i] is known */
Blob flags_ {};
Blob content_ {};
private:
/**
* Add a padding to the input blob
*
* @param toP : Prefix where to add a padding
* @param size : Final size of the prefix with padding
*
* @return Copy of the input Blob but with a padding
*/
Blob addPadding(Blob toP, size_t size) {
Blob copy = toP;
for ( auto i = copy.size(); i < size; i++ )
copy.push_back(0);
swapBit(copy, size_ + 1);
return copy;
}
/**
* Check if the bit a pos 'pos' is active, i.e. equal to 1
*
* @param b : Blob to check
* @param pos : Position to check
*
* @return true if the bit is equal to 1, false otherwise
*
* @throw out_of_range if bit is superior to blob size * 8
*/
bool isActiveBit(const Blob &b, size_t pos) const {
if ( pos >= content_.size() * 8 )
throw std::out_of_range("Can't detect active bit at pos, pos larger than prefix size or empty prefix");
return ((b[pos / 8] >> (7 - (pos % 8)) ) & 1) == 1;
}
/**
* Swap bit at position bit [from 0 to 1 and vice-versa]
*
* @param b : Blob to swap
* @param bit : Bit to swap on b
*
* @return the input prefix with the bit at pos 'bit' swapped
*
* @throw out_of_range if bit is superior to blob size * 8
*/
void swapBit(Blob &b, size_t bit) {
if ( bit >= b.size() * 8 )
throw std::out_of_range("bit larger than prefix size.");
size_t offset_bit = (8 - bit) % 8;
b[bit / 8] ^= (1 << offset_bit);
}
};
using Value = std::pair<InfoHash, dht::Value::Id>;
struct OPENDHT_PUBLIC IndexEntry : public dht::Value::Serializable<IndexEntry> {
static const ValueType TYPE;
virtual void unpackValue(const dht::Value& v) {
Serializable<IndexEntry>::unpackValue(v);
name = v.user_type;
}
virtual dht::Value packValue() const {
auto pack = Serializable<IndexEntry>::packValue();
pack.user_type = name;
return pack;
}
Blob prefix;
Value value;
std::string name;
MSGPACK_DEFINE_MAP(prefix, value)
};
class OPENDHT_PUBLIC Pht {
static constexpr const char* INVALID_KEY = "Key does not match the PHT key spec.";
/* Prefixes the user_type for all dht values put on the DHT */
static constexpr const char* INDEX_PREFIX = "index.pht.";
public:
/* This is the maximum number of entries per node. This parameter is
* critical and influences the traffic a lot during a lookup operation.
*/
static constexpr const size_t MAX_NODE_ENTRY_COUNT {16};
/* A key for a an index entry */
using Key = std::map<std::string, Blob>;
/* Specifications of the keys. It defines the number, the length and the
* serialization order of fields. */
using KeySpec = std::map<std::string, size_t>;
using LookupCallback = std::function<void(std::vector<std::shared_ptr<Value>>& values, Prefix p)>;
typedef void (*LookupCallbackRaw)(std::vector<std::shared_ptr<Value>>* values, Prefix* p, void *user_data);
static LookupCallback
bindLookupCb(LookupCallbackRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](std::vector<std::shared_ptr<Value>>& values, Prefix p) {
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, (Prefix*) &p, user_data);
};
}
using LookupCallbackSimple = std::function<void(std::vector<std::shared_ptr<Value>>& values)>;
typedef void (*LookupCallbackSimpleRaw)(std::vector<std::shared_ptr<Value>>* values, void *user_data);
static LookupCallbackSimple
bindLookupCbSimple(LookupCallbackSimpleRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](std::vector<std::shared_ptr<Value>>& values) {
raw_cb((std::vector<std::shared_ptr<Value>>*) &values, user_data);
};
}
Pht(std::string name, KeySpec k_spec, std::shared_ptr<DhtRunner> dht)
: name_(INDEX_PREFIX + name), canary_(name_ + ".canary"), keySpec_(k_spec), dht_(dht) {}
virtual ~Pht () { }
/**
* Lookup a key for a value.
*/
void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true);
void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true)
{
lookup(k, [=](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); }, done_cb, exact_match);
}
/**
* Wrapper function which call the private one.
*
* @param k : Key to insert [i.e map of string, blob]
* @param v : Value to insert
* @param done_cb : Callbakc which going to be call when all the insert is done
*/
void insert(Key k, Value v, DoneCallbackSimple done_cb = {}) {
Prefix p = linearize(k);
auto lo = std::make_shared<int>(0);
auto hi = std::make_shared<int>(p.size_);
IndexEntry entry;
entry.value = v;
entry.prefix = p.content_;
entry.name = name_;
Pht::insert(p, entry, lo, hi, clock::now(), true, done_cb);
}
private:
/**
* Insert function which really insert onto the pht
*
* @param kp : Prefix to insert (linearize the the key)
* @param entry : Entry created from the value
* @param lo : Lowest point to start in the prefix
* @param hi : Highest point to end in the prefix
* @param time_p : Timepoint to use for the insertion into the dht (must be < now)
* @param check_split : If this flag is true then the algoritm will not use the merge algorithm
* @param done_cb : Callback to call when the insert is done
*/
void insert(Prefix kp, IndexEntry entry, std::shared_ptr<int> lo, std::shared_ptr<int> hi, time_point time_p,
bool check_split, DoneCallbackSimple done_cb = {});
class Cache {
public:
/**
* Insert all needed node into the tree according to a prefix
* @param p : Prefix that we need to insert
*/
void insert(const Prefix& p);
/**
* Lookup into the tree to return the maximum prefix length in the cache tree
*
* @param p : Prefix that we are looking for
*
* @return : The size of the longest prefix known in the cache between 0 and p.size_
*/
int lookup(const Prefix& p);
private:
static constexpr const size_t MAX_ELEMENT {1024};
static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {5};
struct Node {
time_point last_reply; /* Made the assocation between leaves and leaves multimap */
std::shared_ptr<Node> parent; /* Share_ptr to the parent, it allow the self destruction of tree */
std::weak_ptr<Node> left_child; /* Left child, for bit equal to 1 */
std::weak_ptr<Node> right_child; /* Right child, for bit equal to 0 */
};
std::weak_ptr<Node> root_; /* Root of the tree */
/**
* This mutlimap contains all prefix insert in the tree in time order
* We could then delete the last one if there is too much node
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
};
/* Callback used for insert value by using the pht */
using RealInsertCallback = std::function<void(std::shared_ptr<Prefix> p, IndexEntry entry)>;
using LookupCallbackWrapper = std::function<void(std::vector<std::shared_ptr<IndexEntry>>& values, Prefix p)>;
/**
* Performs a step in the lookup operation. Each steps are performed
* asynchronously.
*
* @param k : Prefix on which the lookup is performed
* @param lo : lowest bound on the prefix (where to start)
* @param hi : highest bound on the prefix (where to stop)
* @param vals : Shared ptr to a vector of IndexEntry (going to contains all values found)
* @param cb : Callback to use at the end of the lookupStep (call on the value of vals)
* @param done_cb : Callback at the end of the lookupStep
* @param max_common_prefix_len: used in the inexacte lookup match case, indicate the longest common prefix found
* @param start : If start is set then lo and hi will be ignore for the first step, if the step fail lo and hi will be used
* @param all_values : If all value is true then all value met during the lookupstep will be in the vector vals
*/
void lookupStep(Prefix k, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
LookupCallbackWrapper cb, DoneCallbackSimple done_cb,
std::shared_ptr<unsigned> max_common_prefix_len,
int start = -1, bool all_values = false);
/**
* Apply the zcurve algorithm on the list of input prefix
*
* @param all_prefix : Vector of prefix to interleave
*
* @return The output prefix where all flags and content are interleaves
*/
Prefix zcurve(const std::vector<Prefix>& all_prefix) const;
/**
* Linearizes the key into a unidimensional key. A pht only takes
* unidimensional key.
*
* @param Key The initial key.
*
* @return the prefix of the linearized key.
*/
virtual Prefix linearize(Key k) const;
/**
* Looking where to put the data cause if there is free space on the node
* above then this node will became the real leave.
*
* @param p Share_ptr on the Prefix to check
* @param entry The entry to put at the prefix p
* @param end_cb Callback to use at the end of counting
*/
void getRealPrefix(std::shared_ptr<Prefix> p, IndexEntry entry, RealInsertCallback end_cb );
/**
* Looking where to put the data cause if there is free space on the node
* above then this node will became the real leave.
*
* @param p Share_ptr on the Prefix to check
* @param entry The entry to put at the prefix p
* @param end_cb Callback to use at the end of counting
*/
void checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p);
/**
* Search for the split location by comparing 'compared' to all values in vals.
*
* @param compared : Value which going to be compared
* @param vals : The vector of values to compare with comapred
* @return position compared diverge from all others
*/
size_t foundSplitLocation(Prefix compared, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals) {
for ( size_t i = 0; i < compared.content_.size() * 8 - 1; i++ )
for ( auto const& v : *vals)
if ( Prefix(v->prefix).isContentBitActive(i) != compared.isContentBitActive(i) )
return i + 1;
return compared.content_.size() * 8 - 1;
}
/**
* Put canary from the split point until the last known canary and add the prefix at the good place
*
* @param insert : Prefix to insertm but also prefix which going to check where we need to split
* @param vals : Vector of vals for the comparaison
* @param entry : Entry to put on the pht
* @param end_cb : Callback to apply to the insert prefi (here does the insert)
*/
void split(Prefix insert, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals, IndexEntry entry, RealInsertCallback end_cb);
/**
* Tells if the key is valid according to the key spec.
*/
bool validKey(const Key& k) const {
return k.size() == keySpec_.size() and
std::equal(k.begin(), k.end(), keySpec_.begin(),
[&](const Key::value_type& key, const KeySpec::value_type& key_spec) {
return key.first == key_spec.first and key.second.size() <= key_spec.second;
}
);
}
/**
* Updates the canary token on the node responsible for the specified
* Prefix.
*/
void updateCanary(Prefix p);
const std::string name_;
const std::string canary_;
const KeySpec keySpec_;
Cache cache_;
std::shared_ptr<DhtRunner> dht_;
};
} /* indexation */
} /* dht */
+7 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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,6 +19,8 @@
#pragma once
#include "def.h"
#include <msgpack.hpp>
#ifndef _WIN32
@@ -53,7 +55,7 @@ namespace dht {
* An InfoHash is a byte array of HASH_LEN bytes.
* InfoHashes identify nodes and values in the Dht.
*/
class InfoHash final : public std::array<uint8_t, HASH_LEN> {
class OPENDHT_PUBLIC InfoHash final : public std::array<uint8_t, HASH_LEN> {
public:
constexpr InfoHash() : std::array<uint8_t, HASH_LEN>() {}
constexpr InfoHash(const std::array<uint8_t, HASH_LEN>& h) : std::array<uint8_t, HASH_LEN>(h) {}
@@ -96,11 +98,7 @@ public:
* Forget about the ``XOR-metric''. An id is just a path from the
* root of the tree, so bits are numbered from the start.
*/
#ifdef WIN32_NATIVE
static inline int cmp(const InfoHash& __restrict id1, const InfoHash& __restrict id2) {
#else
static inline int cmp(const InfoHash& __restrict__ id1, const InfoHash& __restrict__ id2) {
#endif
static inline int cmp(const InfoHash& id1, const InfoHash& id2) {
return std::memcmp(id1.data(), id2.data(), HASH_LEN);
}
@@ -196,7 +194,8 @@ public:
static InfoHash getRandom();
friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, InfoHash& h);
std::string toString() const;
+10 -40
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -24,6 +24,7 @@
#include <iostream>
#include <fstream>
#include <chrono>
namespace dht {
namespace log {
@@ -61,48 +62,17 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
/**
* Print va_list to std::ostream (used for logging).
*/
void
printLog(std::ostream& s, char const* m, va_list args) {
static constexpr int BUF_SZ = 8192;
char buffer[BUF_SZ];
int ret = vsnprintf(buffer, sizeof(buffer), m, args);
if (ret < 0)
return;
s.write(buffer, std::min(ret, BUF_SZ));
if (ret >= BUF_SZ)
s << "[[TRUNCATED]]";
s.put('\n');
}
OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
void
enableLogging(dht::DhtRunner& dht)
{
dht.setLoggers(
[](char const* m, va_list args){ std::cerr << red; printLog(std::cerr, m, args); std::cerr << def; },
[](char const* m, va_list args){ std::cout << yellow; printLog(std::cout, m, args); std::cout << def; },
[](char const* m, va_list args){ printLog(std::cout, m, args); }
);
}
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
void
enableFileLogging(dht::DhtRunner& dht, const std::string& path)
{
auto logfile = std::make_shared<std::fstream>();
logfile->open(path, std::ios::out);
OPENDHT_PUBLIC void
enableFileLogging(dht::DhtRunner &dht, const std::string &path);
dht.setLoggers(
[=](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); }
);
}
void
disableLogging(dht::DhtRunner& dht)
{
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
}
OPENDHT_PUBLIC void
disableLogging(dht::DhtRunner &dht);
} /* log */
} /* dht */
+175
View File
@@ -0,0 +1,175 @@
/*
* Copyright (C) 2016 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
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "infohash.h"
#ifndef OPENDHT_LOG
#define OPENDHT_LOG true
#endif
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;
template<typename T>
LogMethod(T&& t) : func(std::forward<T>(t)) {}
void operator()(char const* format, ...) const {
va_list args;
va_start(args, format);
func(format, args);
va_end(args);
}
void log(char const* format, va_list args) const {
func(format, args);
}
explicit operator bool() const {
return (bool)func;
}
void logPrintable(const uint8_t *buf, size_t buflen) const {
std::string buf_clean(buflen, '\0');
for (size_t i=0; i<buflen; i++)
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
(*this)("%s", buf_clean.c_str());
}
private:
std::function<void(char const*, va_list)> func;
};
struct Logger {
LogMethod DEBUG = NOLOG;
LogMethod WARN = NOLOG;
LogMethod ERR = NOLOG;
void setFilter(const InfoHash& f) {
filter_ = f;
filterEnable_ = filter_ != InfoHash{};
}
inline void log0(const LogMethod& logger, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and not filterEnable_)
logger.log(format, args);
#endif
}
inline void log1(const LogMethod& logger, const InfoHash& f, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f == filter_))
logger.log(format, args);
#endif
}
inline void log2(const LogMethod& logger, const InfoHash& f1, const InfoHash& f2, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f1 == filter_ or f2 == filter_))
logger.log(format, args);
#endif
}
inline void d(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(DEBUG, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(DEBUG, f, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(DEBUG, f1, f2, format, args);
va_end(args);
#endif
}
inline void w(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(WARN, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(WARN, f, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(WARN, f1, f2, format, args);
va_end(args);
#endif
}
inline void e(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(ERR, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(ERR, f, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(ERR, f1, f2, format, args);
va_end(args);
#endif
}
private:
bool filterEnable_ {false};
InfoHash filter_ {};
};
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@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 <array>
#include <cstdint>
namespace dht {
namespace net {
struct TransPrefix : public std::array<uint8_t, 2> {
TransPrefix(const std::string& str) : std::array<uint8_t, 2>({{(uint8_t)str[0], (uint8_t)str[1]}}) {}
static const TransPrefix PING;
static const TransPrefix FIND_NODE;
static const TransPrefix GET_VALUES;
static const TransPrefix ANNOUNCE_VALUES;
static const TransPrefix REFRESH;
static const TransPrefix LISTEN;
};
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
* the kind of request, and the remaining two a sequence number in
* host order.
*/
struct TransId final : public std::array<uint8_t, 4> {
static const constexpr uint16_t INVALID {0};
TransId() { std::fill_n(begin(), 4, 0); }
TransId(const std::array<char, 4>& o) { std::copy(o.begin(), o.end(), begin()); }
TransId(const TransPrefix prefix, uint16_t seqno = 0) {
std::copy_n(prefix.begin(), prefix.size(), begin());
*reinterpret_cast<uint16_t*>(data()+prefix.size()) = seqno;
}
TransId(const char* q, size_t l) : array<uint8_t, 4>() {
if (l > 4) {
length = 0;
} else {
std::copy_n(q, l, begin());
length = l;
}
}
uint16_t getTid() const {
return *reinterpret_cast<const uint16_t*>(&(*this)[2]);
}
uint32_t toInt() const {
return *reinterpret_cast<const uint32_t*>(&(*this)[0]);
}
bool matches(const TransPrefix prefix, uint16_t* tid = nullptr) const {
if (std::equal(begin(), begin()+2, prefix.begin())) {
if (tid)
*tid = getTid();
return true;
} else
return false;
}
unsigned length {4};
};
} /* namespace net */
} /* dht */
+310 -162
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -14,11 +14,9 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "node_cache.h"
@@ -28,6 +26,8 @@
#include "scheduler.h"
#include "utils.h"
#include "rng.h"
#include "rate_limiter.h"
#include "net.h"
#include <vector>
#include <string>
@@ -38,6 +38,10 @@
#include <queue>
namespace dht {
namespace net {
struct Request;
struct Socket;
#ifndef MSG_CONFIRM
#define MSG_CONFIRM 0
@@ -48,6 +52,7 @@ public:
// sent to another peer (http-like).
static const constexpr uint16_t NON_AUTHORITATIVE_INFORMATION {203}; /* incomplete request packet. */
static const constexpr uint16_t UNAUTHORIZED {401}; /* wrong tokens. */
static const constexpr uint16_t NOT_FOUND {404}; /* storage not found */
// for internal use (custom).
static const constexpr uint16_t INVALID_TID_SIZE {421}; /* id was truncated. */
static const constexpr uint16_t UNKNOWN_TID {422}; /* unknown tid */
@@ -58,6 +63,7 @@ public:
static const std::string LISTEN_WRONG_TOKEN; /* wrong token in "listen" request */
static const std::string PUT_NO_INFOHASH; /* no infohash in "put" request */
static const std::string PUT_WRONG_TOKEN; /* got "put" request with wrong token */
static const std::string STORAGE_NOT_FOUND; /* got access request for an unknown storage */
static const std::string PUT_INVALID_ID; /* invalid id in "put" request */
DhtProtocolException(uint16_t code, const std::string& msg="", InfoHash failing_node_id={})
@@ -91,57 +97,11 @@ struct ParsedMessage;
* @param onGetValues callback for "get values" request.
* @param onListen callback for "listen" request.
* @param onAnnounce callback for "announce" request.
* @param onRefresh callback for "refresh" request.
*/
class NetworkEngine final {
struct TransPrefix : public std::array<uint8_t, 2> {
TransPrefix(const std::string& str) : std::array<uint8_t, 2>({{(uint8_t)str[0], (uint8_t)str[1]}}) {}
static const TransPrefix PING;
static const TransPrefix FIND_NODE;
static const TransPrefix GET_VALUES;
static const TransPrefix ANNOUNCE_VALUES;
static const TransPrefix LISTEN;
};
class NetworkEngine final
{
public:
/* Transaction-ids are 4-bytes long, with the first two bytes identifying
* the kind of request, and the remaining two a sequence number in
* host order.
*/
struct TransId final : public std::array<uint8_t, 4> {
static const constexpr uint16_t INVALID {0};
TransId() {}
TransId(const std::array<char, 4>& o) { std::copy(o.begin(), o.end(), begin()); }
TransId(const TransPrefix prefix, uint16_t seqno = 0) {
std::copy_n(prefix.begin(), prefix.size(), begin());
*reinterpret_cast<uint16_t*>(data()+prefix.size()) = seqno;
}
TransId(const char* q, size_t l) : array<uint8_t, 4>() {
if (l > 4) {
length = 0;
} else {
std::copy_n(q, l, begin());
length = l;
}
}
uint16_t getTid() const {
return *reinterpret_cast<const uint16_t*>(&(*this)[2]);
}
bool matches(const TransPrefix prefix, uint16_t* tid = nullptr) const {
if (std::equal(begin(), begin()+2, prefix.begin())) {
if (tid)
*tid = getTid();
return true;
} else
return false;
}
unsigned length {4};
};
/*!
* @class RequestAnswer
* @brief Answer for a request.
@@ -153,6 +113,7 @@ public:
Blob ntoken {};
Value::Id vid {};
std::vector<std::shared_ptr<Value>> values {};
std::vector<std::shared_ptr<FieldValueIndex>> fields {};
std::vector<std::shared_ptr<Node>> nodes4 {};
std::vector<std::shared_ptr<Node>> nodes6 {};
RequestAnswer() {}
@@ -160,16 +121,7 @@ public:
};
/**
* Cancel a request. Setting req->cancelled = true is not enough in the case
* a request is "persistent".
*/
void cancelRequest(std::shared_ptr<Request>& req);
void connectivityChanged();
private:
/**
* @brief when we receive an error message.
*
@@ -195,7 +147,7 @@ private:
* @param saddr (type: sockaddr*) sockaddr* pointer containing address ip information.
* @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
*/
std::function<void(const InfoHash&, sockaddr*, socklen_t)> onReportedAddr;
std::function<void(const InfoHash&, const SockAddr&)> onReportedAddr;
/**
* @brief on ping request callback.
*
@@ -211,7 +163,7 @@ private:
* or ipv6.
*/
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
const InfoHash&,
want_t)> onFindNode {};
/**
* @brief on "get values" request callback.
@@ -222,8 +174,9 @@ private:
* or ipv6.
*/
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
want_t)> onGetValues {};
const InfoHash&,
want_t,
const Query&)> onGetValues {};
/**
* @brief on listen request callback.
*
@@ -233,9 +186,10 @@ private:
* @param rid (type: uint16_t) request id.
*/
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
Blob&,
uint16_t)> onListen {};
const InfoHash&,
const Blob&,
uint32_t,
const Query&)> onListen {};
/**
* @brief on announce request callback.
*
@@ -246,17 +200,30 @@ private:
* @param created (type: time_point) time when the value was created.
*/
std::function<RequestAnswer(std::shared_ptr<Node>,
InfoHash&,
Blob&,
std::vector<std::shared_ptr<Value>>,
time_point)> onAnnounce {};
const InfoHash&,
const Blob&,
const std::vector<std::shared_ptr<Value>>&,
const time_point&)> onAnnounce {};
/**
* @brief on refresh request callback.
*
* @param node (type: std::shared_ptr<Node>) the requesting node.
* @param vhash (type: InfoHash) hash of the value of interest.
* @param token (type: Blob) security token.
* @param vid (type: Value::id) the value id.
*/
std::function<RequestAnswer(std::shared_ptr<Node>,
const InfoHash&,
const Blob&,
const Value::Id&)> onRefresh {};
public:
using SocketCb = std::function<void(const std::shared_ptr<Node>&, RequestAnswer&&)>;
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {}
NetworkEngine(InfoHash& myid, int s, int s6, Logger& log, Scheduler& scheduler,
NetworkEngine(Logger& log, Scheduler& scheduler);
NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
@@ -264,74 +231,196 @@ public:
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce) :
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid),
dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{
transaction_id = std::uniform_int_distribution<decltype(transaction_id)>{1}(rd_device);
}
virtual ~NetworkEngine() {
clear();
};
decltype(NetworkEngine::onAnnounce) onAnnounce,
decltype(NetworkEngine::onRefresh) onRefresh);
virtual ~NetworkEngine();
void clear();
/**
* Sends values (with closest nodes) to a listenner.
*
* @param sa The address of the listenner.
* @param sslen The length of the sockaddr structure.
* @param rid The request id of the initial listen request.
* @param hash The hash key of the value.
* @param want Wether to send ipv4 and/or ipv6 nodes.
* @param ntoken Listen security token.
* @param nodes The ipv4 closest nodes.
* @param nodes6 The ipv6 closest nodes.
* @param values The values to send.
* @param sa The address of the listenner.
* @param sslen The length of the sockaddr structure.
* @param socket_id The tid to use to write to the request socket.
* @param hash The hash key of the value.
* @param want Wether to send ipv4 and/or ipv6 nodes.
* @param ntoken Listen security token.
* @param nodes The ipv4 closest nodes.
* @param nodes6 The ipv6 closest nodes.
* @param values The values to send.
*/
void tellListener(std::shared_ptr<Node> n, uint16_t rid, InfoHash hash, want_t want, Blob ntoken,
std::vector<std::shared_ptr<Node>> nodes, std::vector<std::shared_ptr<Node>> nodes6,
std::vector<std::shared_ptr<Value>> values);
void tellListener(std::shared_ptr<Node> n, uint32_t socket_id, const InfoHash& hash, want_t want, const Blob& ntoken,
std::vector<std::shared_ptr<Node>>&& nodes, std::vector<std::shared_ptr<Node>>&& nodes6,
std::vector<std::shared_ptr<Value>>&& values, const Query& q);
bool isRunning(sa_family_t af) const;
inline want_t want () const { return dht_socket >= 0 && dht_socket6 >= 0 ? (WANT4 | WANT6) : -1; }
/**
* Cancel a request. Setting req->cancelled = true is not enough in the case
* a request is "persistent".
*/
void cancelRequest(std::shared_ptr<Request>& req);
void connectivityChanged(sa_family_t);
/**************
* Requests *
**************/
/**
* Send a "ping" request to a given node.
*
* @param n The node.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request>
sendPing(std::shared_ptr<Node> n, RequestCb on_done, RequestExpiredCb on_expired);
sendPing(std::shared_ptr<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
/**
* Send a "ping" request to a given node.
*
* @param sa The node's ip sockaddr info.
* @param salen The associated sockaddr struct length.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request>
sendPing(const sockaddr* sa, socklen_t salen, RequestCb on_done, RequestExpiredCb on_expired) {
return sendPing(std::make_shared<Node>(zeroes, sa, salen), on_done, on_expired);
sendPing(const sockaddr* sa, socklen_t salen, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, sa, salen),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
std::shared_ptr<Request>
sendFindNode(std::shared_ptr<Node> n,
const InfoHash& target,
want_t want,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendGetValues(std::shared_ptr<Node> n,
const InfoHash& target,
want_t want,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendListen(std::shared_ptr<Node> n,
const InfoHash& infohash,
const Blob& token,
RequestCb on_done,
RequestExpiredCb on_expired);
std::shared_ptr<Request>
sendAnnounceValue(std::shared_ptr<Node> n,
const InfoHash& infohash,
const Value& v,
time_point created,
const Blob& token,
RequestCb on_done,
RequestExpiredCb on_expired);
/**
* Send a "find node" request to a given node.
*
* @param n The node.
* @param target The target hash.
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
* Use NetworkEngine::want()
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request> sendFindNode(std::shared_ptr<Node> n,
const InfoHash& hash,
want_t want,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Send a "get" request to a given node.
*
* @param n The node.
* @param hash The target hash.
* @param query The query describing filters.
* @param token A security token.
* @param want Indicating wether IPv4 or IPv6 are wanted in response.
* Use NetworkEngine::want()
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request> sendGetValues(std::shared_ptr<Node> n,
const InfoHash& hash,
const Query& query,
want_t want,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Send a "listen" request to a given node.
*
* @param n The node.
* @param hash The storage's hash.
* @param query The query describing filters.
* @param token A security token.
* @param previous The previous request "listen" sent to this node.
* @param socket **UNUSED** The socket for further response.
*
* For backward compatibility purpose, sendListen has to
* handle creation of the socket. Therefor, you cannot
* use openSocket yourself. TODO: Once we don't support
* the old "listen" negociation, sendListen shall not
* create the socket itself.
*
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
* @param socket_cb Callback to execute each time new updates arrive on
* the socket.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request> sendListen(std::shared_ptr<Node> n,
const InfoHash& hash,
const Query& query,
const Blob& token,
std::shared_ptr<Request> previous,
RequestCb&& on_done,
RequestExpiredCb&& on_expired,
SocketCb&& socket_cb);
/**
* Send a "announce" request to a given node.
*
* @param n The node.
* @param hash The target hash.
* @param created The time when the value was created (avoiding extended
* value lifetime)
* @param token A security token.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request> sendAnnounceValue(std::shared_ptr<Node> n,
const InfoHash& hash,
const std::shared_ptr<Value>& v,
time_point created,
const Blob& token,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Send a "refresh" request to a given node. Asks a node to keep the
* associated value Value.type.expiration more minutes in its storage.
*
* @param n The node.
* @param hash The target hash.
* @param vid The value id.
* @param token A security token.
* @param on_done Request callback when the request is completed.
* @param on_expired Request callback when the request expires.
*
* @return the request with information concerning its success.
*/
std::shared_ptr<Request> sendRefreshValue(std::shared_ptr<Node> n,
const InfoHash& hash,
const Value::Id& vid,
const Blob& token,
RequestCb&& on_done,
RequestExpiredCb&& on_expired);
/**
* Opens a socket on which a node will be able allowed to write for further
* additionnal updates following the response to a previous request.
*
* @param node The node which will be allowed to write on this socket.
* @param cb The callback to execute once updates arrive on the socket.
*
* @return the socket.
*/
std::shared_ptr<Socket> openSocket(const std::shared_ptr<Node>& node, TransPrefix tp, SocketCb&& cb);
/**
* Closes a socket so that no further data will be red on that socket.
*
* @param socket The socket to close.
*/
void closeSocket(std::shared_ptr<Socket> socket);
/**
* Parses a message and calls appropriate callbacks.
@@ -342,10 +431,12 @@ 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* from, socklen_t fromlen);
void processMessage(const uint8_t *buf, size_t buflen, const SockAddr& addr);
std::shared_ptr<Node> insertNode(const InfoHash& myid, const sockaddr* from, socklen_t fromlen) {
return cache.getNode(myid, from, fromlen, scheduler.time(), 0);
std::shared_ptr<Node> insertNode(const InfoHash& myid, const SockAddr& addr) {
auto n = cache.getNode(myid, addr, scheduler.time(), 0);
onNewNode(n, 0);
return n;
}
std::vector<unsigned> getNodeMessageStats(bool in) {
@@ -357,7 +448,14 @@ public:
void blacklistNode(const std::shared_ptr<Node>& n);
std::vector<std::shared_ptr<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) {
return cache.getCachedNodes(id, sa_f, count);
}
private:
struct PartialMessage;
/***************
* Constants *
***************/
@@ -366,28 +464,29 @@ private:
static const constexpr size_t NODE4_INFO_BUF_LEN {26};
/* the length of a node info buffer in ipv6 format */
static const constexpr size_t NODE6_INFO_BUF_LEN {38};
/* TODO */
/* after a UDP reply, the period during which we tell the link layer about it */
static constexpr std::chrono::seconds UDP_REPLY_TIME {15};
/* Max. time to receive a full fragmented packet */
static constexpr std::chrono::seconds RX_MAX_PACKET_TIME {10};
/* Max. time between packet fragments */
static constexpr std::chrono::seconds RX_TIMEOUT {3};
/* The maximum number of nodes that we snub. There is probably little
reason to increase this value. */
static constexpr unsigned BLACKLISTED_MAX {10};
/* TODO */
static constexpr size_t MTU {1280};
static constexpr size_t MAX_PACKET_VALUE_SIZE {8 * 1024};
static const std::string my_v;
static std::mt19937 rd_device;
/* DHT info */
const InfoHash& myid;
const int dht_socket {-1};
const int dht_socket6 {-1};
const Logger& DHT_LOG;
void process(std::unique_ptr<ParsedMessage>&&, const SockAddr& from);
NodeCache cache {};
sockaddr_storage blacklist[BLACKLISTED_MAX] {};
unsigned next_blacklisted = 0;
bool rateLimit(const SockAddr& addr);
bool rateLimit();
static bool isMartian(const sockaddr* sa, socklen_t len);
bool isNodeBlacklisted(const sockaddr*, socklen_t) const;
static bool isMartian(const SockAddr& addr);
bool isNodeBlacklisted(const SockAddr& addr) const;
void requestStep(std::shared_ptr<Request> req);
@@ -408,29 +507,34 @@ private:
}
struct MessageStats {
unsigned ping {0};
unsigned find {0};
unsigned get {0};
unsigned put {0};
unsigned listen {0};
unsigned ping {0};
unsigned find {0};
unsigned get {0};
unsigned put {0};
unsigned listen {0};
unsigned refresh {0};
};
// basic wrapper for socket sendto function
int send(const char *buf, size_t len, int flags, const sockaddr *sa, socklen_t salen);
int send(const char *buf, size_t len, int flags, const SockAddr& addr);
void sendValueParts(TransId tid, const std::vector<Blob>& svals, const SockAddr& addr);
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<std::shared_ptr<Value>>&);
void maintainRxBuffer(const TransId& tid);
/*************
* Answers *
*************/
/* answer to a ping request */
void sendPong(const sockaddr* sa, socklen_t salen, TransId tid);
void sendPong(const SockAddr& addr, TransId tid);
/* answer to findnodes/getvalues request */
void sendNodesValues(const sockaddr* sa,
socklen_t salen,
void sendNodesValues(const SockAddr& addr,
TransId tid,
const Blob& nodes,
const Blob& nodes6,
const std::vector<std::shared_ptr<Value>>& st,
const Query& query,
const Blob& token);
Blob bufferNodes(sa_family_t af, const InfoHash& id, std::vector<std::shared_ptr<Node>>& nodes);
@@ -440,28 +544,72 @@ private:
std::vector<std::shared_ptr<Node>>& nodes,
std::vector<std::shared_ptr<Node>>& nodes6);
/* answer to a listen request */
void sendListenConfirmation(const sockaddr* sa, socklen_t salen, TransId tid);
void sendListenConfirmation(const SockAddr& addr, TransId tid);
/* answer to put request */
void sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId, Value::Id);
void sendValueAnnounced(const SockAddr& addr, TransId, Value::Id);
/* answer in case of error */
void sendError(const sockaddr* sa,
socklen_t salen,
void sendError(const SockAddr& addr,
TransId tid,
uint16_t code,
const std::string& message,
bool include_id=false);
void deserializeNodesValues(ParsedMessage& msg);
void deserializeNodes(ParsedMessage& msg);
std::queue<time_point> rate_limit_time {};
static std::mt19937 rd_device;
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const int dht_socket {-1};
const int dht_socket6 {-1};
const Logger& DHT_LOG;
NodeCache cache {};
/**
* A comparator to classify IP addresses, only considering the
* first 64 bits in IPv6.
*/
struct cmpSockAddr {
bool operator()(const SockAddr& a, const SockAddr& b) const {
if (a.second != b.second)
return a.second < b.second;
socklen_t start, len;
switch(a.getFamily()) {
case AF_INET:
start = offsetof(sockaddr_in, sin_addr);
len = sizeof(in_addr);
break;
case AF_INET6:
start = offsetof(sockaddr_in6, sin6_addr);
// don't consider more than 64 bits (IPv6)
len = 8;
break;
default:
start = 0;
len = a.second;
break;
}
return std::memcmp((uint8_t*)&a.first+start, (uint8_t*)&b.first+start, len) < 0;
}
};
// global limiting should be triggered by at least 8 different IPs
using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>;
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
IpLimiterMap address_rate_limiter {};
RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {};
// requests handling
uint16_t transaction_id {1};
std::map<uint16_t, std::shared_ptr<Request>> requests {};
std::map<TransId, std::shared_ptr<Request>> requests {};
std::map<TransId, PartialMessage> partial_messages;
std::map<TransId, std::shared_ptr<Socket>> opened_sockets {};
MessageStats in_stats {}, out_stats {};
std::set<SockAddr> blacklist {};
Scheduler& scheduler;
};
}
} /* namespace net */
} /* namespace dht */
+35 -24
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -22,62 +22,71 @@
#include "infohash.h" // includes socket structures
#include "utils.h"
#include "sockaddr.h"
#include <list>
namespace dht {
namespace net {
struct Request;
} /* namespace net */
struct Node {
friend class NetworkEngine;
InfoHash id;
socklen_t sslen {0};
sockaddr_storage ss;
SockAddr addr;
time_point time {time_point::min()}; /* last time eared about */
time_point reply_time {time_point::min()}; /* time of last correct reply received */
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
: id(id), sslen(salen), ss() {
std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss);
if ((unsigned)salen < sizeof(ss))
std::fill_n((uint8_t*)&ss+salen, sizeof(ss)-salen, 0);
}
: id(id), addr(sa, salen) {}
Node(const InfoHash& id, const SockAddr& addr) : id(id), addr(addr) {}
InfoHash getId() const {
return id;
}
std::pair<const sockaddr*, socklen_t> getAddr() const {
return {(const sockaddr*)&ss, sslen};
return {(const sockaddr*)&addr.first, addr.second};
}
std::string getAddrStr() const {
return print_addr(ss, sslen);
return addr.toString();
}
/**
* Makes notice about an additionnal authentication error with this node. Up
* to MAX_AUTH_ERRORS errors are accepted in order to let the node recover.
* Upon this limit, the node expires.
*/
void authError() {
if (++auth_errors > MAX_AUTH_ERRORS)
setExpired();
}
void authSuccess() { auth_errors = 0; }
bool isExpired() const { return expired_; }
bool isGood(time_point now) const;
bool isPendingMessage() const;
size_t getPendingMessageCount() const;
NodeExport exportNode() const { return NodeExport {id, ss, sslen}; }
sa_family_t getFamily() const { return ss.ss_family; }
NodeExport exportNode() const { return NodeExport {id, addr.first, addr.second}; }
sa_family_t getFamily() const { return addr.getFamily(); }
void update(const sockaddr* sa, socklen_t salen);
void update(const SockAddr&);
void requested(std::shared_ptr<Request>& req);
void received(time_point now, std::shared_ptr<Request> req);
void requested(std::shared_ptr<net::Request>& req);
void received(time_point now, std::shared_ptr<net::Request> req);
void setExpired();
/**
* Resets the state of the node so it's not expired anymore.
*/
void reset() { expired_ = false; }
void reset() { expired_ = false; reply_time = time_point::min(); }
std::string toString() const;
friend std::ostream& operator<< (std::ostream& s, const Node& h);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Node& h);
static constexpr const std::chrono::minutes NODE_GOOD_TIME {120};
@@ -88,16 +97,18 @@ struct Node {
static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {1};
private:
/* Number of times we accept authentication errors from this node. */
static const constexpr unsigned MAX_AUTH_ERRORS {3};
std::list<std::weak_ptr<Request>> requests_ {};
std::list<std::weak_ptr<net::Request>> requests_ {};
unsigned auth_errors {0};
bool expired_ {false};
void clearPendingQueue() {
requests_.remove_if([](std::weak_ptr<Request>& w) {
requests_.remove_if([](std::weak_ptr<net::Request>& w) {
return w.expired();
});
}
};
}
+4 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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
@@ -28,7 +28,8 @@ namespace dht {
struct NodeCache {
std::shared_ptr<Node> getNode(const InfoHash& id, sa_family_t family);
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
std::shared_ptr<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed);
std::vector<std::shared_ptr<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count);
/**
* Reset the connectivity state of every node,
@@ -41,7 +42,7 @@ private:
class NodeMap : public std::map<InfoHash, std::weak_ptr<Node>> {
public:
std::shared_ptr<Node> getNode(const InfoHash& id);
std::shared_ptr<Node> getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirmed);
std::shared_ptr<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed);
void clearBadNodes();
};
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2016 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 "utils.h"
#include <queue>
namespace dht {
template<size_t Quota, unsigned long Perdiod=1>
class RateLimiter {
public:
/** Clear outdated records and return current quota usage */
size_t maintain(const time_point& now) {
using namespace std::chrono;
while (not records.empty() and duration_cast<seconds>(now - records.front()) >= seconds(Perdiod))
records.pop();
return records.size();
}
/** Return false if quota is reached, insert record and return true otherwise. */
bool limit(const time_point& now) {
if (maintain(now) >= Quota)
return false;
records.emplace(now);
return true;
}
bool empty() const {
return records.empty();
}
private:
std::queue<time_point> records {};
};
}
+42 -15
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -18,11 +18,37 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "net.h"
namespace dht {
namespace net {
class NetworkEngine;
struct ParsedMessage;
/*!
* @class Socket
* @brief Open route to a node for continous incoming packets.
* @details
* A socket lets a remote node send us continuous packets treated using a
* given callback. This is intended to provide an easy management of
* specific updates nodes can send. For e.g, this is used in the case of the
* "listen" operation for treating updates a node has for a given storage.
*/
struct Socket {
Socket() {}
Socket(std::shared_ptr<Node> node,
TransId id,
std::function<void(const std::shared_ptr<Node>&, ParsedMessage&&)> on_receive) :
node(node), id(id), on_receive(on_receive) {}
std::shared_ptr<Node> node;
TransId id;
std::function<void(const std::shared_ptr<Node>&, ParsedMessage&&)> on_receive {};
};
/*!
* @class Request
* @brief An atomic request destined to a node.
@@ -32,7 +58,8 @@ struct ParsedMessage;
* request is done.
*/
struct Request {
friend class dht::NetworkEngine;
friend class dht::net::NetworkEngine;
std::shared_ptr<Node> node {}; /* the node to whom the request is destined. */
time_point reply_time {time_point::min()}; /* time when we received the response to the request. */
@@ -52,13 +79,13 @@ struct Request {
State getState() const { return state_; }
Request() {}
Request(uint16_t tid,
Request(TransId tid,
std::shared_ptr<Node> node,
Blob&& msg,
std::function<void(const Request& req_status, ParsedMessage&&)> on_done,
std::function<void(const Request& req_status, bool)> on_expired,
bool persistent = false) :
node(node), on_done(on_done), on_expired(on_expired), tid(tid), msg(std::move(msg)), persistent(persistent) { }
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<void(const Request&, bool)> on_expired,
std::shared_ptr<Socket> socket = {}) :
node(node), on_done(on_done), on_expired(on_expired), tid(tid), msg(std::move(msg)), socket(socket) { }
void setExpired() {
if (pending()) {
@@ -68,11 +95,10 @@ struct Request {
}
}
void setDone(ParsedMessage&& msg) {
if (pending() or persistent) {
if (pending()) {
state_ = Request::State::COMPLETED;
on_done(*this, std::forward<ParsedMessage>(msg));
if (not persistent)
clear();
clear();
}
}
@@ -102,12 +128,13 @@ private:
time_point start {time_point::min()}; /* time when the request is created. */
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
std::function<void(const Request& req_status, ParsedMessage&&)> on_done {};
std::function<void(const Request& req_status, bool)> on_expired {};
std::function<void(const Request&, ParsedMessage&&)> on_done {};
std::function<void(const Request&, bool)> on_expired {};
const uint16_t tid {0}; /* the request id. */
Blob msg {}; /* the serialized message. */
const bool persistent {false}; /* the request is not erased upon completion. */
const TransId tid; /* the request id. */
Blob msg {}; /* the serialized message. */
std::shared_ptr<Socket> socket; /* the socket used for further reponses. */
};
} /* namespace net */
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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 -1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -23,6 +24,8 @@
namespace dht {
static constexpr unsigned TARGET_NODES {8};
struct Bucket {
Bucket() : cached() {}
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
+18 -11
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -22,6 +22,7 @@
#pragma once
#include "utils.h"
#include "log_enable.h"
#include <functional>
#include <map>
@@ -36,8 +37,10 @@ namespace dht {
*/
class Scheduler {
public:
Scheduler(const Logger& l) : DHT_LOG(l) {}
struct Job {
Job(std::function<void()>&& f) : do_(std::forward<std::function<void()>>(f)) {}
Job(std::function<void()>&& f) : do_(std::move(f)) {}
std::function<void()> do_;
};
@@ -50,7 +53,7 @@ public:
* @return pointer to the newly scheduled job.
*/
std::shared_ptr<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
auto job = std::make_shared<Job>(std::forward<std::function<void()>>(job_func));
auto job = std::make_shared<Job>(std::move(job_func));
if (t != time_point::max())
timers.emplace(std::move(t), job);
return job;
@@ -66,10 +69,14 @@ public:
*/
void edit(std::shared_ptr<Scheduler::Job>& job, time_point t) {
if (not job) {
std::cerr << "editing an empty job" << std::endl;
DHT_LOG.ERR("editing an empty job");
return;
}
job = add(t, std::move(job->do_));
// std::function move doesn't garantee to leave the object empty.
// Force clearing old value.
auto task = std::move(job->do_);
job->do_ = {};
job = add(t, std::move(task));
}
/**
@@ -89,17 +96,16 @@ public:
if (timer->first > now)
break;
const auto& job = *timer->second;
if (job.do_)
job.do_();
auto job = std::move(timer->second);
timers.erase(timer);
if (job->do_)
job->do_();
}
return getNextJobTime();
}
inline time_point getNextJobTime() const {
//if (not timers.empty())
// std::cout << "Next job in " << print_dt(timers.begin()->first - clock::now()) << std::endl;
return timers.empty() ? time_point::max() : timers.begin()->first;
}
@@ -113,6 +119,7 @@ public:
private:
time_point now {clock::now()};
std::multimap<time_point, std::shared_ptr<Job>> timers {}; /* the jobs ordered by time */
const Logger& DHT_LOG;
};
}
+13 -12
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -40,7 +41,7 @@
namespace dht {
class SecureDht : public Dht {
class OPENDHT_PUBLIC SecureDht : public Dht {
public:
typedef std::function<void(bool)> SignatureCheckCallback;
@@ -70,7 +71,7 @@ public:
return secureType(std::move(tmp_type));
}
virtual void registerType(const ValueType& type) {
virtual void registerType(const ValueType& type) override {
Dht::registerType(secureType(type));
}
virtual void registerType(ValueType&& type) {
@@ -85,18 +86,18 @@ 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.
*/
virtual void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}) override;
virtual void get(const InfoHash& id, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f = {}) override {
get(id, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f));
virtual void get(const InfoHash& id, GetCallback cb, DoneCallback donecb={}, Value::Filter&& = {}, Where&& w = {}) override;
virtual 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));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f));
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={}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f));
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));
}
virtual size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}) override;
virtual size_t listen(const InfoHash& id, GetCallback cb, Value::Filter&& = {}, Where&& w = {}) override;
/**
* Will take ownership of the value, sign it using our private key and put it in the DHT.
@@ -165,7 +166,7 @@ private:
const ValueType CERTIFICATE_TYPE = {
8, "Certificate", std::chrono::hours(24 * 7),
// A certificate can only be stored at it's public key ID.
// A certificate can only be stored at its public key ID.
[](InfoHash id, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t) {
try {
crypto::Certificate crt(v->data);
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2016 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"
#ifndef _WIN32
#include <sys/socket.h>
#else
#include <iso646.h>
#include <ws2def.h>
#include <ws2tcpip.h>
typedef uint16_t sa_family_t;
typedef uint16_t in_port_t;
#endif
namespace dht {
OPENDHT_PUBLIC std::string print_addr(const sockaddr* sa, socklen_t slen);
OPENDHT_PUBLIC std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
struct OPENDHT_PUBLIC SockAddr : public std::pair<sockaddr_storage, socklen_t> {
public:
SockAddr() : pair<sockaddr_storage, socklen_t>::pair({},0) {}
SockAddr(const SockAddr& o) : pair<sockaddr_storage, socklen_t>::pair({},o.second) {
std::copy_n((uint8_t*)&o.first, o.second, (uint8_t*)&first);
}
SockAddr(const sockaddr* sa, socklen_t len) : pair<sockaddr_storage, socklen_t>::pair({},len) {
if (len > sizeof(sockaddr_storage))
throw std::runtime_error("Socket address length is too large");
std::copy_n((uint8_t*)sa, len, (uint8_t*)&first);
}
SockAddr(const sockaddr_storage& ss, socklen_t len) : SockAddr((const sockaddr*)&ss, len) {}
bool operator<(const SockAddr& o) const {
if (second != o.second)
return second < o.second;
return std::memcmp((uint8_t*)&first, (uint8_t*)&o.first, second) < 0;
}
bool equals(const SockAddr& o) const {
return second == o.second
&& std::memcmp((uint8_t*)&first, (uint8_t*)&o.first, second) == 0;
}
SockAddr& operator=(const SockAddr& o) {
std::copy_n((const uint8_t*)&o.first, o.second, (uint8_t*)&first);
second = o.second;
return *this;
}
std::string toString() const {
return print_addr(first, second);
}
sa_family_t getFamily() const { return second > sizeof(sa_family_t) ? first.ss_family : AF_UNSPEC; }
/**
* A comparator to classify IP addresses, only considering the
* first 64 bits in IPv6.
*/
struct ipCmp {
bool operator()(const SockAddr& a, const SockAddr& b) const {
if (a.second != b.second)
return a.second < b.second;
socklen_t start, len;
switch(a.getFamily()) {
case AF_INET:
start = offsetof(sockaddr_in, sin_addr);
len = sizeof(in_addr);
break;
case AF_INET6:
start = offsetof(sockaddr_in6, sin6_addr);
// don't consider more than 64 bits (IPv6)
len = 8;
break;
default:
start = 0;
len = a.second;
break;
}
return std::memcmp((uint8_t*)&a.first+start, (uint8_t*)&b.first+start, len) < 0;
}
};
};
OPENDHT_PUBLIC bool operator==(const SockAddr& a, const SockAddr& b);
OPENDHT_PUBLIC std::string printAddr(const SockAddr& addr);
}
+12 -64
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,24 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define WANT4 1
#define WANT6 2
#include "def.h"
#include <msgpack.hpp>
#ifndef _WIN32
#include <sys/socket.h>
#else
#include <ws2def.h>
#include <ws2tcpip.h>
#endif
#include <chrono>
#include <random>
#include <functional>
@@ -38,17 +29,14 @@
#include <cstdarg>
#define WANT4 1
#define WANT6 2
namespace dht {
static constexpr unsigned TARGET_NODES {8};
using Address = std::pair<sockaddr_storage, socklen_t>;
using NetId = uint32_t;
using want_t = int_fast8_t;
std::string print_addr(const sockaddr* sa, socklen_t slen);
std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
std::string printAddr(const Address& addr);
template <typename Key, typename Item, typename Condition>
void erase_if(std::map<Key, Item>& map, const Condition& condition)
{
@@ -59,10 +47,10 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
}
}
class DhtException : public std::runtime_error {
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occured: " + str) {}
std::runtime_error("DhtException occurred: " + str) {}
};
@@ -84,9 +72,6 @@ print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
static /*constexpr*/ const time_point TIME_INVALID = {time_point::min()};
static /*constexpr*/ const time_point TIME_MAX {time_point::max()};
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>;
@@ -103,45 +88,6 @@ public:
}
};
// 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;
template<typename T>
LogMethod(T&& t) : func(std::forward<T>(t)) {}
void operator()(char const* format, ...) const {
va_list args;
va_start(args, format);
func(format, args);
va_end(args);
}
void logPrintable(const uint8_t *buf, size_t buflen) const {
std::string buf_clean(buflen, '\0');
for (size_t i=0; i<buflen; i++)
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
(*this)("%s", buf_clean.c_str());
}
private:
std::function<void(char const*, va_list)> func;
};
struct Logger {
LogMethod DEBUG = NOLOG;
LogMethod WARN = NOLOG;
LogMethod ERR = NOLOG;
};
// Serialization related definitions and utility functions
using Blob = std::vector<uint8_t>;
@@ -149,7 +95,7 @@ using Blob = std::vector<uint8_t>;
/**
* Provides backward compatibility with msgpack 1.0
*/
Blob unpackBlob(msgpack::object& o);
OPENDHT_PUBLIC Blob unpackBlob(msgpack::object& o);
template <typename Type>
Blob
@@ -169,4 +115,6 @@ unpackMsg(Blob b) {
msgpack::unpacked unpackMsg(Blob b);
msgpack::object* findMapValue(msgpack::object& map, const std::string& key);
} // namespace dht
+448 -15
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -35,10 +35,12 @@
#include <functional>
#include <memory>
#include <chrono>
#include <set>
namespace dht {
struct Value;
struct Query;
/**
* A storage policy is applied once to every incoming value storage requests.
@@ -68,9 +70,9 @@ using StorePolicy = std::function<bool(InfoHash key, std::shared_ptr<Value>& val
*/
using EditPolicy = std::function<bool(InfoHash key, const std::shared_ptr<Value>& old_val, std::shared_ptr<Value>& new_val, InfoHash from, const sockaddr* from_addr, socklen_t from_len)>;
static constexpr const size_t MAX_VALUE_SIZE {1024 * 14};
static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
struct ValueType {
struct OPENDHT_PUBLIC ValueType {
typedef uint16_t Id;
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, InfoHash, const sockaddr*, socklen_t);
@@ -112,14 +114,29 @@ struct ValueType {
* Values are stored at a given InfoHash in the Dht, but also have a
* unique ID to distinguish between values stored at the same location.
*/
struct Value
struct OPENDHT_PUBLIC Value
{
enum class Field : int {
None = 0,
Id, /* Value::id */
ValueType, /* Value::type */
OwnerPk, /* Value::owner */
SeqNum, /* Value::seq */
UserType, /* Value::user_type */
COUNT /* the total number of fields */
};
typedef uint64_t Id;
static const Id INVALID_ID {0};
static const constexpr Id INVALID_ID {0};
class Filter : public std::function<bool(const Value&)> {
using std::function<bool(const Value&)>::function;
public:
Filter() {}
template<typename Functor>
Filter(Functor f) : std::function<bool(const Value&)>::function(f) {}
Filter chain(Filter&& f2) {
auto f1 = *this;
return chain(std::move(f1), std::move(f2));
@@ -135,14 +152,17 @@ struct Value
return f1(v) and f2(v);
};
}
static Filter chain(std::initializer_list<Filter> l) {
const std::vector<Filter> list(l.begin(), l.end());
return [list](const Value& v){
for (const auto& f : list)
static Filter chainAll(std::vector<Filter>&& set) {
if (set.empty()) return {};
return std::bind([](const Value& v, std::vector<Filter>& s) {
for (const auto& f : s)
if (f and not f(v))
return false;
return true;
};
}, std::placeholders::_1, std::move(set));
}
static Filter chain(std::initializer_list<Filter> l) {
return chainAll(std::vector<Filter>(l.begin(), l.end()));
}
static Filter chainOr(Filter&& f1, Filter&& f2) {
if (not f1 or not f2) return AllFilter();
@@ -152,8 +172,10 @@ struct Value
}
};
/* Sneaky functions disguised in classes */
static const Filter AllFilter() {
return [](const Value&){return true;};
return {};
}
static Filter TypeFilter(const ValueType& t) {
@@ -162,6 +184,11 @@ struct Value
return v.type == tid;
};
}
static Filter TypeFilter(const ValueType::Id& tid) {
return [tid](const Value& v) {
return v.type == tid;
};
}
static Filter IdFilter(const Id id) {
return [id](const Value& v) {
@@ -169,12 +196,34 @@ struct Value
};
}
static Filter recipientFilter(const InfoHash& r) {
static Filter RecipientFilter(const InfoHash& r) {
return [r](const Value& v) {
return v.recipient == r;
};
}
static Filter OwnerFilter(const crypto::PublicKey& pk) {
return OwnerFilter(pk.getId());
}
static Filter OwnerFilter(const InfoHash& pkh) {
return [pkh](const Value& v) {
return v.owner and v.owner->getId() == pkh;
};
}
static Filter SeqNumFilter(uint16_t seq_no) {
return [seq_no](const Value& v) {
return v.seq == seq_no;
};
}
static Filter UserTypeFilter(const std::string& ut) {
return [ut](const Value& v) {
return v.user_type == ut;
};
}
class SerializableBase
{
public:
@@ -360,7 +409,7 @@ struct Value
}
/** print value for debugging */
friend std::ostream& operator<< (std::ostream& s, const Value& v);
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Value& v);
std::string toString() const {
std::stringstream ss;
@@ -415,6 +464,34 @@ struct Value
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
}
template <typename Packer>
void msgpack_pack_fields(const std::set<Value::Field>& fields, Packer& pk) const
{
for (const auto& field : fields)
switch (field) {
case Value::Field::Id:
pk.pack(static_cast<uint64_t>(id));
break;
case Value::Field::ValueType:
pk.pack(static_cast<uint64_t>(type));
break;
case Value::Field::OwnerPk:
if (owner)
owner->msgpack_pack(pk);
else
InfoHash().msgpack_pack(pk);
break;
case Value::Field::SeqNum:
pk.pack(static_cast<uint64_t>(seq));
break;
case Value::Field::UserType:
pk.pack(user_type);
break;
default:
break;
}
}
void msgpack_unpack(msgpack::object o);
void msgpack_unpack_body(const msgpack::object& o);
Blob getPacked() const {
@@ -424,6 +501,8 @@ struct Value
return {buffer.data(), buffer.data()+buffer.size()};
}
void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
Id id {INVALID_ID};
/**
@@ -467,6 +546,360 @@ struct Value
using ValuesExport = std::pair<InfoHash, Blob>;
/**
* @class FieldValue
* @brief Describes a value filter.
* @details
* This structure holds the value for a specified field. It's type can either be
* uint64_t, InfoHash or Blob.
*/
struct OPENDHT_PUBLIC FieldValue
{
FieldValue() {}
FieldValue(Value::Field f, uint64_t int_value) : field(f), intValue(int_value) {}
FieldValue(Value::Field f, InfoHash hash_value) : field(f), hashValue(hash_value) {}
FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(blob_value) {}
bool operator==(const FieldValue& fd) const;
// accessors
Value::Field getField() const { return field; }
uint64_t getInt() const { return intValue; }
InfoHash getHash() const { return hashValue; }
Blob getBlob() const { return blobValue; }
template <typename Packer>
void msgpack_pack(Packer& p) const {
p.pack_map(2);
p.pack(std::string("f")); p.pack(static_cast<uint8_t>(field));
p.pack(std::string("v"));
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
p.pack(intValue);
break;
case Value::Field::OwnerPk:
p.pack(hashValue);
break;
case Value::Field::UserType:
p.pack_bin(blobValue.size());
p.pack_bin_body((const char*)blobValue.data(), blobValue.size());
break;
default:
throw msgpack::type_error();
}
}
void msgpack_unpack(msgpack::object msg) {
hashValue = {};
blobValue.clear();
if (auto f = findMapValue(msg, "f"))
field = (Value::Field)f->as<unsigned>();
else
throw msgpack::type_error();
auto v = findMapValue(msg, "v");
if (not v)
throw msgpack::type_error();
else
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
intValue = v->as<decltype(intValue)>();
break;
case Value::Field::OwnerPk:
hashValue = v->as<decltype(hashValue)>();
break;
case Value::Field::UserType:
blobValue = unpackBlob(*v);
break;
default:
throw msgpack::type_error();
}
}
Value::Filter getLocalFilter() const;
private:
Value::Field field {Value::Field::None};
// three possible value types
uint64_t intValue {};
InfoHash hashValue {};
Blob blobValue {};
};
/**
* @struct FieldSelectorDescription
* @brief Describes a selection.
* @details
* This is meant to narrow data to a set of specified fields. This structure is
* used to construct a Select structure.
*/
struct OPENDHT_PUBLIC FieldSelectorDescription
{
FieldSelectorDescription() {}
FieldSelectorDescription(Value::Field f) : field(f) {}
Value::Field getField() const { return field; }
bool operator==(const FieldSelectorDescription& fd) const { return field == fd.field; }
template <typename Packer>
void msgpack_pack(Packer& p) const { p.pack(static_cast<uint8_t>(field)); }
void msgpack_unpack(msgpack::object msg) { field = static_cast<Value::Field>(msg.as<int>()); }
private:
Value::Field field {Value::Field::None};
};
/**
* @class Select
* @brief Serializable Value field selection.
* @details
* This is a container for a list of FieldSelectorDescription instances. It
* describes a complete SELECT query for dht::Value.
*/
struct OPENDHT_PUBLIC Select
{
Select() { }
Select(const std::string& q_str);
bool isSatisfiedBy(const Select& os) const;
/**
* Selects a field of type Value::Field.
*
* @param field the field to require.
*
* @return the resulting Select instance.
*/
Select& field(Value::Field field) {
fieldSelection_.emplace_back(field);
return *this;
}
/**
* Computes the set of selected fields based on previous require* calls.
*
* @return the set of fields.
*/
std::set<Value::Field> getSelection() const {
std::set<Value::Field> fields {};
for (const auto& f : fieldSelection_) {
fields.insert(f.getField());
}
return fields;
}
template <typename Packer>
void msgpack_pack(Packer& pk) const { pk.pack(fieldSelection_); }
void msgpack_unpack(const msgpack::object& o) {
fieldSelection_.clear();
fieldSelection_ = o.as<decltype(fieldSelection_)>();
}
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
private:
std::vector<FieldSelectorDescription> fieldSelection_ {};
};
/**
* @class Where
* @brief Serializable dht::Value filter.
* @details
* This is container for a list of FieldValue instances. It describes a
* complete WHERE query for dht::Value.
*/
struct OPENDHT_PUBLIC Where
{
Where() { }
Where(const std::string& q_str);
bool isSatisfiedBy(const Where& where) const;
/**
* Adds restriction on Value::Id based on the id argument.
*
* @param id the id.
*
* @return the resulting Where instance.
*/
Where& id(Value::Id id) {
filters_.emplace_back(Value::Field::Id, id);
return *this;
}
/**
* Adds restriction on Value::ValueType based on the type argument.
*
* @param type the value type.
*
* @return the resulting Where instance.
*/
Where& valueType(ValueType::Id type) {
filters_.emplace_back(Value::Field::ValueType, type);
return *this;
}
/**
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
*
* @param owner_pk_hash the owner public key fingerprint.
*
* @return the resulting Where instance.
*/
Where& owner(InfoHash owner_pk_hash) {
filters_.emplace_back(Value::Field::OwnerPk, owner_pk_hash);
return *this;
}
/**
* Adds restriction on Value::OwnerPk based on the owner_pk_hash argument.
*
* @param owner_pk_hash the owner public key fingerprint.
*
* @return the resulting Where instance.
*/
Where& seq(uint16_t seq_no) {
filters_.emplace_back(Value::Field::SeqNum, seq_no);
return *this;
}
/**
* Adds restriction on Value::UserType based on the user_type argument.
*
* @param user_type the user type.
*
* @return the resulting Where instance.
*/
Where& userType(std::string user_type) {
filters_.emplace_back(Value::Field::UserType, Blob {user_type.begin(), user_type.end()});
return *this;
}
/**
* Computes the Value::Filter based on the list of field value set.
*
* @return the resulting Value::Filter.
*/
Value::Filter getFilter() const {
if (filters_.empty()) return {};
std::vector<Value::Filter> fset;
fset.reserve(filters_.size());
for (const auto& f : filters_) {
if (auto lf = f.getLocalFilter())
fset.emplace_back(std::move(lf));
}
return Value::Filter::chainAll(std::move(fset));
}
template <typename Packer>
void msgpack_pack(Packer& pk) const { pk.pack(filters_); }
void msgpack_unpack(const msgpack::object& o) {
filters_.clear();
filters_ = o.as<decltype(filters_)>();
}
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Where& q);
private:
std::vector<FieldValue> filters_;
};
/**
* @class Query
* @brief Describes a query destined to another peer.
* @details
* This class describes the list of filters on field values and the field
* itselves to include in the peer response to a GET operation. See
* FieldValue.
*/
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) { };
/**
* Initializes a query based on a SQL-ish formatted string. The abstract
* form of such a string is the following:
*
* [SELECT $field$ [WHERE $field$=$value$]]
*
* where
*
* - $field$ = *|id|value_type|owner_pk|user_type
* - $value$ = $string$|$integer$
* - $string$: a simple string WITHOUT SPACES.
* - $integer$: a simple integer.
*/
Query(std::string q_str) {
auto pos_W = q_str.find("WHERE");
auto pos_w = q_str.find("where");
auto pos = std::min(pos_W != std::string::npos ? pos_W : q_str.size(),
pos_w != std::string::npos ? pos_w : q_str.size());
select = q_str.substr(0, pos);
where = q_str.substr(pos, q_str.size()-pos);
}
/**
* Tell if the query is satisfied by another query.
*/
bool isSatisfiedBy(const Query& q) const;
template <typename Packer>
void msgpack_pack(Packer& pk) const {
pk.pack_map(2);
pk.pack(std::string("s")); pk.pack(select); /* packing field selectors */
pk.pack(std::string("w")); pk.pack(where); /* packing filters */
}
void msgpack_unpack(const msgpack::object& o);
std::string toString() {
std::stringstream ss;
ss << *this;
return ss.str();
}
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Query& q) {
return s << "Query[" << q.select << " " << q.where << "]";
}
Select select {};
Where where {};
bool none {false}; /* When true, any query satisfies this. */
};
/*!
* @class FieldValueIndex
* @brief An index for field values.
* @details
* This structures is meant to manipulate a subset of fields normally contained
* in Value.
*/
struct OPENDHT_PUBLIC FieldValueIndex {
FieldValueIndex() {}
FieldValueIndex(const Value& v, Select s = {});
/**
* Tells if all the fields of this are contained in the other
* FieldValueIndex with the same value.
*
* @param other The other FieldValueIndex instance.
*/
bool containedIn(const FieldValueIndex& other) const;
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi);
void msgpack_unpack_fields(const std::set<Value::Field>& fields,
const msgpack::object& o,
unsigned offset);
std::map<Value::Field, FieldValue> index {};
};
template <typename T,
typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
Value::Filter
+4
View File
@@ -1,5 +1,9 @@
if USE_CYTHON
noinst_HEADERS = \
opendht.pyx \
opendht_cpp.pxd
PYTHON_INSTALL_RECORD = $(builddir)/install_record.txt
pybuild.stamp:
+125 -38
View File
@@ -31,6 +31,7 @@ from libcpp.map cimport map as map
from libcpp cimport bool
from libcpp.utility cimport pair
from libcpp.string cimport string
from libcpp.memory cimport shared_ptr
from cython.parallel import parallel, prange
from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec
@@ -40,19 +41,29 @@ cimport opendht_cpp as cpp
import threading
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) with gil:
cbs = <object>user_data
if 'lookup' in cbs and cbs['lookup']:
vals = []
for val in deref(values):
v = IndexValue()
v._value = val
vals.append(v)
cbs['lookup'](vals, p.toString())
cdef inline void shutdown_callback(void* user_data) with gil:
cbs = <object>user_data
if 'shutdown' in cbs and cbs['shutdown']:
cbs['shutdown']()
ref.Py_DECREF(cbs)
cdef inline bool get_callback(cpp.shared_ptr[cpp.Value] value, void *user_data) with gil:
cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) with gil:
cb = (<object>user_data)['get']
pv = Value()
pv._value = value
return cb(pv)
cdef inline void done_callback(bool done, cpp.vector[cpp.shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
node_ids = []
for n in deref(nodes):
h = NodeEntry()
@@ -64,6 +75,12 @@ cdef inline void done_callback(bool done, cpp.vector[cpp.shared_ptr[cpp.Node]]*
cbs['done'](done, node_ids)
ref.Py_DECREF(cbs)
cdef inline void done_callback_simple(bool done, void *user_data) with gil:
cbs = <object>user_data
if 'done' in cbs and cbs['done']:
cbs['done'](done)
ref.Py_DECREF(cbs)
cdef class _WithID(object):
def __repr__(self):
return "<%s '%s'>" % (self.__class__.__name__, str(self))
@@ -72,7 +89,7 @@ cdef class _WithID(object):
cdef class InfoHash(_WithID):
cdef cpp.InfoHash _infohash
def __init__(self, bytes str=b''):
def __cinit__(self, bytes str=b''):
self._infohash = cpp.InfoHash(str)
def __bool__(InfoHash self):
return not (self._infohash == cpp.InfoHash())
@@ -109,7 +126,7 @@ cdef class InfoHash(_WithID):
return h
cdef class Node(_WithID):
cdef cpp.shared_ptr[cpp.Node] _node
cdef shared_ptr[cpp.Node] _node
def getId(self):
h = InfoHash()
h._infohash = self._node.get().getId()
@@ -120,7 +137,7 @@ cdef class Node(_WithID):
return self._node.get().isExpired()
cdef class NodeEntry(_WithID):
cdef cpp.pair[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _v
cdef cpp.pair[cpp.InfoHash, shared_ptr[cpp.Node]] _v
def getId(self):
h = InfoHash()
h._infohash = self._v.first
@@ -131,7 +148,7 @@ cdef class NodeEntry(_WithID):
return n
cdef class Value(object):
cdef cpp.shared_ptr[cpp.Value] _value
cdef shared_ptr[cpp.Value] _value
def __init__(self, bytes val=b''):
self._value.reset(new cpp.Value(val, len(val)))
def __str__(self):
@@ -163,8 +180,8 @@ cdef class Value(object):
return self._value.get().size()
cdef class NodeSetIter(object):
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]]* _nodes
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator _curIter
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter
def __init__(self, NodeSet s):
self._nodes = &s._nodes
self._curIter = self._nodes.begin()
@@ -177,7 +194,7 @@ cdef class NodeSetIter(object):
return h
cdef class NodeSet(object):
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]] _nodes
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]] _nodes
def size(self):
return self._nodes.size()
def insert(self, NodeEntry l):
@@ -199,7 +216,7 @@ cdef class NodeSet(object):
return h
def __str__(self):
s = ''
cdef map[cpp.InfoHash, cpp.shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator it = self._nodes.begin()
while it != self._nodes.end():
s += deref(it).first.toString().decode() + ' ' + deref(it).second.get().getAddrStr().decode() + '\n'
inc(it)
@@ -215,7 +232,7 @@ cdef class PublicKey(_WithID):
return h
cdef class Certificate(_WithID):
cdef cpp.shared_ptr[cpp.Certificate] _cert
cdef shared_ptr[cpp.Certificate] _cert
def getId(self):
h = InfoHash()
h._infohash = self._cert.get().getId()
@@ -254,49 +271,52 @@ cdef class DhtConfig(object):
self._config.dht_config.node_config.node_id = id._infohash
cdef class DhtRunner(_WithID):
cdef cpp.DhtRunner* thisptr
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
def __cinit__(self):
self.thisptr = new cpp.DhtRunner()
self.thisptr.reset(new cpp.DhtRunner())
def getId(self):
h = InfoHash()
h._infohash = self.thisptr.getId()
h._infohash = self.thisptr.get().getId()
return h
def getNodeId(self):
return self.thisptr.getNodeId().toString()
def bootstrap(self, str host, str port):
self.thisptr.bootstrap(host.encode(), port.encode())
return self.thisptr.get().getNodeId().toString()
def bootstrap(self, str host, str port=None):
if port:
self.thisptr.get().bootstrap(host.encode(), port.encode())
else:
self.thisptr.get().bootstrap(host.encode(), b'4222')
def run(self, Identity id=None, is_bootstrap=False, cpp.in_port_t port=0, str ipv4="", str ipv6="", DhtConfig config=DhtConfig()):
if id:
config.setIdentity(id)
if ipv4 or ipv6:
bind4 = ipv4.encode() if ipv4 else b''
bind6 = ipv6.encode() if ipv6 else b''
self.thisptr.run(bind4, bind6, str(port).encode(), config._config)
self.thisptr.get().run(bind4, bind6, str(port).encode(), config._config)
else:
self.thisptr.run(port, config._config)
self.thisptr.get().run(port, config._config)
def join(self):
self.thisptr.join()
self.thisptr.get().join()
def shutdown(self, shutdown_cb=None):
cb_obj = {'shutdown':shutdown_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
def enableLogging(self):
cpp.enableLogging(self.thisptr[0])
cpp.enableLogging(self.thisptr.get()[0])
def disableLogging(self):
cpp.disableLogging(self.thisptr[0])
cpp.disableLogging(self.thisptr.get()[0])
def enableFileLogging(self, str path):
cpp.enableFileLogging(self.thisptr[0], path)
cpp.enableFileLogging(self.thisptr.get()[0], path.encode())
def isRunning(self):
return self.thisptr.isRunning()
return self.thisptr.get().isRunning()
def getStorageLog(self):
return self.thisptr.getStorageLog().decode()
return self.thisptr.get().getStorageLog().decode()
def getRoutingTablesLog(self, cpp.sa_family_t af):
return self.thisptr.getRoutingTablesLog(af).decode()
return self.thisptr.get().getRoutingTablesLog(af).decode()
def getSearchesLog(self, cpp.sa_family_t af):
return self.thisptr.getSearchesLog(af).decode()
return self.thisptr.get().getSearchesLog(af).decode()
def getNodeMessageStats(self):
stats = []
cdef cpp.vector[unsigned] res = self.thisptr.getNodeMessageStats(False)
cdef cpp.vector[unsigned] res = self.thisptr.get().getNodeMessageStats(False)
for n in res:
stats.append(n)
return stats
@@ -304,14 +324,16 @@ cdef class DhtRunner(_WithID):
def get(self, InfoHash key, get_cb=None, done_cb=None):
"""Retreive values associated with a key on the DHT.
key -- the key for which to search
get_cb -- is set, makes the operation non-blocking. Called when a value is found on the DHT.
done_cb -- optional callback used when get_cb is set. Called when the operation is completed.
key -- the key for which to search
get_cb -- is set, makes the operation non-blocking. Called when a value
is found on the DHT.
done_cb -- optional callback used when get_cb is set. Called when the
operation is completed.
"""
if get_cb:
cb_obj = {'get':get_cb, 'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj), cpp.bindDoneCb(done_callback, <void*>cb_obj))
self.thisptr.get().get(key._infohash, cpp.bindGetCb(get_callback, <void*>cb_obj), cpp.bindDoneCb(done_callback, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
@@ -334,14 +356,14 @@ cdef class DhtRunner(_WithID):
def put(self, InfoHash key, Value val, done_cb=None):
"""Publish a new value on the DHT at key.
key -- the DHT key where to put the value
val -- the value to put on the DHT
key -- the DHT key where to put the value
val -- the value to put on the DHT
done_cb -- optional callback called when the operation is completed.
"""
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
self.thisptr.get().put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
@@ -365,9 +387,74 @@ cdef class DhtRunner(_WithID):
t._cb['cb'] = cb_obj
# avoid the callback being destructed if the token is destroyed
ref.Py_INCREF(cb_obj)
t._t = self.thisptr.listen(t._h, cpp.bindGetCb(get_callback, <void*>cb_obj)).share()
t._t = self.thisptr.get().listen(t._h, cpp.bindGetCb(get_callback, <void*>cb_obj)).share()
return t
def cancelListen(self, ListenToken token):
self.thisptr.cancelListen(token._h, token._t)
self.thisptr.get().cancelListen(token._h, token._t)
ref.Py_DECREF(<object>token._cb['cb'])
# fixme: not thread safe
cdef class IndexValue(object):
cdef cpp.shared_ptr[cpp.IndexValue] _value
def __init__(self, InfoHash h=None, cpp.uint64_t vid=0):
cdef cpp.InfoHash hh = h._infohash
self._value.reset(new cpp.IndexValue(hh, vid))
def __str__(self):
return "(" + self.getKey().toString().decode() +", "+ str(self.getValueId()) +")"
def getKey(self):
h = InfoHash()
h._infohash = self._value.get().first
return h
def getValueId(self):
return self._value.get().second
cdef class Pht(object):
cdef cpp.Pht* thisptr
def __cinit__(self, bytes name, key_spec, DhtRunner dht):
cdef cpp.IndexKeySpec cpp_key_spec
for kk, size in key_spec.items():
cpp_key_spec[bytes(kk, 'utf-8')] = size
self.thisptr = new cpp.Pht(name, cpp_key_spec, dht.thisptr)
property MAX_NODE_ENTRY_COUNT:
def __get__(self):
return cpp.PHT_MAX_NODE_ENTRY_COUNT
def lookup(self, key, lookup_cb=None, done_cb=None):
"""Query the Index with a specified key.
key -- the key for to the entry in the index.
lookup_cb -- function called when the operation is completed. This
function takes a list of IndexValue objects and a string
representation of the prefix where the value was indexed in
the PHT.
"""
cb_obj = {'lookup':lookup_cb, 'done':done_cb} # TODO: donecallback is to be removed
ref.Py_INCREF(cb_obj)
cdef cpp.IndexKey cppk
for kk, v in key.items():
cppk[bytes(kk, 'utf-8')] = bytes(v)
self.thisptr.lookup(
cppk,
cpp.Pht.bindLookupCb(lookup_callback, <void*>cb_obj),
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
)
def insert(self, key, IndexValue value, done_cb=None):
"""Add an index entry to the Index.
key -- the key for to the entry in the index.
value -- an IndexValue object describing the indexed value.
done_cb -- Called when the operation is completed.
"""
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
cdef cpp.IndexKey cppk
for kk, v in key.items():
cppk[bytes(kk, 'utf-8')] = bytes(v)
cdef cpp.IndexValue val
val.first = (<InfoHash>value.getKey())._infohash
val.second = value.getValueId()
self.thisptr.insert(
cppk,
val,
cpp.bindDoneCbSimple(done_callback_simple, <void*>cb_obj)
)
+25 -2
View File
@@ -20,6 +20,7 @@ from libcpp cimport bool
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp.utility cimport pair
from libcpp.map cimport map
ctypedef uint16_t in_port_t
ctypedef unsigned short int sa_family_t;
@@ -27,6 +28,7 @@ ctypedef unsigned short int sa_family_t;
cdef extern from "<memory>" namespace "std" nogil:
cdef cppclass shared_ptr[T]:
shared_ptr() except +
shared_ptr(T*) except +
T* get()
T operator*()
void reset(T*)
@@ -103,19 +105,21 @@ cdef extern from "opendht/callbacks.h" namespace "dht":
ctypedef void (*ShutdownCallbackRaw)(void *user_data)
ctypedef bool (*GetCallbackRaw)(shared_ptr[Value] values, void *user_data)
ctypedef void (*DoneCallbackRaw)(bool done, vector[shared_ptr[Node]]* nodes, void *user_data)
ctypedef void (*DoneCallbackSimpleRaw)(bool done, void *user_data)
cppclass ShutdownCallback:
ShutdownCallback() except +
cppclass GetCallback:
GetCallback() except +
#GetCallback(GetCallbackRaw cb, void *user_data) except +
cppclass DoneCallback:
DoneCallback() except +
#DoneCallback(DoneCallbackRaw, void *user_data) except +
cppclass DoneCallbackSimple:
DoneCallbackSimple() except +
cdef ShutdownCallback bindShutdownCb(ShutdownCallbackRaw cb, void *user_data)
cdef GetCallback bindGetCb(GetCallbackRaw cb, void *user_data)
cdef DoneCallback bindDoneCb(DoneCallbackRaw cb, void *user_data)
cdef DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw cb, void *user_data)
cppclass Config:
InfoHash node_id
@@ -156,3 +160,22 @@ cdef extern from "opendht/log.h" namespace "dht::log":
void disableLogging(DhtRunner& dht)
void enableFileLogging(DhtRunner& dht, const string& path)
cdef extern from "opendht/indexation/pht.h" namespace "dht::indexation":
size_t PHT_MAX_NODE_ENTRY_COUNT "dht::indexation::Pht::MAX_NODE_ENTRY_COUNT"
cdef cppclass Prefix:
Prefix() except +
Prefix(vector[uint8_t]) except +
string toString() const
ctypedef pair[InfoHash, uint64_t] IndexValue "dht::indexation::Value"
ctypedef map[string, vector[uint8_t]] IndexKey "dht::indexation::Pht::Key"
ctypedef map[string, uint32_t] IndexKeySpec "dht::indexation::Pht::KeySpec"
ctypedef void (*LookupCallbackRaw)(vector[shared_ptr[IndexValue]]* values, Prefix* p, void* user_data);
cdef cppclass Pht:
cppclass LookupCallback:
LookupCallback() except +
Pht(string, IndexKeySpec, shared_ptr[DhtRunner]) except +
void lookup(IndexKey k, LookupCallback cb, DoneCallbackSimple doneCb);
void insert(IndexKey k, IndexValue v, DoneCallbackSimple cb)
@staticmethod
LookupCallback bindLookupCb(LookupCallbackRaw cb, void *user_data)
+27 -7
View File
@@ -27,7 +27,7 @@ import random
from dht.network import DhtNetwork
from dht.network import DhtNetworkSubProcess
from dht.tests import PerformanceTest, PersistenceTest
from dht.tests import PerformanceTest, PersistenceTest, PhtTest
from dht import virtual_network_builder
from dht import network as dhtnetwork
@@ -66,7 +66,11 @@ class WorkBench():
def create_virtual_net(self):
if self.virtual_locs > 1:
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__), "-i", self.ifname, "-n", str(self.clusters), '-l', str(self.loss), '-d', str(self.delay)]
cmd = ["python3", os.path.abspath(virtual_network_builder.__file__),
"-i", self.ifname,
"-n", str(self.clusters),
'-l', str(self.loss),
'-d', str(self.delay)]
if not self.disable_ipv4:
cmd.append('-4')
if not self.disable_ipv6:
@@ -90,10 +94,17 @@ class WorkBench():
cmd.extend(['-b', self.local_bootstrap.ip4])
if not self.disable_ipv6 and self.local_bootstrap.ip6:
cmd.extend(['-b6', self.local_bootstrap.ip6])
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while DhtNetworkSubProcess.NOTIFY_TOKEN not in self.procs[i].getline():
# waiting for process to spawn
time.sleep(0.5)
lock = threading.Condition()
def dcb(success):
nonlocal lock
if not success:
DhtNetwork.Log.err("Failed to initialize network...")
with lock:
lock.notify()
with lock:
self.procs[i] = DhtNetworkSubProcess('node'+str(i), cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
self.procs[i].sendPing(done_cb=dcb)
lock.wait()
else:
raise Exception('First create bootstrap.')
@@ -157,11 +168,16 @@ if __name__ == '__main__':
featureArgs = parser.add_mutually_exclusive_group(required=True)
featureArgs.add_argument('--performance', action='store_true', default=False,
help='Launches performance benchmark test. Available args for "-t" are: gets.')
featureArgs.add_argument('--pht', action='store_true', default=False,
help='Launches PHT benchmark test. '\
'Available args for "-t" are: insert. '\
'Timer available by adding "timer" to "-o" args'\
'Use "-m" option for fixing number of keys to create during the test.')
featureArgs.add_argument('--data-persistence', action='store_true', default=0,
help='Launches data persistence benchmark test. '\
'Available args for "-t" are: delete, replace, mult_time. '\
'Available args for "-o" are : dump_str_log, keep_alive, trigger, traffic_plot, op_plot. '\
'Use "-m" to specify the number of producers on the DHT.'\
'Use "-m" to specify the number of producers on the DHT. '\
'Use "-e" to specify the number of values to put on the DHT.')
args = parser.parse_args()
@@ -206,6 +222,10 @@ if __name__ == '__main__':
PerformanceTest(args.test, wb, test_opt).run()
elif args.data_persistence:
PersistenceTest(args.test, wb, test_opt).run()
elif args.pht:
if args.m:
test_opt.update({ 'num_keys' : args.m })
PhtTest(args.test, wb, test_opt).run()
except Exception as e:
print(e)
+265
View File
@@ -0,0 +1,265 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2016 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 <http://www.gnu.org/licenses/>.
import os, sys, time, cmd
import subprocess
import signal
import argparse
import threading
import opendht as dht
class NodeCluster(object):
nodes = []
node_uid = 0
@staticmethod
def run_node(ip4, ip6, p, bootstrap=None, is_bootstrap=False, logfile=None):
print("run_node", ip4, ip6, p, bootstrap, logfile)
n = dht.DhtRunner()
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
if logfile:
n.enableFileLogging(logfile)
if bootstrap:
n.bootstrap(bootstrap[0], bootstrap[1])
time.sleep(.01)
return ((ip4, ip6, p), n, id)
@staticmethod
def find_ip(iface):
if not iface or iface == 'any':
return ('0.0.0.0','')
if_ip4 = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
if_ip6 = netifaces.ifaddresses(iface)[netifaces.AF_INET6][0]['addr']
return (if_ip4, if_ip6)
def __init__(self, iface=None, ip4=None, ip6=None, port=4000, bootstrap=None, first_bootstrap=False, logfile=None):
NodeCluster.iface = iface
self.port = port
ips = NodeCluster.find_ip(iface)
self.logfile = logfile
self.ip4 = ip4 if ip4 else ips[0]
self.ip6 = ip6 if ip6 else ips[1]
self.bootstrap = bootstrap
if bootstrap:
self.bootstrap = (bootstrap.hostname, str(bootstrap.port) if bootstrap.port else "4222")
else:
print("Using fallback bootstrap", self.ip4, self.port)
self.bootstrap = ((self.ip4, str(self.port)))
if first_bootstrap:
print("Starting bootstrap node")
self.nodes.append(NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
self.bootstrap = ((self.ip4, str(self.port)))
self.port += 1
#print(self.ip4, self.ip6, self.port)
def front(self):
if len(self.nodes) == 0:
return None
return self.nodes[0][1]
def get(self, i=None):
if not self.nodes:
return None
if i is None:
l = list(self.nodes)
random.shuffle(l)
return l[0][1]
else:
return self.nodes[i][1]
def getNodeInfoById(self, id=None):
if id:
for n in self.nodes:
if n[1].getNodeId() == id:
return n
return None
def launch_node(self):
node_logfile = (self.logfile + str(self.node_uid) + '.log') if self.logfile else None
n = NodeCluster.run_node(self.ip4, self.ip6, self.port, self.bootstrap, logfile=node_logfile)
self.nodes.append(n)
self.port += 1
self.node_uid += 1
return n
def end_node(self, id=None, shutdown=False, last_msg_stats=None):
"""
Ends a running node.
@param id: The 40 hex chars id of the node.
@type id: bytes
@return: If a node was deleted or not.
@rtype : boolean
"""
lock = threading.Condition()
def shutdown_cb():
nonlocal lock
NodeCluster.Log.log('Done.')
with lock:
lock.notify()
if not self.nodes:
return
elif id:
n = self.getNodeInfoById(id)
if n:
if shutdown:
with lock:
print('Waiting for node to shutdown... ')
n[1].shutdown(shutdown_cb)
lock.wait()
if last_msg_stats:
last_msg_stats.append(self.getMessageStats())
n[1].join()
self.nodes.remove(n)
print(id, 'deleted !')
return True
else:
return False
else:
n = self.nodes.pop()
n[1].join()
return True
def replace_node(self, id=None, shutdown=False, last_msg_stats=None):
random.shuffle(self.nodes)
deleted = self.end_node(id=id, shutdown=shutdown, last_msg_stats=last_msg_stats)
if deleted:
self.launch_node()
def resize(self, n):
n = min(n, 500)
l = len(self.nodes)
if n == l:
return
if n > l:
print("Launching", n-l, "nodes", self.ip4, self.ip6)
for i in range(l, n):
self.launch_node()
else:
print("Ending", l-n, "nodes", self.ip4, self.ip6)
#random.shuffle(self.nodes)
for i in range(n, l):
self.end_node()
def close(self):
self.resize(0)
def getMessageStats(self):
stats = np.array([0,0,0,0,0])
for n in self.nodes:
stats += np.array(n[1].getNodeMessageStats())
stats_list = [len(self.nodes)]
stats_list.extend(stats.tolist())
return stats_list
class ClusterShell(cmd.Cmd):
intro = 'Welcome to the OpenDHT node cluster control. Type help or ? to list commands.\n'
prompt = '>> '
net = None
node = None
log = False
def __init__(self, network):
super(ClusterShell, self).__init__()
self.net = network
def setNode(self, node=None, num=0):
if node == self.node:
return
if self.node:
self.node.disableLogging()
self.node = node
if self.node:
self.prompt = '('+str(num)+') >> '
if self.log:
self.node.enableLogging()
else:
self.prompt = '>> '
def do_exit(self, arg):
self.close()
return True
def do_node(self, arg):
if not arg:
setNode()
else:
nodenum = int(arg)
if nodenum > len(self.net.nodes) or nodenum < 1:
print("Invalid node number:", nodenum, " (accepted: 1-", len(self.net.nodes), ")")
else:
self.setNode(self.net.nodes[nodenum-1][1], nodenum)
def do_ll(self, arg):
if self.node:
print('Node', self.node.getNodeId().decode())
else:
print(len(self.net.nodes), 'nodes running.')
def do_ls(self, arg):
if self.node:
print(self.node.getSearchesLog(0))
else:
print('No node selected.')
def do_log(self, arg):
if self.node:
self.log = not self.log
if self.log:
self.node.enableLogging()
else:
self.node.disableLogging()
def do_EOF(self, line):
self.close()
return True
def close(self):
if self.net:
self.net.close()
self.net = None
if __name__ == '__main__':
import argparse
from urllib.parse import urlparse
net = None
try:
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
parser.add_argument('-n', '--node-num', help='number of dht nodes to run', type=int, default=32)
parser.add_argument('-I', '--iface', help='local interface to bind', default='any')
parser.add_argument('-p', '--port', help='start of port range (port, port+node_num)', type=int, default=4000)
parser.add_argument('-b', '--bootstrap', help='bootstrap address')
parser.add_argument('-d', '--daemonize', help='daemonize process', action='store_true')
parser.add_argument('-l', '--log', help='log file prefix')
args = parser.parse_args()
if args.bootstrap:
args.bootstrap = urlparse('dht://'+args.bootstrap)
net = NodeCluster(iface=args.iface, port=args.port, bootstrap=args.bootstrap, logfile=args.log)
net.resize(args.node_num)
if args.daemonize:
import daemon, lockfile
#pidfile=lockfile.FileLock('/var/run/dhtcluster.'+str(args.port))
with daemon.DaemonContext():
while True:
time.sleep(2)
else:
ClusterShell(net).cmdloop()
except Exception as e:
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
finally:
if net:
net.resize(0)
+234 -174
View File
@@ -25,11 +25,13 @@ import time
import threading
import queue
import re
import traceback
import ipaddress
import netifaces
import numpy as np
from pyroute2.netns.process.proxy import NSPopen
import msgpack
from opendht import *
@@ -37,8 +39,6 @@ from opendht import *
# useful functions
b_space_join = lambda *l: b' '.join(map(bytes, l))
# TODO: find where token "notifyend" gets printed... Or switch to MSGPACK for
# serialisation of packets between both processes.
class DhtNetworkSubProcess(NSPopen):
"""
Handles communication with DhtNetwork sub process.
@@ -47,20 +47,21 @@ class DhtNetworkSubProcess(NSPopen):
process' stdout until it finds 'DhtNetworkSubProcess.NOTIFY_TOKEN' token,
therefor, waits for the sub process to spawn.
"""
# Packet types
REQUEST = 'DhtNetworkSubProcess.request'
ANSWER = 'DhtNetworkSubProcess.answer'
OUT = 'DhtNetworkSubProcess.out'
# requests
NODE_PUT_REQ = b"np"
NEW_NODE_REQ = b"nn"
REMOVE_NODE_REQ = b"rn"
SHUTDOWN_NODE_REQ = b"sdn"
SHUTDOWN_REPLACE_NODE_REQ = b'sdrn'
SHUTDOWN_CLUSTER_REQ = b"sdc"
DUMP_STORAGE_REQ = b"strl"
MESSAGE_STATS = b"gms"
# tokens
NOTIFY_TOKEN = 'notify'
NOTIFY_END_TOKEN = 'notifyend'
PING_REQ = "p"
NODE_PUT_REQ = "np" # "np <hash> <value>"
NEW_NODE_REQ = "nn" # "nn"
REMOVE_NODE_REQ = "rn" # "rn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_NODE_REQ = "sdn" # "sdn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_REPLACE_NODE_REQ = "sdrn" # "sdn <id0>[ <id1>[ id2[...]]]"
SHUTDOWN_CLUSTER_REQ = "sdc" # "sdc"
DUMP_STORAGE_REQ = "strl" # "strl"
MESSAGE_STATS = "gms" # "gms"
def __init__(self, ns, cmd, quit=False, **kwargs):
super(DhtNetworkSubProcess, self).__init__(ns, cmd, **kwargs)
@@ -70,11 +71,11 @@ class DhtNetworkSubProcess(NSPopen):
self._quit = quit
self._lock = threading.Condition()
self._in_queue = queue.Queue()
self._out_queue = queue.Queue()
self._callbacks = {}
self._tid = 0
# starting thread
self._thread = threading.Thread(target=self._communicate)
self._thread.daemon = True
self._thread.start()
def __repr__(self):
@@ -92,42 +93,38 @@ class DhtNetworkSubProcess(NSPopen):
"""
Communication thread. This reads and writes to the sub process.
"""
ENCODING = 'utf-8'
sleep_time = 0.1
stdin_line, stdout_line = '', ''
# first read of process living. Expecting NOTIFY_TOKEN
while DhtNetworkSubProcess.NOTIFY_TOKEN not in stdout_line:
stdout_line = self.stdout.readline().decode()
time.sleep(sleep_time)
with self._lock:
self._out_queue.put(stdout_line)
while not self._quit:
with self._lock:
try:
stdin_line = self._in_queue.get_nowait()
packet = self._in_queue.get_nowait()
# sending data to sub process
self.stdin.write(stdin_line if isinstance(stdin_line, bytes) else
bytes(str(stdin_line), encoding=ENCODING))
self.stdin.write(packet)
self.stdin.flush()
except queue.Empty:
#waiting for next stdin req to send
self._lock.wait(timeout=sleep_time)
pass
# reading response from sub process
for stdout_line in iter(self.stdout.readline, b''):
stdout_line = stdout_line.decode().replace('\n', '')
if stdout_line:
with self._lock:
self._out_queue.put(stdout_line)
# reading from sub process
out_string = ''
for p in msgpack.Unpacker(self.stdout):
if isinstance(p, dict):
self._process_packet(p)
else:
# Some non-msgpack data could slip into the stream. We
# have to treat those as characters.
out_string += chr(p)
if out_string:
print(out_string)
#waiting for next stdin req to send
self._lock.wait(timeout=sleep_time)
with self._lock:
self._lock.notify()
def stop_communicating(self):
def _stop_communicating(self):
"""
Stops the I/O thread from communicating with the subprocess.
"""
@@ -142,12 +139,12 @@ class DhtNetworkSubProcess(NSPopen):
Notifies thread and sub process to terminate. This is blocking call
until the sub process finishes.
"""
self.stop_communicating()
self._stop_communicating()
self.send_signal(signal.SIGINT);
self.wait()
self.release()
def send(self, msg):
def _send(self, msg):
"""
Send data to sub process.
"""
@@ -155,83 +152,76 @@ class DhtNetworkSubProcess(NSPopen):
self._in_queue.put(msg)
self._lock.notify()
def getline(self):
def _process_packet(self, p):
"""
Read line from sub process.
@return: A line on sub process' stdout.
@rtype : str
Process msgpack packet received from
"""
line = ''
with self._lock:
try:
line = self._out_queue.get_nowait()
except queue.Empty:
pass
return line
if not b'tid' in p:
DhtNetwork.Log.err('Bad packet...')
try:
self._callbacks[p[b'tid']](p)
except KeyError:
DhtNetwork.Log.err('Unknown tid...')
def getlinesUntilNotify(self, answer_cb=None):
"""
Reads the stdout queue until a proper notification is given by the sub
process.
@param answer_cb: Callback to call when an answer is given after notify.
The function takes a list of strings as argument.
@type answer_cb: function
"""
notified = False
answer = []
while True:
out = self.getline()
if out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_TOKEN:
notified = True
elif notified and out.split(' ')[0] == DhtNetworkSubProcess.NOTIFY_END_TOKEN:
if answer_cb:
answer_cb(answer)
break
elif notified:
answer.append(out)
elif out:
yield out
else:
time.sleep(0.1)
def _sendRequest(self, request, answer_cb=None):
def _sendRequest(self, request, tid, done_cb):
"""
Sends a request to the sub network and wait for output.
@param request: The serialized request.
@type request: bytes
@type request: Msgpack object
"""
self.send(request + b'\n')
for line in self.getlinesUntilNotify(answer_cb=answer_cb):
DhtNetwork.log(line)
self._callbacks[tid] = done_cb
self._send(request)
def sendGetMessageStats(self):
def sendPing(self, done_cb=None):
"""Sends a ping request to the DhtNetworkSubProcess.
@param done_cb: The callback to be executed when we get a response. This
function takes a boolean "success" as parameter.
@type done_cb: Function
"""
self._tid += 1
def dcb(packet):
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.PING_REQ
}), self._tid, dcb)
def sendGetMessageStats(self, done_cb=None):
"""
Sends DhtNetwork sub process statistics request about nodes messages
sent.
@param done_cb: A function taking as parameter the returned list of
stats.
@type done_cb: function
@return: A list [num_nodes, ping, find, get, put, listen].
@rtype : list
"""
stats = []
def cb(answer):
"""
Callback fed to getlinesUntilNotify made to recover answer from the
DhtNetwork sub process.
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
stats = packet[b'stats']
done_cb([] if not isinstance(stats, list) else done_cb(stats))
except KeyError:
done_cb([])
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.MESSAGE_STATS
}), self._tid, dcb)
@param answer: the list of lines answered by the sub process.
@type answer: function
"""
nonlocal stats
if answer:
stats = [int(v) for v in re.findall("[0-9]+", answer.pop())]
self._sendRequest(DhtNetworkSubProcess.MESSAGE_STATS, answer_cb=cb)
return stats
def sendNodePutRequest(self, _hash, value):
def sendClusterPutRequest(self, _hash, value, done_cb=None):
"""
Sends a put operation request.
@@ -239,40 +229,89 @@ class DhtNetworkSubProcess(NSPopen):
@type _hash: bytes.
@param value: the value.
@type value: bytes.
@param done_cb: A function taking as parameter a boolean "success".
@type done_cb: function
"""
self._sendRequest(b_space_join(DhtNetworkSubProcess.NODE_PUT_REQ, _hash,
value))
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : DhtNetworkSubProcess.NODE_PUT_REQ,
'hash' : _hash,
'value' : value
}), self._tid, dcb)
def sendNodesRequest(self, request, ids=b''):
def sendClusterRequest(self, request, ids=[], done_cb=None):
"""
Send request to a list of nodes or the whole cluster.
@param request: The request. Possible values are:
DhtNetworkSubProcess.NODE_PUT_REQ
DhtNetworkSubProcess.REMOVE_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
DhtNetworkSubProcess.DUMP_STORAGE_REQ
DhtNetworkSubProcess.MESSAGE_STATS
@type request: bytes
@param ids: The list of ids concerned by the request.
@type ids: list
"""
self._sendRequest(b_space_join(request, b_space_join(*ids)))
self._tid += 1
def dcb(packet):
nonlocal done_cb
if not done_cb:
return
try:
done_cb(packet[b'success'])
except KeyError:
done_cb(False)
self._sendRequest(msgpack.packb({
DhtNetworkSubProcess.REQUEST : True,
'tid' : self._tid,
'req' : request,
'ids' : ids
}), self._tid, dcb)
class DhtNetwork(object):
nodes = []
@staticmethod
def log(*to_print):
class Log(object):
BOLD = "\033[1m"
NORMAL = "\033[0m"
print('%s[DhtNetwork-%s]%s' % (BOLD, DhtNetwork.iface, NORMAL), ':' , *to_print, file=sys.stderr)
WHITE = "\033[97m"
RED = "\033[31m"
YELLOW = "\033[33m"
@staticmethod
def _log_with_color(*to_print, color=None):
color = color if color else DhtNetwork.Log.WHITE
print('%s%s[DhtNetwork-%s]%s%s' %
(DhtNetwork.Log.BOLD, color, DhtNetwork.iface, DhtNetwork.Log.NORMAL, color),
*to_print, DhtNetwork.Log.NORMAL, file=sys.stderr)
@staticmethod
def log(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.WHITE)
@staticmethod
def warn(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.YELLOW)
@staticmethod
def err(*to_print):
DhtNetwork.Log._log_with_color(*to_print, color=DhtNetwork.Log.RED)
@staticmethod
def run_node(ip4, ip6, p, bootstrap=[], is_bootstrap=False):
DhtNetwork.log("run_node", ip4, ip6, p, bootstrap)
DhtNetwork.Log.log("run_node", ip4, ip6, p, bootstrap)
n = DhtRunner()
n.run(ipv4=ip4 if ip4 else "", ipv6=ip6 if ip6 else "", port=p, is_bootstrap=is_bootstrap)
for b in bootstrap:
@@ -297,7 +336,7 @@ class DhtNetwork(object):
self.ip6 = ip6 if ip6 else ips[1]
self.bootstrap = bootstrap
if first_bootstrap:
DhtNetwork.log("Starting bootstrap node")
DhtNetwork.Log.log("Starting bootstrap node")
self.nodes.append(DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap, is_bootstrap=True))
self.bootstrap = [(self.ip4, str(self.port))]
self.port += 1
@@ -309,6 +348,9 @@ class DhtNetwork(object):
return self.nodes[0][1]
def get(self, i=None):
if not self.nodes:
return None
if i is None:
l = list(self.nodes)
random.shuffle(l)
@@ -321,14 +363,13 @@ class DhtNetwork(object):
for n in self.nodes:
if n[1].getNodeId() == id:
return n
else:
return None
return None
def launch_node(self):
n = DhtNetwork.run_node(self.ip4, self.ip6, self.port, self.bootstrap)
self.nodes.append(n)
if not self.bootstrap:
DhtNetwork.log("Using fallback bootstrap", self.ip4, self.port)
DhtNetwork.Log.log("Using fallback bootstrap", self.ip4, self.port)
self.bootstrap = [(self.ip4, str(self.port))]
self.port += 1
return n
@@ -346,25 +387,25 @@ class DhtNetwork(object):
lock = threading.Condition()
def shutdown_cb():
nonlocal lock
DhtNetwork.log('Done.')
DhtNetwork.Log.log('Done.')
with lock:
lock.notify()
if not self.nodes:
return
elif id is not None:
elif id:
n = self.getNodeInfoById(id)
if n:
if shutdown:
with lock:
DhtNetwork.log('Waiting for node to shutdown... ')
DhtNetwork.Log.log('Waiting for node to shutdown... ')
n[1].shutdown(shutdown_cb)
lock.wait()
if last_msg_stats:
last_msg_stats.append(self.getMessageStats())
n[1].join()
self.nodes.remove(n)
DhtNetwork.log(id, 'deleted !')
DhtNetwork.Log.log(id, 'deleted !')
return True
else:
return False
@@ -385,11 +426,11 @@ class DhtNetwork(object):
if n == l:
return
if n > l:
DhtNetwork.log("Launching", n-l, "nodes", self.ip4, self.ip6)
DhtNetwork.Log.log("Launching", n-l, "nodes", self.ip4, self.ip6)
for i in range(l, n):
self.launch_node()
else:
DhtNetwork.log("Ending", l-n, "nodes", self.ip4, self.ip6)
DhtNetwork.Log.log("Ending", l-n, "nodes", self.ip4, self.ip6)
#random.shuffle(self.nodes)
for i in range(n, l):
self.end_node()
@@ -409,30 +450,39 @@ if __name__ == '__main__':
lock = threading.Condition()
quit = False
def notify_benchmark(answer=[]):
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_TOKEN)
for line in answer:
sys.stdout.write(str(line)+'\n')
sys.stdout.write('%s\n' % DhtNetworkSubProcess.NOTIFY_END_TOKEN)
sys.stdout.flush()
def send_msgpack_packet(packet):
sys.stdout.buffer.write(packet)
sys.stdout.buffer.flush()
def listen_to_mother_nature(stdin, q):
def notify_benchmark(packet, success):
"""Notifies the benchmark when an operation has been completed.
@param success: If the operation has been successful
@type success: boolean
@param packet: The packet we are providing an answer for.
@type packet: dict
"""
send_msgpack_packet(msgpack.packb({
DhtNetworkSubProcess.ANSWER : True,
'tid' : packet[b'tid'],
'success' : success
}))
def send_stats(packet, stats):
send_msgpack_packet(msgpack.packb({
DhtNetworkSubProcess.ANSWER : True,
'tid' : packet[b'tid'],
'stats' : stats
}))
def listen_to_mother_nature(q):
global quit
def parse_req(req):
split_req = req.split(' ')
op = split_req[0]
hashes = [this_hash.replace('\n', '').encode() for this_hash in split_req[1:]]
return (op, hashes)
while not quit:
req = stdin.readline()
parsed_req = parse_req(req)
q.put(parsed_req)
with lock:
lock.notify()
for p in msgpack.Unpacker(sys.stdin.buffer.raw):
if isinstance(p, dict) and DhtNetworkSubProcess.REQUEST.encode() in p:
with lock:
q.put(p)
lock.notify()
def handler(signum, frame):
global quit
@@ -466,48 +516,52 @@ if __name__ == '__main__':
net.resize(args.node_num)
q = queue.Queue()
t = threading.Thread(target=listen_to_mother_nature, args=(sys.stdin, q))
t = threading.Thread(target=listen_to_mother_nature, args=tuple([q]))
t.daemon = True
t.start()
notify_benchmark()
msg_stats = []
with lock:
while not quit:
lock.wait()
try:
req,req_args = q.get_nowait()
packet = q.get_nowait()
except queue.Empty:
pass
lock.wait()
else:
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ.decode()
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ.decode()
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ.decode()
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ.decode()
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ.decode()
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ.decode()
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ.decode()
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS.decode()
NODE_PUT_REQ = DhtNetworkSubProcess.NODE_PUT_REQ
NEW_NODE_REQ = DhtNetworkSubProcess.NEW_NODE_REQ
REMOVE_NODE_REQ = DhtNetworkSubProcess.REMOVE_NODE_REQ
SHUTDOWN_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_NODE_REQ
SHUTDOWN_REPLACE_NODE_REQ = DhtNetworkSubProcess.SHUTDOWN_REPLACE_NODE_REQ
SHUTDOWN_CLUSTER_REQ = DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ
DUMP_STORAGE_REQ = DhtNetworkSubProcess.DUMP_STORAGE_REQ
MESSAGE_STATS = DhtNetworkSubProcess.MESSAGE_STATS
if req in [SHUTDOWN_NODE_REQ,
SHUTDOWN_REPLACE_NODE_REQ,
REMOVE_NODE_REQ]:
def delete_request(req, n):
req = packet[b'req'].decode()
success = True
if req in [SHUTDOWN_NODE_REQ, SHUTDOWN_REPLACE_NODE_REQ, REMOVE_NODE_REQ]:
def delete_request(req, nid):
global msg_stats
if not nid:
return
if req == SHUTDOWN_NODE_REQ:
net.end_node(id=n, shutdown=True, last_msg_stats=msg_stats)
net.end_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
elif req == SHUTDOWN_REPLACE_NODE_REQ:
net.replace_node(id=n, shutdown=True, last_msg_stats=msg_stats)
net.replace_node(id=nid, shutdown=True, last_msg_stats=msg_stats)
elif req == REMOVE_NODE_REQ:
net.end_node(id=n, last_msg_stats=msg_stats)
net.end_node(id=nid, last_msg_stats=msg_stats)
if len(req) > 0:
for n in req_args:
delete_request(req, n)
nodes = packet[b'ids']
if nodes:
for nid in nodes:
delete_request(req, nid)
else:
delete_request(req, net.get().getNodeId())
n = net.get()
if n:
delete_request(req, n.getNodeId())
else:
success = False
elif req == SHUTDOWN_CLUSTER_REQ:
for n in net.nodes:
net.end_node(id=n[2], shutdown=True, last_msg_stats=msg_stats)
@@ -515,20 +569,26 @@ if __name__ == '__main__':
elif req == NEW_NODE_REQ:
net.launch_node()
elif req == NODE_PUT_REQ:
_hash, v = req_args[:2]
net.get().put(InfoHash(_hash), Value(v))
_hash = packet[b'hash']
v = packet[b'value']
n = net.get()
if n:
n.put(InfoHash(_hash), Value(v))
else:
success = False
elif req == DUMP_STORAGE_REQ:
for n in [m[1] for m in net.nodes if m[1].getNodeId() in req_args]:
hashes = packet[b'ids']
for n in [m[1] for m in net.nodes if m[1].getNodeId() in hashes]:
net.log(n.getStorageLog())
elif MESSAGE_STATS in req:
elif req == MESSAGE_STATS:
stats = sum([np.array(x) for x in [net.getMessageStats()]+msg_stats])
notify_benchmark(answer=[stats])
send_stats(packet, [int(_) for _ in stats])
msg_stats.clear()
continue
notify_benchmark()
notify_benchmark(packet, success)
except Exception as e:
DhtNetwork.log(e)
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
finally:
if net:
net.resize(0)
+362 -120
View File
@@ -3,6 +3,7 @@
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
import sys
import os
import threading
import random
@@ -10,10 +11,16 @@ import string
import time
import subprocess
import re
import collections
from matplotlib.ticker import FuncFormatter
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout
from opendht import *
from dht.network import DhtNetwork, DhtNetworkSubProcess
@@ -27,8 +34,40 @@ bit_format = None
Kbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-1) + 'Kb')
Mbit_format = FuncFormatter(lambda x, pos: '%1.1f' % (x*1024**-2) + 'Mb')
def random_str_val(size=1024):
"""Creates a random string value of specified size.
@param size: Size, in bytes, of the value.
@type size: int
@return: Random string value
@rtype : str
"""
return ''.join(random.choice(string.hexdigits) for _ in range(size))
def random_hash():
return InfoHash(''.join(random.SystemRandom().choice(string.hexdigits) for _ in range(40)).encode())
"""Creates random InfoHash.
"""
return InfoHash(random_str_val(size=40).encode())
def timer(f, *args):
"""
Start a timer which count time taken for execute function f
@param f : Function to time
@type f : function
@param args : Arguments of the function f
@type args : list
@rtype : timer
@return : Time taken by the function f
"""
start = time.time()
f(*args)
return time.time() - start
def reset_before_test(featureTestMethod):
"""
@@ -70,6 +109,21 @@ def display_plot(yvals, xvals=None, yformatter=None, display_time=3, **kwargs):
plt.plot(yvals, **kwargs)
plt.pause(display_time)
def display_traffic_plot(ifname):
"""Displays the traffic plot for a given interface name.
@param ifname: Interface name.
@type ifname: string
"""
ydata = []
xdata = []
# warning: infinite loop
interval = 2
for rate in iftop_traffic_data(ifname, interval=interval):
ydata.append(rate)
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
"""
Generator (yields data) function collecting traffic data from iftop
@@ -125,13 +179,13 @@ def iftop_traffic_data(ifname, interval=2, rate_type='send_receive'):
###########
class FeatureTest(object):
done = 0
lock = None
"""
This is a base test.
"""
done = 0
lock = None
def __init__(self, test, workbench):
"""
@param test: The test string indicating the test to run. This string is
@@ -143,6 +197,7 @@ class FeatureTest(object):
"""
self._test = test
self._workbench = workbench
self._bootstrap = self._workbench.get_bootstrap()
def _reset(self):
"""
@@ -156,7 +211,155 @@ class FeatureTest(object):
def run(self):
raise NotImplementedError('This method must be implemented.')
##################################
# PHT #
##################################
class PhtTest(FeatureTest):
"""TODO
"""
indexEntries = None
prefix = None
key = None
def __init__(self, test, workbench, opts):
"""
@param test: is one of the following:
- 'insert': indexes a considerable amount of data in
the PHT structure.
TODO
@type test: string
@param opts: Dictionnary containing options for the test. Allowed
options are:
- 'num_keys': this specifies the number of keys to insert
in the PHT during the test.
@type opts: dict
"""
super(PhtTest, self).__init__(test, workbench)
self._num_keys = opts['num_keys'] if 'num_keys' in opts else 32
self._timer = True if 'timer' in opts else False
def _reset(self):
super(PhtTest, self)._reset()
PhtTest.indexEntries = []
@staticmethod
def lookupCb(vals, prefix):
PhtTest.indexEntries = list(vals)
PhtTest.prefix = prefix.decode()
DhtNetwork.log('Index name: <todo>')
DhtNetwork.log('Leaf prefix:', prefix)
for v in vals:
DhtNetwork.log('[ENTRY]:', v)
@staticmethod
def lookupDoneCb(ok):
DhtNetwork.log('[LOOKUP]:', PhtTest.key, "--", "success!" if ok else "Fail...")
with FeatureTest.lock:
FeatureTest.lock.notify()
@staticmethod
def insertDoneCb(ok):
DhtNetwork.log('[INSERT]:', PhtTest.key, "--", "success!" if ok else "Fail...")
with FeatureTest.lock:
FeatureTest.lock.notify()
@staticmethod
def drawTrie(trie_dict):
"""
Draws the trie structure of the PHT from dictionnary.
@param trie_dict: Dictionnary of index entries (prefix -> entry).
@type trie_dict: dict
"""
prefixes = list(trie_dict.keys())
if len(prefixes) == 0:
return
edges = list([])
for prefix in prefixes:
for i in range(-1, len(prefix)-1):
u = prefix[:i+1]
x = ("." if i == -1 else u, u+"0")
y = ("." if i == -1 else u, u+"1")
if x not in edges:
edges.append(x)
if y not in edges:
edges.append(y)
# TODO: use a binary tree position layout...
# UPDATE : In a better way [change lib]
G = nx.Graph(sorted(edges, key=lambda x: len(x[0])))
plt.title("PHT: Tree")
pos=graphviz_layout(G,prog='dot')
nx.draw(G, pos, with_labels=True, node_color='white')
plt.show()
def run(self):
try:
if self._test == 'insert':
self._insertTest()
except Exception as e:
print(e)
finally:
self._bootstrap.resize(1)
###########
# Tests #
###########
@reset_before_test
def _insertTest(self):
"""TODO: Docstring for _massIndexTest.
"""
bootstrap = self._bootstrap
bootstrap.resize(2)
dht = bootstrap.get(1)
NUM_DIG = max(math.log(self._num_keys, 2)/4, 5) # at least 5 digit keys.
keyspec = collections.OrderedDict([('foo', NUM_DIG)])
pht = Pht(b'foo_index', keyspec, dht)
DhtNetwork.log('PHT has',
pht.MAX_NODE_ENTRY_COUNT,
'node'+ ('s' if pht.MAX_NODE_ENTRY_COUNT > 1 else ''),
'per leaf bucket.')
keys = [{
[_ for _ in keyspec.keys()][0] :
''.join(random.SystemRandom().choice(string.hexdigits)
for _ in range(NUM_DIG)).encode()
} for n in range(self._num_keys)]
all_entries = {}
# Index all entries.
for key in keys:
PhtTest.key = key
with FeatureTest.lock:
time_taken = timer(pht.insert, key, IndexValue(random_hash()), PhtTest.insertDoneCb)
if self._timer:
DhtNetwork.log('This insert step took : ', time_taken, 'second')
FeatureTest.lock.wait()
time.sleep(1)
# Recover entries now that the trie is complete.
for key in keys:
PhtTest.key = key
with FeatureTest.lock:
time_taken = timer(pht.lookup, key, PhtTest.lookupCb, PhtTest.lookupDoneCb)
if self._timer:
DhtNetwork.log('This lookup step took : ', time_taken, 'second')
FeatureTest.lock.wait()
all_entries[PhtTest.prefix] = [e.__str__()
for e in PhtTest.indexEntries]
for p in all_entries.keys():
DhtNetwork.log('All entries under prefix', p, ':')
DhtNetwork.log(all_entries[p])
PhtTest.drawTrie(all_entries)
##################################
# DHT #
@@ -164,7 +367,7 @@ class FeatureTest(object):
class DhtFeatureTest(FeatureTest):
"""
This is base test. A method run() implementation is required.
This is a base dht test.
"""
#static variables used by class callbacks
successfullTransfer = lambda lv,fv: len(lv) == len(fv)
@@ -173,7 +376,6 @@ class DhtFeatureTest(FeatureTest):
def __init__(self, test, workbench):
super(DhtFeatureTest, self).__init__(test, workbench)
self.bootstrap = self._workbench.get_bootstrap()
def _reset(self):
super(DhtFeatureTest, self)._reset()
@@ -183,15 +385,15 @@ class DhtFeatureTest(FeatureTest):
@staticmethod
def getcb(value):
vstr = value.__str__()[:100]
DhtNetwork.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
DhtNetwork.Log.log('[GET]: %s' % vstr + ("..." if len(vstr) > 100 else ""))
DhtFeatureTest.foreignValues.append(value)
return True
@staticmethod
def putDoneCb(ok, nodes):
if not ok:
DhtNetwork.log("[PUT]: failed!")
with FeatureTest.lock:
if not ok:
DhtNetwork.Log.log("[PUT]: failed!")
FeatureTest.done -= 1
FeatureTest.lock.notify()
@@ -199,7 +401,7 @@ class DhtFeatureTest(FeatureTest):
def getDoneCb(ok, nodes):
with FeatureTest.lock:
if not ok:
DhtNetwork.log("[GET]: failed!")
DhtNetwork.Log.log("[GET]: failed!")
else:
for node in nodes:
if not node.getNode().isExpired():
@@ -210,10 +412,10 @@ class DhtFeatureTest(FeatureTest):
def _dhtPut(self, producer, _hash, *values):
with FeatureTest.lock:
for val in values:
vstr = val.__str__()[:100]
DhtNetwork.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
vstr = val.__str__()[:100]
DhtNetwork.Log.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
while FeatureTest.done > 0:
FeatureTest.lock.wait()
@@ -222,7 +424,7 @@ class DhtFeatureTest(FeatureTest):
DhtFeatureTest.foreignNodes = []
with FeatureTest.lock:
FeatureTest.done += 1
DhtNetwork.log('[GET]:', _hash.toString())
DhtNetwork.Log.log('[GET]:', _hash.toString())
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
while FeatureTest.done > 0:
FeatureTest.lock.wait()
@@ -234,7 +436,6 @@ class DhtFeatureTest(FeatureTest):
for n in DhtFeatureTest.foreignNodes:
nodes.add(n)
class PersistenceTest(DhtFeatureTest):
"""
This tests persistence of data on the network.
@@ -292,8 +493,8 @@ class PersistenceTest(DhtFeatureTest):
config.setNodeId(InfoHash(_hash_str.encode()))
n = DhtRunner()
n.run(config=config)
n.bootstrap(self.bootstrap.ip4,
str(self.bootstrap.port))
n.bootstrap(self._bootstrap.ip4,
str(self._bootstrap.port))
DhtNetwork.log('Node','['+_hash_str+']',
'started around', _hash.toString().decode()
if n.isRunning() else
@@ -302,24 +503,24 @@ class PersistenceTest(DhtFeatureTest):
trigger_nodes.append(n)
def _result(self, local_values, new_nodes):
bootstrap = self.bootstrap
bootstrap = self._bootstrap
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
DhtNetwork.log('[GET]: Only %s on %s values persisted.' %
DhtNetwork.Log.log('[GET]: Only %s on %s values persisted.' %
(len(DhtFeatureTest.foreignValues), len(local_values)))
else:
DhtNetwork.log('[GET]: All values successfully persisted.')
DhtNetwork.Log.log('[GET]: All values successfully persisted.')
if DhtFeatureTest.foreignValues:
if new_nodes:
DhtNetwork.log('Values are newly found on:')
DhtNetwork.Log.log('Values are newly found on:')
for node in new_nodes:
DhtNetwork.log(node)
DhtNetwork.Log.log(node)
if self._dump_storage:
DhtNetwork.log('Dumping all storage log from '\
DhtNetwork.Log.log('Dumping all storage log from '\
'hosting nodes.')
for proc in self._workbench.procs:
proc.sendNodesRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
proc.sendClusterRequest(DhtNetworkSubProcess.DUMP_STORAGE_REQ, DhtFeatureTest.foreignNodes)
else:
DhtNetwork.log("Values didn't reach new hosting nodes after shutdown.")
DhtNetwork.Log.log("Values didn't reach new hosting nodes after shutdown.")
def run(self):
try:
@@ -334,13 +535,14 @@ class PersistenceTest(DhtFeatureTest):
else:
raise NameError("This test is not defined '" + self._test + "'")
except Exception as e:
print(e)
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
finally:
if self._traffic_plot or self._op_plot:
plot_fname = "traffic-plot"
print('plot saved to', plot_fname)
plt.savefig(plot_fname)
self.bootstrap.resize(1)
self._bootstrap.resize(1)
###########
# Tests #
@@ -353,71 +555,89 @@ class PersistenceTest(DhtFeatureTest):
"""
trigger_nodes = []
wb = self._workbench
bootstrap = self.bootstrap
bootstrap = self._bootstrap
# Value representing an ICE packet. Each ICE packet is around 1KB.
VALUE_SIZE = 1024
NUM_VALUES = self._num_values/wb.node_num if self._num_values else 5
nr_values = NUM_VALUES * wb.node_num
nr_nodes = wb.node_num
nr_nodes_cv = threading.Condition()
num_values_per_hash = self._num_values/wb.node_num if self._num_values else 5
values = [b''.join(random.choice(string.hexdigits).encode() for _ in range(VALUE_SIZE)) for __ in range(NUM_VALUES)]
# nodes and values counters
total_nr_values = 0
nr_nodes = wb.node_num
op_cv = threading.Condition()
# values string in string format. Used for sending cluster request.
hashes = [random_hash() for _ in range(wb.node_num)]
# initial set of values
i = 0
for h in hashes:
self._dhtPut(bootstrap.front(), h, *[Value(v) for v in values])
print("at: ", i)
i += 1
def normalBehavior(do, t, log=None):
nonlocal nr_values
def normalBehavior(do, t):
nonlocal total_nr_values, op_cv
while True:
do()
time.sleep(random.choice(range(t)))
with op_cv:
do()
time.sleep(random.uniform(0.0, float(t)))
def putRequest():
nonlocal hashes, values, nr_values
nr_values += 1
DhtNetwork.log("Random value put on the DHT.", "(now "+ str(nr_values)+" values on the dht)")
random.choice(wb.procs).sendNodePutRequest(random.choice(hashes).toString(), random.choice(values))
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30))
nonlocal hashes, VALUE_SIZE, total_nr_values
lock = threading.Condition()
def dcb(success):
nonlocal total_nr_values, lock
if success:
total_nr_values += 1
DhtNetwork.Log.log("INFO: "+ str(total_nr_values)+" values put on the dht since begining")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Random value put on the DHT...")
random.choice(wb.procs).sendClusterPutRequest(random.choice(hashes).toString(),
random_str_val(size=VALUE_SIZE).encode(),
done_cb=dcb)
lock.wait()
puts = threading.Thread(target=normalBehavior, args=(putRequest, 30.0/wb.node_num))
puts.daemon = True
puts.start()
def newNodeRequest():
nonlocal nr_nodes
with nr_nodes_cv:
lock = threading.Condition()
def dcb(success):
nonlocal nr_nodes, lock
nr_nodes += 1
DhtNetwork.log("Node joining the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
nr_nodes_cv.notify()
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.NEW_NODE_REQ)
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*60))
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Node joining...")
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.NEW_NODE_REQ, done_cb=dcb)
lock.wait()
connections = threading.Thread(target=normalBehavior, args=(newNodeRequest, 1*50.0/wb.node_num))
connections.daemon = True
connections.start()
def shutdownNodeRequest():
nonlocal nr_nodes
with nr_nodes_cv:
nr_nodes -= 1
DhtNetwork.log("Node quitting the DHT.", "(now "+str(nr_nodes)+" nodes on the dht)")
nr_nodes_cv.notify()
random.choice(wb.procs).sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ)
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60))
lock = threading.Condition()
def dcb(success):
nonlocal nr_nodes, lock
if success:
nr_nodes -= 1
DhtNetwork.Log.log("INFO: now "+str(nr_nodes)+" nodes on the dht")
else:
DhtNetwork.Log.err("Oops.. No node to shutodwn.")
with lock:
lock.notify()
with lock:
DhtNetwork.Log.warn("Node shutting down...")
random.choice(wb.procs).sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_NODE_REQ, done_cb=dcb)
lock.wait()
shutdowns = threading.Thread(target=normalBehavior, args=(shutdownNodeRequest, 1*60.0/wb.node_num))
shutdowns.daemon = True
shutdowns.start()
for h in hashes:
self._trigger_dp(trigger_nodes, h)
if self._traffic_plot:
ydata = []
xdata = []
# warning: infinite loop
interval = 2
for rate in iftop_traffic_data("br"+wb.ifname, interval=interval):
ydata.append(rate)
xdata.append((xdata[-1] if len(xdata) > 0 else 0) + interval)
display_plot(ydata, xvals=xdata, yformatter=Kbit_format, color='blue')
display_traffic_plot('br'+wb.ifname)
else:
# blocks in matplotlib thread
while True:
@@ -430,7 +650,7 @@ class PersistenceTest(DhtFeatureTest):
It uses Dht shutdown call from the API to gracefuly finish the nodes one
after the other.
"""
bootstrap = self.bootstrap
bootstrap = self._bootstrap
ops_count = []
@@ -447,36 +667,54 @@ class PersistenceTest(DhtFeatureTest):
self._dhtGet(consumer, myhash)
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
if DhtFeatureTest.foreignValues:
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
len(local_values), ' values successfully put.')
else:
DhtNetwork.log('[GET]: 0 values successfully put')
DhtNetwork.Log.log('[GET]: 0 values successfully put')
if DhtFeatureTest.foreignValues and DhtFeatureTest.foreignNodes:
DhtNetwork.log('Values are found on :')
DhtNetwork.Log.log('Values are found on :')
for node in DhtFeatureTest.foreignNodes:
DhtNetwork.log(node)
DhtNetwork.Log.log(node)
for _ in range(max(1, int(self._workbench.node_num/32))):
DhtNetwork.log('Removing all nodes hosting target values...')
DhtNetwork.Log.log('Removing all nodes hosting target values...')
cluster_ops_count = 0
for proc in self._workbench.procs:
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
proc.sendNodesRequest(
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
lock = threading.Condition()
def dcb(success):
nonlocal lock
if not success:
DhtNetwork.Log.err("Failed to shutdown.")
with lock:
lock.notify()
with lock:
proc.sendClusterRequest(
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
DhtFeatureTest.foreignNodes
)
DhtNetwork.log('sending message stats request')
stats = proc.sendGetMessageStats()
cluster_ops_count += sum(stats[1:])
DhtNetwork.log("5 seconds wait...")
DhtFeatureTest.foreignNodes,
done_cb=dcb
)
lock.wait()
DhtNetwork.Log.log('sending message stats request')
def msg_dcb(stats):
nonlocal cluster_ops_count, lock
if stats:
cluster_ops_count += sum(stats[1:])
with lock:
lock.notify()
with lock:
proc.sendGetMessageStats(done_cb=msg_dcb)
lock.wait()
DhtNetwork.Log.log("5 seconds wait...")
time.sleep(5)
ops_count.append(cluster_ops_count/self._workbench.node_num)
# checking if values were transfered to new nodes
foreignNodes_before_delete = DhtFeatureTest.foreignNodes
DhtNetwork.log('[GET]: trying to fetch persistent values')
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
self._dhtGet(consumer, myhash)
new_nodes = set(DhtFeatureTest.foreignNodes) - set(foreignNodes_before_delete)
@@ -485,7 +723,11 @@ class PersistenceTest(DhtFeatureTest):
if self._op_plot:
display_plot(ops_count, color='blue')
else:
DhtNetwork.log("[GET]: either couldn't fetch values or nodes hosting values...")
DhtNetwork.Log.log("[GET]: either couldn't fetch values or nodes hosting values...")
if traffic_plot_thread:
print("Traffic plot running for ever. Ctrl-c for stopping it.")
traffic_plot_thread.join()
@reset_before_test
def _replaceClusterTest(self):
@@ -494,7 +736,7 @@ class PersistenceTest(DhtFeatureTest):
"""
clusters = 8
bootstrap = self.bootstrap
bootstrap = self._bootstrap
bootstrap.resize(3)
consumer = bootstrap.get(1)
@@ -507,16 +749,16 @@ class PersistenceTest(DhtFeatureTest):
self._dhtGet(consumer, myhash)
initial_nodes = DhtFeatureTest.foreignNodes
DhtNetwork.log('Replacing', clusters, 'random clusters successively...')
DhtNetwork.Log.log('Replacing', clusters, 'random clusters successively...')
for n in range(clusters):
i = random.randint(0, len(self._workbench.procs)-1)
proc = self._workbench.procs[i]
DhtNetwork.log('Replacing', proc)
proc.sendNodesRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
DhtNetwork.Log.log('Replacing', proc)
proc.sendClusterRequest(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ)
self._workbench.stop_cluster(i)
self._workbench.start_cluster(i)
DhtNetwork.log('[GET]: trying to fetch persistent values')
DhtNetwork.Log.log('[GET]: trying to fetch persistent values')
self._dhtGet(consumer, myhash)
new_nodes = set(DhtFeatureTest.foreignNodes) - set(initial_nodes)
@@ -531,17 +773,17 @@ class PersistenceTest(DhtFeatureTest):
minutes for the nodes to trigger storage maintenance.
"""
trigger_nodes = []
bootstrap = self.bootstrap
bootstrap = self._bootstrap
N_PRODUCERS = self._num_producers if self._num_values else 16
DP_TIMEOUT = 1
hashes = []
# Generating considerable amount of values of size 1KB.
# Generating considerable amount of values of size 1KB.
VALUE_SIZE = 1024
NUM_VALUES = self._num_values if self._num_values else 50
values = [Value(''.join(random.choice(string.hexdigits) for _ in range(VALUE_SIZE)).encode()) for _ in range(NUM_VALUES)]
values = [Value(random_str_val(size=VALUE_SIZE).encode()) for _ in range(NUM_VALUES)]
bootstrap.resize(N_PRODUCERS+2)
consumer = bootstrap.get(N_PRODUCERS+1)
@@ -555,21 +797,21 @@ class PersistenceTest(DhtFeatureTest):
nodes = set([])
self._gottaGetThemAllPokeNodes(consumer, hashes, nodes=nodes)
DhtNetwork.log("Values are found on:")
DhtNetwork.Log.log("Values are found on:")
for n in nodes:
DhtNetwork.log(n)
DhtNetwork.Log.log(n)
DhtNetwork.log("Creating 8 nodes around all of these hashes...")
DhtNetwork.Log.log("Creating 8 nodes around all of these hashes...")
for _hash in hashes:
self._trigger_dp(trigger_nodes, _hash, count=8)
DhtNetwork.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
DhtNetwork.Log.log('Waiting', DP_TIMEOUT+1, 'minutes for normal storage maintenance.')
time.sleep((DP_TIMEOUT+1)*60)
DhtNetwork.log('Deleting old nodes from previous search.')
DhtNetwork.Log.log('Deleting old nodes from previous search.')
for proc in self._workbench.procs:
DhtNetwork.log('[REMOVE]: sending delete request to', proc)
proc.sendNodesRequest(
DhtNetwork.Log.log('[REMOVE]: sending delete request to', proc)
proc.sendClusterRequest(
DhtNetworkSubProcess.REMOVE_NODE_REQ,
nodes)
@@ -610,9 +852,10 @@ class PerformanceTest(DhtFeatureTest):
else:
raise NameError("This test is not defined '" + self._test + "'")
except Exception as e:
print(e)
traceback.print_tb(e.__traceback__)
print(type(e).__name__+':', e, file=sys.stderr)
finally:
self.bootstrap.resize(1)
self._bootstrap.resize(1)
###########
@@ -624,7 +867,7 @@ class PerformanceTest(DhtFeatureTest):
"""
Tests for performance of the DHT doing multiple get() operation.
"""
bootstrap = self.bootstrap
bootstrap = self._bootstrap
plt.ion()
@@ -649,7 +892,7 @@ class PerformanceTest(DhtFeatureTest):
def getcb(v):
nonlocal bootstrap
DhtNetwork.log("found", v)
DhtNetwork.Log.log("found", v)
return True
def donecb(ok, nodes, start):
@@ -657,7 +900,7 @@ class PerformanceTest(DhtFeatureTest):
t = time.time()-start
with lock:
if not ok:
DhtNetwork.log("failed !")
DhtNetwork.Log.log("failed !")
times.append(t)
done -= 1
lock.notify()
@@ -689,7 +932,7 @@ class PerformanceTest(DhtFeatureTest):
for n in range(10):
self._workbench.replace_cluster()
plt.pause(2)
DhtNetwork.log("Getting 50 random hashes succesively.")
DhtNetwork.Log.log("Getting 50 random hashes succesively.")
for i in range(50):
with lock:
for _ in range(1):
@@ -713,8 +956,7 @@ class PerformanceTest(DhtFeatureTest):
deleting around the target hash.
"""
bootstrap = self.bootstrap
bootstrap = self._bootstrap
bootstrap.resize(3)
consumer = bootstrap.get(1)
@@ -725,28 +967,28 @@ class PerformanceTest(DhtFeatureTest):
for _ in range(max(1, int(self._workbench.node_num/32))):
self._dhtGet(consumer, myhash)
DhtNetwork.log("Waiting 15 seconds...")
DhtNetwork.Log.log("Waiting 15 seconds...")
time.sleep(15)
self._dhtPut(producer, myhash, *local_values)
#checking if values were transfered
self._dhtGet(consumer, myhash)
DhtNetwork.log('Values are found on :')
DhtNetwork.Log.log('Values are found on :')
for node in DhtFeatureTest.foreignNodes:
DhtNetwork.log(node)
DhtNetwork.Log.log(node)
if not DhtFeatureTest.successfullTransfer(local_values, DhtFeatureTest.foreignValues):
if DhtFeatureTest.foreignValues:
DhtNetwork.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
DhtNetwork.Log.log('[GET]: Only ', len(DhtFeatureTest.foreignValues) ,' on ',
len(local_values), ' values successfully put.')
else:
DhtNetwork.log('[GET]: 0 values successfully put')
DhtNetwork.Log.log('[GET]: 0 values successfully put')
DhtNetwork.log('Removing all nodes hosting target values...')
DhtNetwork.Log.log('Removing all nodes hosting target values...')
for proc in self._workbench.procs:
DhtNetwork.log('[REMOVE]: sending shutdown request to', proc)
proc.sendNodesRequest(
DhtNetwork.Log.log('[REMOVE]: sending shutdown request to', proc)
proc.sendClusterRequest(
DhtNetworkSubProcess.SHUTDOWN_NODE_REQ,
DhtFeatureTest.foreignNodes
)
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# Copyright (c) 2016 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/>.
from twisted.web import server, resource
from twisted.internet import reactor, endpoints
from urllib.parse import urlparse
import opendht as dht
import base64, json
class DhtServer(resource.Resource):
isLeaf = True
node = dht.DhtRunner()
def __init__(self, port, bootstrap):
self.node.run(port=port)
b_url = urlparse('//'+bootstrap)
self.node.bootstrap(b_url.hostname, str(b_url.port) if b_url.port else '4222')
def render_GET(self, req):
uri = req.uri[1:]
h = dht.InfoHash(uri) if len(uri) == 40 else dht.InfoHash.get(uri.decode())
print('GET', '"'+uri.decode()+'"', h)
res = self.node.get(h)
req.setHeader(b"content-type", b"application/json")
return json.dumps({'{:x}'.format(v.id):{'base64':base64.b64encode(v.data).decode()} for v in res}).encode()
def render_POST(self, req):
uri = req.uri[1:]
data = req.args[b'data'][0] if b'data' in req.args else None
if not data and b'base64' in req.args:
data = base64.b64decode(req.args[b'base64'][0])
h = dht.InfoHash(uri) if len(uri) == 40 else dht.InfoHash.get(uri.decode())
print('POST', h, data)
req.setHeader(b"content-type", b"application/json")
if data:
self.node.put(h, dht.Value(data))
return json.dumps({'success':True}).encode()
else:
req.setResponseCode(400)
return json.dumps({'success':False, 'error':'no data parameter'}).encode()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Launch an OpenDHT node with an HTTP control interface')
parser.add_argument('-p', '--port', help='OpenDHT port to bind', type=int, default=4222)
parser.add_argument('-hp', '--http-port', help='HTTP port to bind', type=int, default=8080)
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default="bootstrap.ring.cx:4222")
args = parser.parse_args()
endpoints.serverFromString(reactor, "tcp:"+str(args.http_port)).listen(server.Site(DhtServer(args.port, args.bootstrap)))
reactor.run()
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 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/>.
import time
import argparse
import time
import asyncio
from datetime import datetime
import opendht as dht
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default='bootstrap.ring.cx')
parser.add_argument('-n', '--num-ops', help='number of concurrent operations on the DHT', type=int, default=8)
parser.add_argument('-p', '--period', help='duration between each test (seconds)', type=int, default=60)
parser.add_argument('-t', '--timeout', help='timeout for a test to complete (seconds)', type=float, default=15)
args = parser.parse_args()
node1 = dht.DhtRunner()
node1.run()
node2 = dht.DhtRunner()
node2.run()
node1.bootstrap(args.bootstrap)
node2.bootstrap(args.bootstrap)
loop = asyncio.get_event_loop()
pending_tests = {}
keys = [dht.InfoHash.getRandom() for _ in range(args.num_ops)]
def listen_cb(key, val):
global pending_tests
kstr = str(key)
if kstr in pending_tests:
if pending_tests[kstr]['v'].id == val.id:
pending_tests.pop(kstr, None)
else:
print("Expected vid", val.id, "got", pending_tests[kstr]['v'].id)
return True
def listen(key):
node1.listen(key, lambda v: loop.call_soon_threadsafe(listen_cb, key, v))
for key in keys:
listen(key)
next_test = time.time()
while True:
start = time.time()
#print(datetime.fromtimestamp(start).strftime('%Y-%m-%d %H:%M:%S'), 'Test started')
for key in keys:
val = dht.Value(str(dht.InfoHash.getRandom()).encode())
pending_tests[str(key)] = {'v':val, 'c':0}
node2.put(key, val, lambda ok, nodes: ok)
while len(pending_tests):
loop.stop()
loop.run_forever()
time.sleep(1)
if time.time()-start > args.timeout:
print('Test timeout !')
exit(1)
end = time.time()
print(datetime.fromtimestamp(end).strftime('%Y-%m-%d %H:%M:%S'),
'Test completed successfully in', end-start)
next_test += args.period
if next_test > end:
time.sleep(next_test-end)
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 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/>.
import opendht as dht
import time
import asyncio
ping_node = dht.DhtRunner()
ping_node.run(port = 5632)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run(port = 5633)
#pong_node.enableLogging()
pong_node.bootstrap("192.168.49.55", "5632");
#pong_node.bootstrap("192.168.49.55", "5632");
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
i = 0
MAX = 8192
loop = asyncio.get_event_loop()
def done(h, ok):
print(h, "over", ok)
def ping(node, h):
global i
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
else:
loop.stop()
def pong(node, h):
print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h);
return True
ping_node.listen(loc_ping, lambda v: pong(pong_node, loc_pong))
pong_node.listen(loc_pong, lambda v: pong(ping_node, loc_ping))
ping(pong_node, loc_ping)
loop.run_forever()
+4 -2
View File
@@ -18,7 +18,7 @@
import time, sys, os
from pprint import pprint
from math import cos, sin, pi
from urllib import request
import urllib3
import gzip
import asyncio
@@ -35,6 +35,8 @@ from mpl_toolkits.basemap import Basemap
import GeoIP
http = urllib3.PoolManager()
done = 0
all_nodes = NodeSet()
@@ -72,7 +74,7 @@ def check_dl(fname, url):
if os.path.isfile(fname):
return
print('downloading', url)
ghandle = gzip.GzipFile(fileobj=request.urlopen(url))
ghandle = gzip.GzipFile(fileobj=http.request('GET', url, headers={'User-Agent': 'Mozilla/5.0'}, preload_content=False))
with open(fname, 'wb') as out:
for line in ghandle:
out.write(line)
+105
View File
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg3492"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="256"
height="256"
viewBox="0 0 256 255.99999"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><title
id="title3357">OpenDHT</title><metadata
id="metadata3498"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title>OpenDHT</dc:title><dc:rights><cc:Agent><dc:title></dc:title></cc:Agent></dc:rights><dc:creator><cc:Agent><dc:title>Savoir-faire Linux Inc.</dc:title></cc:Agent></dc:creator><dc:relation>https://opendht.net</dc:relation></cc:Work></rdf:RDF></metadata><defs
id="defs3496"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3534"><path
d="m 0,0 1152,0 0,648 L 0,648 0,0 Z"
id="path3536"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1056"
id="namedview3494"
showgrid="false"
units="px"
fit-margin-top="5"
fit-margin-right="5"
fit-margin-bottom="5"
fit-margin-left="5"
inkscape:zoom="1.9555556"
inkscape:cx="63.161953"
inkscape:cy="141.16919"
inkscape:window-x="1985"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g3532" /><g
id="g3500"
inkscape:groupmode="layer"
inkscape:label="SFL-logo-DHT"
transform="matrix(1.25,0,0,-1.25,-589.00821,604.10631)"><g
id="g3530"><g
id="g3532"
clip-path="url(#clipPath3534)"><g
id="g3359"
transform="matrix(0.9931555,0,0,0.99058777,1.5489503,0.9813209)"><g
transform="translate(485.3798,383.7826)"
id="g3538"><path
inkscape:connector-curvature="0"
id="path3540"
style="fill:#47b3d1;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,50.03 40.554,90.586 90.586,90.586 50.028,0 90.587,-40.556 90.587,-90.586 0,-50.03 -40.559,-90.588 -90.587,-90.588 C 40.554,-90.588 0,-50.03 0,0" /></g><g
transform="translate(576.0338,313.2273)"
id="g3542"><path
inkscape:connector-curvature="0"
id="path3544"
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,54.307 -24.009,102.977 -61.954,136.075 -17.613,-16.526 -28.632,-39.996 -28.632,-66.056 0,-49.629 39.916,-89.912 89.393,-90.555 0.396,-0.009 0.792,-0.033 1.193,-0.033 L 0,-0.082 0,0 Z" /></g><g
transform="translate(575.9661,292.6626)"
id="g3546"><path
inkscape:connector-curvature="0"
id="path3548"
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -1.439,49.482 -41.105,89.355 -90.504,91.12 0,-0.178 -0.015,-0.355 -0.015,-0.536 C -90.519,40.578 -49.998,0.039 0,0" /></g><g
transform="translate(532.4411,337.497)"
id="g3550"><path
inkscape:connector-curvature="0"
id="path3552"
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -10.555,0 -20.236,-3.754 -27.777,-10 16.565,-21.182 42.472,-34.815 71.442,-34.834 0.01,0.415 -0.072,0.821 -0.072,1.241 C 43.593,-19.516 24.077,0 0,0" /></g><g
transform="translate(576.0338,313.2273)"
id="g3554"><path
inkscape:connector-curvature="0"
id="path3556"
style="fill:#0091ba;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 0,54.307 24.014,102.977 61.954,136.075 79.567,119.549 90.586,96.079 90.586,70.019 90.586,20.39 50.675,-19.893 1.198,-20.536 0.797,-20.545 0.406,-20.569 0.005,-20.569 l 0,20.487 C 0.005,-0.053 0,-0.029 0,0" /></g><g
transform="translate(576.1063,292.6626)"
id="g3558"><path
inkscape:connector-curvature="0"
id="path3560"
style="fill:#007aa3;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 1.44,49.482 41.105,89.355 90.504,91.12 0,-0.178 0.01,-0.355 0.01,-0.536 C 90.514,40.578 49.998,0.039 0,0" /></g><g
transform="translate(619.6266,337.497)"
id="g3562"><path
inkscape:connector-curvature="0"
id="path3564"
style="fill:#006382;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 10.56,0 20.241,-3.754 27.782,-10 -16.57,-21.182 -42.405,-34.815 -71.375,-34.834 -0.009,0.415 0,0.821 0,1.241 C -43.593,-19.516 -24.072,0 0,0" /></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

+14 -2
View File
@@ -3,6 +3,7 @@ SUBDIRS = argon2
lib_LTLIBRARIES = libopendht.la
AM_CPPFLAGS = -I../include/opendht
libopendht_la_CXXFLAGS = @CXXFLAGS@
libopendht_la_LDFLAGS = @LDFLAGS@ @GnuTLS_LIBS@ @Nettle_LIBS@
libopendht_la_LIBADD = ./argon2/libargon2.la
@@ -19,7 +20,9 @@ libopendht_la_SOURCES = \
crypto.cpp \
securedht.cpp \
dhtrunner.cpp \
default_types.cpp
default_types.cpp \
indexation/pht.cpp \
log.cpp
if WIN32
libopendht_la_SOURCES += rng.cpp
@@ -27,13 +30,17 @@ endif
nobase_include_HEADERS = \
../include/opendht.h \
../include/opendht/def.h \
../include/opendht/dht.h \
../include/opendht/callbacks.h \
../include/opendht/node_cache.h \
../include/opendht/routing_table.h \
../include/opendht/network_engine.h \
../include/opendht/net.h \
../include/opendht/scheduler.h \
../include/opendht/rate_limiter.h \
../include/opendht/utils.h \
../include/opendht/sockaddr.h \
../include/opendht/infohash.h \
../include/opendht/node.h \
../include/opendht/value.h \
@@ -42,4 +49,9 @@ nobase_include_HEADERS = \
../include/opendht/dhtrunner.h \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/rng.h
../include/opendht/log_enable.h \
../include/opendht/rng.h \
../include/opendht/indexation/pht.h
nobase_noinst_HEADERS = \
../include/opendht/request.h
+11 -1
View File
@@ -10,4 +10,14 @@ libargon2_la_SOURCES = \
encoding.c \
ref.c
EXTRA_libargon2_la_SOURCES = opt.c
noinst_HEADERS = \
argon2.h \
core.h \
blake2/blake2.h \
blake2/blake2-impl.h \
blake2/blamka-round-ref.h \
blake2/blamka-round-opt.h \
thread.h \
encoding.h \
opt.h \
ref.h
+73 -22
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <string.h>
@@ -19,6 +23,18 @@
#include "encoding.h"
#include "core.h"
const char *argon2_type2string(argon2_type type, int uppercase) {
switch (type) {
case Argon2_d:
return uppercase ? "Argon2d" : "argon2d";
case Argon2_i:
return uppercase ? "Argon2i" : "argon2i";
case Argon2_id:
return uppercase ? "Argon2id" : "argon2id";
}
return NULL;
}
int argon2_ctx(argon2_context *context, argon2_type type) {
/* 1. Validate all inputs */
@@ -30,7 +46,7 @@ int argon2_ctx(argon2_context *context, argon2_type type) {
return result;
}
if (Argon2_d != type && Argon2_i != type) {
if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
return ARGON2_INCORRECT_TYPE;
}
@@ -81,25 +97,19 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt, const size_t saltlen,
void *hash, const size_t hashlen, char *encoded,
const size_t encodedlen, argon2_type type,
const size_t encodedlen, argon2_type type,
const uint32_t version){
argon2_context context;
int result;
uint8_t *out;
/* Detect and reject overflowing sizes */
/* TODO: This should probably be fixed in the function signature */
if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
return ARGON2_PWD_TOO_LONG;
}
if (hashlen > ARGON2_MAX_OUTLEN) {
return ARGON2_OUTPUT_TOO_LONG;
}
if (saltlen > ARGON2_MAX_SALT_LENGTH) {
return ARGON2_SALT_TOO_LONG;
if (hashlen < ARGON2_MIN_OUTLEN) {
return ARGON2_OUTPUT_TOO_SHORT;
}
out = malloc(hashlen);
@@ -194,6 +204,26 @@ int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER);
}
int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, const size_t hashlen,
char *encoded, const size_t encodedlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
NULL, hashlen, encoded, encodedlen, Argon2_id,
ARGON2_VERSION_NUMBER);
}
int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash, const size_t hashlen) {
return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
hash, hashlen, NULL, 0, Argon2_id,
ARGON2_VERSION_NUMBER);
}
static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {
size_t i;
uint8_t d = 0U;
@@ -212,13 +242,19 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
int ret;
int decode_result;
uint32_t encoded_len;
size_t encoded_len_tmp;
if(encoded == NULL) {
return ARGON2_DECODING_FAIL;
}
encoded_len_tmp = strlen(encoded);
/* max values, to be updated in decode_string */
encoded_len = strlen(encoded);
if (UINT32_MAX < encoded_len_tmp) {
return ARGON2_DECODING_FAIL;
}
encoded_len = (uint32_t)encoded_len_tmp;
ctx.adlen = encoded_len;
ctx.saltlen = encoded_len;
ctx.outlen = encoded_len;
@@ -226,6 +262,8 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
ctx.free_cbk = NULL;
ctx.secret = NULL;
ctx.secretlen = 0;
ctx.pwdlen = 0;
ctx.pwd = NULL;
ctx.ad = malloc(ctx.adlen);
ctx.salt = malloc(ctx.saltlen);
ctx.out = malloc(ctx.outlen);
@@ -277,6 +315,11 @@ int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
return argon2_verify(encoded, pwd, pwdlen, Argon2_d);
}
int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
return argon2_verify(encoded, pwd, pwdlen, Argon2_id);
}
int argon2d_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_d);
}
@@ -285,6 +328,10 @@ int argon2i_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_i);
}
int argon2id_ctx(argon2_context *context) {
return argon2_ctx(context, Argon2_id);
}
int argon2_verify_ctx(argon2_context *context, const char *hash,
argon2_type type) {
int result;
@@ -309,6 +356,10 @@ int argon2i_verify_ctx(argon2_context *context, const char *hash) {
return argon2_verify_ctx(context, hash, Argon2_i);
}
int argon2id_verify_ctx(argon2_context *context, const char *hash) {
return argon2_verify_ctx(context, hash, Argon2_id);
}
const char *argon2_error_message(int error_code) {
switch (error_code) {
case ARGON2_OK:
@@ -389,8 +440,8 @@ const char *argon2_error_message(int error_code) {
}
size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,
uint32_t saltlen, uint32_t hashlen) {
return strlen("$argon2x$v=$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost)
+ numlen(parallelism) + b64len(saltlen) + b64len(hashlen)
+ numlen(ARGON2_VERSION_NUMBER);
uint32_t saltlen, uint32_t hashlen, argon2_type type) {
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) +
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) +
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1;
}
+66 -8
View File
@@ -1,13 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_H
@@ -24,6 +29,8 @@ extern "C" {
/* Symbols visibility control */
#ifdef A2_VISCTL
#define ARGON2_PUBLIC __attribute__((visibility("default")))
#elif _MSC_VER
#define ARGON2_PUBLIC __declspec(dllexport)
#else
#define ARGON2_PUBLIC
#endif
@@ -204,7 +211,11 @@ typedef struct Argon2_Context {
} argon2_context;
/* Argon2 primitive type */
typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;
typedef enum Argon2_type {
Argon2_d = 0,
Argon2_i = 1,
Argon2_id = 2
} argon2_type;
/* Version of the algorithm */
typedef enum Argon2_version {
@@ -213,6 +224,14 @@ typedef enum Argon2_version {
ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
} argon2_version;
/*
* Function that gives the string representation of an argon2_type.
* @param type The argon2_type that we want the string for
* @param uppercase Whether the string should have the first letter uppercase
* @return NULL if invalid type, otherwise the string representation.
*/
ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase);
/*
* Function that performs memory-hard hashing with certain degree of parallelism
* @param context Pointer to the Argon2 internal structure
@@ -278,6 +297,21 @@ ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
const size_t saltlen, void *hash,
const size_t hashlen);
ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism,
const void *pwd, const size_t pwdlen,
const void *salt, const size_t saltlen,
const size_t hashlen, char *encoded,
const size_t encodedlen);
ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost,
const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
const size_t pwdlen, const void *salt,
const size_t saltlen, void *hash,
const size_t hashlen);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
const uint32_t parallelism, const void *pwd,
@@ -300,6 +334,9 @@ ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd,
ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd,
const size_t pwdlen);
ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd,
const size_t pwdlen);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd,
const size_t pwdlen, argon2_type type);
@@ -324,6 +361,17 @@ ARGON2_PUBLIC int argon2d_ctx(argon2_context *context);
*/
ARGON2_PUBLIC int argon2i_ctx(argon2_context *context);
/**
* Argon2id: Version of Argon2 where the first half-pass over memory is
* password-independent, the rest are password-dependent (on the password and
* salt). OK against side channels (they reduce to 1/2-pass Argon2i), and
* better with w.r.t. tradeoff attacks (similar to Argon2d).
*****
* @param context Pointer to current Argon2 context
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2id_ctx(argon2_context *context);
/**
* Verify if a given password is correct for Argon2d hashing
* @param context Pointer to current Argon2 context
@@ -342,6 +390,16 @@ ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash);
*/
ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash);
/**
* Verify if a given password is correct for Argon2id hashing
* @param context Pointer to current Argon2 context
* @param hash The password hash to verify. The length of the hash is
* specified by the context outlen member
* @return Zero if successful, a non zero error code otherwise
*/
ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context,
const char *hash);
/* generic function underlying the above ones */
ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash,
argon2_type type);
@@ -363,7 +421,7 @@ ARGON2_PUBLIC const char *argon2_error_message(int error_code);
*/
ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,
uint32_t parallelism, uint32_t saltlen,
uint32_t hashlen);
uint32_t hashlen, argon2_type type);
#if defined(__cplusplus)
}
+18 -5
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef PORTABLE_BLAKE2_IMPL_H
#define PORTABLE_BLAKE2_IMPL_H
@@ -134,10 +151,6 @@ static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
return (w >> c) | (w << (64 - c));
}
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void burn(void *v, size_t n) {
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
void secure_wipe_memory(void *v, size_t n);
#endif
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef PORTABLE_BLAKE2_H
#define PORTABLE_BLAKE2_H
+24 -7
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
@@ -44,7 +61,7 @@ static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
}
static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
burn(S, sizeof(*S)); /* wipe */
secure_wipe_memory(S, sizeof(*S)); /* wipe */
blake2b_set_lastblock(S); /* invalidate for further use */
}
@@ -140,7 +157,7 @@ int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
memset(block, 0, BLAKE2B_BLOCKBYTES);
memcpy(block, key, keylen);
blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
burn(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
secure_wipe_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
}
return 0;
}
@@ -267,9 +284,9 @@ int blake2b_final(blake2b_state *S, void *out, size_t outlen) {
}
memcpy(out, buffer, S->outlen);
burn(buffer, sizeof(buffer));
burn(S->buf, sizeof(S->buf));
burn(S->h, sizeof(S->h));
secure_wipe_memory(buffer, sizeof(buffer));
secure_wipe_memory(S->buf, sizeof(S->buf));
secure_wipe_memory(S->h, sizeof(S->h));
return 0;
}
@@ -307,7 +324,7 @@ int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
ret = blake2b_final(&S, out, outlen);
fail:
burn(&S, sizeof(S));
secure_wipe_memory(&S, sizeof(S));
return ret;
}
@@ -365,7 +382,7 @@ int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {
memcpy(out, out_buffer, toproduce);
}
fail:
burn(&blake_state, sizeof(blake_state));
secure_wipe_memory(&blake_state, sizeof(blake_state));
return ret;
#undef TRY
}
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef BLAKE_ROUND_MKA_OPT_H
#define BLAKE_ROUND_MKA_OPT_H
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef BLAKE_ROUND_MKA_H
#define BLAKE_ROUND_MKA_H
+31 -28
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
/*For memory wiping*/
@@ -252,26 +256,28 @@ int fill_memory_blocks(argon2_instance_t *instance) {
uint32_t r, s;
argon2_thread_handle_t *thread = NULL;
argon2_thread_data *thr_data = NULL;
int rc = ARGON2_OK;
if (instance == NULL || instance->lanes == 0) {
return ARGON2_THREAD_FAIL;
rc = ARGON2_THREAD_FAIL;
goto fail;
}
/* 1. Allocating space for threads */
thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t));
if (thread == NULL) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
thr_data = calloc(instance->lanes, sizeof(argon2_thread_data));
if (thr_data == NULL) {
free(thread);
return ARGON2_MEMORY_ALLOCATION_ERROR;
rc = ARGON2_MEMORY_ALLOCATION_ERROR;
goto fail;
}
for (r = 0; r < instance->passes; ++r) {
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
int rc;
uint32_t l;
/* 2. Calling threads */
@@ -280,11 +286,9 @@ int fill_memory_blocks(argon2_instance_t *instance) {
/* 2.1 Join a thread if limit is exceeded */
if (l >= instance->threads) {
rc = argon2_thread_join(thread[l - instance->threads]);
if (rc) {
free(thr_data);
free(thread);
return ARGON2_THREAD_FAIL;
if (argon2_thread_join(thread[l - instance->threads])) {
rc = ARGON2_THREAD_FAIL;
goto fail;
}
}
@@ -297,12 +301,10 @@ int fill_memory_blocks(argon2_instance_t *instance) {
instance; /* preparing the thread input */
memcpy(&(thr_data[l].pos), &position,
sizeof(argon2_position_t));
rc = argon2_thread_create(&thread[l], &fill_segment_thr,
(void *)&thr_data[l]);
if (rc) {
free(thr_data);
free(thread);
return ARGON2_THREAD_FAIL;
if (argon2_thread_create(&thread[l], &fill_segment_thr,
(void *)&thr_data[l])) {
rc = ARGON2_THREAD_FAIL;
goto fail;
}
/* fill_segment(instance, position); */
@@ -312,9 +314,9 @@ int fill_memory_blocks(argon2_instance_t *instance) {
/* 3. Joining remaining threads */
for (l = instance->lanes - instance->threads; l < instance->lanes;
++l) {
rc = argon2_thread_join(thread[l]);
if (rc) {
return ARGON2_THREAD_FAIL;
if (argon2_thread_join(thread[l])) {
rc = ARGON2_THREAD_FAIL;
goto fail;
}
}
}
@@ -324,13 +326,14 @@ int fill_memory_blocks(argon2_instance_t *instance) {
#endif
}
fail:
if (thread != NULL) {
free(thread);
}
if (thr_data != NULL) {
free(thr_data);
}
return ARGON2_OK;
return rc;
}
int validate_inputs(const argon2_context *context) {
@@ -575,7 +578,7 @@ int initialize(argon2_instance_t *instance, argon2_context *context) {
if (ARGON2_OK != result) {
return result;
}
memcpy(&(instance->memory), p, sizeof(instance->memory));
instance->memory = (block *)p;
} else {
result = allocate_memory(&(instance->memory), instance->memory_blocks);
if (ARGON2_OK != result) {
+11 -7
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_CORE_H
+48 -12
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -291,21 +308,26 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
size_t maxsaltlen = ctx->saltlen;
size_t maxoutlen = ctx->outlen;
int validation_result;
const char* type_string;
ctx->adlen = 0;
ctx->saltlen = 0;
ctx->outlen = 0;
ctx->pwdlen = 0;
if (type == Argon2_i)
CC("$argon2i");
else if (type == Argon2_d)
CC("$argon2d");
else
/* We should start with the argon2_type we are using */
CC("$");
type_string = argon2_type2string(type, 0);
if (type_string) {
CC(type_string);
} else {
return ARGON2_INCORRECT_TYPE;
ctx->version = ARGON2_VERSION_10;
}
/* Reading the version number if the default is suppressed */
ctx->version = ARGON2_VERSION_10;
CC_opt("$v=", DECIMAL(ctx->version));
CC("$m=");
DECIMAL(ctx->m_cost);
CC(",t=");
@@ -370,16 +392,19 @@ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
dst_len -= sb_len; \
} while ((void)0, 0)
if (type == Argon2_i)
SS("$argon2i$v=");
else if (type == Argon2_d)
SS("$argon2d$v=");
else
const char* type_string = argon2_type2string(type, 0);
SS("$");
if (type_string) {
SS(type_string);
} else {
return ARGON2_ENCODING_FAIL;
}
if (validate_inputs(ctx) != ARGON2_OK) {
return validate_inputs(ctx);
}
SS("$v=");
SX(ctx->version);
SS("$m=");
SX(ctx->m_cost);
@@ -412,7 +437,18 @@ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
}
size_t b64len(uint32_t len) {
return (((size_t)len + 2) / 3) * 4;
size_t olen = ((size_t)len / 3) << 2;
switch (len % 3) {
case 2:
olen++;
/* fall through */
case 1:
olen += 2;
break;
}
return olen;
}
size_t numlen(uint32_t num) {
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ENCODING_H
#define ENCODING_H
#include "argon2.h"
+15 -8
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
@@ -135,7 +139,10 @@ void fill_segment(const argon2_instance_t *instance,
return;
}
data_independent_addressing = (instance->type == Argon2_i);
data_independent_addressing =
(instance->type == Argon2_i) ||
(instance->type == Argon2_id && (position.pass == 0) &&
(position.slice < ARGON2_SYNC_POINTS / 2));
pseudo_rands =
(uint64_t *)malloc(sizeof(uint64_t) * instance->segment_length);
+11 -7
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_OPT_H
+15 -8
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
@@ -145,7 +149,10 @@ void fill_segment(const argon2_instance_t *instance,
return;
}
data_independent_addressing = (instance->type == Argon2_i);
data_independent_addressing =
(instance->type == Argon2_i) ||
(instance->type == Argon2_id && (position.pass == 0) &&
(position.slice < ARGON2_SYNC_POINTS / 2));
pseudo_rands =
(uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));
+11 -7
View File
@@ -1,14 +1,18 @@
/*
* Argon2 source code package
* Argon2 reference source code package - reference C implementations
*
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_REF_H
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include "thread.h"
#if defined(_WIN32)
#include <windows.h>
+17
View File
@@ -1,3 +1,20 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef ARGON2_THREAD_H
#define ARGON2_THREAD_H
/*
+22 -1
View File
@@ -47,4 +47,25 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
};
}
}
DoneCallbackSimple
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](bool success) {
raw_cb(success, user_data);
};
}
std::string
NodeStats::toString() const
{
std::stringstream ss;
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;
}
return ss.str();
}
}
+315 -47
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -83,6 +83,18 @@ namespace crypto {
static constexpr std::array<size_t, 3> AES_LENGTHS {{128/8, 192/8, 256/8}};
static constexpr size_t PASSWORD_SALT_LENGTH {16};
constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) {
return (min_res > 256/8) ? GNUTLS_DIG_SHA512 : (
(min_res > 128/8) ? GNUTLS_DIG_SHA256 : (
GNUTLS_DIG_SHA1));
}
constexpr size_t gnutlsHashSize(int algo) {
return (algo == GNUTLS_DIG_SHA512) ? 512/8 : (
(algo == GNUTLS_DIG_SHA256) ? 256/8 : (
(algo == GNUTLS_DIG_SHA1) ? 160/8 : 0 ));
}
size_t aesKeySize(size_t max)
{
size_t aes_key_len = 0;
@@ -128,8 +140,7 @@ Blob aesEncrypt(const Blob& data, const Blob& key)
Blob aesEncrypt(const Blob& data, const std::string& password)
{
Blob salt;
Blob key = stretchKey(password, salt);
key.resize(256 / 8);
Blob key = stretchKey(password, salt, 256 / 8);
Blob encrypted = aesEncrypt(data, key);
encrypted.insert(encrypted.begin(), salt.begin(), salt.end());
return encrypted;
@@ -175,13 +186,12 @@ Blob aesDecrypt(const Blob& data, const std::string& password)
if (data.size() <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH};
Blob key = stretchKey(password, salt);
key.resize(256 / 8);
Blob key = stretchKey(password, salt, 256/8);
Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()};
return aesDecrypt(encrypted, key);
}
Blob stretchKey(const std::string& password, Blob& salt)
Blob stretchKey(const std::string& password, Blob& salt, size_t key_length)
{
if (salt.empty()) {
salt.resize(PASSWORD_SALT_LENGTH);
@@ -193,35 +203,27 @@ Blob stretchKey(const std::string& password, Blob& salt)
auto ret = argon2i_hash_raw(16, 64*1024, 1, password.data(), password.size(), salt.data(), salt.size(), res.data(), res.size());
if (ret != ARGON2_OK)
throw CryptoException("Can't compute argon2i !");
return hash(res);
return hash(res, key_length);
}
Blob hash(const Blob& data)
Blob hash(const Blob& data, size_t hash_len)
{
auto algo = gnutlsHashAlgo(hash_len);
size_t res_size = gnutlsHashSize(algo);
Blob res;
size_t res_size = 64;
res.resize(res_size);
const gnutls_datum_t gdat {(uint8_t*)data.data(), (unsigned)data.size()};
if (gnutls_fingerprint(GNUTLS_DIG_SHA512, &gdat, res.data(), &res_size))
if (gnutls_fingerprint(algo, &gdat, res.data(), &res_size))
throw CryptoException("Can't compute hash !");
res.resize(res_size);
res.resize(std::min(hash_len, res_size));
return res;
}
PrivateKey::PrivateKey()
{
#if GNUTLS_VERSION_NUMBER < 0x030300
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize GnuTLS.");
#endif
}
{}
PrivateKey::PrivateKey(gnutls_x509_privkey_t k) : x509_key(k)
{
#if GNUTLS_VERSION_NUMBER < 0x030300
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize GnuTLS.");
#endif
gnutls_privkey_init(&key);
if (gnutls_privkey_import_x509(key, k, GNUTLS_PRIVKEY_IMPORT_COPY) != GNUTLS_E_SUCCESS) {
key = nullptr;
@@ -231,10 +233,6 @@ PrivateKey::PrivateKey(gnutls_x509_privkey_t k) : x509_key(k)
PrivateKey::PrivateKey(const Blob& import, const std::string& password)
{
#if GNUTLS_VERSION_NUMBER < 0x030300
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize GnuTLS.");
#endif
int err = gnutls_x509_privkey_init(&x509_key);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize private key !");
@@ -266,14 +264,9 @@ PrivateKey::PrivateKey(const Blob& import, const std::string& password)
PrivateKey::PrivateKey(PrivateKey&& o) noexcept : key(o.key), x509_key(o.x509_key)
{
#if GNUTLS_VERSION_NUMBER < 0x030300
// gnutls_global_init already succeeded at least once here so no real need to check.
int ret = gnutls_global_init();
assert(ret == GNUTLS_E_SUCCESS);
#endif
o.key = nullptr;
o.x509_key = nullptr;
};
}
PrivateKey::~PrivateKey()
{
@@ -285,9 +278,6 @@ PrivateKey::~PrivateKey()
gnutls_x509_privkey_deinit(x509_key);
x509_key = nullptr;
}
#if GNUTLS_VERSION_NUMBER < 0x030300
gnutls_global_deinit();
#endif
}
PrivateKey&
@@ -311,6 +301,8 @@ PrivateKey::sign(const Blob& data) const
{
if (!key)
throw CryptoException("Can't sign data: no private key set !");
if (std::numeric_limits<unsigned>::max() < data.size())
throw CryptoException("Can't sign data: too large !");
gnutls_datum_t sig;
const gnutls_datum_t dat {(unsigned char*)data.data(), (unsigned)data.size()};
if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS)
@@ -733,13 +725,54 @@ Certificate::toString(bool chain) const
return ss.str();
}
std::string
Certificate::print() const
{
gnutls_datum_t out;
gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &out);
std::string ret(out.data, out.data+out.size);
gnutls_free(out.data);
return ret;
}
void
Certificate::revoke(const PrivateKey& key, const Certificate& to_revoke)
{
if (revocation_lists.empty())
revocation_lists.emplace(std::make_shared<RevocationList>());
auto& list = *(*revocation_lists.begin());
list.revoke(to_revoke);
list.sign(key, *this);
}
void
Certificate::addRevocationList(RevocationList&& list)
{
addRevocationList(std::make_shared<RevocationList>(std::forward<RevocationList>(list)));
}
void
Certificate::addRevocationList(std::shared_ptr<RevocationList> list)
{
if (revocation_lists.find(list) != revocation_lists.end())
return; // Already in the list
if (not list->isSignedBy(*this))
throw CryptoException("CRL is not signed by this certificate");
revocation_lists.emplace(std::move(list));
}
std::chrono::system_clock::time_point
Certificate::getExpiration() const
{
auto t = gnutls_x509_crt_get_expiration_time(cert);
if (t == (time_t)-1)
return std::chrono::system_clock::time_point::min();
return std::chrono::system_clock::from_time_t(t);
}
PrivateKey
PrivateKey::generate(unsigned key_length)
{
#if GNUTLS_VERSION_NUMBER < 0x030300
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize GnuTLS.");
#endif
gnutls_x509_privkey_t key;
if (gnutls_x509_privkey_init(&key) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize private key.");
@@ -751,20 +784,25 @@ PrivateKey::generate(unsigned key_length)
return PrivateKey{key};
}
PrivateKey
PrivateKey::generateEC()
{
gnutls_x509_privkey_t key;
if (gnutls_x509_privkey_init(&key) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't initialize private key.");
int err = gnutls_x509_privkey_generate(key, GNUTLS_PK_EC, gnutls_sec_param_to_pk_bits(GNUTLS_PK_EC, GNUTLS_SEC_PARAM_ULTRA), 0);
if (err != GNUTLS_E_SUCCESS) {
gnutls_x509_privkey_deinit(key);
throw CryptoException(std::string("Can't generate EC key pair: ") + gnutls_strerror(err));
}
return PrivateKey{key};
}
Identity
generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
{
#if GNUTLS_VERSION_NUMBER < 0x030300
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
return {};
#endif
auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
#if GNUTLS_VERSION_NUMBER < 0x030300
gnutls_global_deinit();
#endif
return {std::move(key), std::move(cert)};
}
@@ -816,6 +854,10 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
gnutls_x509_crt_set_key_usage(cert, key_usage);
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
// 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) {
std::cerr << "Error when signing certificate" << std::endl;
@@ -833,5 +875,231 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
return ret;
}
std::vector<std::shared_ptr<RevocationList>>
Certificate::getRevocationLists() const
{
std::vector<std::shared_ptr<RevocationList>> ret;
ret.reserve(revocation_lists.size());
for (const auto& crl : revocation_lists)
ret.emplace_back(crl);
return ret;
}
RevocationList::RevocationList()
{
gnutls_x509_crl_init(&crl);
}
RevocationList::RevocationList(const Blob& b)
{
gnutls_x509_crl_init(&crl);
try {
unpack(b.data(), b.size());
} catch (const std::exception& e) {
gnutls_x509_crl_deinit(crl);
crl = nullptr;
throw e;
}
}
RevocationList::~RevocationList()
{
if (crl) {
gnutls_x509_crl_deinit(crl);
crl = nullptr;
}
}
void
RevocationList::pack(Blob& b) const
{
gnutls_datum_t gdat {nullptr, 0};
if (auto err = gnutls_x509_crl_export2(crl, GNUTLS_X509_FMT_DER, &gdat)) {
throw CryptoException(std::string("Can't export CRL: ") + gnutls_strerror(err));
}
b.insert(b.end(), gdat.data, gdat.data + gdat.size);
}
void
RevocationList::unpack(const uint8_t* dat, size_t dat_size)
{
if (std::numeric_limits<unsigned>::max() < dat_size)
throw CryptoException("Can't load CRL: too large!");
const gnutls_datum_t gdat {(uint8_t*)dat, (unsigned)dat_size};
if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM))
if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) {
throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem)
+ " DER: " + gnutls_strerror(err_der));
}
}
void
RevocationList::msgpack_unpack(msgpack::object o)
{
try {
if (o.type == msgpack::type::BIN)
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
else {
Blob dat = unpackBlob(o);
unpack(dat.data(), dat.size());
}
} catch (...) {
throw msgpack::type_error();
}
}
bool
RevocationList::isRevoked(const Certificate& crt) const
{
auto ret = gnutls_x509_crt_check_revocation(crt.cert, &crl, 1);
if (ret < 0)
throw CryptoException(std::string("Can't check certificate revocation status: ") + gnutls_strerror(ret));
return ret != 0;
}
void
RevocationList::revoke(const Certificate& crt, std::chrono::system_clock::time_point t)
{
if (t == time_point::min())
t = clock::now();
if (auto err = gnutls_x509_crl_set_crt(crl, crt.cert, std::chrono::system_clock::to_time_t(t)))
throw CryptoException(std::string("Can't revoke certificate: ") + gnutls_strerror(err));
}
static std::string
getCRLIssuerDN(gnutls_x509_crl_t cert, const char* oid)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = gnutls_x509_crl_get_issuer_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
RevocationList::getIssuerName() const
{
return getCRLIssuerDN(crl, GNUTLS_OID_X520_COMMON_NAME);
}
/** Read CRL issuer User ID (UID) */
std::string
RevocationList::getIssuerUID() const
{
return getCRLIssuerDN(crl, GNUTLS_OID_LDAP_UID);
}
RevocationList::time_point
RevocationList::getNextUpdateTime() const
{
auto t = gnutls_x509_crl_get_next_update(crl);
if (t == (time_t)-1)
return std::chrono::system_clock::time_point::min();
return std::chrono::system_clock::from_time_t(t);
}
RevocationList::time_point
RevocationList::getUpdateTime() const
{
auto t = gnutls_x509_crl_get_this_update(crl);
if (t == (time_t)-1)
return std::chrono::system_clock::time_point::min();
return std::chrono::system_clock::from_time_t(t);
}
enum class Endian : uint32_t
{
LITTLE = 0,
BIG = 1
};
template <typename T>
T endian(T w, Endian endian = Endian::BIG)
{
// this gets optimized out into if (endian == host_endian) return w;
union { uint64_t quad; uint32_t islittle; } t;
t.quad = 1;
if (t.islittle ^ (uint32_t)endian) return w;
T r = 0;
// decent compilers will unroll this (gcc)
// or even convert straight into single bswap (clang)
for (size_t i = 0; i < sizeof(r); i++) {
r <<= 8;
r |= w & 0xff;
w >>= 8;
}
return r;
}
void
RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration validity)
{
if (auto err = gnutls_x509_crl_set_version(crl, 2))
throw CryptoException(std::string("Can't set CRL version: ") + gnutls_strerror(err));
auto now = std::chrono::system_clock::now();
auto next_update = (validity == duration{}) ? ca.getExpiration() : now + validity;
if (auto err = gnutls_x509_crl_set_this_update(crl, std::chrono::system_clock::to_time_t(now)))
throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crl_set_next_update(crl, std::chrono::system_clock::to_time_t(next_update)))
throw CryptoException(std::string("Can't set CRL next update time: ") + gnutls_strerror(err));
uint64_t number {0};
size_t number_sz {sizeof(number)};
unsigned critical {0};
gnutls_x509_crl_get_number(crl, &number, &number_sz, &critical);
if (number == 0) {
// initialize to a random number
number_sz = sizeof(number);
random_device rdev;
std::generate_n((uint8_t*)&number, sizeof(number), std::bind(rand_byte, std::ref(rdev)));
} else
number = endian(endian(number) + 1);
if (auto err = gnutls_x509_crl_set_number(crl, &number, sizeof(number)))
throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crl_sign2(crl, ca.cert, key.x509_key, GNUTLS_DIG_SHA512, 0))
throw CryptoException(std::string("Can't sign certificate revocation list: ") + gnutls_strerror(err));
// to be able to actually use the CRL we need to serialize/deserialize it
auto packed = getPacked();
unpack(packed.data(), packed.size());
}
bool
RevocationList::isSignedBy(const Certificate& issuer) const
{
unsigned result {0};
auto err = gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result);
if (err < 0) {
//std::cout << "Can't verify CRL: " << err << " " << result << " " << gnutls_strerror(err) << std::endl;
return false;
}
return result == 0;
}
Blob
RevocationList::getNumber() const
{
Blob number(20);
size_t number_sz {number.size()};
unsigned critical {0};
gnutls_x509_crl_get_number(crl, number.data(), &number_sz, &critical);
if (number_sz != number.size())
number.resize(number_sz);
return number;
}
std::string
RevocationList::toString() const
{
gnutls_datum_t out;
gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_FULL, &out);
std::string ret(out.data, out.data+out.size);
gnutls_free(out.data);
return ret;
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1705 -878
View File
File diff suppressed because it is too large. Load diff
+243 -92
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -37,6 +37,8 @@
namespace dht {
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
DhtRunner::DhtRunner() : dht_()
{
#ifdef _WIN32
@@ -104,7 +106,8 @@ DhtRunner::run(const sockaddr_in* local4, const sockaddr_in6* local6, DhtRunner:
std::lock_guard<std::mutex> lck(storage_mtx);
if (not pending_ops_prio.empty())
return true;
if (not pending_ops.empty() and getStatus() >= NodeStatus::Connecting)
auto s = getStatus();
if (not pending_ops.empty() and (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping)))
return true;
}
return false;
@@ -127,10 +130,14 @@ DhtRunner::join()
{
running = false;
cv.notify_all();
bootstrap_cv.notify_all();
if (dht_thread.joinable())
dht_thread.join();
if (rcv_thread.joinable())
rcv_thread.join();
if (bootstrap_thread.joinable())
bootstrap_thread.join();
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops = decltype(pending_ops)();
@@ -208,6 +215,12 @@ DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
dht_->setLoggers(std::forward<LogMethod>(error), std::forward<LogMethod>(warn), std::forward<LogMethod>(debug));
}
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
dht_->setLogFilter(f);
}
void
DhtRunner::registerType(const ValueType& type) {
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -220,11 +233,27 @@ DhtRunner::importValues(const std::vector<ValuesExport>& values) {
dht_->importValues(values);
}
int
unsigned
DhtRunner::getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return dht_->getNodesStats(af, good_return, dubious_return, cached_return, incoming_return);
const auto stats = dht_->getNodesStats(af);
if (good_return)
*good_return = stats.good_nodes;
if (dubious_return)
*dubious_return = stats.dubious_nodes;
if (cached_return)
*cached_return = stats.cached_nodes;
if (incoming_return)
*incoming_return = stats.incoming_nodes;
return stats.good_nodes + stats.dubious_nodes;
}
NodeStats
DhtRunner::getNodesStats(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return dht_->getNodesStats(af);
}
std::vector<unsigned>
@@ -241,6 +270,12 @@ DhtRunner::getStorageLog() const
return dht_->getStorageLog();
}
std::string
DhtRunner::getStorageLog(const InfoHash& f) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return dht_->getStorageLog(f);
}
std::string
DhtRunner::getRoutingTablesLog(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -252,7 +287,13 @@ DhtRunner::getSearchesLog(sa_family_t af) const
std::lock_guard<std::mutex> lck(dht_mtx);
return dht_->getSearchesLog(af);
}
std::vector<Address>
std::string
DhtRunner::getSearchLog(const InfoHash& f, sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return dht_->getSearchLog(f, af);
}
std::vector<SockAddr>
DhtRunner::getPublicAddress(sa_family_t af)
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -287,22 +328,14 @@ DhtRunner::loop_()
decltype(pending_ops) ops {};
{
std::lock_guard<std::mutex> lck(storage_mtx);
ops = std::move(pending_ops_prio);
auto s = getStatus();
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping))) ?
std::move(pending_ops) : std::move(pending_ops_prio);
}
while (not ops.empty()) {
ops.front()(*dht_);
ops.pop();
}
if (getStatus() >= NodeStatus::Connecting) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
ops = std::move(pending_ops);
}
while (not ops.empty()) {
ops.front()(*dht_);
ops.pop();
}
}
time_point wakeup {};
decltype(rcv) received {};
@@ -315,7 +348,7 @@ DhtRunner::loop_()
for (const auto& pck : received) {
auto& buf = pck.first;
auto& from = pck.second;
wakeup = dht_->periodic(buf.data(), buf.size()-1, (sockaddr*)&from.first, from.second);
wakeup = dht_->periodic(buf.data(), buf.size()-1, from);
}
received.clear();
} else {
@@ -327,6 +360,15 @@ DhtRunner::loop_()
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
if (status4 == NodeStatus::Disconnected and status6 == NodeStatus::Disconnected) {
// We have lost connection with the DHT. Try to recover using bootstrap nodes.
std::unique_lock<std::mutex> lck(bootstrap_mtx);
bootstrap_nodes = bootstrap_nodes_all;
tryBootstrapContinuously();
} else {
std::unique_lock<std::mutex> lck(bootstrap_mtx);
bootstrap_nodes.clear();
}
if (statusCb)
statusCb(status4, status6);
}
@@ -400,19 +442,19 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
if(rc > 0) {
std::array<uint8_t, 1024 * 64> buf;
sockaddr_storage from;
socklen_t fromlen {sizeof(from)};
SockAddr from;
from.second = sizeof(from.first);
if(s4 >= 0 && FD_ISSET(s4, &readfds))
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from, &fromlen);
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from.first, &from.second);
else if(s6 >= 0 && FD_ISSET(s6, &readfds))
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from, &fromlen);
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (struct sockaddr*)&from.first, &from.second);
else
break;
if (rc > 0) {
{
std::lock_guard<std::mutex> lck(sock_mtx);
rcv.emplace_back(Blob {buf.begin(), buf.begin()+rc+1}, std::make_pair(from, fromlen));
rcv.emplace_back(Blob {buf.begin(), buf.begin()+rc+1}, from);
}
cv.notify_all();
}
@@ -429,104 +471,129 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
}
void
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f)
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::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, vcb, dcb, std::move(f), std::move(w));
});
}
cv.notify_all();
}
void
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f)
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
{
get(InfoHash::get(key), vcb, dcb, f);
get(InfoHash::get(key), vcb, dcb, f, 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));
});
}
cv.notify_all();
}
std::future<size_t>
DhtRunner::listen(InfoHash hash, GetCallback vcb, Value::Filter f)
DhtRunner::listen(InfoHash hash, GetCallback vcb, Value::Filter f, Where w)
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto ret_token = std::make_shared<std::promise<size_t>>();
pending_ops.emplace([=](SecureDht& dht) mutable {
ret_token->set_value(dht.listen(hash, vcb, std::move(f)));
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
ret_token->set_value(dht.listen(hash, vcb, std::move(f), std::move(w)));
});
}
cv.notify_all();
return ret_token->get_future();
}
std::future<size_t>
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f)
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
{
return listen(InfoHash::get(key), vcb, f);
return listen(InfoHash::get(key), vcb, f, w);
}
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
}
cv.notify_all();
}
void
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
auto tk = token.get();
dht.cancelListen(h, tk);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
auto tk = token.get();
dht.cancelListen(h, tk);
});
}
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, bool permanent)
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto sv = std::make_shared<Value>(std::move(value));
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, sv, cb, {}, permanent);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto sv = std::make_shared<Value>(std::move(value));
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, sv, cb, created, permanent);
});
}
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, value, cb, {}, permanent);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, value, cb, created, permanent);
});
}
cv.notify_all();
}
void
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, bool permanent)
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
{
put(InfoHash::get(key), std::forward<Value>(value), cb, permanent);
put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
}
void
DhtRunner::cancelPut(const InfoHash& h , const Value::Id& id)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
}
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putSigned(hash, value, cb);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putSigned(hash, value, cb);
});
}
cv.notify_all();
}
@@ -545,10 +612,12 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putEncrypted(hash, to, value, cb);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putEncrypted(hash, to, value, cb);
});
}
cv.notify_all();
}
@@ -564,18 +633,77 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
}
void
DhtRunner::tryBootstrapContinuously()
{
if (bootstrap_thread.joinable()) {
if (bootstraping)
return; // already running
else
bootstrap_thread.join();
}
bootstraping = true;
bootstrap_thread = std::thread([this]() {
auto next = clock::now();
do {
decltype(bootstrap_nodes) nodes;
{
std::lock_guard<std::mutex> lck(bootstrap_mtx);
nodes = bootstrap_nodes;
}
next += BOOTSTRAP_PERIOD;
{
std::mutex mtx;
std::unique_lock<std::mutex> blck(mtx);
unsigned ping_count(0);
// Reverse: try last inserted bootstrap nodes first
for (auto it = nodes.rbegin(); it != nodes.rend(); it++) {
++ping_count;
try {
bootstrap(getAddrInfo(it->first, it->second), [&](bool) {
if (not running)
return;
{
std::unique_lock<std::mutex> blck(mtx);
--ping_count;
}
bootstrap_cv.notify_all();
});
} catch (std::invalid_argument& e) {
--ping_count;
std::cerr << e.what() << std::endl;
}
}
// wait at least until the next BOOTSTRAP_PERIOD
bootstrap_cv.wait_until(blck, next, [&]() { return not running; });
// wait for bootstrap requests to end.
if (running)
bootstrap_cv.wait(blck, [&]() { return not running or ping_count == 0; });
}
// update state
{
std::lock_guard<std::mutex> lck(dht_mtx);
bootstraping = running and
status4 == NodeStatus::Disconnected and
status6 == NodeStatus::Disconnected;
}
} while (bootstraping);
});
}
std::vector<std::pair<sockaddr_storage, socklen_t>>
DhtRunner::getAddrInfo(const char* host, const char* service)
DhtRunner::getAddrInfo(const std::string& host, const std::string& service)
{
std::vector<std::pair<sockaddr_storage, socklen_t>> ips {};
if (not host or not service or strlen(host) == 0)
if (host.empty())
return ips;
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
addrinfo* info = nullptr;
int rc = getaddrinfo(host, service, &hints, &info);
int rc = getaddrinfo(host.c_str(), service.c_str(), &hints, &info);
if(rc != 0)
throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
@@ -590,18 +718,35 @@ DhtRunner::getAddrInfo(const char* host, const char* service)
}
void
DhtRunner::bootstrap(const char* host, const char* service)
DhtRunner::bootstrap(const std::string& host, const std::string& service)
{
bootstrap(getAddrInfo(host, service));
std::lock_guard<std::mutex> lck(bootstrap_mtx);
bootstrap_nodes_all.emplace_back(host, service);
bootstrap_nodes.emplace_back(host, service);
tryBootstrapContinuously();
}
void
DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes)
DhtRunner::clearBootstrap()
{
std::lock_guard<std::mutex> lck(bootstrap_mtx);
bootstrap_nodes_all.clear();
}
void
DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
for (auto& node : nodes)
dht.pingNode((sockaddr*)&node.first, node.second);
dht.pingNode((sockaddr*)&node.first, node.second, cb ? [rem,cb](bool ok) {
auto& r = *rem;
r.first--;
r.second |= ok;
if (not r.first)
cb(r.second);
} : DoneCallbackSimple{});
});
cv.notify_all();
}
@@ -609,30 +754,36 @@ DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>&
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
}
cv.notify_all();
}
void
DhtRunner::connectivityChanged()
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
}
cv.notify_all();
}
void
DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb) {
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.findCertificate(hash, cb);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.findCertificate(hash, cb);
});
}
cv.notify_all();
}
+538
View File
@@ -0,0 +1,538 @@
/*
* Copyright (C) 2014-2017 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>
*
* 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 "indexation/pht.h"
#include "rng.h"
namespace dht {
namespace indexation {
/**
* Output the blob into string and readable way
*
* @param bl : Blob to print
*
* @return string that represent the blob into a readable way
*/
static std::string blobToString(const Blob &bl) {
std::stringstream ss;
auto bn = bl.size() % 8;
auto n = bl.size() / 8;
for (size_t i = 0; i < bl.size(); i++)
ss << std::bitset<8>(bl[i]) << " ";
if (bn)
for (unsigned b=0; b < bn; b++)
ss << (char)((bl[n] & (1 << (7 - b))) ? '1':'0');
return ss.str();
}
std::string Prefix::toString() const {
std::stringstream ss;
ss << "Prefix : " << std::endl << "\tContent_ : \"";
ss << blobToString(content_);
ss << "\"" << std::endl;
ss << "\tFlags_ : \"";
ss << blobToString(flags_);
ss << "\"" << std::endl;
return ss.str();
}
void Pht::Cache::insert(const Prefix& p) {
size_t i = 0;
auto now = clock::now();
std::shared_ptr<Node> curr_node;
while ((leaves_.size() > 0
and leaves_.begin()->first + NODE_EXPIRE_TIME < now)
or leaves_.size() > MAX_ELEMENT) {
leaves_.erase(leaves_.begin());
}
if (not (curr_node = root_.lock()) ) {
/* Root does not exist, need to create one*/
curr_node = std::make_shared<Node>();
root_ = curr_node;
}
curr_node->last_reply = now;
/* Iterate through all bit of the Blob */
for ( i = 0; i < p.size_; i++ ) {
/* According to the bit define which node is the next one */
auto& next = ( p.isContentBitActive(i) ) ? curr_node->right_child : curr_node->left_child;
/**
* If lock, node exists
* else create it
*/
if (auto n = next.lock()) {
curr_node = std::move(n);
} else {
/* Create the next node if doesn't exist*/
auto tmp_curr_node = std::make_shared<Node>();
tmp_curr_node->parent = curr_node;
next = tmp_curr_node;
curr_node = std::move(tmp_curr_node);
}
curr_node->last_reply = now;
}
/* Insert the leaf (curr_node) into the multimap */
leaves_.emplace(std::move(now), std::move(curr_node) );
}
int Pht::Cache::lookup(const Prefix& p) {
int pos = -1;
auto now = clock::now(), last_node_time = now;
/* Before lookup remove the useless one [i.e. too old] */
while ( leaves_.size() > 0
and leaves_.begin()->first + NODE_EXPIRE_TIME < now ) {
leaves_.erase(leaves_.begin());
}
auto next = root_;
std::shared_ptr<Node> curr_node;
while ( auto n = next.lock() ) {
++pos;
/* Safe since pos is equal to 0 until here */
if ( (unsigned) pos >= p.content_.size() * 8) break;
curr_node = n;
last_node_time = curr_node->last_reply;
curr_node->last_reply = now;
/* Get the Prefix bit by bit, starting from left */
next = ( p.isContentBitActive(pos) ) ? curr_node->right_child : curr_node->left_child;
}
if ( pos >= 0 ) {
auto to_erase = leaves_.find(last_node_time);
if ( to_erase != leaves_.end() )
leaves_.erase( to_erase );
leaves_.emplace( std::move(now), std::move(curr_node) );
}
return pos;
}
const ValueType IndexEntry::TYPE = ValueType::USER_DATA;
constexpr std::chrono::minutes Pht::Cache::NODE_EXPIRE_TIME;
void Pht::lookupStep(Prefix p, std::shared_ptr<int> lo, std::shared_ptr<int> hi,
std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals,
LookupCallbackWrapper cb, DoneCallbackSimple done_cb,
std::shared_ptr<unsigned> max_common_prefix_len,
int start, bool all_values)
{
struct node_lookup_result {
bool done {false};
bool is_pht {false};
};
/* start could be under 0 but after the compare it to 0 it always will be unsigned, so we can cast it*/
auto mid = (start >= 0) ? (unsigned) start : (*lo + *hi)/2;
auto first_res = std::make_shared<node_lookup_result>();
auto second_res = std::make_shared<node_lookup_result>();
auto on_done = [=](bool ok) {
bool is_leaf = first_res->is_pht and not second_res->is_pht;
if (not ok) {
if (done_cb)
done_cb(false);
}
else if (is_leaf or *lo > *hi) {
// leaf node
Prefix to_insert = p.getPrefix(mid);
cache_.insert(to_insert);
if (cb) {
if (vals->size() == 0 and max_common_prefix_len and mid > 0) {
auto p_ = (p.getPrefix(mid)).getSibling().getFullSize();
*lo = mid;
*hi = p_.size_;
lookupStep(p_, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
}
cb(*vals, to_insert);
}
if (done_cb)
done_cb(true);
} else if (first_res->is_pht) {
// internal node
*lo = mid+1;
lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
} else {
// first get failed before second.
if (done_cb)
done_cb(false);
}
};
if (*lo <= *hi) {
auto pht_filter = [&](const dht::Value& v) {
return v.user_type.compare(0, name_.size(), name_) == 0;
};
auto on_get = [=](const std::shared_ptr<dht::Value>& value, std::shared_ptr<node_lookup_result> res) {
if (value->user_type == canary_) {
res->is_pht = true;
}
else {
IndexEntry entry;
entry.unpackValue(*value);
auto it = std::find_if(vals->cbegin(), vals->cend(), [&](const std::shared_ptr<IndexEntry>& ie) {
return ie->value == entry.value;
});
/* If we already got the value then get the next one */
if (it != vals->cend())
return true;
if (max_common_prefix_len) { /* inexact match case */
auto common_bits = Prefix::commonBits(p, entry.prefix);
if (vals->empty()) {
vals->emplace_back(std::make_shared<IndexEntry>(entry));
*max_common_prefix_len = common_bits;
}
else {
if (common_bits == *max_common_prefix_len) /* this is the max so far */
vals->emplace_back(std::make_shared<IndexEntry>(entry));
else if (common_bits > *max_common_prefix_len) { /* new max found! */
vals->clear();
vals->emplace_back(std::make_shared<IndexEntry>(entry));
*max_common_prefix_len = common_bits;
}
}
} else if (all_values or entry.prefix == p.content_) /* exact match case */
vals->emplace_back(std::make_shared<IndexEntry>(entry));
}
return true;
};
dht_->get(p.getPrefix(mid).hash(),
std::bind(on_get, std::placeholders::_1, first_res),
[=](bool ok) {
if (not ok) {
// DHT failed
first_res->done = true;
if (done_cb and second_res->done)
on_done(false);
}
else {
if (not first_res->is_pht) {
// Not a PHT node.
*hi = mid-1;
lookupStep(p, lo, hi, vals, cb, done_cb, max_common_prefix_len, -1, all_values);
} else {
first_res->done = true;
if (second_res->done or mid >= p.size_ - 1)
on_done(true);
}
}
}, pht_filter);
if (mid < p.size_ - 1)
dht_->get(p.getPrefix(mid+1).hash(),
std::bind(on_get, std::placeholders::_1, second_res),
[=](bool ok) {
if (not ok) {
// DHT failed
second_res->done = true;
if (done_cb and first_res->done)
on_done(false);
}
else {
second_res->done = true;
if (first_res->done)
on_done(true);
}
}, pht_filter);
} else {
on_done(true);
}
}
void Pht::lookup(Key k, Pht::LookupCallback cb, DoneCallbackSimple done_cb, bool exact_match) {
auto prefix = linearize(k);
auto values = std::make_shared<std::vector<std::shared_ptr<IndexEntry>>>();
auto lo = std::make_shared<int>(0);
auto hi = std::make_shared<int>(prefix.size_);
std::shared_ptr<unsigned> max_common_prefix_len = not exact_match ? std::make_shared<unsigned>(0) : nullptr;
lookupStep(prefix, lo, hi, values,
[=](std::vector<std::shared_ptr<IndexEntry>>& entries, Prefix p) {
std::vector<std::shared_ptr<Value>> vals(entries.size());
std::transform(entries.begin(), entries.end(), vals.begin(),
[](const std::shared_ptr<IndexEntry>& ie) {
return std::make_shared<Value>(ie->value);
});
cb(vals, p);
}, done_cb, max_common_prefix_len, cache_.lookup(prefix));
}
void Pht::updateCanary(Prefix p) {
// TODO: change this... copy value
dht::Value canary_value;
canary_value.user_type = canary_;
dht_->put(p.hash(), std::move(canary_value),
[=](bool){
static std::bernoulli_distribution d(0.5);
crypto::random_device rd;
if (p.size_ and d(rd))
updateCanary(p.getPrefix(-1));
}
);
if (p.size_) {
dht::Value canary_second_value;
canary_second_value.user_type = canary_;
dht_->put(p.getSibling().hash(), std::move(canary_second_value));
}
}
void Pht::insert(Prefix kp, IndexEntry entry, std::shared_ptr<int> lo, std::shared_ptr<int> hi, time_point time_p,
bool check_split, DoneCallbackSimple done_cb) {
if (time_p + ValueType::USER_DATA.expiration < clock::now()) return;
auto vals = std::make_shared<std::vector<std::shared_ptr<IndexEntry>>>();
auto final_prefix = std::make_shared<Prefix>();
lookupStep(kp, lo, hi, vals,
[=](std::vector<std::shared_ptr<IndexEntry>>&, Prefix p) {
*final_prefix = Prefix(p);
},
[=](bool ok){
if (not ok) {
if (done_cb)
done_cb(false);
} else {
RealInsertCallback real_insert = [=]( std::shared_ptr<Prefix> p, IndexEntry entry) {
updateCanary(*p);
checkPhtUpdate(*p, entry, time_p);
cache_.insert(*p);
dht_->put(p->hash(), std::move(entry), done_cb , time_p);
};
if ( not check_split or final_prefix->size_ == kp.size_ ) {
real_insert(final_prefix, std::move(entry));
} else {
if ( vals->size() < MAX_NODE_ENTRY_COUNT ) {
getRealPrefix(final_prefix, std::move(entry), real_insert);
}
else {
split(*final_prefix, vals, entry, real_insert);
}
}
}
}, nullptr, cache_.lookup(kp), true
);
}
Prefix Pht::zcurve(const std::vector<Prefix>& all_prefix) const {
Prefix p;
if ( all_prefix.size() == 1 )
return all_prefix[0];
/* All prefix got the same size (thanks to padding) */
size_t prefix_size = all_prefix[0].content_.size();
/* Loop on all uint8_t of the input prefix */
for ( size_t j = 0, bit = 0; j < prefix_size; j++) {
uint8_t mask = 0x80;
/* For each of the 8 bits of the input uint8_t */
for ( int i = 0; i < 8; ) {
uint8_t flags = 0;
uint8_t content = 0;
/* For each bit of the output uint8_t */
for ( int k = 0 ; k < 8; k++ ) {
auto diff = k - i;
/*get the content 'c', and the flag 'f' of the input prefix */
auto c = all_prefix[bit].content_[j] & mask;
auto f = all_prefix[bit].flags_[j] & mask;
/* Move this bit at the right position according to the diff
and merge it into content and flags in the same way */
content |= ( diff >= 0 ) ? c >> diff : c << std::abs(diff);
flags |= ( diff >= 0 ) ? f >> diff : f << std::abs(diff);
/* If we are on the last prefix of the vector get back to the first and
,move the mask in order to get the n + 1nth bit */
if ( ++bit == all_prefix.size() ) { bit = 0; ++i; mask >>= 1; }
}
/* Add the next flags + content to the output prefix */
p.content_.push_back(content);
p.flags_.push_back(flags);
p.size_ += 8;
}
}
return p;
}
Prefix Pht::linearize(Key k) const {
if (not validKey(k)) { throw std::invalid_argument(INVALID_KEY); }
std::vector<Prefix> all_prefix;
all_prefix.reserve(k.size());
/* Get the max size of the keyspec and take it for size limit (for padding) */
auto max = std::max_element(keySpec_.begin(), keySpec_.end(),
[](const std::pair<std::string, size_t>& a, const std::pair<std::string, size_t>& b) {
return a.second < b.second;
})->second + 1;
for ( auto const& it : k ) {
Prefix p = Blob {it.second.begin(), it.second.end()};
p.addPaddingContent(max);
p.updateFlags();
all_prefix.emplace_back(std::move(p));
}
return zcurve(all_prefix);
}
void Pht::getRealPrefix(std::shared_ptr<Prefix> p, IndexEntry entry, RealInsertCallback end_cb ) {
if ( p->size_ == 0 ) {
end_cb(p, std::move(entry));
return;
}
auto total = std::make_shared<unsigned int>(0); /* Will contains the total number of data on 3 nodes */
auto ended = std::make_shared<unsigned int>(0); /* Just indicate how many have end */
auto parent = std::make_shared<Prefix>(p->getPrefix(-1));
auto sibling = std::make_shared<Prefix>(p->getSibling());
auto pht_filter = [&](const dht::Value& v) {
return v.user_type.compare(0, name_.size(), name_) == 0;
};
/* Lambda will count total number of data node */
auto count = [=]( const std::shared_ptr<dht::Value> value ) {
if ( value->user_type != canary_)
(*total)++;
return true;
};
auto on_done = [=] ( bool ) {
(*ended)++;
/* Only the last one do the CallBack*/
if ( *ended == 3 ) {
if ( *total < MAX_NODE_ENTRY_COUNT )
end_cb(parent, std::move(entry));
else
end_cb(p, std::move(entry));
}
};
dht_->get(parent->hash(),
count,
on_done,
pht_filter
);
dht_->get(p->hash(),
count,
on_done,
pht_filter
);
dht_->get(sibling->hash(),
count,
on_done,
pht_filter
);
}
void Pht::checkPhtUpdate(Prefix p, IndexEntry entry, time_point time_p) {
Prefix full = entry.prefix;
if ( p.content_.size() * 8 >= full.content_.size() * 8 ) return;
auto next_prefix = full.getPrefix( p.size_ + 1 );
dht_->listen(next_prefix.hash(),
[=](const std::shared_ptr<dht::Value> &value) {
if (value->user_type == canary_) {
insert(full, entry, std::make_shared<int>(0), std::make_shared<int>(full.size_), time_p, false, nullptr);
/* Cancel listen since we found where we need to update*/
return false;
}
return true;
},
[=](const dht::Value& v) {
/* Filter value v thats start with the same name as ours */
return v.user_type.compare(0, name_.size(), name_) == 0;
}
);
}
void Pht::split(Prefix insert, std::shared_ptr<std::vector<std::shared_ptr<IndexEntry>>> vals, IndexEntry entry, RealInsertCallback end_cb ) {
auto full = Prefix(entry.prefix);
auto loc = foundSplitLocation(full, vals);
auto prefix_to_insert = std::make_shared<Prefix>(full.getPrefix(loc));
for(;loc != insert.size_ - 1; loc--) {
updateCanary(full.getPrefix(loc));
}
end_cb(prefix_to_insert, entry);
}
} /* indexation */
} /* dht */
+14 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -91,4 +91,17 @@ std::ostream& operator<< (std::ostream& s, const InfoHash& h)
return s;
}
std::istream& operator>> (std::istream& s, InfoHash& h)
{
std::array<char, HASH_LEN*2> dat;
s.exceptions(std::istream::eofbit | std::istream::failbit);
s.read(&(*dat.begin()), dat.size());
for (size_t i = 0; i < HASH_LEN; i++) {
unsigned res = 0;
sscanf(dat.data() + 2*i, "%02x", &res);
h[i] = res;
}
return s;
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2014-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "log.h"
namespace dht {
namespace log {
/**
* Print va_list to std::ostream (used for logging).
*/
void
printLog(std::ostream& s, char const *m, va_list args) {
// print log to buffer
std::array<char, 8192> buffer;
int ret = vsnprintf(buffer.data(), buffer.size(), m, args);
if (ret < 0)
return;
// write timestamp
using namespace std::chrono;
using log_precision = microseconds;
constexpr auto den = log_precision::period::den;
auto micro = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
s << "[" << std::setfill('0') << std::setw(6) << micro / den << "."
<< std::setfill('0') << std::setw(6) << micro % den << "]" << " ";
// write log
s.write(buffer.data(), std::min((size_t) ret, buffer.size()));
if ((size_t) ret >= buffer.size())
s << "[[TRUNCATED]]";
s << std::endl;
}
void
enableLogging(dht::DhtRunner &dht) {
dht.setLoggers(
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
std::cerr << def;
},
[](char const *m, va_list args) {
std::cout << yellow;
printLog(std::cout, m, args);
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>();
logfile->open(path, std::ios::out);
dht.setLoggers(
[=](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); }
);
}
void
disableLogging(dht::DhtRunner &dht) {
dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
}
}
}
+748 -326
View File
File diff suppressed because it is too large. Load diff
+8 -9
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <sim.desaulniers@gmail.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -65,15 +65,14 @@ Node::getPendingMessageCount() const
}
void
Node::update(const sockaddr* sa, socklen_t salen)
Node::update(const SockAddr& new_addr)
{
std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss);
sslen = salen;
addr = new_addr;
}
/** To be called when a message was sent to the node */
void
Node::requested(std::shared_ptr<Request>& req)
Node::requested(std::shared_ptr<net::Request>& req)
{
requests_.emplace_back(req);
}
@@ -81,12 +80,12 @@ Node::requested(std::shared_ptr<Request>& req)
/** To be called when a message was received from the node.
Req should be true if the message was an aswer to a request we made*/
void
Node::received(time_point now, std::shared_ptr<Request> req)
Node::received(time_point now, std::shared_ptr<net::Request> req)
{
time = now;
expired_ = false;
if (req) {
reply_time = now;
expired_ = false;
for (auto it = requests_.begin(); it != requests_.end();) {
auto r = it->lock();
if (not r or r == req)
@@ -119,7 +118,7 @@ Node::toString() const
std::ostream& operator<< (std::ostream& s, const Node& h)
{
s << h.id << " " << print_addr(h.ss, h.sslen);
s << h.id << " " << h.addr.toString();
return s;
}
+39 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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,10 +27,42 @@ NodeCache::getNode(const InfoHash& id, sa_family_t family) {
}
std::shared_ptr<Node>
NodeCache::getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirm) {
NodeCache::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm) {
if (id == zeroes)
return std::make_shared<Node>(id, sa, sa_len);
return (sa->sa_family == AF_INET ? cache_4 : cache_6).getNode(id, sa, sa_len, now, confirm);
return std::make_shared<Node>(id, addr);
return (addr.getFamily() == AF_INET ? cache_4 : cache_6).getNode(id, addr, now, confirm);
}
std::vector<std::shared_ptr<Node>>
NodeCache::getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) {
const auto& c = (sa_f == AF_INET ? cache_4 : cache_6);
auto it_p = c.lower_bound(id),
it_n = it_p;
std::vector<std::shared_ptr<Node>> nodes;
nodes.reserve(std::min(c.size(), count));
NodeMap::const_iterator it;
if (it_p != c.begin()) /* Create 2 separate iterator if we could */
--it_p;
while (nodes.size() < count and (it_n != c.end() or it_p != c.end())) {
/* 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.end()) it = it_n++;
else if (it_n == c.end()) it = it_p--;
else it = id.xorCmp(it_p->first, it_n->first) < 0 ? it_p-- : it_n++;
if (it == c.begin())
it_p = c.end();
if (auto n = it->second.lock())
if ( not n->isExpired() )
nodes.emplace_back(std::move(n));
}
return nodes;
}
void
@@ -57,15 +89,15 @@ NodeCache::NodeMap::getNode(const InfoHash& id)
}
std::shared_ptr<Node>
NodeCache::NodeMap::getNode(const InfoHash& id, const sockaddr* sa, socklen_t sa_len, time_point now, int confirm)
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm)
{
auto it = emplace(id, std::weak_ptr<Node>{});
auto node = it.first->second.lock();
if (not node) {
node = std::make_shared<Node>(id, sa, sa_len);
node = std::make_shared<Node>(id, addr);
it.first->second = node;
} else if (confirm || node->time < now - Node::NODE_EXPIRE_TIME) {
node->update(sa, sa_len);
node->update(addr);
}
return node;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 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 -3
View File
@@ -17,10 +17,21 @@ Bucket::randomNode()
{
if (nodes.empty())
return nullptr;
std::uniform_int_distribution<unsigned> rand_node(0, nodes.size()-1);
unsigned expired_node_count = std::count_if(nodes.cbegin(), nodes.cend(), [](const decltype(nodes)::value_type& node) {
return node->isExpired();
});
auto prioritize_not_expired = expired_node_count < nodes.size();
std::uniform_int_distribution<unsigned> rand_node(0, prioritize_not_expired
? nodes.size() - expired_node_count - 1
: nodes.size()-1);
unsigned nn = rand_node(rd);
for (auto& n : nodes)
if (not nn--) return n;
for (auto& n : nodes) {
if (not (prioritize_not_expired and n->isExpired())) {
if (not nn--)
return n;
}
}
return nodes.back();
}
@@ -59,6 +70,8 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
unsigned
RoutingTable::depth(const RoutingTable::const_iterator& it) const
{
if (it == end())
return 0;
int bit1 = it->first.lowbit();
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
return std::max(bit1, bit2)+1;
+10 -21
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@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
@@ -50,12 +51,6 @@ SecureDht::SecureDht(int s, int s6, SecureDht::Config conf)
if (s < 0 && s6 < 0)
return;
#if GNUTLS_VERSION_NUMBER < 0x030300
int rc = gnutls_global_init();
if (rc != GNUTLS_E_SUCCESS)
throw DhtException(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
#endif
for (const auto& type : DEFAULT_TYPES)
registerType(type);
@@ -76,18 +71,12 @@ SecureDht::SecureDht(int s, int s6, SecureDht::Config conf)
}, [this](bool ok) {
if (ok)
DHT_LOG.DEBUG("SecureDht: public key announced successfully");
else
DHT_LOG.ERR("SecureDht: error while announcing public key!");
}, {}, true);
}
}
SecureDht::~SecureDht()
{
#if GNUTLS_VERSION_NUMBER < 0x030300
gnutls_global_deinit();
#endif
}
{}
ValueType
SecureDht::secureType(ValueType&& type)
@@ -99,7 +88,7 @@ SecureDht::secureType(ValueType&& type)
return false;
}
else
DHT_LOG.WARN("Signature verification succeded");
DHT_LOG.WARN("Signature verification succeeded");
}
return type.storePolicy(id, v, nid, a, al);
};
@@ -291,15 +280,15 @@ SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
}
void
SecureDht::get(const InfoHash& id, GetCallback cb, DoneCallback donecb, Value::Filter&& f)
SecureDht::get(const InfoHash& id, GetCallback cb, DoneCallback donecb, Value::Filter&& f, Where&& w)
{
Dht::get(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)), donecb);
Dht::get(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)), donecb, {}, std::forward<Where>(w));
}
size_t
SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f)
SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f, Where&& w)
{
return Dht::listen(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)));
return Dht::listen(id, getCallbackFilter(cb, std::forward<Value::Filter>(f)), {}, std::forward<Where>(w));
}
void
@@ -333,7 +322,7 @@ SecureDht::putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallb
},
[hash,val,this,callback,permanent] (bool /* ok */) {
sign(*val);
put(hash, val, callback, {}, permanent);
put(hash, val, callback, time_point::max(), permanent);
},
Value::IdFilter(val->id)
);
@@ -350,7 +339,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_pt
}
DHT_LOG.WARN("Encrypting data for PK: %s", pk->getId().toString().c_str());
try {
put(hash, encrypt(*val, *pk), callback, {}, permanent);
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());
if (callback)
+18 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 Savoir-faire Linux Inc.
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
*/
#include "utils.h"
#include "sockaddr.h"
#include "default_types.h"
namespace dht {
@@ -47,10 +48,14 @@ print_addr(const sockaddr_storage& ss, socklen_t sslen)
}
std::string
printAddr(const Address& addr) {
printAddr(const SockAddr& addr) {
return print_addr((const sockaddr*)&addr.first, addr.second);
}
bool operator==(const SockAddr& a, const SockAddr& b) {
return a.equals(b);
}
time_point from_time_t(std::time_t t) {
return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now());
}
@@ -85,4 +90,15 @@ unpackMsg(Blob b) {
return msgpack::unpack((const char*)b.data(), b.size());
}
msgpack::object*
findMapValue(msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if (o.key.type == msgpack::type::STR && o.key.as<std::string>() == key)
return &o.val;
}
return nullptr;
}
}
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff. Show more