Compare commits

...
140 Commits
Author SHA1 Message Date
Adrien Béraud 446da4b792 value: use move in where 2022-12-30 20:42:16 -05:00
Adrien Béraud aa958b0f1d value: inline filter 2022-12-30 20:42:14 -05:00
Adrien Béraud 58be07a8b0 infohash: add to_view() 2022-12-30 20:42:11 -05:00
Adrien Béraud 6c61ac53c4 proxy client: cleanup 2022-12-30 20:42:08 -05:00
Sébastien Blin 6e73a78a8b unifiedpush: remove unifiedpush parameter
Because there is multiple unifiedpush endpoint (ntfy.sh is one),
we should not pass it as an option to dhtnode, but use the one
provided by the user in the token (from unified push library).
2022-12-30 20:36:49 -05:00
Amin Bandali f2623bd51d build/cmake: Set opendht-c-static's OUTPUT_NAME to opendht-c. 2022-12-30 20:35:17 -05:00
Sébastien Blin d6a99d0edd proxyclient: add possibility to set the platform
This allow android to change the platform to "unifiedpush".
2022-11-17 11:46:09 -05:00
Sébastien Blin b9ccc968b2 proxyserver: add support for UnifiedPush standard
Make the proxy able to support the UnifiedPush platform, so that
applications using the proxy server can use any UnifiedPush provider.

Documentation: https://unifiedpush.org/

How to test:
+ Install a UnifiedPush provider on a device (e.g. https://ntfy.sh)
+ Run dhtnode with a proxyserver and --unifiedpush https://ntfy.sh
+ Subscribe to a random topic on ntfy (e.g. "dhtproxytest")
+ Subscribe to a hash on the DHT:
    curl -X SUBSCRIBE http://my.dht.proxy:8000/key/foo \
         -d '{"key":"dhtproxytest", "platform":"unifiedpush"}'
+ Send data on the subscribed hash

Note: the topic should be completely random.
2022-10-11 15:14:51 -04:00
Sébastien Blin 7e33c4fc76 dht_proxy_server: fix push notifications if tls is enabled
If the proxy got TLS enabled, this doesn't mean that the REST
endpoint for push notifications is also using TLS.

Also, fix an incorrect log.
2022-10-11 11:54:37 -04:00
Adrien Béraud 39bb520339 proxy server: don't send refresh notification for non-push operations 2022-09-22 12:46:54 -04:00
Sébastien Blin 18e53b9ec8 proxyserver: send correct value id to client
when searching for a value to put, the proxy server returned
a json with value->id = 0, causing the client to not refreshing
correctly the values later (when timeout-ing, the value to refresh
is not found).
2022-09-15 11:45:11 -04:00
Sébastien Blin 0b5379380a rust: update os_socketaddr to latest version 2022-09-08 11:47:02 -04:00
Sébastien Blin b800012c57 proxyserver: add topic to msgpack 2022-09-08 11:15:28 -04:00
Sébastien Blin ebeff20215 dht_proxy_server: fix permanent put
When a second permanent put request was received, we didn't call
async_wait after changing the expiration, causing push to not be
sent the second day and presence to expire on some devices after
~3 days.
2022-09-07 16:47:37 -04:00
Adrien Béraud 16ff16bd39 docker, ci: update restinio 2022-09-02 17:15:29 -04:00
Adrien Béraud 0d28a7bdab ci/github: update restinio 2022-09-02 17:14:58 -04:00
Adrien Béraud 69a1bdfc45 update version to 2.4.10 2022-09-02 17:01:23 -04:00
Adrien Béraud af7d88b057 crypto: allow to build all from std::string_view 2022-08-11 14:52:14 -04:00
Sébastien Blin abe2e018b6 Merge pull request #629 from AmarOk1412/fix/request_timeout
http: modify timeout behaviour
2022-08-11 14:41:10 -04:00
Sébastien Blin 2e79ee4f11 dht_proxy_client: fix not contextually convertible to 'bool' error
The current master is broken with clang, this fix the issue.
2022-08-11 14:30:59 -04:00
Sébastien Blin 8b022d0022 Merge branch 'master' into fix/request_timeout 2022-08-11 13:49:44 -04:00
Sébastien Blin 5399dbdfbc proxy_client: reconnect account if local ip changes
When switching between two network interfaces, local address will
change but not the public ip. This generally cause the client to
not correctly updates its candidates.
In this patch, we inject in the proxy client the local candidates
and use it to check if the network changed.
2022-08-11 12:32:44 -04:00
Sébastien Blin 0e3bca1dde http: modify timeout behaviour
In the previous version, the timeout for the connection could be
set only after async_connect while the request is sending.
This means if async_connect is slow (it can happen as if there is
an ipv6 endpoint, it can try to resolve it during dozens of seconds
before falling back on ipv4).

In this patch, it moves the timeout callback in the request. This
callback will be set just before async_connect, to be sure that we
are using the callback while connecting.
2022-08-11 11:17:30 -04:00
Adrien Béraud a992aa1f05 crypto: allow to build all from std::string_view 2022-07-28 17:11:25 -04:00
Adrien Béraud 1a267418dd thread pool: release tasks on stop 2022-07-28 17:08:08 -04:00
kkostiuk 0f8d891476 iOS: drop support for voip notifications 2022-07-25 15:26:57 -04:00
Adrien Béraud b9c79a1de5 thread pool: release tasks on stop 2022-07-20 16:35:47 -04:00
Adrien Béraud 2c7edb695f update version to 2.4.9 2022-07-18 11:43:35 -04:00
Adrien Béraud c3ad33687e misc: fix various warnings 2022-07-17 14:41:41 -04:00
Adrien Béraud 9c5e5cd7b7 proxy server: export symbols for ProxyServerConfig 2022-07-17 14:41:02 -04:00
Adrien Béraud 9048e4a31c peer discovery: cleanup, reduce memory usage 2022-07-17 14:29:54 -04:00
Adrien Béraud ba1b3c26c5 procy client: use new routes 2022-07-17 13:00:05 -04:00
Adrien Béraud c6b4e317df dhtrunner: only start peer discovery if proxy is disabled 2022-07-17 13:00:05 -04:00
Adrien Béraud 44267a72de ci/github: cleanup 2022-07-17 13:00:05 -04:00
Adrien Béraud 8c1c5d09c7 build: use Wno-deprecated 2022-07-17 13:00:05 -04:00
Adrien Béraud acadeb220a docker: add dhtnode image 2022-07-05 20:02:45 -04:00
Adrien Béraud ff7c80d416 build/dev: build in sanitize mode 2022-07-05 19:39:36 -04:00
Adrien Béraud 577f2a0645 proxy server: allow to configure address to bind 2022-07-05 19:32:29 -04:00
Adrien Béraud 48e718ffd8 ci/github: update release action 2022-07-05 16:49:54 -04:00
Adrien Béraud 07d25a4140 docker: install systemd 2022-07-05 16:48:23 -04:00
Adrien Béraud 2f7fabf1c7 ci/github: use secrets.AUTH_TOKEN 2022-07-05 16:25:42 -04:00
Adrien Béraud 60274655dd ci/github: release on tag 2022-07-05 16:20:20 -04:00
Adrien Béraud eace3d91b2 docker: add python3-virtualenv 2022-07-05 15:21:32 -04:00
Adrien Béraud 86cc41f446 docker: use Ubuntu 22.04 for LLVM build 2022-07-05 15:12:27 -04:00
Adrien Béraud 3ac5b9466a ci/github: don't build static lib 2022-07-05 15:10:02 -04:00
Adrien Béraud c95c3de136 docker: use Ubuntu 22.04 2022-07-05 15:09:07 -04:00
Adrien Béraud a865d6854c ci/github: use unique names for steps 2022-07-05 14:57:31 -04:00
Adrien Béraud 52b735b1b9 ci/github: build Python Wheel 2022-07-05 14:27:02 -04:00
Adrien Béraud f862305f78 ci/github: build LLVM Docker images 2022-07-05 14:18:24 -04:00
Adrien Béraud ce7ffbf2cd build/python: add dist target 2022-07-05 14:18:24 -04:00
Adrien Béraud 687f643059 build/python: add pyproject.toml 2022-07-05 14:18:24 -04:00
Adrien Béraud f6e3fc99e6 build/cmake: refactor library linking 2022-07-05 14:18:24 -04:00
Adrien Béraud 293662a710 proxyserver: cleanup, avoid ref-to-temporary 2022-07-05 12:16:41 -04:00
Adrien Béraud 437252bfcc proxyserver: add bundleId at the end of ProxyServerConfig 2022-07-04 18:20:32 -04:00
kkostiuk ead21d24a0 proxyserver: add application bundle id option 2022-07-04 18:17:12 -04:00
Adrien Béraud 53de63e829 update version to 2.4.8 2022-06-30 16:10:25 -04:00
Adrien Béraud 633a03d76a ios: support multiple notification types
- VOIP notifications for iOS < 14.5
- alert and background notifications for iOS >= 14.5
2022-06-30 15:44:16 -04:00
Adrien Béraud 3e5fbb0b5c Update codeql-analysis.yml 2022-06-30 10:48:25 -04:00
Adrien Béraud 6d13e301f9 Create codeql-analysis.yml 2022-06-30 10:43:18 -04:00
Adrien Béraud 4d356b6dca ci/github: add experimental docker build action 2022-06-29 16:39:49 -04:00
Adrien Béraud 44a251de56 build/autotools: don't export internal symbols 2022-06-28 16:23:40 -04:00
Adrien Béraud 1c536a4c51 update version to 2.4.7 2022-06-28 14:23:23 -04:00
Adrien Béraud 502a649f42 build/cmake: use max version for cmake_minimum_required 2022-06-28 14:22:49 -04:00
Adrien Béraud 12a52c78ac x509: make PrivateKey::getPublicKey() thread-safe 2022-06-28 14:12:45 -04:00
Adrien Béraud df2a775927 build/autotols: allow to build with header-only msgpack-cxx installation 2022-06-28 14:12:45 -04:00
Adrien Béraud 2c86ccbe15 build/pkgconfig: update project description 2022-06-28 14:12:45 -04:00
Adrien Béraud b9321a338b buiild/autotools: use -fvisibility=hidden in release mode 2022-06-28 14:12:45 -04:00
Adrien Béraud dc9a211fb0 crypto: protect Id caching with atomic_bool 2022-06-27 15:40:45 -04:00
Adrien Béraud d49b394eae crypto: cache public key id 2022-06-27 15:40:45 -04:00
Adrien Béraud f82c68a871 crypto: remove support for GnuTLS < 3.4 2022-06-27 15:40:45 -04:00
Sébastien Blin 3f4235da69 infohash: fix alignment warning 2022-06-27 15:32:50 -04:00
Sébastien Blin e259cb0847 infohash: remove optimization due to weird warnings
Current operator== creates a very weird warning about using an
uninitialized value (no warning without the reinterpret_cast).
2022-06-27 14:37:25 -04:00
Adrien Béraud 08f9b424de cmake: allow to build with header-only msgpack-cxx installation 2022-06-23 14:26:26 -04:00
Adrien Béraud d33c3515f8 update version to 2.4.6 2022-06-23 10:05:28 -04:00
Adrien Béraud 0a70b0f80f dhtrunner: don't bind port if proxy is used 2022-06-22 22:20:15 -04:00
Adrien Béraud 949cbb9fc7 sockaddr: allow to release ownership 2022-06-22 22:20:15 -04:00
Adrien Béraud 37cfbffdca dhtcnode: cleanup 2022-06-22 22:20:15 -04:00
Adrien Béraud efad2ada89 dhtrunner: make getPublicAddress const 2022-06-22 22:20:15 -04:00
Adrien Béraud d825f4e5ae misc: use std::make_unique 2022-06-08 13:14:09 -04:00
Adrien Béraud baa2a5d21c dhtrunner: remove support for running both dht and proxy client
If configured to run as a proxy client, no port will be bound and the local dht node
won't be instantiated.
2022-06-08 13:14:09 -04:00
Sébastien Blin b3f9683018 securedht: avoid to update cache if not necessary 2022-06-08 13:07:06 -04:00
Adrien Béraud 6d1819acb9 securedht: fix warning 2022-06-07 15:58:16 -04:00
Adrien Béraud d6ee44b640 dhtrunner: use consistent path for state 2022-06-07 15:38:44 -04:00
Peter Saveliev 383c53d71f python/tools: network builder v2
* `-n`: interfaces number check (1 <= ifnum <= 245)
* `-b`: turn on NDB debug logging, very chatty, dump topology DB files
* `-v`: verbose mode, print main operations
* fix code formatting (isort, flake8, black)
* code refactoring
2022-06-07 15:29:07 -04:00
Peter Saveliev 833c647524 python/tools: update network builder
Use updated pyroute2 API:

* NSPopen import from the root
* NDB instead of IPDB

No logic changes, only translated obsoleted API calls.
No code formatting.
2022-06-07 15:29:07 -04:00
Adrien Béraud 7f6f50411c autotools: fix check for CppUnit 2022-05-30 10:07:04 -04:00
Adrien Béraud 1c7089c055 github: add minimal build 2022-05-25 11:27:15 -04:00
Adrien Béraud 4641780fe6 update version to 2.4.5 2022-05-25 11:05:34 -04:00
Adrien Béraud c67df2ead3 tasks: generate compile commands 2022-05-25 11:04:59 -04:00
Adrien Béraud 5f743344e5 value: cleanup, move sign & encrypt to cpp 2022-05-25 11:04:46 -04:00
Michael Cho 56442acc84 value: fix build without jsoncpp 2022-05-25 09:49:30 -04:00
Adrien Béraud 41c9104b8a value: add inline specifier to inline methods 2022-05-05 11:33:53 -04:00
Adrien Béraud 126f0ca966 update version to 2.4.4 2022-05-03 14:46:07 -04:00
Adrien Béraud adeca7fa1f tests/dhtrunner: split count per key 2022-04-25 13:48:57 -04:00
Adrien Béraud 5527b6553d c: use void for dht_version 2022-04-25 13:43:59 -04:00
Adrien Béraud 5a6b9db60c securedht: move crypto ops to Value 2022-04-25 13:43:57 -04:00
Adrien Béraud 8f1c075897 update version to 2.4.3 2022-04-22 21:12:54 -04:00
Adrien Béraud fca11e621c tools/dhtcnode: use version arg, cleanup 2022-04-22 21:10:53 -04:00
Adrien Béraud 38a7234ae3 dht: increase max hashes to 1G 2022-04-22 21:01:36 -04:00
Adrien Béraud 115a0c683f c: add dht_infohash_from_hex_null 2022-04-22 21:00:18 -04:00
Adrien Béraud 61b7bed0f8 network engine: minor refactoring 2022-04-22 20:25:18 -04:00
Adrien Béraud dcd8ec7394 tests/dhtrunner: use unlimited store size 2022-04-22 20:25:18 -04:00
Adrien Béraud 51880afcce tests/dhtrunner: consider value expiration for counting 2022-04-22 20:25:18 -04:00
Adrien Béraud db3a4e52b2 dht: add config max_store_keys 2022-04-22 20:24:59 -04:00
Adrien Béraud af8e66b813 tools/dhtnode: show basic storage stats on "ll" 2022-04-20 16:11:21 -04:00
Adrien Béraud 9646eb9374 NodeInfo: add storage stats 2022-04-20 16:10:25 -04:00
Adrien Béraud 0df2fbe5de tools/dhtcnode: print version on startup 2022-04-20 16:09:24 -04:00
Adrien Béraud c39eceeddf tools/dhtcnode: include stdio.h before readline.h 2022-04-20 16:09:08 -04:00
Adrien Béraud 11396c315e c: add dht_version() 2022-04-20 16:08:12 -04:00
Adrien Béraud 955af06e29 dht: add getStorageLimit 2022-04-20 15:56:14 -04:00
Adrien Béraud e207e59226 tools/dhtcnode: count values in listen, add "ll" 2022-04-20 12:23:25 -04:00
Adrien Béraud 0302cee8d5 tools/dhtcnode: use memset instead of bzero 2022-04-19 17:45:14 -04:00
Adrien Béraud 8f4031c8cb update version to 2.4.2
Fix typo in 2.4.1 release
2022-04-19 15:37:46 -04:00
Adrien Béraud f72d1ffa64 update version to 2.4.1 2022-04-19 15:07:55 -04:00
Adrien Béraud 90c65fb0be tests/dhtrunner: increase put count 2022-04-19 15:07:13 -04:00
Adrien Béraud c8eb704a92 dhtrunner: prevent integer underflow in UDP rx callback 2022-04-19 14:51:24 -04:00
Adrien Béraud 4c5e26922c net: increase max queue size
Queue is also time-bounded.
Allow for larger bursts of packets.
2022-04-18 17:24:27 -04:00
Adrien Béraud 724c3e431c dht: notify listeners when value is removed because of limits 2022-04-18 17:19:32 -04:00
Adrien Béraud a9ddf49ecc storage: check size before returning oldest 2022-04-18 17:18:08 -04:00
Adrien Béraud de3dba7ce4 cmake/c: respect OPENDHT_STATIC/SHARED flags 2022-04-15 21:07:56 -04:00
Adrien Béraud cd9eda6511 tools/dhtcnode: increase shutdown pooling period 2022-04-15 21:06:45 -04:00
Adrien Béraud ed972fd365 dht: allow to store up to 64k values per hash 2022-04-15 20:12:48 -04:00
Adrien Béraud 75834fb08f dht: fix potential of-by-one largest computation, cleanup 2022-04-15 20:12:48 -04:00
Adrien Béraud 9991c976ff dht: prevent potential use-after-free in storageChanged 2022-04-15 20:12:48 -04:00
Adrien Béraud 92b08bbbc9 dht: pass value directly to storageChanged 2022-04-15 20:12:48 -04:00
Adrien Béraud 4f9b50dd60 print_addr: use ostringstream insted of stringstream 2022-04-15 19:18:24 -04:00
Adrien Béraud d6d73efa37 dht: update storage bucket on refresh 2022-04-15 19:14:12 -04:00
Adrien Béraud 19a4729bf2 test/dhtrunner: use random port, add more assertions 2022-04-14 20:12:57 -04:00
Adrien Béraud 405b8739ab dhtrunner: always call opEnded once per op 2022-04-14 20:12:55 -04:00
Adrien Béraud 7ed11a02ae c: cleanup dhtcnode 2022-04-12 17:04:55 -04:00
Adrien Béraud 3442e0acd9 build/dev: cleanup launch.json 2022-04-12 15:38:48 -04:00
Adrien Béraud 59f86861d2 docker: install libtool 2022-04-12 15:38:48 -04:00
Adrien Béraud 091d01a799 c: update dhtcnode 2022-04-12 15:38:48 -04:00
Adrien Béraud 1ed45cdcf9 c: support log to stdout/stderr 2022-04-12 15:38:48 -04:00
Adrien Béraud c40ba83cb3 c: support building with autotools 2022-04-12 15:38:48 -04:00
Adrien Béraud 7dc5aa9dfd build/dev: build in build_dev 2022-04-06 12:19:11 -04:00
Adrien Béraud 808eb688b3 tests: wait for put callback before retrieving certificate 2022-04-06 12:18:42 -04:00
Adrien Béraud 12b75a612c misc: fix various clang-tidy warnings 2022-04-06 12:18:20 -04:00
Sprite ac79dc5761 cmake: fix incorrectly linking to libatomic on macOS 2022-04-03 20:44:23 -04:00
Adrien Béraud fe6676f2e6 unit tests: run on pull request 2022-04-03 20:23:37 -04:00
71 changed files with 1969 additions and 989 deletions

No files matched your search

+57 -2
View File
@@ -1,9 +1,10 @@
name: C/C++ CI
on: [push]
on: [push, pull_request]
jobs:
build:
build-ubuntu:
name: Ubuntu/GCC build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@@ -27,3 +28,57 @@ jobs:
run: make
- name: make check
run: make check
build-ubuntu-minimal:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: deps
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
- name: cmake
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DOPENDHT_TESTS=On -DOPENDHT_PEER_DISCOVERY=Off -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=Off -DOPENDHT_PROXY_CLIENT=Off
- name: make
run: cd build && make
build-macos:
name: macOS/Clang build
runs-on: macos-11
steps:
- uses: actions/checkout@v3
- name: deps
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl http-parser cppunit
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz
ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz
cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none .
make -j8 && sudo make install
cd ../../.. && rm -rf restinio
- name: cmake
run: |
mkdir build && cd build
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DOPENDHT_TESTS=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On
- name: make
run: cd build && make
+3 -3
View File
@@ -18,9 +18,9 @@ jobs:
- name: restinio
run: |
mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+53
View File
@@ -0,0 +1,53 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
container:
image: ghcr.io/savoirfairelinux/opendht/opendht-deps:latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+223
View File
@@ -0,0 +1,223 @@
name: Release actions
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME_DEPS: ${{ github.repository }}/opendht-deps
IMAGE_NAME: ${{ github.repository }}/opendht
IMAGE_NAME_DEPS_LLVM: ${{ github.repository }}/opendht-deps-llvm
IMAGE_NAME_LLVM: ${{ github.repository }}/opendht-llvm
IMAGE_NAME_DHTNODE: ${{ github.repository }}/dhtnode
jobs:
build-and-push-deps-image:
name: Dependency Docker image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDeps
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-image:
name: OpenDHT Docker image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-deps-image-llvm:
name: Dependency Docker image (LLVM)
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDepsLlvm
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-image-llvm:
name: OpenDHT Docker image (LLVM)
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileLlvm
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-image-dhtnode:
name: dhtnode Docker image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DHTNODE }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDhtnode
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-python-wheel:
name: Release and build Python Wheel package
runs-on: ubuntu-latest
container: ghcr.io/savoirfairelinux/opendht/opendht-deps:latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: cmake
run: |
mkdir build && cd build && \
cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DOPENDHT_STATIC=Off \
-DOPENDHT_PYTHON=On \
-DOPENDHT_C=Off \
-DOPENDHT_PEER_DISCOVERY=On \
-DOPENDHT_TOOLS=Off \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On
- name: build
run: cd build && make dist
- uses: actions/upload-artifact@v3
with:
name: opendht-wheels-linux
path: build/python/dist/*.whl
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
with:
draft: true
files: build/python/dist/*.whl
+1
View File
@@ -76,4 +76,5 @@ doc/Doxyfile
# build dir
build
build_dev
.DS_Store
+8 -8
View File
@@ -5,9 +5,9 @@
"name": "dhtnode",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/tools/dhtnode",
"program": "${workspaceFolder}/build_dev/tools/dhtnode",
"args": ["-v", "-p", "4222"],
"cwd": "${workspaceFolder}/build",
"cwd": "${workspaceFolder}/build_dev",
"environment": [],
"setupCommands": [
{
@@ -30,8 +30,8 @@
"name": "tests",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/opendht_unit_tests",
"cwd": "${workspaceFolder}/build",
"program": "${workspaceFolder}/build_dev/opendht_unit_tests",
"cwd": "${workspaceFolder}/build_dev",
"environment": [],
"setupCommands": [
{
@@ -41,14 +41,14 @@
}
],
"preLaunchTask": "build",
"linux": {
"linux": {
"MIMode": "gdb",
"externalConsole": false,
},
"osx": {
},
"osx": {
"MIMode": "lldb",
"externalConsole": true,
},
},
}
]
}
+5 -3
View File
@@ -5,7 +5,7 @@
"label": "build",
"type": "shell",
"options": {
"cwd": "${workspaceRoot}/build"
"cwd": "${workspaceRoot}/build_dev"
},
"command": "make",
"args": ["-j4"],
@@ -15,12 +15,14 @@
"label": "cmake",
"type": "shell",
"options": {
"cwd": "${workspaceRoot}/build"
"cwd": "${workspaceRoot}/build_dev"
},
"command": "cmake",
"args": [
"${workspaceRoot}",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=On",
"-DCMAKE_BUILD_TYPE=Debug",
"-DOPENDHT_SANITIZE=On",
"-DOPENDHT_PROXY_CLIENT=On",
"-DOPENDHT_PROXY_SERVER=On",
"-DOPENDHT_TESTS=On",
@@ -37,7 +39,7 @@
"command": "mkdir",
"args": [
"-p",
"${workspaceRoot}/build"
"${workspaceRoot}/build_dev"
]
},
]
+43 -36
View File
@@ -1,10 +1,4 @@
cmake_minimum_required (VERSION 3.10)
if(POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
if(POLICY CMP0069)
cmake_policy(SET CMP0069 NEW)
endif()
cmake_minimum_required (VERSION 3.10..3.20)
if(POLICY CMP0073)
cmake_policy(SET CMP0073 NEW)
endif()
@@ -15,11 +9,12 @@ project (opendht)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
include(CheckIncludeFileCXX)
include(FindPkgConfig)
include(cmake/CheckAtomic.cmake)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 4.0)
set (opendht_VERSION_MINOR 4.10)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -48,7 +43,15 @@ option (OPENDHT_C "Build C bindings" OFF)
find_package(Doxygen)
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
# Build flags
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED on)
# Dependencies
if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
link_libraries (atomic)
endif ()
list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
if (NOT MSVC)
set (THREADS_PREFER_PTHREAD_FLAG TRUE)
@@ -56,7 +59,10 @@ if (NOT MSVC)
find_package (PkgConfig REQUIRED)
find_package (GnuTLS 3.3 REQUIRED)
pkg_search_module (Nettle REQUIRED nettle)
find_package (msgpack REQUIRED)
check_include_file_cxx(msgpack.hpp HAVE_MSGPACKCXX)
if (NOT HAVE_MSGPACKCXX)
find_package (msgpack REQUIRED)
endif()
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
@@ -123,12 +129,8 @@ if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
endif()
# Build flags
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED on)
if (NOT MSVC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wno-deprecated -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
endif ()
@@ -316,10 +318,13 @@ if (OPENDHT_STATIC)
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht")
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
target_link_libraries(opendht-static
PRIVATE ${argon2_LIBRARIES}
PRIVATE ${argon2_LIBRARIES}
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES}
${Jsoncpp_STATIC_LIBRARIES} ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}
${OPENSSL_STATIC_LIBRARIES})
if (APPLE)
target_link_libraries(opendht-static PRIVATE SYSTEM "-framework CoreFoundation" "-framework Security")
endif()
else ()
if (OPENDHT_TOOLS)
function (add_obj_lib name libfile)
@@ -380,34 +385,37 @@ if (OPENDHT_SHARED)
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES})
if (APPLE)
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES}
SYSTEM "-framework CoreFoundation" "-framework Security")
else ()
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES})
target_link_libraries(opendht PRIVATE SYSTEM "-framework CoreFoundation" "-framework Security")
endif ()
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
endif ()
if (OPENDHT_C)
add_library (opendht-c SHARED
c/opendht.cpp
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
if (OPENDHT_SHARED)
target_link_libraries(opendht-c opendht)
else ()
target_link_libraries(opendht-c opendht-static)
add_library (opendht-c SHARED
c/opendht.cpp
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
target_link_libraries(opendht-c PRIVATE opendht)
install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c)
endif ()
if (OPENDHT_STATIC)
add_library (opendht-c-static STATIC
c/opendht.cpp
c/opendht_c.h
)
set_target_properties (opendht-c-static PROPERTIES OUTPUT_NAME "opendht-c")
target_link_libraries(opendht-c-static PRIVATE opendht-static)
install (TARGETS opendht-c-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c-static)
endif ()
# PkgConfig module
@@ -416,7 +424,6 @@ if (OPENDHT_C)
opendht-c.pc
@ONLY
)
install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht-c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install (FILES c/opendht_c.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/opendht)
endif ()
+4
View File
@@ -4,6 +4,10 @@ SUBDIRS =
SUBDIRS += src
if ENABLE_C
SUBDIRS += c
endif
if ENABLE_TOOLS
SUBDIRS += tools
endif
+15
View File
@@ -0,0 +1,15 @@
lib_LTLIBRARIES = libopendht-c.la
noinst_HEADERS = opendht_c.h
AM_CPPFLAGS = -DOPENDHT_C_BUILD -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
if OPENDHT_SHARED
AM_CPPFLAGS += -Dopendht_c_EXPORTS
endif
libopendht_c_la_LIBADD = $(LIBOBJS) ../src/.libs/libopendht.la
libopendht_c_la_SOURCES = \
opendht.cpp
nobase_include_HEADERS = \
opendht_c.h
+23 -11
View File
@@ -17,7 +17,9 @@
*/
#include "opendht_c.h"
#include "opendht.h"
#include <opendht.h>
#include <opendht/log.h>
using ValueSp = std::shared_ptr<dht::Value>;
using PrivkeySp = std::shared_ptr<dht::crypto::PrivateKey>;
@@ -30,6 +32,11 @@ extern "C" {
#include <errno.h>
const char* dht_version()
{
return dht::version();
}
// dht::InfoHash
inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) {
@@ -69,7 +76,11 @@ bool dht_infohash_is_zero(const dht_infohash* h) {
}
void dht_infohash_from_hex(dht_infohash* h, const char* dat) {
*h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2)));
*h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat, HASH_LEN*2)));
}
void dht_infohash_from_hex_null(dht_infohash* h, const char* dat) {
*h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat)));
}
const char* dht_pkid_print(const dht_pkid* h) {
@@ -331,9 +342,16 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
config.proxy_server = conf->proxy_server ? std::string(conf->proxy_server) : std::string{};
config.push_node_id = conf->push_node_id ? std::string(conf->push_node_id) : std::string{};
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.push_topic = conf->push_topic ? std::string(conf->push_topic) : std::string{};
config.push_platform = conf->push_platform ? std::string(conf->push_platform) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
runner->run(port, config);
dht::DhtRunner::Context context;
if (conf->log) {
context.logger = dht::log::getStdLogger();
}
runner->run(port, config, std::move(context));
} catch(...) {
return ENOTCONN;
}
@@ -488,14 +506,8 @@ struct sockaddr** dht_runner_get_public_address(const dht_runner* r) {
if (addrs.empty())
return nullptr;
auto ret = (struct sockaddr**)malloc(sizeof(struct sockaddr*) * (addrs.size() + 1));
for (size_t i=0; i<addrs.size(); i++) {
if (const auto& addr = addrs[i]) {
ret[i] = (struct sockaddr*)malloc(addr.getLength());
memcpy((struct sockaddr*)ret[i], addr.get(), addr.getLength());
} else {
ret[i] = nullptr;
}
}
for (size_t i=0; i<addrs.size(); i++)
ret[i] = addrs[i].release();
ret[addrs.size()] = nullptr;
return ret;
}
+7 -1
View File
@@ -22,7 +22,7 @@
extern "C" {
#endif
#include "def.h"
#include <opendht/def.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdbool.h>
@@ -36,6 +36,8 @@ struct OPENDHT_C_PUBLIC dht_data_view {
};
typedef struct dht_data_view dht_data_view;
OPENDHT_C_PUBLIC const char* dht_version(void);
// dht::Blob
struct OPENDHT_C_PUBLIC dht_blob;
typedef struct dht_blob dht_blob;
@@ -48,6 +50,7 @@ typedef struct dht_infohash dht_infohash;
OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat);
OPENDHT_C_PUBLIC void dht_infohash_from_hex_null(dht_infohash* h, const char* dat);
OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str);
OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h);
@@ -143,10 +146,13 @@ struct OPENDHT_PUBLIC dht_runner_config {
const char* proxy_server;
const char* push_node_id;
const char* push_token;
const char* push_topic;
const char* push_platform;
bool peer_discovery;
bool peer_publish;
dht_certificate* server_ca;
dht_identity client_identity;
bool log;
};
typedef struct dht_runner_config dht_runner_config;
OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config);
+15 -12
View File
@@ -2,6 +2,7 @@
INCLUDE(CheckCXXSourceCompiles)
INCLUDE(CheckLibraryExists)
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/DetermineGCCCompatible.cmake")
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
@@ -32,6 +33,7 @@ function(check_working_cxx_atomics64 varname)
std::atomic<uint64_t> x (0);
int main() {
uint64_t i = x.load(std::memory_order_relaxed);
(void)i;
return 0;
}
" ${varname})
@@ -39,9 +41,10 @@ int main() {
endfunction(check_working_cxx_atomics64)
# This isn't necessary on MSVC, so avoid command-line switch annoyance
# by only running on GCC-like hosts.
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
# Check for (non-64-bit) atomic operations.
if(MSVC)
set(HAVE_CXX_ATOMICS_WITHOUT_LIB True)
elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
# First check if atomics work without the library.
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
@@ -57,16 +60,16 @@ endif()
# Check for 64 bit atomic operations.
if(MSVC)
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
else()
elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
# First check if atomics work without the library.
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
endif()
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
endif()
endif()
endif()
+13
View File
@@ -0,0 +1,13 @@
# Determine if the compiler has GCC-compatible command-line syntax.
if(NOT DEFINED LLVM_COMPILER_IS_GCC_COMPATIBLE)
if(CMAKE_COMPILER_IS_GNUCXX)
set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON)
elseif( MSVC )
set(LLVM_COMPILER_IS_GCC_COMPATIBLE OFF)
elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON)
elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" )
set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON)
endif()
endif()
+30 -17
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 4)
m4_define([opendht_patch_version], 0)
m4_define([opendht_patch_version], 10)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -18,18 +18,33 @@ 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 -pedantic-errors"],
[CXXFLAGS="${CXXFLAGS} -O3 -pedantic-errors"])
[CXXFLAGS="${CXXFLAGS} -g -Og -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -Wno-deprecated -pedantic-errors"],
[CXXFLAGS="${CXXFLAGS} -O3 -Wno-deprecated -pedantic-errors -fvisibility=hidden"])
CPPFLAGS+=" -DOPENDHT_BUILD"
AM_CONDITIONAL([OPENDHT_SHARED], [test "x$enable_shared" != xno])
AM_COND_IF(OPENDHT_SHARED, [
CPPFLAGS+=" -Dopendht_EXPORTS"
])
AC_PROG_CXX
AM_PROG_AR
LT_INIT()
LT_LANG(C++)
AC_LANG(C++)
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX(17,[noext],[mandatory])
dnl Check for logs
AC_ARG_ENABLE([logs], [AS_HELP_STRING([--disable-logs], [Disable 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])
AS_IF([test "x$enable_logs" != "xno"], [], [
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are disabled])
])
dnl Check for C binding
AC_ARG_ENABLE([c], [AS_HELP_STRING([--disable-c], [Disable DHT C binding])])
AM_CONDITIONAL(ENABLE_C, test x$enable_c != "xno")
AM_COND_IF(ENABLE_C, [
AC_DEFINE([OPENDHT_C], [], [Define if DHT C biding is enabled])
])
dnl Check for indexation
@@ -99,11 +114,6 @@ AM_CONDITIONAL(WIN32, [test "x$SYS" = "xmingw32"])
AS_IF([test "x$SYS" = "xandroid"],
[], [LDFLAGS="${LDFLAGS} -lpthread"])
LT_INIT()
LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(17,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
AC_ARG_ENABLE([proxy_server], AS_HELP_STRING([--enable-proxy-server], [Enable proxy server ability]), proxy_server=yes, proxy_server=no)
@@ -122,8 +132,8 @@ AC_ARG_ENABLE([proxy_client], AS_HELP_STRING([--enable-proxy-client], [Enable pr
AM_CONDITIONAL(ENABLE_PROXY_CLIENT, test x$proxy_client == xyes)
AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [Enable tests]), build_tests=yes, build_tests=no)
AM_CONDITIONAL(ENABLE_TESTS, test x$build_tests == xyes)
AM_COND_IF([ENABLE_TESTS], [
AM_CONDITIONAL(ENABLE_TESTS, test "x$build_tests" == xyes)
AS_IF([test "x$build_tests" == xyes], [
PKG_CHECK_MODULES([CppUnit], [cppunit >= 1.12])
])
@@ -131,7 +141,9 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
AC_CHECK_HEADERS([msgpack.hpp], [], [
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
])
PKG_CHECK_MODULES([Argon2], [libargon2])
AC_SUBST(argon2_lib, [", libargon2"])
@@ -160,7 +172,7 @@ AS_IF([test "x$have_openssl" = "xyes"], [
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files]))
AC_CHECK_HEADERS([asio.hpp],, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0], [have_fmt=yes], [have_fmt=no])
AS_IF([test "x$have_fmt" = "xyes"], [
@@ -198,6 +210,7 @@ AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([Makefile
src/Makefile
c/Makefile
tools/Makefile
python/Makefile
python/setup.py
+1
View File
@@ -12,5 +12,6 @@ RUN git clone https://github.com/savoirfairelinux/opendht.git \
-DOPENDHT_TOOLS=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+6 -6
View File
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -9,8 +9,8 @@ RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y \
build-essential pkg-config cmake git wget \
autotools-dev autoconf \
cython3 python3-dev python3-setuptools \
libtool autotools-dev autoconf \
cython3 python3-dev python3-setuptools python3-build python3-virtualenv \
libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \
libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \
libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \
@@ -18,9 +18,9 @@ RUN apt-get update && apt-get install -y \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+28
View File
@@ -0,0 +1,28 @@
FROM ubuntu:20.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN apt-get update && apt-get install -y \
dialog apt-utils \
&& apt-get clean \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update && apt-get install -y \
build-essential pkg-config cmake git wget \
libtool autotools-dev autoconf \
cython3 python3-dev python3-setuptools \
libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \
libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \
libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../.. && rm -rf restinio
+7 -6
View File
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -8,9 +8,10 @@ RUN apt-get update && apt-get install -y \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config git wget libncurses5-dev libreadline-dev \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \
libtool git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip \
python3-setuptools libcppunit-dev python3-pip python3-build python3-virtualenv \
autotools-dev autoconf libssl-dev libargon2-dev \
libfmt-dev libhttp-parser-dev libasio-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y \
@@ -21,9 +22,9 @@ ENV CXX c++
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+4
View File
@@ -0,0 +1,4 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht:latest
CMD ["dhtnode", "-b", "bootstrap.jami.net", "-p", "4222", "--proxyserver", "8080"]
EXPOSE 4222/udp
EXPOSE 8080/tcp
+16
View File
@@ -0,0 +1,16 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
-DOPENDHT_PEER_DISCOVERY=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_TOOLS=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+1
View File
@@ -12,5 +12,6 @@ RUN git clone https://github.com/savoirfairelinux/opendht.git \
-DOPENDHT_TOOLS=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+5
View File
@@ -82,6 +82,8 @@ struct OPENDHT_PUBLIC NodeInfo {
NodeStats ipv4 {};
NodeStats ipv6 {};
size_t ongoing_ops {0};
size_t storage_values {0};
size_t storage_size {0};
in_port_t bound4 {0};
in_port_t bound6 {0};
@@ -132,6 +134,9 @@ struct OPENDHT_PUBLIC Config {
/* If non-0, overrides the default maximum store size. -1 means no limit. */
ssize_t max_store_size {0};
/* If non-0, overrides the default maximum store key count. -1 means no limit. */
ssize_t max_store_keys {0};
/**
* Use appropriate bahavior for a public IP, stable node:
* - No connectivity change triggered when a search fails
+29 -12
View File
@@ -32,6 +32,9 @@ extern "C" {
#include <vector>
#include <memory>
#include <atomic>
#include <mutex>
#include <string_view>
#ifdef _WIN32
#include <iso646.h>
@@ -84,7 +87,8 @@ struct OPENDHT_PUBLIC PublicKey
/** Import public key from serialized data */
PublicKey(const uint8_t* dat, size_t dat_size);
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
PublicKey(std::string_view pk) : PublicKey((const uint8_t*)pk.data(), pk.size()) {}
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; }
~PublicKey();
explicit operator bool() const { return pk; }
@@ -100,12 +104,12 @@ struct OPENDHT_PUBLIC PublicKey
/**
* Get public key fingerprint
*/
InfoHash getId() const;
const InfoHash& getId() const;
/**
* Get public key long fingerprint
*/
PkId getLongId() const;
const PkId& getLongId() const;
bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const;
inline bool checkSignature(const Blob& data, const Blob& signature) const {
@@ -116,7 +120,9 @@ struct OPENDHT_PUBLIC PublicKey
inline Blob encrypt(const Blob& data) const {
return encrypt(data.data(), data.size());
}
inline Blob encrypt(std::string_view data) const {
return encrypt((const uint8_t*)data.data(), data.size());
}
void pack(Blob& b) const;
int pack(uint8_t* out, size_t* out_len) const;
void unpack(const uint8_t* dat, size_t dat_size);
@@ -138,6 +144,11 @@ struct OPENDHT_PUBLIC PublicKey
gnutls_pubkey_t pk {nullptr};
private:
mutable InfoHash cachedId_ {};
mutable PkId cachedLongId_ {};
mutable std::atomic_bool idCached_ {false};
mutable std::atomic_bool longIdCached_ {false};
PublicKey(const PublicKey&) = delete;
PublicKey& operator=(const PublicKey&) = delete;
void encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t dst_size) const;
@@ -160,7 +171,9 @@ struct OPENDHT_PUBLIC PrivateKey
PrivateKey& operator=(PrivateKey&& o) noexcept;
PrivateKey(const uint8_t* src, size_t src_size, const char* password = nullptr);
PrivateKey(const Blob& src, const std::string& password = {}) : PrivateKey(src.data(), src.size(), password.data()) {}
PrivateKey(const Blob& src, const std::string& password = {}) : PrivateKey(src.data(), src.size(), password.c_str()) {}
PrivateKey(std::string_view src, const std::string& password = {}) : PrivateKey((const uint8_t*)src.data(), src.size(), password.c_str()) {}
~PrivateKey();
explicit operator bool() const { return key; }
@@ -175,6 +188,7 @@ struct OPENDHT_PUBLIC PrivateKey
* @returns the signature data.
*/
Blob sign(const uint8_t* data, size_t data_len) const;
inline Blob sign(std::string_view dat) const { return sign((const uint8_t*)dat.data(), dat.size()); }
inline Blob sign(const Blob& dat) const { return sign(dat.data(), dat.size()); }
/**
@@ -201,6 +215,7 @@ private:
PrivateKey& operator=(const PrivateKey&) = delete;
Blob decryptBloc(const uint8_t* src, size_t src_size) const;
mutable std::mutex publicKeyMutex_ {};
mutable std::shared_ptr<PublicKey> publicKey_ {};
};
@@ -286,6 +301,7 @@ class OPENDHT_PUBLIC CertificateRequest {
public:
CertificateRequest();
CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(std::string_view src) : CertificateRequest((const uint8_t*)src.data(), src.size()) {}
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
@@ -319,8 +335,9 @@ private:
class OPENDHT_PUBLIC OcspRequest
{
public:
OcspRequest(gnutls_ocsp_req_t r) : request(r) {};
OcspRequest(gnutls_ocsp_req_t r) : request(r) {}
OcspRequest(const uint8_t* dat_ptr, size_t dat_size);
OcspRequest(std::string_view dat): OcspRequest((const uint8_t*)dat.data(), dat.size()) {}
~OcspRequest();
/*
@@ -338,7 +355,7 @@ class OPENDHT_PUBLIC OcspResponse
{
public:
OcspResponse(const uint8_t* dat_ptr, size_t dat_size);
OcspResponse(const std::string& response) : OcspResponse((const uint8_t*)response.data(), response.size()) {};
OcspResponse(std::string_view response) : OcspResponse((const uint8_t*)response.data(), response.size()) {}
~OcspResponse();
Blob pack() const;
@@ -380,12 +397,10 @@ struct OPENDHT_PUBLIC Certificate {
* ordered from subject to issuer
*/
Certificate(const Blob& crt);
Certificate(const std::string& pem) : cert(nullptr) {
unpack((const uint8_t*)pem.data(), pem.size());
}
Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
unpack(dat, dat_size);
}
Certificate(std::string_view pem) : Certificate((const uint8_t*)pem.data(), pem.size()) {}
/**
* Import certificate chain (PEM or DER),
@@ -486,9 +501,9 @@ struct OPENDHT_PUBLIC Certificate {
PublicKey getPublicKey() const;
/** Same as getPublicKey().getId() */
InfoHash getId() const;
const InfoHash& getId() const;
/** Same as getPublicKey().getLongId() */
PkId getLongId() const;
const PkId& getLongId() const;
Blob getSerialNumber() const;
@@ -606,6 +621,8 @@ private:
Certificate& operator=(const Certificate&) = delete;
mutable InfoHash cachedId_ {};
mutable PkId cachedLongId_ {};
mutable std::atomic_bool idCached_ {false};
mutable std::atomic_bool longIdCached_ {false};
struct crlNumberCmp {
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
+6 -3
View File
@@ -302,6 +302,9 @@ public:
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
max_store_size = limit;
}
size_t getStorageLimit() const override {
return max_store_size;
}
/**
* Returns the total memory usage of stored values and the number
@@ -340,7 +343,7 @@ private:
static constexpr unsigned LISTEN_NODES {4};
/* The maximum number of hashes we're willing to track. */
static constexpr unsigned MAX_HASHES {1024 * 1024};
static constexpr unsigned MAX_HASHES {1024 * 1024 * 1024};
/* The maximum number of searches we keep data about. */
static constexpr unsigned MAX_SEARCHES {1024 * 1024};
@@ -447,13 +450,13 @@ private:
// Storage
void storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t tid, Query&& = {}, int version = 0);
bool storageStore(const InfoHash& id, const Sp<Value>& value, time_point created, const SockAddr& sa = {}, bool permanent = false);
bool storageErase(const InfoHash& id, Value::Id vid);
bool storageRefresh(const InfoHash& id, Value::Id vid);
void expireStore();
void expireStorage(InfoHash h);
void expireStore(decltype(store)::iterator);
void storageChanged(const InfoHash& id, Storage& st, ValueStorage&, bool newValue);
void storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>>& values, size_t totalSize);
void storageChanged(const InfoHash& id, Storage& st, const Sp<Value>&, bool newValue);
std::string printStorageLog(const decltype(store)::value_type&) const;
/**
+4
View File
@@ -221,6 +221,7 @@ public:
* Set the in-memory storage limit in bytes
*/
virtual void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) = 0;
virtual size_t getStorageLimit() const = 0;
/**
* Returns the total memory usage of stored values and the number
@@ -264,6 +265,9 @@ public:
virtual void setPushNotificationToken(const std::string&) {};
virtual void setPushNotificationTopic(const std::string&) {};
virtual void setPushNotificationPlatform(const std::string&) {};
/**
* Call linked callback with a push notification
* @param notification to process
+38
View File
@@ -67,6 +67,22 @@ public:
#endif
}
virtual void setPushNotificationTopic(const std::string& topic) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
notificationTopic_ = topic;
#else
(void) topic;
#endif
}
virtual void setPushNotificationPlatform(const std::string& platform) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
platform_ = platform;
#else
(void) platform;
#endif
}
virtual ~DhtProxyClient();
/**
@@ -263,6 +279,7 @@ public:
void dumpTables() const override {}
std::vector<unsigned> getNodeMessageStats(bool) override { return {}; }
void setStorageLimit(size_t) override {}
virtual size_t getStorageLimit() const override { return 0; }
void connectivityChanged(sa_family_t) override {
getProxyInfos();
}
@@ -335,6 +352,8 @@ private:
NodeStatus statusIpv6_ {NodeStatus::Disconnected};
NodeStats stats4_ {};
NodeStats stats6_ {};
SockAddr localAddrv4_;
SockAddr localAddrv6_;
SockAddr publicAddressV4_;
SockAddr publicAddressV6_;
std::atomic_bool launchConnectedCbs_ {false};
@@ -399,6 +418,25 @@ private:
*/
std::string deviceKey_ {};
/**
* Notification topic for ios notifications.
*/
std::string notificationTopic_ {};
/**
* Platform for push notifications (supported android, ios, unifiedpush)
*/
std::string platform_
#ifdef __ANDROID__
{"android"};
#else
#ifdef __APPLE__
{"ios"};
#else
{};
#endif
#endif
const std::function<void()> loopSignal_;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
+21 -7
View File
@@ -40,7 +40,8 @@ namespace dht {
enum class PushType {
None = 0,
Android,
iOS
iOS,
UnifiedPush
};
}
MSGPACK_ADD_ENUM(dht::PushType)
@@ -61,11 +62,13 @@ class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
using RequestStatus = restinio::request_handling_status_t;
struct ProxyServerConfig {
struct OPENDHT_PUBLIC ProxyServerConfig {
std::string address {};
in_port_t port {8000};
std::string pushServer {};
std::string persistStatePath {};
dht::crypto::Identity identity {};
std::string bundleId {};
};
/**
@@ -273,6 +276,8 @@ private:
restinio::router::route_params_t params);
#ifdef OPENDHT_PUSH_NOTIFICATIONS
PushType getTypeFromString(const std::string& type);
std::string getDefaultTopic(PushType type);
/**
* Subscribe to push notifications for an iOS or Android device.
* Method: SUBSCRIBE "/{InfoHash: .*}"
@@ -300,7 +305,7 @@ private:
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, Json::Value&& json, PushType type, bool highPriority);
void sendPushNotification(const std::string& key, Json::Value&& json, PushType type, bool highPriority, const std::string& topic);
/**
* Send push notification with an expire timeout.
@@ -308,9 +313,10 @@ private:
* @param pushToken
* @param json
* @param type
* @param topic
*/
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
std::function<Json::Value()> json, PushType type);
std::function<Json::Value()> json, PushType type, const std::string& topic);
/**
* Remove a push listener between a client and a hash
@@ -382,11 +388,12 @@ private:
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
Sp<Value> value;
PushType type;
std::string topic;
template <typename Packer>
void msgpack_pack(Packer& p) const
{
p.pack_map(2 + (sessionCtx ? 1 : 0) + (clientId.empty() ? 0 : 1) + (type == PushType::None ? 0 : 2));
p.pack_map(2 + (sessionCtx ? 1 : 0) + (clientId.empty() ? 0 : 1) + (type == PushType::None ? 0 : 2) + (topic.empty() ? 0 : 1));
p.pack("value"); p.pack(value);
p.pack("exp"); p.pack(to_time_t(expiration));
if (not clientId.empty()) {
@@ -400,6 +407,9 @@ private:
p.pack("t"); p.pack(type);
p.pack("token"); p.pack(pushToken);
}
if (not topic.empty()) {
p.pack("top"); p.pack(topic);
}
}
void msgpack_unpack(const msgpack::object& o);
@@ -415,6 +425,7 @@ private:
mutable std::atomic<time_point> lastStatsReset_ {time_point::min()};
std::string pushServer_;
std::string bundleId_;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener {
@@ -425,11 +436,12 @@ private:
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
PushType type;
std::string topic;
template <typename Packer>
void msgpack_pack(Packer& p) const
{
p.pack_map(sessionCtx ? 4 : 3);
p.pack_map(3 + (sessionCtx ? 1 : 0) + (topic.empty() ? 0 : 1));
p.pack("cid"); p.pack(clientId);
p.pack("exp"); p.pack(to_time_t(expiration));
if (sessionCtx) {
@@ -437,6 +449,9 @@ private:
p.pack("sid"); p.pack(sessionCtx->sessionId);
}
p.pack("t"); p.pack(type);
if (!topic.empty()) {
p.pack("top"); p.pack(topic);
}
}
void msgpack_unpack(const msgpack::object& o);
@@ -446,7 +461,6 @@ private:
MSGPACK_DEFINE_ARRAY(listeners)
};
std::map<std::string, PushListener> pushListeners_;
proxy::ListenToken tokenPushNotif_ {0};
#endif //OPENDHT_PUSH_NOTIFICATIONS
};
+18 -20
View File
@@ -61,6 +61,8 @@ public:
std::string proxy_server {};
std::string push_node_id {};
std::string push_token {};
std::string push_topic {};
std::string push_platform {};
bool peer_discovery {false};
bool peer_publish {false};
std::shared_ptr<dht::crypto::Certificate> server_ca;
@@ -273,13 +275,13 @@ public:
* Usefull to restart a node and get things running fast without putting load on the network.
*/
void bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple cb={});
void bootstrap(const SockAddr& addr, DoneCallbackSimple cb={});
void bootstrap(SockAddr addr, 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);
void bootstrap(std::vector<NodeExport> nodes);
/**
* Add host:service to bootstrap nodes, and ping this node.
@@ -335,6 +337,7 @@ public:
std::pair<size_t, size_t> getStoreSize() const;
void getStorageLimit() const;
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT);
std::vector<NodeExport> exportNodes() const;
@@ -371,8 +374,8 @@ public:
std::string getRoutingTablesLog(sa_family_t af) const;
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);
std::vector<SockAddr> getPublicAddress(sa_family_t af = AF_UNSPEC) const;
std::vector<std::string> getPublicAddressStr(sa_family_t af = AF_UNSPEC) const;
void getPublicAddress(std::function<void(std::vector<SockAddr>&&)>, sa_family_t af = AF_UNSPEC);
// securedht methods
@@ -436,7 +439,6 @@ public:
/**
* Start or stop the proxy
* @param proxify if we want to use the proxy
* @param deviceKey non empty to enable push notifications
*/
void enableProxy(bool proxify);
@@ -447,6 +449,16 @@ public:
*/
void setPushNotificationToken(const std::string& token);
/**
* Sets the push notification topic
*/
void setPushNotificationTopic(const std::string& topic);
/**
* Sets the push notification platform
*/
void setPushNotificationPlatform(const std::string& platform);
/**
* Insert a push notification to process for OpenDHT
*/
@@ -473,12 +485,9 @@ private:
DoneCallback bindOpDoneCallback(DoneCallback&& cb);
DoneCallbackSimple bindOpDoneCallback(DoneCallbackSimple&& cb);
/** Local DHT instance */
/** DHT instance */
std::unique_ptr<SecureDht> dht_;
/** Proxy client instance */
std::unique_ptr<SecureDht> dht_via_proxy_;
/** true if we are currently using a proxy */
std::atomic_bool use_proxy {false};
@@ -490,17 +499,6 @@ private:
* reset dht clients
*/
void resetDht();
/**
* @return the current active DHT
*/
SecureDht* activeDht() const;
/**
* Store current listeners and translates global tokens for each client.
*/
struct Listener;
std::map<size_t, Listener> listeners_;
size_t listener_token_ {1};
mutable std::mutex dht_mtx {};
std::thread dht_thread {};
+15 -2
View File
@@ -114,13 +114,16 @@ public:
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
const asio::ip::address& local_address() const;
void timeout(const std::chrono::seconds& timeout, HandlerCb cb = {});
void close();
private:
template<typename T>
T wrapCallabck(T cb) const {
T wrapCallback(T cb) const {
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
cb(params...);
};
@@ -142,6 +145,8 @@ private:
asio::streambuf read_buf_;
std::istream istream_;
asio::ip::address local_address_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
bool checkOcsp_ {false};
@@ -261,6 +266,11 @@ public:
return resolver_->get_url();
};
void timeout(const std::chrono::seconds& timeout, HandlerCb cb = {}) {
timeout_ = timeout;
timeoutCb_ = cb;
}
/** The previous request in case of redirect following */
std::shared_ptr<Request> getPrevious() const {
return prev_.lock();
@@ -370,6 +380,9 @@ private:
std::weak_ptr<Request> prev_;
unsigned num_redirect {0};
bool follow_redirect {true};
HandlerCb timeoutCb_ {};
std::chrono::seconds timeout_ {0};
};
} // namespace http
+3 -7
View File
@@ -103,13 +103,7 @@ public:
static constexpr inline Hash zero() noexcept { return Hash{}; }
bool operator==(const Hash& h) const {
auto a = reinterpret_cast<const uint32_t*>(data_.data());
auto b = reinterpret_cast<const uint32_t*>(h.data_.data());
constexpr unsigned n = N / sizeof(uint32_t);
for (unsigned i=0; i < n; i++)
if (a[i] != b[i])
return false;
return true;
return data_ == h.data_;
}
bool operator!=(const Hash& h) const { return !(*this == h); }
@@ -255,6 +249,8 @@ public:
template <size_t M>
OPENDHT_PUBLIC friend std::istream& operator>> (std::istream& s, Hash<M>& h);
/** Returns view to thread-allocated memory, only valid until the next call to this function. */
std::string_view to_view() const { return std::string_view(to_c_str(), N*2); }
const char* to_c_str() const;
std::string toString() const;
+10 -10
View File
@@ -252,12 +252,12 @@ public:
* @param values The values to send.
* @param version If version = 1, a request will be used to answer to the listener
*/
void tellListener(Sp<Node> n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken,
void tellListener(const Sp<Node>& n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken,
std::vector<Sp<Node>>&& nodes, std::vector<Sp<Node>>&& nodes6,
std::vector<Sp<Value>>&& values, const Query& q, int version);
void tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values, int version);
void tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values, int version);
void tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values, int version);
void tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector<Value::Id>& values, int version);
bool isRunning(sa_family_t af) const;
inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; }
@@ -278,7 +278,7 @@ public:
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
sendPing(const Sp<Node>& n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
/**
* Send a "ping" request to a given node.
@@ -309,7 +309,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendFindNode(Sp<Node> n,
Sp<Request> sendFindNode(const Sp<Node>& n,
const InfoHash& hash,
want_t want = -1,
RequestCb&& on_done = {},
@@ -328,7 +328,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendGetValues(Sp<Node> n,
Sp<Request> sendGetValues(const Sp<Node>& n,
const InfoHash& hash,
const Query& query,
want_t want,
@@ -357,7 +357,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendListen(Sp<Node> n,
Sp<Request> sendListen(const Sp<Node>& n,
const InfoHash& hash,
const Query& query,
const Blob& token,
@@ -377,7 +377,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendAnnounceValue(Sp<Node> n,
Sp<Request> sendAnnounceValue(const Sp<Node>& n,
const InfoHash& hash,
const Sp<Value>& v,
time_point created,
@@ -397,7 +397,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendRefreshValue(Sp<Node> n,
Sp<Request> sendRefreshValue(const Sp<Node>& n,
const InfoHash& hash,
const Value::Id& vid,
const Blob& token,
@@ -416,7 +416,7 @@ public:
*
* @return the request with information concerning its success.
*/
Sp<Request> sendUpdateValues(Sp<Node> n,
Sp<Request> sendUpdateValues(const Sp<Node>& n,
const InfoHash& infohash,
const std::vector<Sp<Value>>& values,
time_point created,
+1 -1
View File
@@ -42,7 +42,7 @@ namespace dht {
namespace net {
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 64;
static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650);
int bindSocket(const SockAddr& addr, SockAddr& bound);
+4
View File
@@ -173,6 +173,10 @@ public:
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
dht_->setStorageLimit(limit);
}
size_t getStorageLimit() const override {
return dht_->getStorageLimit();
}
std::vector<NodeExport> exportNodes() const override {
return dht_->exportNodes();
}
+9
View File
@@ -236,6 +236,15 @@ public:
return *reinterpret_cast<sockaddr_in6*>(get());
}
/**
* Releases the ownership of the managed object, if any.
* The caller is responsible for deleting the object with free().
*/
inline sockaddr* release() {
len = 0;
return addr.release();
}
/**
* Return true if address is a loopback IP address.
*/
+53 -55
View File
@@ -171,29 +171,29 @@ struct OPENDHT_PUBLIC Value
template<typename Functor>
Filter(Functor f) : std::function<bool(const Value&)>::function(f) {}
Filter chain(Filter&& f2) {
inline Filter chain(Filter&& f2) {
auto f1 = *this;
return chain(std::move(f1), std::move(f2));
}
Filter chainOr(Filter&& f2) {
inline Filter chainOr(Filter&& f2) {
auto f1 = *this;
return chainOr(std::move(f1), std::move(f2));
}
static Filter chain(Filter&& f1, Filter&& f2) {
static inline Filter chain(Filter&& f1, Filter&& f2) {
if (not f1) return std::move(f2);
if (not f2) return std::move(f1);
return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
return f1(v) and f2(v);
};
}
static Filter chain(const Filter& f1, const Filter& f2) {
static inline Filter chain(const Filter& f1, const Filter& f2) {
if (not f1) return f2;
if (not f2) return f1;
return [f1,f2](const Value& v) {
return f1(v) and f2(v);
};
}
static Filter chainAll(std::vector<Filter>&& set) {
static inline Filter chainAll(std::vector<Filter>&& set) {
if (set.empty()) return {};
return [set = std::move(set)](const Value& v) {
for (const auto& f : set)
@@ -202,18 +202,18 @@ struct OPENDHT_PUBLIC Value
return true;
};
}
static Filter chain(std::initializer_list<Filter> l) {
static inline Filter chain(std::initializer_list<Filter> l) {
return chainAll(std::vector<Filter>(l.begin(), l.end()));
}
static Filter chainOr(Filter&& f1, Filter&& f2) {
static inline Filter chainOr(Filter&& f1, Filter&& f2) {
if (not f1 or not f2) return {};
return [f1=std::move(f1),f2=std::move(f2)](const Value& v) {
return f1(v) or f2(v);
};
}
static Filter notFilter(Filter&& f) {
static inline Filter notFilter(Filter&& f) {
if (not f) return [](const Value&) { return false; };
return [f](const Value& v) { return not f(v); };
return [f = std::move(f)](const Value& v) { return not f(v); };
}
std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values) {
if (not (*this))
@@ -228,50 +228,50 @@ struct OPENDHT_PUBLIC Value
/* Sneaky functions disguised in classes */
static const Filter AllFilter() {
static inline Filter AllFilter() {
return {};
}
static Filter TypeFilter(const ValueType& t) {
static inline Filter TypeFilter(const ValueType& t) {
return [tid = t.id](const Value& v) {
return v.type == tid;
};
}
static Filter TypeFilter(const ValueType::Id& tid) {
static inline Filter TypeFilter(const ValueType::Id& tid) {
return [tid](const Value& v) {
return v.type == tid;
};
}
static Filter IdFilter(const Id id) {
static inline Filter IdFilter(const Id id) {
return [id](const Value& v) {
return v.id == id;
};
}
static Filter RecipientFilter(const InfoHash& r) {
static inline Filter RecipientFilter(const InfoHash& r) {
return [r](const Value& v) {
return v.recipient == r;
};
}
static Filter OwnerFilter(const crypto::PublicKey& pk) {
static inline Filter OwnerFilter(const crypto::PublicKey& pk) {
return OwnerFilter(pk.getId());
}
static Filter OwnerFilter(const InfoHash& pkh) {
static inline 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) {
static inline Filter SeqNumFilter(uint16_t seq_no) {
return [seq_no](const Value& v) {
return v.seq == seq_no;
};
}
static Filter UserTypeFilter(std::string ut) {
static inline Filter UserTypeFilter(std::string ut) {
return [ut = std::move(ut)](const Value& v) {
return v.user_type == ut;
};
@@ -343,10 +343,10 @@ struct OPENDHT_PUBLIC Value
return unpack<T>(*this);
}
bool isEncrypted() const {
inline bool isEncrypted() const {
return not cypher.empty();
}
bool isSigned() const {
inline bool isSigned() const {
return owner and not signature.empty();
}
@@ -355,37 +355,24 @@ struct OPENDHT_PUBLIC Value
* Afterward, checkSignature() will return true and owner will
* be set to the corresponding public key.
*/
void sign(const crypto::PrivateKey& key) {
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = key.getSharedPublicKey();
signature = key.sign(getToSign());
}
void sign(const crypto::PrivateKey& key);
/**
* Check that the value is signed and that the signature matches.
* If true, the owner field will contain the signer public key.
*/
bool checkSignature() const {
inline bool checkSignature() const {
return isSigned() and owner->checkSignature(getToSign(), signature);
}
std::shared_ptr<crypto::PublicKey> getOwner() const {
return std::static_pointer_cast<crypto::PublicKey>(owner);
inline std::shared_ptr<crypto::PublicKey> getOwner() const {
return owner;
}
/**
* Sign the value with from and returns the encrypted version for to.
*/
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
if (isEncrypted())
throw DhtException("Data is already encrypted.");
setRecipient(to.getId());
sign(from);
Value nv {id};
nv.setCypher(to.encrypt(getToEncrypt()));
return nv;
}
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to);
Value() {}
@@ -453,18 +440,18 @@ struct OPENDHT_PUBLIC Value
return id == o.id and contentEquals(o);
}
void setRecipient(const InfoHash& r) {
inline void setRecipient(const InfoHash& r) {
recipient = r;
}
void setCypher(Blob&& c) {
inline void setCypher(Blob&& c) {
cypher = std::move(c);
}
/**
* Pack part of the data to be signed (must always be done the same way)
*/
Blob getToSign() const {
inline Blob getToSign() const {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
msgpack_pack_to_sign(pk);
@@ -474,7 +461,7 @@ struct OPENDHT_PUBLIC Value
/**
* Pack part of the data to be encrypted
*/
Blob getToEncrypt() const {
inline Blob getToEncrypt() const {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
msgpack_pack_to_encrypt(pk);
@@ -484,7 +471,7 @@ struct OPENDHT_PUBLIC Value
/** print value for debugging */
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Value& v);
std::string toString() const {
inline std::string toString() const {
std::stringstream ss;
ss << *this;
return ss.str();
@@ -638,8 +625,16 @@ struct OPENDHT_PUBLIC Value
*/
unsigned priority {0};
inline bool isSignatureChecked() const {
return signatureChecked;
}
inline bool isDecrypted() const {
return decrypted;
}
bool checkSignature();
Sp<Value> decrypt(const crypto::PrivateKey& key);
private:
friend class SecureDht;
/* Cache for crypto ops */
bool signatureChecked {false};
bool signatureValid {false};
@@ -809,11 +804,11 @@ struct OPENDHT_PUBLIC Where
*
* @return the resulting Where instance.
*/
Where& id(Value::Id id) {
Where&& id(Value::Id id) {
FieldValue fv {Value::Field::Id, id};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
return std::move(*this);
}
/**
@@ -823,11 +818,11 @@ struct OPENDHT_PUBLIC Where
*
* @return the resulting Where instance.
*/
Where& valueType(ValueType::Id type) {
Where&& valueType(ValueType::Id type) {
FieldValue fv {Value::Field::ValueType, type};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
return std::move(*this);
}
/**
@@ -837,11 +832,11 @@ struct OPENDHT_PUBLIC Where
*
* @return the resulting Where instance.
*/
Where& owner(InfoHash owner_pk_hash) {
Where&& owner(InfoHash owner_pk_hash) {
FieldValue fv {Value::Field::OwnerPk, owner_pk_hash};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
return std::move(*this);
}
/**
@@ -851,11 +846,11 @@ struct OPENDHT_PUBLIC Where
*
* @return the resulting Where instance.
*/
Where& seq(uint16_t seq_no) {
Where&& seq(uint16_t seq_no) {
FieldValue fv {Value::Field::SeqNum, seq_no};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
return std::move(*this);
}
/**
@@ -865,11 +860,11 @@ struct OPENDHT_PUBLIC Where
*
* @return the resulting Where instance.
*/
Where& userType(std::string_view user_type) {
Where&& userType(std::string_view user_type) {
FieldValue fv {Value::Field::UserType, Blob {user_type.begin(), user_type.end()}};
if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
filters_.emplace_back(std::move(fv));
return *this;
return std::move(*this);
}
/**
@@ -878,7 +873,10 @@ struct OPENDHT_PUBLIC Where
* @return the resulting Value::Filter.
*/
Value::Filter getFilter() const {
if (filters_.empty()) return {};
if (filters_.empty())
return {};
if (filters_.size() == 1)
return filters_[0].getLocalFilter();
std::vector<Value::Filter> fset;
fset.reserve(filters_.size());
for (const auto& f : filters_) {
+1 -1
View File
@@ -3,7 +3,7 @@ exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenDHT
Description: C++14 Distributed Hash Table library
Description: C++17 Distributed Hash Table library
Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs.private: @http_parser_lib@ -pthread
+6 -1
View File
@@ -3,10 +3,15 @@ set(CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
configure_file(setup.py.in setup.py)
configure_file(pyproject.toml pyproject.toml COPYONLY)
add_custom_target(python ALL
COMMAND python3 setup.py build
DEPENDS opendht opendht_cpp.pxd opendht.pyx)
DEPENDS opendht opendht_cpp.pxd opendht.pyx pyproject.toml)
add_custom_target(dist
COMMAND python3 -m build
DEPENDS opendht opendht_cpp.pxd opendht.pyx pyproject.toml)
install(CODE "execute_process(COMMAND python3 setup.py install --root=\$ENV{DESTDIR}/ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
if (OPENDHT_TOOLS)
+2 -1
View File
@@ -2,7 +2,8 @@ if USE_CYTHON
noinst_HEADERS = \
opendht.pyx \
opendht_cpp.pxd
opendht_cpp.pxd \
pyproject.toml
PYTHON_INSTALL_RECORD = $(builddir)/install_record.txt
+3
View File
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel", "Cython"]
build-backend = "setuptools.build_meta"
+1 -1
View File
@@ -20,7 +20,7 @@ help).
## Python dependencies
- pyroute2 >=0.3.14
- pyroute2 >=0.6.9
- matplotlib
- GeoIP (used by `scanner.py` for drawing map of the world)
- ipaddress
+1 -1
View File
@@ -30,7 +30,7 @@ import traceback
import ipaddress
import netifaces
import numpy as np
from pyroute2.netns.process.proxy import NSPopen
from pyroute2 import NSPopen
import msgpack
from opendht import *
+233 -87
View File
@@ -15,107 +15,253 @@
#
# 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 argparse
import os
import subprocess
import argparse, subprocess
from pyroute2 import NDB, NSPopen
from pyroute2 import IPDB, NetNS
from pyroute2.netns.process.proxy import NSPopen
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Creates a virtual network topology for testing')
parser.add_argument('-i', '--ifname', help='interface name', default='ethdht')
parser.add_argument('-n', '--ifnum', type=int, help='number of isolated interfaces to create', default=1)
parser.add_argument('-r', '--remove', help='remove instead of adding network interfaces', action="store_true")
parser.add_argument('-l', '--loss', help='simulated packet loss (percent)', type=int, default=0)
parser.add_argument('-d', '--delay', help='simulated latency (ms)', type=int, default=0)
parser.add_argument('-4', '--ipv4', help='Enable IPv4', action="store_true")
parser.add_argument('-6', '--ipv6', help='Enable IPv6', action="store_true")
def int_range(mini, maxi):
def check_ifnum(arg):
try:
ret = int(arg)
except ValueError:
raise argparse.ArgumentTypeError('must be an integer')
if ret > maxi or ret < mini:
raise argparse.ArgumentTypeError(
f'must be {mini} <= int <= {maxi}'
)
return ret
return check_ifnum
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Creates a virtual network topology for testing'
)
parser.add_argument(
'-i', '--ifname', help='interface name', default='ethdht'
)
parser.add_argument(
'-n',
'--ifnum',
type=int_range(1, 245),
help='number of isolated interfaces to create',
default=1,
)
parser.add_argument(
'-r',
'--remove',
help='remove instead of adding network interfaces',
action='store_true',
)
parser.add_argument(
'-l',
'--loss',
help='simulated packet loss (percent)',
type=int,
default=0,
)
parser.add_argument(
'-d', '--delay', help='simulated latency (ms)', type=int, default=0
)
parser.add_argument(
'-4', '--ipv4', help='Enable IPv4', action='store_true'
)
parser.add_argument(
'-6', '--ipv6', help='Enable IPv6', action='store_true'
)
parser.add_argument(
'-b',
'--debug',
help='Turn on debug logging and dump topology databases',
action='store_true',
)
parser.add_argument(
'-v',
'--verbose',
help='Turn on verbose output on netns and interfaces operations',
action='store_true',
)
args = parser.parse_args()
local_addr4 = '10.0.42.'
local_addr6 = '2001:db9::'
brige_name = 'br'+args.ifname
bripv4 = f'{local_addr4}1/24'
bripv6 = f'{local_addr6}1/64'
bridge_name = f'br{args.ifname}'
tap_name = f'tap{args.ifname}'
veth_names = []
namespaces = []
ipv4addrs = []
ipv6addrs = []
for ifn in range(args.ifnum):
namespaces.append(f'node{ifn}')
veth_names.append(f'{args.ifname}{ifn}')
ipv4addrs.append(f'{local_addr4}{ifn+8}/24' if args.ipv4 else None)
ipv6addrs.append(f'{local_addr6}{ifn+8}/64' if args.ipv6 else None)
ip = None
try:
ip = IPDB()
with NDB(log='debug' if args.debug else None) as ndb:
if args.remove:
# cleanup interfaces
for ifn in range(args.ifnum):
iface = args.ifname+str(ifn)
if iface in ip.interfaces:
with ip.interfaces[iface] as i:
i.remove()
if 'tap'+args.ifname in ip.interfaces:
with ip.interfaces['tap'+args.ifname] as i:
i.remove()
if brige_name in ip.interfaces:
with ip.interfaces[brige_name] as i:
i.remove()
for ifn in range(args.ifnum):
netns = NetNS('node'+str(ifn))
netns.close()
netns.remove()
else:
for ifn in range(args.ifnum):
iface = args.ifname+str(ifn)
if not iface in ip.interfaces:
ip.create(kind='veth', ifname=iface, peer=iface+'.1').commit()
# cleanup interfaces in the main namespace
for iface in veth_names + [bridge_name] + [tap_name]:
if iface in ndb.interfaces:
ndb.interfaces[iface].remove().commit()
if args.verbose:
print(f'link: del main/{iface}')
ip.create(kind='tuntap', ifname='tap'+args.ifname, mode='tap').commit()
with ip.create(kind='bridge', ifname=brige_name) as i:
for ifn in range(args.ifnum):
iface = args.ifname+str(ifn)
i.add_port(ip.interfaces[iface])
i.add_port(ip.interfaces['tap'+args.ifname])
if args.ipv4:
i.add_ip(local_addr4+'1/24')
if args.ipv6:
i.add_ip(local_addr6+'1/64')
i.up()
with ip.interfaces['tap'+args.ifname] as tap:
tap.up()
for ifn in range(args.ifnum):
iface = args.ifname+str(ifn)
nns = NetNS('node'+str(ifn))
iface1 = iface+'.1'
with ip.interfaces[iface1] as i:
i.net_ns_fd = nns.netns
with ip.interfaces[iface] as i:
i.up()
ip_ns = IPDB(nl=nns)
# cleanup namespaces
for nsname in namespaces:
try:
with ip_ns.interfaces.lo as lo:
lo.up()
with ip_ns.interfaces[iface1] as i:
if args.ipv4:
i.add_ip(local_addr4+str(ifn+8)+'/24')
if args.ipv6:
i.add_ip(local_addr6+str(ifn+8)+'/64')
i.up()
finally:
ip_ns.release()
nsp = NSPopen(nns.netns, ["tc", "qdisc", "add", "dev", iface1, "root", "netem", "delay", str(args.delay)+"ms", str(int(args.delay/2))+"ms", "loss", str(args.loss)+"%", "25%"], stdout=subprocess.PIPE)
#print(nsp.communicate()[0].decode())
ndb.netns[nsname].remove().commit()
if args.verbose:
print(f'netns: del {nsname}')
except KeyError:
pass
else:
# create ports
for veth, nsname, ipv4addr, ipv6addr in zip(
veth_names, namespaces, ipv4addrs, ipv6addrs
):
# create a network namespace and launch NDB for it
#
# another possible solution could be simply to attach
# the namespace to the main NDB instance, but it can
# take a lot of memory in case of many interfaces, thus
# launch and discard netns NDB instances
netns = NDB(
log='debug' if args.debug else None,
sources=[
{
'target': 'localhost',
'netns': nsname,
'kind': 'netns',
}
],
)
if args.verbose:
print(f'netns: add {nsname}')
# create the port and push the peer into the namespace
(
ndb.interfaces.create(
**{
'ifname': veth,
'kind': 'veth',
'state': 'up',
'peer': {'ifname': veth, 'net_ns_fd': nsname},
}
).commit()
)
if args.verbose:
print(f'link: add main/{veth} <-> {nsname}/{veth}')
# bring up namespace's loopback
(
netns.interfaces.wait(ifname='lo', timeout=3)
.set('state', 'up')
.commit()
)
if args.verbose:
print(f'link: set {nsname}/lo')
# bring up the peer
with netns.interfaces.wait(ifname=veth, timeout=3) as i:
i.set('state', 'up')
if args.ipv4:
i.add_ip(ipv4addr)
if args.ipv6:
i.add_ip(ipv6addr)
if args.verbose:
print(f'link: set {nsname}/{veth}, {ipv4addr}, {ipv6addr}')
# disconnect the namespace NDB agent, not removing the NS
if args.debug:
fname = f'{nsname}-ndb.db'
print(f'dump: netns topology database {fname}')
netns.schema.backup(fname)
netns.close()
# set up the emulation QDisc
nsp = NSPopen(
nsname,
[
'tc',
'qdisc',
'add',
'dev',
veth,
'root',
'netem',
'delay',
f'{args.delay}ms',
f'{int(args.delay)/2}ms',
'loss',
f'{args.loss}%',
'25%',
],
stdout=subprocess.PIPE,
)
nsp.communicate()
nsp.wait()
nsp.release()
if args.verbose:
print(
f'netem: add {nsname}/{veth}, '
f'{args.delay}, {args.loss}'
)
if args.ipv4:
subprocess.call(["sysctl", "-w", "net.ipv4.conf."+brige_name+".forwarding=1"])
if args.ipv6:
subprocess.call(["sysctl", "-w", "net.ipv6.conf."+brige_name+".forwarding=1"])
# create the tap
#
# for some reason we should create the tap inteface first,
# and only then bring it up, thus two commit() calls
(
ndb.interfaces.create(
kind='tuntap', ifname=tap_name, mode='tap'
)
.commit()
.set('state', 'up')
.commit()
)
if args.verbose:
print(f'link: add main/{tap_name}')
except Exception as e:
print('Error',e)
finally:
if ip:
ip.release()
# create the bridge and add all the ports
with ndb.interfaces.create(
ifname=bridge_name, kind='bridge', state='up'
) as i:
if args.ipv4:
i.add_ip(bripv4)
if args.ipv6:
i.add_ip(bripv6)
for iface in veth_names + [tap_name]:
i.add_port(iface)
if args.verbose:
print(f'link: add main/{bridge_name}, {bripv4}, {bripv6}')
with open(os.devnull, 'w') as fnull:
if args.ipv4:
subprocess.call(
[
'sysctl',
'-w',
f'net.ipv4.conf.{bridge_name}.forwarding=1',
],
stdout=fnull,
)
if args.verbose:
print(f'sysctl: set {bridge_name} ipv4 forwarding')
if args.ipv6:
subprocess.call(
[
'sysctl',
'-w',
f'net.ipv6.conf.{bridge_name}.forwarding=1',
],
stdout=fnull,
)
if args.verbose:
print(f'sysctl: set {bridge_name} ipv4 forwarding')
if args.debug:
fname = 'main-ndb.db'
print('dump: the main netns topology database')
ndb.schema.backup(fname)
+1 -1
View File
@@ -8,4 +8,4 @@ edition = "2018"
[dependencies]
libc="0.2.0"
os_socketaddr="0.1.0"
os_socketaddr="0.2.3"
+10
View File
@@ -47,6 +47,8 @@ impl DhtRunnerConfig {
proxy_server: ptr::null(),
push_node_id: ptr::null(),
push_token: ptr::null(),
push_topic: ptr::null(),
push_platform: ptr::null(),
peer_discovery: false,
peer_publish: false,
server_ca: ptr::null_mut(),
@@ -73,6 +75,14 @@ impl DhtRunnerConfig {
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_push_topic(&mut self, push_topic: &str) {
self.push_topic = CString::new(push_topic).unwrap().as_ptr();
}
pub fn set_push_platform(&mut self, push_platform: &str) {
self.push_platform = CString::new(push_platform).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
self.dht_config.id.privatekey = Box::into_raw(privatekey);
self.dht_config.id.certificate = Box::into_raw(certificate);
+2
View File
@@ -118,6 +118,8 @@ pub struct DhtRunnerConfig
pub proxy_server: *const c_char,
pub push_node_id: *const c_char,
pub push_token: *const c_char,
pub push_topic: *const c_char,
pub push_platform: *const c_char,
pub peer_discovery: bool,
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
-3
View File
@@ -84,6 +84,3 @@ if ENABLE_INDEXATION
libopendht_la_SOURCES += indexation/pht.cpp
nobase_include_HEADERS += ../include/opendht/indexation/pht.h
endif
clean-local:
rm -rf libargon2.la
+55 -78
View File
@@ -43,18 +43,6 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
// support for GnuTLS < 3.4.
#if GNUTLS_VERSION_NUMBER < 0x030400
#define GNUTLS_PKCS_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES
#define GNUTLS_PKCS_PKCS12_ARCFOUR GNUTLS_PKCS_USE_PKCS12_ARCFOUR
#define GNUTLS_PKCS_PKCS12_RC2_40 GNUTLS_PKCS_USE_PKCS12_RC2_40
#define GNUTLS_PKCS_PBES2_3DES GNUTLS_PKCS_USE_PBES2_3DES
#define GNUTLS_PKCS_PBES2_AES_128 GNUTLS_PKCS_USE_PBES2_AES_128
#define GNUTLS_PKCS_PBES2_AES_192 GNUTLS_PKCS_USE_PBES2_AES_192
#define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256
#endif
#define DHT_AES_LEGACY_ENCRYPT 0
#define DHT_AES_LEGACY_DECRYPT 1
namespace dht {
@@ -110,10 +98,6 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
#if DHT_AES_LEGACY_ENCRYPT
gcm_aes_update(&aes, data_length, data);
#endif
gcm_aes_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
return ret;
@@ -377,12 +361,13 @@ PrivateKey::getPublicKey() const
const std::shared_ptr<PublicKey>&
PrivateKey::getSharedPublicKey() const
{
if (publicKey_)
return publicKey_;
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
publicKey_ = pk;
std::lock_guard<std::mutex> lock(publicKeyMutex_);
if (not publicKey_) {
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
publicKey_ = pk;
}
return publicKey_;
}
@@ -542,36 +527,36 @@ PublicKey::encrypt(const uint8_t* data, size_t data_len) const
return ret;
}
InfoHash
const InfoHash&
PublicKey::getId() const
{
if (not pk)
return {};
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get public key ID: wrong output length.");
return id;
if (pk and not idCached_.load()) {
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get public key ID: wrong output length.");
cachedId_ = id;
idCached_.store(true);
}
return cachedId_;
}
PkId
const PkId&
PublicKey::getLongId() const
{
if (not pk)
return {};
#if GNUTLS_VERSION_NUMBER < 0x030401
throw CryptoException("Can't get 256 bits public key ID: GnuTLS 3.4.1 or higher required.");
#else
PkId h;
size_t sz = h.size();
if (auto err = gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz))
throw CryptoException(std::string("Can't get 256 bits public key ID: ") + gnutls_strerror(err));
if (sz != h.size())
throw CryptoException("Can't get 256 bits public key ID: wrong output length.");
return h;
#endif
if (pk and not longIdCached_.load()) {
PkId h;
size_t sz = h.size();
if (auto err = gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz))
throw CryptoException(std::string("Can't get 256 bits public key ID: ") + gnutls_strerror(err));
if (sz != h.size())
throw CryptoException("Can't get 256 bits public key ID: wrong output length.");
cachedLongId_ = h;
longIdCached_.store(true);
}
return cachedLongId_;
}
gnutls_digest_algorithm_t
@@ -848,42 +833,36 @@ Certificate::getPublicKey() const
return pk_ret;
}
InfoHash
const InfoHash&
Certificate::getId() const
{
if (not cert)
return {};
if (cachedId_)
return cachedId_;
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate public key ID: wrong output length.");
cachedId_ = id;
return id;
if (cert and not idCached_.load()) {
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate public key ID: wrong output length.");
cachedId_ = id;
idCached_.store(true);
}
return cachedId_;
}
PkId
const PkId&
Certificate::getLongId() const
{
if (not cert)
return {};
if (cachedLongId_)
return cachedLongId_;
#if GNUTLS_VERSION_NUMBER < 0x030401
throw CryptoException("Can't get certificate 256 bits public key ID: GnuTLS 3.4.1 or higher required.");
#else
PkId id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length.");
cachedLongId_ = id;
return id;
#endif
if (cert and not longIdCached_.load()) {
PkId id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length.");
cachedLongId_ = id;
longIdCached_.store(true);
}
return cachedLongId_;
}
Blob
@@ -1771,10 +1750,8 @@ std::ostream& operator<< (std::ostream& o, const TrustList::VerifyResult& h)
o << "* Certificate has expired" << std::endl;
if (h.result & GNUTLS_CERT_UNEXPECTED_OWNER)
o << "* The owner is not the expected one" << std::endl;
#if GNUTLS_VERSION_NUMBER >= 0x030401
if (h.result & GNUTLS_CERT_PURPOSE_MISMATCH)
o << "* Certificate or an intermediate does not match the intended purpose" << std::endl;
#endif
if (h.result & GNUTLS_CERT_MISMATCH)
o << "* Certificate presented isn't the expected one" << std::endl;
} else {
+71 -66
View File
@@ -1194,15 +1194,20 @@ Dht::cancelPut(const InfoHash& id, const Value::Id& vid)
};
canceled |= sr_cancel_put(dht4.searches);
canceled |= sr_cancel_put(dht6.searches);
if (canceled)
storageErase(id, vid);
if (canceled) {
auto st = store.find(id);
if (st != store.end()) {
if (auto value = st->second.remove(id, vid))
storageRemoved(id, st->second, {value}, value->size());
}
}
return canceled;
}
// Storage
void
Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newValue)
Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool newValue)
{
if (newValue) {
if (not st.local_listeners.empty()) {
@@ -1212,8 +1217,8 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newVa
cbs.reserve(st.local_listeners.size());
for (const auto& l : st.local_listeners) {
std::vector<Sp<Value>> vals;
if (not l.second.filter or l.second.filter(*v.data))
vals.push_back(v.data);
if (not l.second.filter or l.second.filter(*v))
vals.push_back(v);
if (not vals.empty()) {
if (logger_)
logger_->d(id, "[store %s] sending update local listener with token %lu",
@@ -1234,14 +1239,14 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newVa
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
auto f = l.second.query.where.getFilter();
if (f and not f(*v.data))
if (f and not f(*v))
continue;
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
vals.push_back(v.data);
vals.push_back(v);
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
network_engine.tellListener(node_listeners.first, l.first, id, 0, ntoken, {}, {},
std::move(vals), l.second.query, l.second.version);
@@ -1282,26 +1287,18 @@ Dht::storageStore(const InfoHash& id, const Sp<Value>& value, time_point created
vs->expiration_job = scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id));
}
if (total_store_size > max_store_size) {
auto value = vs->data;
auto value_diff = store.second.values_diff;
expireStore();
storageChanged(id, st->second, value, value_diff > 0);
} else {
storageChanged(id, st->second, vs->data, store.second.values_diff > 0);
}
storageChanged(id, st->second, *vs, store.second.values_diff > 0);
}
return std::get<0>(store);
}
bool
Dht::storageErase(const InfoHash& id, Value::Id vid)
{
auto st = store.find(id);
if (st == store.end())
return false;
auto ret = st->second.remove(id, vid);
total_store_size += ret.size_diff;
total_values += ret.values_diff;
return ret.values_diff;
}
void
Dht::storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t socket_id, Query&& query, int version)
{
@@ -1333,36 +1330,8 @@ Dht::expireStore(decltype(store)::iterator i)
const auto& id = i->first;
auto& st = i->second;
auto stats = st.expire(id, scheduler.time());
total_store_size += stats.first;
total_values -= stats.second.size();
if (not stats.second.empty()) {
if (logger_)
logger_->d(id, "[store %s] discarded %ld expired values (%ld bytes)",
id.toString().c_str(), stats.second.size(), -stats.first);
if (not st.listeners.empty()) {
if (logger_)
logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size());
std::vector<Value::Id> ids;
ids.reserve(stats.second.size());
for (const auto& v : stats.second)
ids.emplace_back(v->id);
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version);
}
}
}
for (const auto& local_listeners : st.local_listeners) {
local_listeners.second.get_cb(stats.second, true);
}
storageRemoved(id, st, stats.second, -stats.first);
}
}
@@ -1374,6 +1343,41 @@ Dht::expireStorage(InfoHash h)
expireStore(i);
}
void
Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>>& values, size_t totalSize)
{
if (logger_)
logger_->d(id, "[store %s] discarded %ld values (%ld bytes)",
id.toString().c_str(), values.size(), totalSize);
total_store_size -= totalSize;
total_values -= values.size();
if (not st.listeners.empty()) {
if (logger_)
logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size());
std::vector<Value::Id> ids;
ids.reserve(values.size());
for (const auto& v : values)
ids.emplace_back(v->id);
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version);
}
}
}
for (const auto& local_listeners : st.local_listeners) {
local_listeners.second.get_cb(values, true);
}
}
void
Dht::expireStore()
{
@@ -1399,23 +1403,23 @@ Dht::expireStore()
break;
}
auto largest = store_quota.begin();
for (auto it = ++largest; it != store_quota.end(); ++it) {
for (auto it = std::next(largest); it != store_quota.end(); ++it) {
if (it->second.size() > largest->second.size())
largest = it;
}
if (logger_)
logger_->w("No space left: discarding value of largest consumer %s", largest->first.toString().c_str());
while (true) {
auto exp_value = largest->second.getOldest();
auto storage = store.find(exp_value.first);
if (storage != store.end()) {
auto ret = storage->second.remove(exp_value.first, exp_value.second);
total_store_size += ret.size_diff;
total_values += ret.values_diff;
if (logger_)
logger_->w("Discarded %ld bytes, still %ld used", largest->first.toString().c_str(), total_store_size);
if (ret.values_diff)
break;
if (largest != store_quota.end()) {
while (true) {
auto exp_value = largest->second.getOldest();
auto storage = store.find(exp_value.first);
if (storage != store.end()) {
if (logger_)
logger_->w("Storage quota full: discarding value from %s at %s %016" PRIx64, largest->first.toString().c_str(), exp_value.first.to_c_str(), exp_value.second);
if (auto value = storage->second.remove(exp_value.first, exp_value.second)) {
storageRemoved(storage->first, storage->second, {value}, value->size());
break;
}
}
}
}
}
@@ -1664,7 +1668,7 @@ Dht::dumpTables() const
std::string
Dht::getStorageLog() const
{
std::stringstream out;
std::ostringstream out;
for (const auto& s : store)
out << printStorageLog(s);
out << std::endl << std::endl;
@@ -1789,7 +1793,8 @@ Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, cons
myid(config.node_id ? config.node_id : InfoHash::getRandom(rd)),
store(),
store_quota(),
max_store_keys(config.max_store_size ? (int)config.max_store_size : MAX_HASHES),
max_store_keys(config.max_store_keys ? (int)config.max_store_keys : MAX_HASHES),
max_store_size(config.max_store_size ? (int)config.max_store_size : DEFAULT_STORAGE_LIMIT),
max_searches(config.max_searches ? (int)config.max_searches : MAX_SEARCHES),
network_engine(myid, fromDhtConfig(config), std::move(sock), logger_, rd, scheduler,
std::bind(&Dht::onError, this, _1, _2),
@@ -2558,7 +2563,7 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
}
}
auto expiration = s->second.refresh(now, vid, types);
auto expiration = s->second.refresh(id, now, vid, types);
if (expiration.first) {
scheduler.cancel(expiration.first->expiration_job);
if (expiration.second != time_point::max()) {
+52 -26
View File
@@ -26,6 +26,7 @@
#include <http_parser.h>
#include <deque>
namespace dht {
struct DhtProxyClient::InfoState {
@@ -116,6 +117,9 @@ DhtProxyClient::DhtProxyClient(
, loopSignal_(signal)
, jsonReader_(Json::CharReaderBuilder{}.newCharReader())
{
localAddrv4_.setFamily(AF_INET);
localAddrv6_.setFamily(AF_INET6);
jsonBuilder_["commentStyle"] = "None";
jsonBuilder_["indentation"] = "";
if (logger_) {
@@ -311,26 +315,30 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va
return;
}
try {
auto request = buildRequest("/" + key.toString());
auto request = buildRequest("/key/" + key.toString());
auto reqid = request->id();
//request->set_connection_type(restinio::http_connection_header_t::keep_alive);
request->set_method(restinio::http_method_get());
setHeaderFields(*request);
auto opstate = std::make_shared<OperationState>();
Value::Filter filter = w.empty() ? f : f.chain(w.getFilter());
auto rxBuf = std::make_shared<LineSplit>();
request->add_on_body_callback([this, key, opstate, filter, rxBuf, cb](const char* at, size_t length){
request->add_on_body_callback([
this,
key,
opstate,
filter = Value::Filter::chain(std::move(f), w.getFilter()),
rxBuf = std::make_shared<LineSplit>(),
cb
](const char* at, size_t length){
try {
auto& b = *rxBuf;
b.append(at, length);
rxBuf->append(at, length);
// one value per body line
std::vector<Sp<Value>> values;
while (b.getLine('\n') and !opstate->stop) {
while (rxBuf->getLine('\n') and !opstate->stop) {
std::string err;
Json::Value json;
const auto& line = b.line();
const auto& line = rxBuf->line();
if (!jsonReader_->parse(line.data(), line.data() + line.size(), &json, &err)){
opstate->ok.store(false);
return;
@@ -481,7 +489,7 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
logger_->d("[proxy:client] [put] [search %s] executing for %s", key.to_c_str(), val->toString().c_str());
try {
auto request = buildRequest("/" + key.toString());
auto request = buildRequest("/key/" + key.toString());
auto reqid = request->id();
request->set_method(restinio::http_method_post());
setHeaderFields(*request);
@@ -657,6 +665,12 @@ DhtProxyClient::queryProxyInfo(const Sp<InfoState>& infoState, const Sp<http::Re
if (!jsonReader_->parse(response.body.data(), response.body.data() + response.body.size(), &proxyInfos, &err)){
onProxyInfos(Json::Value{}, family);
} else if (not infoState->cancel) {
if (auto req = response.request.lock()) {
if (auto conn = req->get_connection()) {
const auto& localAddr = conn->local_address();
proxyInfos["local_ip"] = localAddr.to_string();
}
}
onProxyInfos(proxyInfos, family);
}
}
@@ -688,10 +702,17 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
std::unique_lock<std::mutex> l(lockCurrentProxyInfos_);
auto oldStatus = std::max(statusIpv4_, statusIpv6_);
auto& status = family == AF_INET ? statusIpv4_ : statusIpv6_;
auto ipChanged = false;
auto& pubAddress = family == AF_INET? publicAddressV4_ : publicAddressV6_;
auto& localAddress = family == AF_INET? localAddrv4_ : localAddrv6_;
if (not proxyInfos.isMember("node_id")) {
if (logger_)
logger_->e("[proxy:client] [info] request failed for %s", family == AF_INET ? "ipv4" : "ipv6");
status = NodeStatus::Disconnected;
if (pubAddress) {
pubAddress = {};
ipChanged = true;
}
} else {
if (logger_)
logger_->d("[proxy:client] [info] got proxy reply for %s",
@@ -700,19 +721,25 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
myid = InfoHash(proxyInfos["node_id"].asString());
stats4_ = NodeStats(proxyInfos["ipv4"]);
stats6_ = NodeStats(proxyInfos["ipv6"]);
if (stats4_.good_nodes + stats6_.good_nodes)
auto publicIp = parsePublicAddress(proxyInfos["public_ip"]);
ipChanged = pubAddress && pubAddress.toString() != publicIp.toString();
pubAddress = publicIp;
if (proxyInfos.isMember("local_ip")) {
std::string localIp = proxyInfos["local_ip"].asString();
if (localAddress.toString() != localIp) {
localAddress.setAddress(localIp.c_str());
ipChanged = (bool)localAddress;
}
}
if (!ipChanged && stats4_.good_nodes + stats6_.good_nodes)
status = NodeStatus::Connected;
else if (stats4_.dubious_nodes + stats6_.dubious_nodes)
else if (!ipChanged && stats4_.dubious_nodes + stats6_.dubious_nodes)
status = NodeStatus::Connecting;
else
status = NodeStatus::Disconnected;
auto publicIp = parsePublicAddress(proxyInfos["public_ip"]);
auto publicFamily = publicIp.getFamily();
if (publicFamily == AF_INET)
publicAddressV4_ = publicIp;
else if (publicFamily == AF_INET6)
publicAddressV6_ = publicIp;
} catch (const std::exception& e) {
if (logger_)
logger_->e("[proxy:client] [info] error processing: %s", e.what());
@@ -738,7 +765,10 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1));
}
else if (newStatus == NodeStatus::Disconnected) {
nextProxyConfirmationTimer_->expires_at(std::chrono::steady_clock::now() + std::chrono::minutes(1));
auto next = std::chrono::steady_clock::now();
if (!ipChanged)
next += std::chrono::minutes(1);
nextProxyConfirmationTimer_->expires_at(next);
nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1));
}
l.unlock();
@@ -838,7 +868,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
else {
method = ListenMethod::SUBSCRIBE;
header.method(restinio::http_method_subscribe());
header.request_target("/" + key.toString());
header.request_target("/key/" + key.toString());
}
sendListen(header, l->second.cb, opstate, l->second, method);
return token;
@@ -924,7 +954,7 @@ DhtProxyClient::handleExpireListener(const asio::error_code &ec, const InfoHash&
if (not deviceKey_.empty()) {
// UNSUBSCRIBE
auto request = buildRequest("/" + key.toString());
auto request = buildRequest("/key/" + key.toString());
auto reqid = request->id();
try {
request->set_method(restinio::http_method_unsubscribe());
@@ -1299,12 +1329,8 @@ DhtProxyClient::getPushRequest(Json::Value& body) const
body["key"] = deviceKey_;
body["client_id"] = pushClientId_;
body["session_id"] = pushSessionId_;
#ifdef __ANDROID__
body["platform"] = "android";
#endif
#ifdef __APPLE__
body["platform"] = "apple";
#endif
body["topic"] = notificationTopic_;
body["platform"] = platform_;
}
std::string
+131 -68
View File
@@ -173,6 +173,9 @@ DhtProxyServer::PermanentPut::msgpack_unpack(const msgpack::object& o)
if (auto val = findMapValue(o, "value"sv)) {
value = std::make_shared<dht::Value>(*val);
}
if (auto top = findMapValue(o, "top"sv)) {
topic = top->as<std::string>();
}
}
#ifdef OPENDHT_PUSH_NOTIFICATIONS
@@ -194,6 +197,9 @@ DhtProxyServer::Listener::msgpack_unpack(const msgpack::object& o)
if (auto t = findMapValue(o, "t"sv)) {
type = t->as<PushType>();
}
if (auto top = findMapValue(o, "top"sv)) {
topic = top->as<std::string>();
}
}
#endif
@@ -205,7 +211,8 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
dht_(dht), persistPath_(config.persistStatePath), logger_(logger),
printStatsTimer_(std::make_unique<asio::steady_timer>(*ioContext_, 3s)),
connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
pushServer_(config.pushServer)
pushServer_(config.pushServer),
bundleId_(config.bundleId)
{
if (not dht_)
throw std::invalid_argument("A DHT instance must be provided");
@@ -264,6 +271,8 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
// build http server
auto settings = restinio::run_on_this_thread_settings_t<RestRouterTraitsTls>();
addServerSettings(settings);
if (not config.address.empty())
settings.address(config.address);
settings.port(config.port);
settings.tls_context(std::move(tls_context));
httpsServer_ = std::make_unique<restinio::http_server_t<RestRouterTraitsTls>>(
@@ -281,6 +290,8 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
else {
auto settings = restinio::run_on_this_thread_settings_t<RestRouterTraits>();
addServerSettings(settings);
if (not config.address.empty())
settings.address(config.address);
settings.port(config.port);
httpServer_ = std::make_unique<restinio::http_server_t<RestRouterTraits>>(
ioContext_,
@@ -372,7 +383,7 @@ DhtProxyServer::loadState(Is& is, size_t size) {
pput.second.expireNotifyTimer = std::make_unique<asio::steady_timer>(io_context(), pput.second.expiration - proxy::OP_MARGIN);
pput.second.expireNotifyTimer->async_wait(std::bind(
&DhtProxyServer::handleNotifyPushListenExpire, this,
std::placeholders::_1, pput.second.pushToken, std::move(jsonProvider), pput.second.type));
std::placeholders::_1, pput.second.pushToken, std::move(jsonProvider), pput.second.type, pput.second.topic));
}
#endif
dht_->put(put.first, pput.second.value, DoneCallbackSimple{}, time_point::max(), true);
@@ -392,7 +403,7 @@ DhtProxyServer::loadState(Is& is, size_t size) {
for (auto& listeners : pushListener.second.listeners) {
for (auto& listener : listeners.second) {
listener.internalToken = dht_->listen(listeners.first,
[this, infoHash=listeners.first, pushToken=pushListener.first, type=listener.type, clientId=listener.clientId, sessionCtx = listener.sessionCtx]
[this, infoHash=listeners.first, pushToken=pushListener.first, type=listener.type, clientId=listener.clientId, sessionCtx = listener.sessionCtx, topic=listener.topic]
(const std::vector<std::shared_ptr<Value>>& values, bool expired) {
// Build message content
Json::Value json;
@@ -404,7 +415,7 @@ DhtProxyServer::loadState(Is& is, size_t size) {
json["s"] = sessionCtx->sessionId;
}
if (expired and values.size() < 2){
std::stringstream ss;
std::ostringstream ss;
for(size_t i = 0; i < values.size(); ++i){
if(i != 0) ss << ",";
ss << values[i]->id;
@@ -414,7 +425,7 @@ DhtProxyServer::loadState(Is& is, size_t size) {
auto maxPrio = 1000u;
for (const auto& v : values)
maxPrio = std::min(maxPrio, v->priority);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0, topic);
return true;
}
);
@@ -429,7 +440,7 @@ DhtProxyServer::loadState(Is& is, size_t size) {
return json;
};
listener.expireNotifyTimer->async_wait(std::bind(&DhtProxyServer::handleNotifyPushListenExpire, this,
std::placeholders::_1, pushListener.first, std::move(jsonProvider), listener.type));
std::placeholders::_1, pushListener.first, std::move(jsonProvider), listener.type, listener.topic));
// cancel push listen
listener.expireTimer = std::make_unique<asio::steady_timer>(io_context(), listener.expiration);
listener.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPushListen, this,
@@ -745,6 +756,22 @@ DhtProxyServer::listen(restinio::request_handle_t request,
#ifdef OPENDHT_PUSH_NOTIFICATIONS
PushType
DhtProxyServer::getTypeFromString(const std::string& type) {
if (type == "android")
return PushType::Android;
else if (type == "ios")
return PushType::iOS;
else if (type == "unifiedpush")
return PushType::UnifiedPush;
return PushType::None;
}
std::string
DhtProxyServer::getDefaultTopic(PushType) {
return bundleId_;
}
RequestStatus
DhtProxyServer::subscribe(restinio::request_handle_t request,
restinio::router::route_params_t params)
@@ -771,7 +798,11 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
response.set_body(RESP_MSG_NO_TOKEN);
return response.done();
}
auto type = root["platform"].asString() == "android" ? PushType::Android : PushType::iOS;
auto type = getTypeFromString(root["platform"].asString());
auto topic = root["topic"].asString();
if (topic.empty()) {
topic = getDefaultTopic(type);
}
auto clientId = root["client_id"].asString();
auto sessionId = root["session_id"].asString();
@@ -802,6 +833,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
auto timeout = std::chrono::steady_clock::now() + proxy::OP_TIMEOUT;
listener.expiration = timeout;
listener.type = type;
listener.topic = topic;
if (listener.expireNotifyTimer)
listener.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
else
@@ -815,7 +847,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
return json;
};
listener.expireNotifyTimer->async_wait(std::bind(&DhtProxyServer::handleNotifyPushListenExpire, this,
std::placeholders::_1, pushToken, std::move(jsonProvider), listener.type));
std::placeholders::_1, pushToken, std::move(jsonProvider), listener.type, listener.topic));
if (!listener.expireTimer)
listener.expireTimer = std::make_unique<asio::steady_timer>(io_context(), timeout);
else
@@ -850,7 +882,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
// =========== No existing listener for an infoHash ============
// Add listen on dht
listener.internalToken = dht_->listen(infoHash,
[this, infoHash, pushToken, type, clientId, sessionCtx = listener.sessionCtx]
[this, infoHash, pushToken, type, clientId, sessionCtx = listener.sessionCtx, topic]
(const std::vector<std::shared_ptr<Value>>& values, bool expired){
// Build message content
Json::Value json;
@@ -862,8 +894,8 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
json["s"] = sessionCtx->sessionId;
}
if (expired and values.size() < 2){
std::stringstream ss;
for(size_t i = 0; i < values.size(); ++i){
std::ostringstream ss;
for(size_t i = 0; i < values.size(); ++i) {
if(i != 0) ss << ",";
ss << values[i]->id;
}
@@ -872,7 +904,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
auto maxPrio = 1000u;
for (const auto& v : values)
maxPrio = std::min(maxPrio, v->priority);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0, topic);
return true;
}
);
@@ -928,7 +960,7 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
void
DhtProxyServer::handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
std::function<Json::Value()> jsonProvider, PushType type)
std::function<Json::Value()> jsonProvider, PushType type, const std::string& topic)
{
if (ec == asio::error::operation_aborted)
return;
@@ -937,8 +969,8 @@ DhtProxyServer::handleNotifyPushListenExpire(const asio::error_code &ec, const s
logger_->e("[proxy:server] [subscribe] error sending put refresh: %s", ec.message().c_str());
}
if (logger_)
logger_->d("[proxy:server] [subscribe] sending put refresh to %s token", pushToken.c_str());
sendPushNotification(pushToken, jsonProvider(), type, false);
logger_->d("[proxy:server] [subscribe] sending refresh to %s token", pushToken.c_str());
sendPushNotification(pushToken, jsonProvider(), type, false, topic);
}
void
@@ -980,45 +1012,70 @@ DhtProxyServer::handleCancelPushListen(const asio::error_code &ec, const std::st
}
void
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, PushType type, bool highPriority)
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, PushType type, bool highPriority, const std::string& topic)
{
if (pushServer_.empty())
return;
unsigned reqid = 0;
try {
auto request = std::make_shared<http::Request>(io_context(), pushHostPort_.first, pushHostPort_.second,
httpsServer_ ? true : false, logger_);
std::shared_ptr<http::Request> request;
http::Url tokenUrl(token);
if (type == PushType::UnifiedPush)
request = std::make_shared<http::Request>(io_context(), tokenUrl.protocol + "://" + tokenUrl.host, logger_);
else
request = std::make_shared<http::Request>(io_context(), pushHostPort_.first, pushHostPort_.second, pushHostPort_.first.find("https://") == 0, logger_);;
reqid = request->id();
request->set_target("/api/push");
request->set_target(type == PushType::UnifiedPush ? (tokenUrl.target) : "/api/push");
request->set_method(restinio::http_method_post());
request->set_header_field(restinio::http_field_t::host, pushServer_.c_str());
request->set_header_field(restinio::http_field_t::host, type == PushType::UnifiedPush ? tokenUrl.host.c_str() : pushServer_.c_str());
request->set_header_field(restinio::http_field_t::user_agent, "RESTinio client");
request->set_header_field(restinio::http_field_t::accept, "*/*");
request->set_header_field(restinio::http_field_t::content_type, "application/json");
// NOTE: see https://github.com/appleboy/gorush
Json::Value notification(Json::objectValue);
Json::Value tokens(Json::arrayValue);
tokens[0] = token;
notification["tokens"] = std::move(tokens);
notification["platform"] = type == PushType::Android ? 2 : 1;
notification["data"] = std::move(json);
notification["priority"] = highPriority ? "high" : "normal";
if (type == PushType::Android)
notification["time_to_live"] = 3600 * 24; // 24 hours
else {
const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24);
uint32_t exp = std::chrono::duration_cast<std::chrono::seconds>(expiration.time_since_epoch()).count();
notification["expiration"] = exp;
if (type == PushType::UnifiedPush) {
Json::Value notification(Json::objectValue);
notification["message"] = Json::writeString(jsonBuilder_, std::move(json));
notification["topic"] = token;
notification["priority"] = highPriority ? 5 : 1;
request->set_body(Json::writeString(jsonBuilder_, std::move(json)));
} else {
// NOTE: see https://github.com/appleboy/gorush
Json::Value notification(Json::objectValue);
Json::Value tokens(Json::arrayValue);
tokens[0] = token;
notification["tokens"] = std::move(tokens);
notification["platform"] = type == PushType::Android ? 2 : 1;
notification["data"] = std::move(json);
notification["priority"] = highPriority ? "high" : "normal";
if (type == PushType::Android)
notification["time_to_live"] = 3600 * 24; // 24 hours
else {
const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24);
uint32_t exp = std::chrono::duration_cast<std::chrono::seconds>(expiration.time_since_epoch()).count();
notification["expiration"] = exp;
if (!topic.empty())
notification["topic"] = topic;
if (highPriority) {
Json::Value alert(Json::objectValue);
alert["title"]="hello";
notification["push_type"] = "alert";
notification["alert"] = alert;
notification["mutable_content"] = true;
} else {
notification["push_type"] = "background";
notification["content_available"] = true;
}
}
Json::Value notifications(Json::arrayValue);
notifications[0] = notification;
Json::Value content;
content["notifications"] = std::move(notifications);
request->set_body(Json::writeString(jsonBuilder_, content));
}
Json::Value notifications(Json::arrayValue);
notifications[0] = notification;
Json::Value content;
content["notifications"] = std::move(notifications);
request->set_body(Json::writeString(jsonBuilder_, content));
request->add_on_state_change_callback([this, reqid]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
@@ -1036,7 +1093,7 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:server] [notification] error send push: %i", e.what());
logger_->e("[proxy:server] [notification] error send push: %s", e.what());
if (reqid) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
@@ -1104,13 +1161,14 @@ DhtProxyServer::put(restinio::request_handle_t request,
logger_->d("[proxy:server] [put %s] %s %s", infoHash.toString().c_str(),
value->toString().c_str(), (permanent ? "permanent" : ""));
if (permanent) {
std::string pushToken, clientId, sessionId, platform;
std::string pushToken, clientId, sessionId, platform, topic;
auto& pVal = root["permanent"];
if (pVal.isObject()){
pushToken = pVal["key"].asString();
clientId = pVal["client_id"].asString();
platform = pVal["platform"].asString();
sessionId = pVal["session_id"].asString();
topic = pVal["topic"].asString();
}
std::lock_guard<std::mutex> lock(lockSearchPuts_);
auto timeout = std::chrono::steady_clock::now() + proxy::OP_TIMEOUT;
@@ -1133,7 +1191,7 @@ DhtProxyServer::put(restinio::request_handle_t request,
}
}
auto response = initHttpResponse(request->create_response());
response.append_body(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
response.append_body(Json::writeString(jsonBuilder_, pp.second.value->toJson()) + "\n");
return response.done();
}
}
@@ -1145,34 +1203,17 @@ DhtProxyServer::put(restinio::request_handle_t request,
pput.value = value;
pput.expiration = timeout;
if (not pput.expireTimer) {
auto &ctx = io_context();
// cancel permanent put
pput.expireTimer = std::make_unique<asio::steady_timer>(ctx, timeout);
pput.expireTimer = std::make_unique<asio::steady_timer>(io_context(), timeout);
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not pushToken.empty()){
bool isAndroid = platform == "android";
if (not pushToken.empty()) {
pput.pushToken = pushToken;
pput.clientId = clientId;
pput.type = isAndroid ? PushType::Android : PushType::iOS;
pput.type = getTypeFromString(platform);
if (topic.empty())
topic = getDefaultTopic(pput.type);
pput.topic = topic;
pput.sessionCtx = std::make_shared<PushSessionContext>(sessionId);
// notify push listen expire
auto jsonProvider = [infoHash, clientId, vid, sessionCtx = pput.sessionCtx](){
Json::Value json;
json["timeout"] = infoHash.toString();
json["to"] = clientId;
json["vid"] = std::to_string(vid);
std::lock_guard<std::mutex> l(sessionCtx->lock);
json["s"] = sessionCtx->sessionId;
return json;
};
if (!pput.expireNotifyTimer)
pput.expireNotifyTimer = std::make_unique<asio::steady_timer>(ctx,
timeout - proxy::OP_MARGIN);
else
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
pput.expireNotifyTimer->async_wait(std::bind(
&DhtProxyServer::handleNotifyPushListenExpire, this,
std::placeholders::_1, pushToken, std::move(jsonProvider), pput.type));
}
#endif
} else {
@@ -1185,12 +1226,34 @@ DhtProxyServer::put(restinio::request_handle_t request,
}
}
pput.expireTimer->expires_at(timeout);
if (pput.expireNotifyTimer)
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
}
pput.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPermamentPut, this,
std::placeholders::_1, infoHash, vid));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
// notify put permanent expiration
if (pput.sessionCtx) {
auto jsonProvider = [infoHash, clientId, vid, sessionCtx = pput.sessionCtx](){
Json::Value json;
json["timeout"] = infoHash.toString();
json["to"] = clientId;
json["vid"] = std::to_string(vid);
std::lock_guard<std::mutex> l(sessionCtx->lock);
json["s"] = sessionCtx->sessionId;
return json;
};
if (!pput.expireNotifyTimer)
pput.expireNotifyTimer = std::make_unique<asio::steady_timer>(io_context(),
timeout - proxy::OP_MARGIN);
else
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
pput.expireNotifyTimer->async_wait(std::bind(
&DhtProxyServer::handleNotifyPushListenExpire, this,
std::placeholders::_1, pushToken, std::move(jsonProvider), pput.type, pput.topic));
}
#endif
}
dht_->put(infoHash, value, [this, request, value](bool ok){
if (ok){
auto response = initHttpResponse(request->create_response());
+165 -252
View File
@@ -38,15 +38,6 @@ namespace dht {
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
struct DhtRunner::Listener {
size_t tokenClassicDht {0};
size_t tokenProxyDht {0};
ValueCallback gcb;
InfoHash hash {};
Value::Filter f;
Where w;
};
struct NodeInsertionPack {
dht::InfoHash nodeId;
in_port_t port;
@@ -55,9 +46,6 @@ struct NodeInsertionPack {
};
DhtRunner::DhtRunner() : dht_()
#ifdef OPENDHT_PROXY_CLIENT
, dht_via_proxy_()
#endif //OPENDHT_PROXY_CLIENT
{
#ifdef _WIN32
WSADATA wsd;
@@ -119,8 +107,9 @@ DhtRunner::run(const Config& config, Context&& context)
local6.setFamily(AF_INET6);
}
auto state_path = config.dht_config.node_config.persist_path;
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
if (not state_path.empty())
state_path += "_port.txt";
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
std::ifstream inConfig(state_path);
if (inConfig.is_open()) {
in_port_t port;
@@ -143,68 +132,59 @@ DhtRunner::run(const Config& config, Context&& context)
if (context.logger) {
logger_ = context.logger;
}
if (not context.sock) {
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
}
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
if (context.logger) {
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
{
std::lock_guard<std::mutex> lck(sock_mtx);
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
while (rcv.size() > maxSize) {
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop_front();
}
rcv.splice(rcv.end(), std::move(pkts));
ret = std::move(rcv_free);
}
cv.notify_all();
return ret;
});
#ifdef OPENDHT_PROXY_CLIENT
config_ = config;
identityAnnouncedCb_ = context.identityAnnouncedCb;
#endif
auto dht = std::make_unique<Dht>(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger);
dht_ = std::make_unique<SecureDht>(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger);
enableProxy(not config.proxy_server.empty());
if (config.proxy_server.empty()) {
if (not context.sock) {
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
}
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
{
std::lock_guard<std::mutex> lck(sock_mtx);
rcv.splice(rcv.end(), std::move(pkts));
size_t dropped = 0;
while (rcv.size() > net::RX_QUEUE_MAX_SIZE) {
rcv.pop_front();
dropped++;
}
if (dropped and logger_) {
logger_->w("[runner %p] dropped %zu packets: queue is full!", this, dropped);
}
ret = std::move(rcv_free);
}
cv.notify_all();
return ret;
});
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
auto dht = std::make_unique<Dht>(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger);
dht_ = std::make_unique<SecureDht>(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger);
} else {
enableProxy(true);
}
} catch(const std::exception& e) {
config_ = {};
identityAnnouncedCb_ = {};
dht_.reset();
#ifdef OPENDHT_PROXY_CLIENT
dht_via_proxy_.reset();
#endif
running = State::Idle;
throw;
}
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(context.logger);
}
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
}
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
}
if (not config.threaded)
@@ -239,46 +219,50 @@ DhtRunner::run(const Config& config, Context&& context)
}
});
if (config.peer_discovery or config.peer_publish) {
if (config.proxy_server.empty()) {
if (config.peer_discovery or config.peer_publish) {
#ifdef OPENDHT_PEER_DISCOVERY
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
#else
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
#endif
}
}
#ifdef OPENDHT_PEER_DISCOVERY
auto netId = config.dht_config.node_config.network;
if (config.peer_discovery) {
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
addr.setPort(v.port);
if (v.nodeId != dht_->getNodeId() && netId == v.net){
bootstrap(v.nodeId, addr);
auto netId = config.dht_config.node_config.network;
if (config.peer_discovery) {
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
addr.setPort(v.port);
if (v.nodeId != dht_->getNodeId() && netId == v.net){
bootstrap(v.nodeId, addr);
}
});
}
if (config.peer_publish) {
msgpack::sbuffer sbuf_node;
NodeInsertionPack adc;
adc.net = netId;
adc.nodeId = dht_->getNodeId();
if (auto socket = dht_->getSocket()) {
// IPv4
if (const auto& bound4 = socket->getBoundRef(AF_INET)) {
adc.port = bound4.getPort();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
// IPv6
if (const auto& bound6 = socket->getBoundRef(AF_INET6)) {
adc.port = bound6.getPort();
sbuf_node.clear();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
});
}
if (config.peer_publish) {
msgpack::sbuffer sbuf_node;
NodeInsertionPack adc;
adc.net = netId;
adc.nodeId = dht_->getNodeId();
// IPv4
if (const auto& bound4 = dht_->getSocket()->getBoundRef(AF_INET)) {
adc.port = bound4.getPort();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
// IPv6
if (const auto& bound6 = dht_->getSocket()->getBoundRef(AF_INET6)) {
adc.port = bound6.getPort();
sbuf_node.clear();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
#endif
}
}
void
@@ -287,7 +271,8 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
auto expected = State::Running;
if (not running.compare_exchange_strong(expected, State::Stopping)) {
if (expected == State::Stopping and ongoing_ops) {
shutdownCallbacks_.emplace_back(std::move(cb));
if (cb)
shutdownCallbacks_.emplace_back(std::move(cb));
}
else if (cb) {
lck.unlock();
@@ -301,12 +286,10 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops.emplace([=](SecureDht&) mutable {
auto onShutdown = [this]{ opEnded(); };
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(onShutdown, stop);
#endif
if (dht_)
dht_->shutdown(onShutdown, stop);
else
opEnded();
});
cv.notify_all();
}
@@ -409,31 +392,25 @@ void
DhtRunner::dumpTables() const
{
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->dumpTables();
dht_->dumpTables();
}
InfoHash
DhtRunner::getId() const
{
if (auto dht = activeDht())
return dht->getId();
return {};
return dht_ ? dht_->getId() : InfoHash{};
}
std::shared_ptr<crypto::PublicKey>
DhtRunner::getPublicKey() const
{
if (auto dht = activeDht())
return dht->getPublicKey();
return {};
return dht_ ? dht_->getPublicKey() : std::shared_ptr<crypto::PublicKey>{};
}
InfoHash
DhtRunner::getNodeId() const
{
if (auto dht = activeDht())
return dht->getNodeId();
return {};
return dht_ ? dht_->getNodeId() : InfoHash{};
}
@@ -475,10 +452,6 @@ DhtRunner::setLogger(const Sp<Logger>& logger) {
logger_ = logger;
if (dht_)
dht_->setLogger(logger);
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLogger(logger);
#endif
}
void
@@ -492,16 +465,12 @@ DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLogFilter(f);
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLogFilter(f);
#endif
}
void
DhtRunner::registerType(const ValueType& type) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->registerType(type);
dht_->registerType(type);
}
void
@@ -514,7 +483,7 @@ 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);
const auto stats = activeDht()->getNodesStats(af);
const auto stats = dht_->getNodesStats(af);
if (good_return)
*good_return = stats.good_nodes;
if (dubious_return)
@@ -530,19 +499,19 @@ NodeStats
DhtRunner::getNodesStats(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getNodesStats(af);
return dht_->getNodesStats(af);
}
NodeInfo
DhtRunner::getNodeInfo() const {
std::lock_guard<std::mutex> lck(dht_mtx);
NodeInfo info {};
if (auto dht = activeDht()) {
info.id = dht->getId();
info.node_id = dht->getNodeId();
info.ipv4 = dht->getNodesStats(AF_INET);
info.ipv6 = dht->getNodesStats(AF_INET6);
if (auto sock = dht->getSocket()) {
if (dht_) {
info.id = dht_->getId();
info.node_id = dht_->getNodeId();
info.ipv4 = dht_->getNodesStats(AF_INET);
info.ipv6 = dht_->getNodesStats(AF_INET6);
if (auto sock = dht_->getSocket()) {
info.bound4 = sock->getBoundRef(AF_INET).getPort();
info.bound6 = sock->getBoundRef(AF_INET6).getPort();
}
@@ -563,6 +532,7 @@ DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
info.node_id = dht.getNodeId();
info.ipv4 = dht.getNodesStats(AF_INET);
info.ipv6 = dht.getNodesStats(AF_INET6);
std::tie(info.storage_size, info.storage_values) = dht.getStoreSize();
if (auto sock = dht.getSocket()) {
info.bound4 = sock->getBoundRef(AF_INET).getPort();
info.bound6 = sock->getBoundRef(AF_INET6).getPort();
@@ -578,49 +548,49 @@ std::vector<unsigned>
DhtRunner::getNodeMessageStats(bool in) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getNodeMessageStats(in);
return dht_->getNodeMessageStats(in);
}
std::string
DhtRunner::getStorageLog() const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getStorageLog();
return dht_->getStorageLog();
}
std::string
DhtRunner::getStorageLog(const InfoHash& f) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getStorageLog(f);
return dht_->getStorageLog(f);
}
std::string
DhtRunner::getRoutingTablesLog(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getRoutingTablesLog(af);
return dht_->getRoutingTablesLog(af);
}
std::string
DhtRunner::getSearchesLog(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getSearchesLog(af);
return dht_->getSearchesLog(af);
}
std::string
DhtRunner::getSearchLog(const InfoHash& f, sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
return activeDht()->getSearchLog(f, af);
return dht_->getSearchLog(f, af);
}
std::vector<SockAddr>
DhtRunner::getPublicAddress(sa_family_t af)
DhtRunner::getPublicAddress(sa_family_t af) const
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (auto dht = activeDht())
return dht->getPublicAddress(af);
if (dht_)
return dht_->getPublicAddress(af);
return {};
}
std::vector<std::string>
DhtRunner::getPublicAddressStr(sa_family_t af)
DhtRunner::getPublicAddressStr(sa_family_t af) const
{
auto addrs = getPublicAddress(af);
std::vector<std::string> ret(addrs.size());
@@ -643,15 +613,12 @@ DhtRunner::getPublicAddress(std::function<void(std::vector<SockAddr>&&)> cb, sa_
void
DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->registerCertificate(cert);
dht_->registerCertificate(cert);
}
void
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
std::lock_guard<std::mutex> lck(dht_mtx);
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
#endif
if (dht_)
dht_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
}
@@ -659,8 +626,7 @@ DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
time_point
DhtRunner::loop_()
{
auto dht = activeDht();
if (not dht)
if (not dht_)
return {};
decltype(pending_ops) ops {};
@@ -671,7 +637,7 @@ DhtRunner::loop_()
std::move(pending_ops) : std::move(pending_ops_prio);
}
while (not ops.empty()) {
ops.front()(*dht);
ops.front()(*dht_);
ops.pop();
}
@@ -704,13 +670,13 @@ DhtRunner::loop_()
if (now - pkt.received > net::RX_QUEUE_MAX_DELAY)
dropped++;
else
wakeup = dht->periodic(pkt.data.data(), pkt.data.size(), std::move(pkt.from), now);
wakeup = dht_->periodic(pkt.data.data(), pkt.data.size(), std::move(pkt.from), now);
pkt.data.clear();
}
received_treated.splice(received_treated.end(), std::move(received));
} else {
// Or just run the scheduler
wakeup = dht->periodic(nullptr, 0, nullptr, 0, clock::now());
wakeup = dht_->periodic(nullptr, 0, nullptr, 0, clock::now());
}
if (not received_treated.empty()) {
@@ -722,8 +688,8 @@ DhtRunner::loop_()
if (dropped && logger_)
logger_->e("[runner %p] Dropped %zu packets with high delay.", this, dropped);
NodeStatus nstatus4 = dht->updateStatus(AF_INET);
NodeStatus nstatus6 = dht->updateStatus(AF_INET6);
NodeStatus nstatus4 = dht_->updateStatus(AF_INET);
NodeStatus nstatus6 = dht_->updateStatus(AF_INET6);
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
@@ -781,27 +747,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
return ret_token->get_future();
}
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
cv.notify_all();
return ret_token->get_future();
@@ -817,21 +763,13 @@ void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
if (running != State::Running)
return;
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
opEnded();
});
#endif // OPENDHT_PROXY_CLIENT
cv.notify_all();
}
@@ -839,21 +777,13 @@ void
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
if (running != State::Running)
return;
ongoing_ops++;
pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
opEnded();
});
#endif // OPENDHT_PROXY_CLIENT
cv.notify_all();
}
@@ -886,7 +816,7 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
return;
}
ongoing_ops++;
pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable {
pending_ops.emplace([=, value = std::move(value), cb = std::move(cb)](SecureDht& dht) mutable {
dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
@@ -1066,7 +996,7 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple cb)
}
void
DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple cb)
DhtRunner::bootstrap(SockAddr addr, DoneCallbackSimple cb)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
@@ -1075,7 +1005,7 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple cb)
return;
}
ongoing_ops++;
pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
pending_ops_prio.emplace([addr = std::move(addr), cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
dht.pingNode(std::move(addr), std::move(cb));
});
cv.notify_all();
@@ -1094,12 +1024,12 @@ DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
}
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
DhtRunner::bootstrap(std::vector<NodeExport> nodes)
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (running != State::Running)
return;
pending_ops_prio.emplace([=](SecureDht& dht) {
pending_ops_prio.emplace([nodes = std::move(nodes)](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
@@ -1142,23 +1072,9 @@ void
DhtRunner::resetDht()
{
peerDiscovery_.reset();
#ifdef OPENDHT_PROXY_CLIENT
listeners_.clear();
dht_via_proxy_.reset();
#endif // OPENDHT_PROXY_CLIENT
dht_.reset();
}
SecureDht*
DhtRunner::activeDht() const
{
#ifdef OPENDHT_PROXY_CLIENT
return use_proxy? dht_via_proxy_.get() : dht_.get();
#else
return dht_.get();
#endif // OPENDHT_PROXY_CLIENT
}
void
DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeId)
{
@@ -1171,7 +1087,7 @@ DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeI
enableProxy(use_proxy and not config_.proxy_server.empty());
#else
if (not proxy.empty())
std::cerr << "DHT proxy requested but OpenDHT built without proxy support." << std::endl;
throw std::runtime_error("DHT proxy requested but OpenDHT built without proxy support.");
#endif
}
@@ -1179,54 +1095,37 @@ void
DhtRunner::enableProxy(bool proxify)
{
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_) {
dht_via_proxy_->shutdown({});
if (dht_) {
dht_->shutdown({});
}
if (proxify) {
// Init the proxy client
auto dht_via_proxy = std::unique_ptr<DhtInterface>(
new DhtProxyClient(
auto dht_via_proxy = std::make_unique<DhtProxyClient>(
config_.server_ca,
config_.client_identity,
[this]{
if (config_.threaded) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) mutable {});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) mutable {});
cv.notify_all();
}
},
config_.proxy_server, config_.push_node_id, logger_)
);
#ifdef OPENDHT_PUSH_NOTIFICATIONS
config_.proxy_server, config_.push_node_id, logger_);
if (not config_.push_token.empty())
dht_via_proxy->setPushNotificationToken(config_.push_token);
#endif
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_));
// add current listeners
for (auto& l: listeners_)
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
if (not config_.push_topic.empty())
dht_via_proxy->setPushNotificationTopic(config_.push_topic);
if (not config_.push_platform.empty())
dht_via_proxy->setPushNotificationPlatform(config_.push_platform);
dht_ = std::make_unique<SecureDht>(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_);
// and use it
use_proxy = proxify;
} else {
use_proxy = proxify;
std::lock_guard<std::mutex> lck(storage_mtx);
if (not listeners_.empty()) {
pending_ops.emplace([this](SecureDht& /*dht*/) mutable {
if (not dht_)
return;
for (auto& l : listeners_) {
if (not l.second.tokenClassicDht) {
l.second.tokenClassicDht = dht_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
}
}
});
}
}
#else
if (proxify)
std::cerr << "DHT proxy requested but OpenDHT built without proxy support." << std::endl;
throw std::runtime_error("DHT proxy requested but OpenDHT built without proxy support.");
#endif
}
@@ -1234,16 +1133,8 @@ void
DhtRunner::forwardAllMessages(bool forward)
{
std::lock_guard<std::mutex> lck(dht_mtx);
#ifdef OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->forwardAllMessages(forward);
#endif // OPENDHT_PROXY_CLIENT
if (dht_)
dht_->forwardAllMessages(forward);
#else
(void) forward;
#endif // OPENDHT_PROXY_SERVER
}
/**
@@ -1254,24 +1145,46 @@ DhtRunner::setPushNotificationToken(const std::string& token) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
config_.push_token = token;
if (dht_via_proxy_)
dht_via_proxy_->setPushNotificationToken(token);
if (dht_)
dht_->setPushNotificationToken(token);
#else
(void) token;
#endif
}
void
DhtRunner::setPushNotificationTopic(const std::string& topic) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
config_.push_topic = topic;
if (dht_)
dht_->setPushNotificationTopic(topic);
#else
(void) topic;
#endif
}
void
DhtRunner::setPushNotificationPlatform(const std::string& platform) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
config_.push_platform = platform;
if (dht_)
dht_->setPushNotificationPlatform(platform);
#else
(void) platform;
#endif
}
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
{
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) {
if (dht_via_proxy_)
dht_via_proxy_->pushNotificationReceived(data);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) {
if (dht_)
dht_->pushNotificationReceived(data);
});
cv.notify_all();
#else
(void) data;
+26 -19
View File
@@ -567,9 +567,12 @@ Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, Conn
}
auto& base = ssl_socket_? ssl_socket_->lowest_layer() : *socket_;
ConnectHandlerCb wcb = [&base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
ConnectHandlerCb wcb = [this, &base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) {
if (!ec) {
auto socket = base.native_handle();
local_address_ = base.local_endpoint().address();
// Once connected, set a keep alive on the TCP socket with 30 seconds delay
// This will generate broken pipes as soon as possible.
// Note this needs to be done once connected to have a valid native_handle()
@@ -614,10 +617,12 @@ Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, Conn
if (cb)
cb(ec, endpoint);
};
#pragma GCC diagnostic pop
if (ssl_socket_)
asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(wcb)));
asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallback(std::move(wcb)));
else
asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(wcb)));
asio::async_connect(*socket_, std::move(endpoints), wrapCallback(std::move(wcb)));
}
void
@@ -662,8 +667,8 @@ Connection::async_write(BytesHandlerCb cb)
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_write(*ssl_socket_, write_buf_, wrapCallabck(std::move(cb)));
else if (socket_) asio::async_write(*socket_, write_buf_, wrapCallabck(std::move(cb)));
if (ssl_socket_) asio::async_write(*ssl_socket_, write_buf_, wrapCallback(std::move(cb)));
else if (socket_) asio::async_write(*socket_, write_buf_, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
}
@@ -675,8 +680,8 @@ Connection::async_read_until(const char* delim, BytesHandlerCb cb)
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
}
@@ -688,8 +693,8 @@ Connection::async_read_until(char delim, BytesHandlerCb cb)
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
}
@@ -701,8 +706,8 @@ Connection::async_read(size_t bytes, BytesHandlerCb cb)
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read(*ssl_socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallabck(std::move(cb)));
else if (socket_) asio::async_read(*socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallabck(std::move(cb)));
if (ssl_socket_) asio::async_read(*ssl_socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallback(std::move(cb)));
else if (socket_) asio::async_read(*socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
}
@@ -723,16 +728,15 @@ Connection::async_read_some(size_t bytes, BytesHandlerCb cb)
else socket_->async_read_some(buf, onEnd);
}
const asio::ip::address&
Connection::local_address() const
{
return local_address_;
}
void
Connection::timeout(const std::chrono::seconds timeout, HandlerCb cb)
Connection::timeout(const std::chrono::seconds& timeout, HandlerCb cb)
{
if (!is_open()){
if (logger_)
logger_->e("[connection:%i] closed, can't timeout", id_);
if (cb)
cb(asio::error::operation_aborted);
return;
}
if (!timeout_timer_)
timeout_timer_ = std::make_unique<asio::steady_timer>(ctx_);
timeout_timer_->expires_at(std::chrono::steady_clock::now() + timeout);
@@ -1191,6 +1195,9 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
else
conn_ = std::make_shared<Connection>(ctx_, false/*ssl*/, logger_);
if (conn_ && timeoutCb_)
conn_->timeout(timeout_, std::move(timeoutCb_));
// try to connect to any until one works
std::weak_ptr<Request> wthis = shared_from_this();
conn_->async_connect(std::move(endpoints), [wthis, cb, isHttps]
+14 -13
View File
@@ -116,7 +116,7 @@ NetworkEngine::~NetworkEngine() {
}
void
NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash, want_t want,
NetworkEngine::tellListener(const Sp<Node>& node, Tid socket_id, const InfoHash& hash, want_t want,
const Blob& ntoken, std::vector<Sp<Node>>&& nodes,
std::vector<Sp<Node>>&& nodes6, std::vector<Sp<Value>>&& values,
const Query& query, int version)
@@ -135,7 +135,7 @@ NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash,
}
void
NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values, int version)
NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values, int version)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
@@ -186,7 +186,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
}
void
NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values, int version)
NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector<Value::Id>& values, int version)
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
@@ -415,7 +415,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
return;
}
std::unique_ptr<ParsedMessage> msg {new ParsedMessage};
auto msg = std::make_unique<ParsedMessage>();
try {
msgpack::unpacked msg_res = msgpack::unpack((const char*)buf, buflen);
msg->msgpack_unpack(msg_res.get());
@@ -699,7 +699,7 @@ NetworkEngine::send(const SockAddr& addr, const char *buf, size_t len, bool conf
}
Sp<Request>
NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
Tid tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
@@ -757,7 +757,7 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
}
Sp<Request>
NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t want,
RequestCb&& on_done, RequestExpiredCb&& on_expired) {
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
@@ -802,7 +802,7 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
Sp<Request>
NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query& query, want_t want,
NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const Query& query, want_t want,
RequestCb&& on_done, RequestExpiredCb&& on_expired) {
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
@@ -1073,7 +1073,7 @@ NetworkEngine::bufferNodes(sa_family_t af, const InfoHash& id, want_t want,
}
Sp<Request>
NetworkEngine::sendListen(Sp<Node> n,
NetworkEngine::sendListen(const Sp<Node>& n,
const InfoHash& hash,
const Query& query,
const Blob& token,
@@ -1142,7 +1142,7 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
}
Sp<Request>
NetworkEngine::sendAnnounceValue(Sp<Node> n,
NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
const InfoHash& infohash,
const Sp<Value>& value,
time_point created,
@@ -1155,11 +1155,12 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
bool add_created = created < scheduler.time();
pk.pack(KEY_A); pk.pack_map(add_created ? 5 : 4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(infohash);
auto v = packValueHeader(buffer, {value});
if (created < scheduler.time()) {
if (add_created) {
pk.pack(KEY_REQ_CREATION);
pk.pack(to_time_t(created));
}
@@ -1200,7 +1201,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
}
Sp<Request>
NetworkEngine::sendUpdateValues(Sp<Node> n,
NetworkEngine::sendUpdateValues(const Sp<Node>& n,
const InfoHash& infohash,
const std::vector<Sp<Value>>& values,
time_point created,
@@ -1246,7 +1247,7 @@ NetworkEngine::sendUpdateValues(Sp<Node> n,
}
Sp<Request>
NetworkEngine::sendRefreshValue(Sp<Node> n,
NetworkEngine::sendRefreshValue(const Sp<Node>& n,
const InfoHash& infohash,
const Value::Id& vid,
const Blob& token,
+2
View File
@@ -148,6 +148,8 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
#ifdef MSG_CONFIRM
if (replied)
flags |= MSG_CONFIRM;
#else
(void) replied;
#endif
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
+1 -1
View File
@@ -28,7 +28,7 @@ struct OpCacheValueStorage
Sp<Value> data {};
unsigned refCount {1};
system_clock::time_point updated {system_clock::time_point::min()};
explicit OpCacheValueStorage(Sp<Value> val) : data(val) {}
explicit OpCacheValueStorage(Sp<Value> val) : data(std::move(val)) {}
};
class OpValueCache {
+3 -3
View File
@@ -194,7 +194,7 @@ PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
if (not lrunning_)
return;
sockFd_.async_send_to(asio::buffer(sbuf_.data(), sbuf_.size()), peer,
sockFd_.async_send_to(asio::buffer((const void*)sbuf_.data(), sbuf_.size()), peer,
[logger=logger_, peer] (const asio::error_code& ec, size_t)
{
if (ec and (ec != asio::error::operation_aborted) and logger)
@@ -209,8 +209,8 @@ PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
void
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
{
msgpack::sbuffer pack_buf_c;
pack_buf_c.write(pack_buf.data(),pack_buf.size());
msgpack::sbuffer pack_buf_c(pack_buf.size());
pack_buf_c.write(pack_buf.data(), pack_buf.size());
std::lock_guard<std::mutex> lck(mtx_);
messages_[type] = std::move(pack_buf_c);
+2 -2
View File
@@ -74,14 +74,14 @@ struct Request {
Blob&& msg,
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<void(const Request&, bool)> on_expired) :
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)) { }
node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_expired(std::move(on_expired)), msg(std::move(msg)) { }
Request(MessageType type, Tid tid,
Sp<Node> node,
Blob&& msg,
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<bool(const Request&, DhtProtocolException&&)> on_error,
std::function<void(const Request&, bool)> on_expired) :
node(node), tid(tid), type(type), on_done(on_done), on_error(on_error), on_expired(on_expired), msg(std::move(msg)) { }
node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_error(std::move(on_error)), on_expired(std::move(on_expired)), msg(std::move(msg)) { }
Tid getTid() const { return tid; }
MessageType getType() const { return type; }
+19 -45
View File
@@ -71,37 +71,21 @@ SecureDht::~SecureDht() = default;
ValueType
SecureDht::secureType(ValueType&& type)
{
type.storePolicy = [this,type](InfoHash id, Sp<Value>& v, const InfoHash& nid, const SockAddr& a) {
if (v->isSigned()) {
if (!v->signatureChecked) {
v->signatureChecked = true;
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
}
if (!v->signatureValid) {
if (logger_)
logger_->w("Signature verification failed");
return false;
}
}
type.storePolicy = [type](InfoHash id, Sp<Value>& v, const InfoHash& nid, const SockAddr& a) {
if (v->isSigned())
return v->checkSignature();
return type.storePolicy(id, v, nid, a);
};
type.editPolicy = [this,type](InfoHash id, const Sp<Value>& o, Sp<Value>& n, const InfoHash& nid, const SockAddr& a) {
if (!o->isSigned())
if (not o->isSigned())
return type.editPolicy(id, o, n, nid, a);
if (o->owner != n->owner) {
if (logger_)
logger_->w("Edition forbidden: owner changed.");
return false;
}
if (!n->signatureChecked) {
n->signatureChecked = true;
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
}
if (!n->signatureValid) {
if (o->owner != n->owner or not n->isSigned()) {
if (logger_)
logger_->w("Edition forbidden: signature verification failed.");
return false;
}
if (not n->checkSignature())
return false;
if (o->seq == n->seq) {
// If the data is exactly the same,
// it can be reannounced, possibly by someone else.
@@ -253,19 +237,14 @@ SecureDht::checkValue(const Sp<Value>& v)
#endif
return {};
}
if (v->decrypted) {
return v->decryptedValue;
}
v->decrypted = true;
try {
Value decrypted_val (decrypt(*v));
if (decrypted_val.recipient == getId()) {
if (decrypted_val.owner)
nodesPubKeys_[decrypted_val.owner->getId()] = decrypted_val.owner;
v->decryptedValue = std::make_shared<Value>(std::move(decrypted_val));
return v->decryptedValue;
auto isDecrypted = v->isDecrypted();
if (auto decrypted_val = v->decrypt(*key_)) {
auto cacheValue = not isDecrypted and decrypted_val->owner;
if (cacheValue)
nodesPubKeys_[decrypted_val->owner->getId()] = decrypted_val->owner;
return decrypted_val;
}
// Ignore values belonging to other people
} catch (const std::exception& e) {
if (logger_)
logger_->w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
@@ -273,17 +252,12 @@ SecureDht::checkValue(const Sp<Value>& v)
}
// Check signed values
else if (v->isSigned()) {
if (v->signatureChecked) {
return v->signatureValid ? v : Sp<Value>{};
}
v->signatureChecked = true;
if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
v->signatureValid = true;
if (enableCache_)
auto cacheValue = not v->isSignatureChecked() and enableCache_ and v->owner;
if (v->checkSignature()) {
if (cacheValue)
nodesPubKeys_[v->owner->getId()] = v->owner;
return v;
}
else if (logger_)
} else if (logger_)
logger_->w("Signature verification failed for %s", v->toString().c_str());
}
// Forward normal values
@@ -352,7 +326,7 @@ SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
void
SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (not key_ or not hash or not val) {
if (callback)
callback(false, {});
return;
@@ -391,7 +365,7 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
dht_->put(hash, val, callback, time_point::max(), permanent);
},
Value::IdFilter(val->id),
std::move(Where().id(val->id))
Where().id(val->id)
);
}
+27 -9
View File
@@ -37,18 +37,32 @@ public:
storedValues_.emplace(expiration, std::pair<InfoHash, Value::Id>(id, value.id));
}
void erase(const InfoHash& id, const Value& value, time_point expiration) {
totalSize_ -= value.size();
auto range = storedValues_.equal_range(expiration);
for (auto rit = range.first; rit != range.second;) {
if (rit->second.first == id && rit->second.second == value.id) {
totalSize_ -= value.size();
storedValues_.erase(rit);
break;
return;
} else
++rit;
}
// printf("StorageBucket::erase can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
}
void refresh(const InfoHash& id, const Value& value, time_point old_expiration, time_point expiration) {
auto range = storedValues_.equal_range(old_expiration);
for (auto rit = range.first; rit != range.second;) {
if (rit->second.first == id && rit->second.second == value.id) {
storedValues_.erase(rit);
storedValues_.emplace(expiration, std::pair<InfoHash, Value::Id>(id, value.id));
return;
} else
++rit;
}
// printf("StorageBucket::refresh can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id);
insert(id, value, expiration);
}
size_t size() const { return totalSize_; }
std::pair<InfoHash, Value::Id> getOldest() const { return storedValues_.begin()->second; }
std::pair<InfoHash, Value::Id> getOldest() const { return storedValues_.empty() ? std::pair<InfoHash, Value::Id>{} : storedValues_.begin()->second; }
private:
std::multimap<time_point, std::pair<InfoHash, Value::Id>> storedValues_;
size_t totalSize_ {0};
@@ -74,7 +88,7 @@ struct Storage {
size_t listener_token {1};
/* The maximum number of values we store for a given hash. */
static constexpr unsigned MAX_VALUES {1024};
static constexpr unsigned MAX_VALUES {64 * 1024};
/**
* Changes caused by an operation on the storage.
@@ -144,11 +158,14 @@ struct Storage {
* @return time of the next expiration, time_point::max() if no expiration
*/
std::pair<ValueStorage*, time_point>
refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) {
refresh(const InfoHash& id, const time_point& now, const Value::Id& vid, const TypeStore& types) {
for (auto& vs : values)
if (vs.data->id == vid) {
vs.created = now;
vs.expiration = std::max(vs.expiration, now + types.getType(vs.data->type).expiration);
auto oldExp = vs.expiration;
vs.expiration = std::max(oldExp, now + types.getType(vs.data->type).expiration);
if (vs.store_bucket)
vs.store_bucket->refresh(id, *vs.data, oldExp, vs.expiration);
return {&vs, vs.expiration};
}
return {nullptr, time_point::max()};
@@ -160,7 +177,7 @@ struct Storage {
local_listeners.erase(token);
}
StoreDiff remove(const InfoHash& id, Value::Id);
Sp<Value> remove(const InfoHash& id, Value::Id);
std::pair<ssize_t, std::vector<Sp<Value>>> expire(const InfoHash& id, time_point now);
@@ -229,7 +246,7 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
return std::make_pair(nullptr, StoreDiff{});
}
Storage::StoreDiff
Sp<Value>
Storage::remove(const InfoHash& id, Value::Id vid)
{
auto it = std::find_if (values.begin(), values.end(), [&](const ValueStorage& vr) {
@@ -243,8 +260,9 @@ Storage::remove(const InfoHash& id, Value::Id vid)
if (it->expiration_job)
it->expiration_job->cancel();
total_size -= size;
auto value = it->data;
values.erase(it);
return {-size, -1, 0};
return value;
}
Storage::StoreDiff
+1
View File
@@ -106,6 +106,7 @@ ThreadPool::stop()
{
std::lock_guard<std::mutex> l(lock_);
running_ = false;
tasks_ = {};
cv_.notify_all();
}
+1 -1
View File
@@ -106,7 +106,7 @@ print_addr(const sockaddr* sa, socklen_t slen)
{
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
std::stringstream out;
std::ostringstream out;
if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
if (sa->sa_family == AF_INET6)
out << "[" << hbuf << "]";
+56
View File
@@ -254,6 +254,62 @@ unpackId(const Json::Value& json, const std::string& key) {
}
#endif
void
Value::sign(const crypto::PrivateKey& key)
{
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = key.getSharedPublicKey();
signature = key.sign(getToSign());
}
Value
Value::encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to)
{
if (isEncrypted())
throw DhtException("Data is already encrypted.");
setRecipient(to.getId());
sign(from);
Value nv {id};
nv.setCypher(to.encrypt(getToEncrypt()));
return nv;
}
bool
Value::checkSignature()
{
if (!signatureChecked) {
signatureChecked = true;
if (isSigned()) {
signatureValid = owner and owner->checkSignature(getToSign(), signature);
} else {
signatureValid = true;
}
}
return signatureValid;
}
Sp<Value>
Value::decrypt(const crypto::PrivateKey& key)
{
if (not decrypted) {
decrypted = true;
if (isEncrypted()) {
auto decryptedBlob = key.decrypt(cypher);
auto msg = msgpack::unpack((const char*)decryptedBlob.data(), decryptedBlob.size());
auto v = std::make_unique<Value>(id);
v->msgpack_unpack_body(msg.get());
if (v->recipient != key.getPublicKey().getId())
throw crypto::DecryptError("Recipient mismatch");
// Ignore values belonging to other people
if (not v->owner or not v->owner->checkSignature(v->getToSign(), v->signature))
throw crypto::DecryptError("Signature mismatch");
decryptedValue = std::move(v);
}
}
return decryptedValue;
}
bool
FieldValue::operator==(const FieldValue& vfd) const
{
+1 -1
View File
@@ -53,7 +53,7 @@ public:
CallbackQueue clear() {
std::vector<Sp<Value>> expired_values;
expired_values.reserve(values.size());
for (const auto& v : values)
for (auto& v : values)
expired_values.emplace_back(std::move(v.second.data));
values.clear();
CallbackQueue ret;
+2 -2
View File
@@ -309,13 +309,13 @@ DhtProxyTester::testShutdownStop()
for (size_t i = 0; i < C; i++) {
auto nodeTest = std::make_shared<dht::DhtRunner>();
nodeTest->run(0, clientConfig);
nodeTest->put(key, dht::Value(mtu), [&](bool ok) {
nodeTest->put(key, dht::Value(mtu), [&](bool /*ok*/) {
callback_count++;
});
nodeTest->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
return true;
},[&](bool ok){
},[&](bool /*ok*/){
callback_count++;
});
bool done = false;
+54 -21
View File
@@ -35,9 +35,11 @@ DhtRunnerTester::setUp() {
dht::DhtRunner::Config config;
config.dht_config.node_config.max_peer_req_per_sec = -1;
config.dht_config.node_config.max_req_per_sec = -1;
config.dht_config.node_config.max_store_size = -1;
config.dht_config.node_config.max_store_keys = -1;
node1.run(42222, config);
node2.run(42232, config);
node1.run(0, config);
node2.run(0, config);
node2.bootstrap(node1.getBound());
}
@@ -54,15 +56,17 @@ DhtRunnerTester::tearDown() {
node1.shutdown(shutdown);
node2.shutdown(shutdown);
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 12s, [&]{ return done == 2; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return done == 2u; }));
node1.join();
node2.join();
}
void
DhtRunnerTester::testConstructors() {
CPPUNIT_ASSERT(node1.getBoundPort() == 42222);
CPPUNIT_ASSERT(node2.getBoundPort() == 42232);
CPPUNIT_ASSERT(node1.getBoundPort());
CPPUNIT_ASSERT_EQUAL(node1.getBoundPort(), node1.getBound().getPort());
CPPUNIT_ASSERT(node2.getBoundPort());
CPPUNIT_ASSERT_EQUAL(node2.getBoundPort(), node2.getBound().getPort());
dht::DhtRunner::Config config {};
dht::DhtRunner::Context context {};
@@ -90,34 +94,53 @@ void
DhtRunnerTester::testListen() {
std::mutex mutex;
std::condition_variable cv;
std::atomic_uint valueCount(0);
std::atomic_uint valueCounta(0);
std::atomic_uint valueCountb(0);
std::atomic_uint valueCountc(0);
std::atomic_uint valueCountd(0);
unsigned putCount(0);
unsigned putOkCount(0);
unsigned putOkCount1(0);
unsigned putOkCount2(0);
unsigned putOkCount3(0);
auto a = dht::InfoHash::get("234");
auto b = dht::InfoHash::get("2345");
auto c = dht::InfoHash::get("23456");
auto d = dht::InfoHash::get("234567");
constexpr unsigned N = 256;
constexpr unsigned N = 2048;
constexpr unsigned SZ = 56 * 1024;
auto ftokena = node1.listen(a, [&](const std::shared_ptr<dht::Value>&) {
valueCount++;
auto ftokena = node1.listen(a, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
if (expired)
valueCounta -= values.size();
else
valueCounta += values.size();
return true;
});
auto ftokenb = node1.listen(b, [&](const std::shared_ptr<dht::Value>&) {
valueCount++;
/*if (expired)
valueCountb -= values.size();
else
valueCountb += values.size();*/
valueCountb++;
return false;
});
auto ftokenc = node1.listen(c, [&](const std::shared_ptr<dht::Value>&) {
valueCount++;
auto ftokenc = node1.listen(c, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
if (expired)
valueCountc -= values.size();
else
valueCountc += values.size();
return true;
});
auto ftokend = node1.listen(d, [&](const std::shared_ptr<dht::Value>&) {
valueCount++;
auto ftokend = node1.listen(d, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
if (expired)
valueCountd -= values.size();
else
valueCountd += values.size();
return true;
});
@@ -130,21 +153,21 @@ DhtRunnerTester::testListen() {
node2.put(a, dht::Value("v1"), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
if (ok) putOkCount1++;
cv.notify_all();
});
node2.put(b, dht::Value("v2"), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
if (ok) putOkCount2++;
cv.notify_all();
});
auto bigVal = std::make_shared<dht::Value>();
bigVal->data = mtu;
node2.put(c, bigVal, [&](bool ok) {
node2.put(c, std::move(bigVal), [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
if (ok) putOkCount3++;
cv.notify_all();
});
}
@@ -152,7 +175,9 @@ DhtRunnerTester::testListen() {
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 3u; }));
CPPUNIT_ASSERT_EQUAL(N * 3u, putOkCount);
CPPUNIT_ASSERT_EQUAL(N, putOkCount1);
CPPUNIT_ASSERT_EQUAL(N, putOkCount2);
CPPUNIT_ASSERT_EQUAL(N, putOkCount3);
}
CPPUNIT_ASSERT(ftokena.valid());
@@ -168,7 +193,10 @@ DhtRunnerTester::testListen() {
CPPUNIT_ASSERT(tokena);
CPPUNIT_ASSERT(tokenc);
CPPUNIT_ASSERT(tokend);
CPPUNIT_ASSERT_EQUAL(N * 2u + 1u, valueCount.load());
CPPUNIT_ASSERT_EQUAL(N, valueCounta.load());
CPPUNIT_ASSERT_EQUAL(1u, valueCountb.load());
CPPUNIT_ASSERT_EQUAL(N, valueCountc.load());
CPPUNIT_ASSERT_EQUAL(0u, valueCountd.load());
node1.cancelListen(a, tokena);
node1.cancelListen(b, std::move(ftokenb));
@@ -199,6 +227,11 @@ DhtRunnerTester::testIdOps() {
node2.run(42232, config2, std::move(context2));
node2.bootstrap(node1.getBound());
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 1; }));
}
node1.findCertificate(node2.getId(), [&](const std::shared_ptr<dht::crypto::Certificate>& crt){
CPPUNIT_ASSERT(crt);
std::lock_guard<std::mutex> lk(mutex);
+6 -3
View File
@@ -1,7 +1,9 @@
if (OPENDHT_SHARED)
set (OPENDHT_LIBS opendht)
set (OPENDHT_C_LIBS opendht-c)
else ()
set (OPENDHT_LIBS opendht-static)
set (OPENDHT_C_LIBS opendht-c-static)
if (MSVC)
set (MSC_COMPAT_SOURCES ${MSC_COMPAT_DIR}/wingetopt.c)
endif ()
@@ -9,8 +11,8 @@ endif ()
function (configure_tool name extra_files)
add_executable (${name} ${name}.cpp ${extra_files})
target_link_libraries (${name} LINK_PUBLIC ${READLINE_LIBRARIES})
target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS})
add_dependencies(${name} ${OPENDHT_LIBS})
target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS} ${READLINE_LIBRARIES})
if (MSVC)
target_sources(${name} PRIVATE ${MSC_COMPAT_SOURCES})
target_include_directories (${name} PRIVATE ${MSC_COMPAT_DIR})
@@ -29,7 +31,8 @@ endif ()
if (OPENDHT_C)
add_executable (dhtcnode dhtcnode.c)
target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES})
add_dependencies(dhtcnode ${OPENDHT_C_LIBS})
target_link_libraries (dhtcnode LINK_PUBLIC ${OPENDHT_C_LIBS} ${READLINE_LIBRARIES})
target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c)
endif ()
+7
View File
@@ -11,3 +11,10 @@ dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
dhtscanner_SOURCES = dhtscanner.cpp
dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
if ENABLE_C
bin_PROGRAMS += dhtcnode
dhtcnode_CFLAGS = -std=c11 -isystem @top_srcdir@/c -isystem @top_srcdir@/include
dhtcnode_SOURCES = dhtcnode.c
dhtcnode_LDFLAGS = -lopendht-c -lreadline -L@top_builddir@/c/.libs
endif
+219 -59
View File
@@ -1,20 +1,53 @@
/*
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <opendht_c.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <getopt.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <arpa/inet.h>
struct op_context {
dht_runner* runner;
int d;
atomic_bool stop;
};
struct listen_context {
dht_runner* runner;
dht_op_token* token;
size_t count;
};
bool dht_value_callback(const dht_value* value, bool expired, void* user_data)
{
struct listen_context* ctx = (struct listen_context*) user_data;
if (expired)
ctx->count--;
else
ctx->count++;
dht_data_view data = dht_value_get_data(value);
printf("Value callback %s: %.*s.\n", expired ? "expired" : "new", (int)data.size, data.data);
printf("Listen: %s value: %.*s (total %zu).\n", expired ? "expired" : "new", (int)data.size, data.data, ctx->count);
return true;
}
@@ -26,16 +59,30 @@ bool dht_get_callback(const dht_value* value, void* user_data)
return true;
}
void dht_done_callback(bool ok, void* user_data)
void dht_get_done_callback(bool ok, void* user_data)
{
dht_runner* runner = (dht_runner*)user_data;
printf("Done callback. %s\n", ok ? "Success !" : "Failure :-(");
printf("Get completed: %s\n", ok ? "success !" : "failure :-(");
}
void op_context_free(void* user_data)
void dht_put_done_callback(bool ok, void* user_data)
{
dht_runner* runner = (dht_runner*)user_data;
printf("Put completed: %s\n", ok ? "success !" : "failure :-(");
}
void dht_shutdown_callback(void* user_data)
{
printf("Stopped.\n");
struct op_context* ctx = (struct op_context*)user_data;
printf("op_context_free %d.\n", ctx->d);
atomic_store(&ctx->stop, true);
}
void listen_context_free(void* user_data)
{
printf("listen_context_free.\n");
struct listen_context* ctx = (struct listen_context*)user_data;
dht_op_token_delete(ctx->token);
free(ctx);
}
@@ -60,66 +107,179 @@ char* print_addr(const struct sockaddr* addr) {
return s;
}
int main()
struct dht_params {
bool help;
bool version;
bool generate_identity;
bool service;
bool peer_discovery;
bool log;
const char* bootstrap;
unsigned network;
in_port_t port;
};
static const struct option long_options[] = {
{"help", no_argument , NULL, 'h'},
{"port", required_argument, NULL, 'p'},
{"net", required_argument, NULL, 'n'},
{"bootstrap", required_argument, NULL, 'b'},
{"identity", no_argument , NULL, 'i'},
{"verbose", no_argument , NULL, 'v'},
{"service", no_argument , NULL, 's'},
{"peer-discovery", no_argument , NULL, 'D'},
{"no-rate-limit", no_argument , NULL, 'U'},
{"persist", required_argument, NULL, 'f'},
{"logfile", required_argument, NULL, 'l'},
{"syslog", no_argument , NULL, 'L'},
{"version", no_argument , NULL, 'V'},
{NULL, 0 , NULL, 0}
};
struct dht_params
parse_args(int argc, char **argv) {
struct dht_params params;
memset(&params, 0, sizeof params);
int opt;
while ((opt = getopt_long(argc, argv, "hisvDp:n:b:f:l:", long_options, NULL)) != -1) {
switch (opt) {
case 'p': {
int port_arg = atoi(optarg);
if (port_arg >= 0 && port_arg < 0x10000)
params.port = port_arg;
}
break;
case 'D':
params.peer_discovery = true;
break;
case 'n':
params.network = strtoul(optarg, NULL, 0);
break;
case 'b':
params.bootstrap = (optarg[0] == '=') ? optarg+1 : optarg;
break;
case 'h':
params.help = true;
break;
case 'v':
params.log = true;
break;
case 'i':
params.generate_identity = true;
break;
case 's':
params.service = true;
break;
case 'V':
params.version = true;
break;
default:
break;
}
}
return params;
}
dht_infohash parse_key(const char* key_str) {
dht_infohash key;
dht_infohash_from_hex_null(&key, key_str);
if (dht_infohash_is_zero(&key)) {
dht_infohash_get_from_string(&key, key_str);
printf("Using h(%s) = %s\n", key_str, dht_infohash_print(&key));
}
return key;
}
int main(int argc, char **argv)
{
dht_identity id = dht_identity_generate("testNode", NULL);
dht_infohash cert_id = dht_certificate_get_id(id.certificate);
printf("Cert ID: %s\n", dht_infohash_print(&cert_id));
struct dht_params params = parse_args(argc, argv);
dht_publickey* pk = dht_certificate_get_publickey(id.certificate);
dht_infohash pk_id = dht_publickey_get_id(pk);
printf("PK ID: %s\n", dht_infohash_print(&pk_id));
dht_publickey_delete(pk);
pk = dht_privatekey_get_publickey(id.privatekey);
pk_id = dht_publickey_get_id(pk);
printf("Key ID: %s\n", dht_infohash_print(&pk_id));
dht_publickey_delete(pk);
dht_identity_delete(&id);
if (params.version) {
printf("OpenDHT version %s\n", dht_version());
return EXIT_SUCCESS;
}
dht_runner* runner = dht_runner_new();
dht_runner_run(runner, 4040);
dht_runner_config dht_config;
dht_runner_config_default(&dht_config);
dht_config.peer_discovery = params.peer_discovery; // Look for other peers on the network
dht_config.peer_publish = params.peer_discovery; // Publish our own peer info
dht_config.dht_config.node_config.network = params.network;
dht_config.log = params.log;
dht_runner_run_config(runner, params.port, &dht_config);
dht_infohash h;
dht_infohash_random(&h);
printf("random hash: %s\n", dht_infohash_print(&h));
// Put data
const char* data_str = "yo, this is some data";
dht_value* val = dht_value_new_from_string(data_str);
dht_runner_put(runner, &h, val, dht_done_callback, runner, false);
dht_value_unref(val);
// Get data
dht_runner_get(runner, &h, dht_get_callback, dht_done_callback, runner);
// Listen for data
struct op_context* ctx = malloc(sizeof(struct op_context));
ctx->runner = runner;
ctx->d = 42;
dht_op_token* token = dht_runner_listen(runner, &h, dht_value_callback, op_context_free, ctx);
sleep(1);
dht_runner_bootstrap(runner, "bootstrap.jami.net", NULL);
sleep(2);
struct sockaddr** addrs = dht_runner_get_public_address(runner);
for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) {
struct sockaddr* addr = *addrIt;
char* addr_str = print_addr(addr);
free(addr);
printf("Found public address: %s\n", addr_str);
free(addr_str);
if (params.bootstrap) {
printf("Bootstrap using %s\n", params.bootstrap);
dht_runner_bootstrap(runner, params.bootstrap, NULL);
}
free(addrs);
dht_runner_cancel_listen(runner, &h, token);
dht_op_token_delete(token);
char cmd[64];
char arg[64];
char value[256];
dht_infohash key;
while (true) {
const char* line_read = readline("> ");
if (!line_read)
break;
if (!*line_read)
continue;
add_history(line_read);
memset(cmd, 0, sizeof cmd);
memset(arg, 0, sizeof arg);
memset(value, 0, sizeof value);
sscanf(line_read, "%64s %64s %256s", cmd, arg, value);
if (!strcmp(cmd, "la")) {
struct sockaddr** addrs = dht_runner_get_public_address(runner);
if (addrs) {
for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) {
struct sockaddr* addr = *addrIt;
char* addr_str = print_addr(addr);
free(addr);
printf("Found public address: %s\n", addr_str);
free(addr_str);
}
free(addrs);
}
}
else if (!strcmp(cmd, "ll")) {
key = dht_runner_get_node_id(runner);
printf("DHT node %s running on port %u\n", dht_infohash_print(&key), dht_runner_get_bound_port(runner, AF_INET));
}
else if (!strcmp(cmd, "g")) {
key = parse_key(arg);
dht_runner_get(runner, &key, dht_get_callback, dht_get_done_callback, runner);
}
else if (!strcmp(cmd, "l")) {
key = parse_key(arg);
struct listen_context* ctx = malloc(sizeof(struct listen_context));
ctx->runner = runner;
ctx->count = 0;
ctx->token = dht_runner_listen(runner, &key, dht_value_callback, listen_context_free, ctx);
}
else if (!strcmp(cmd, "p")) {
key = parse_key(arg);
dht_value* val = dht_value_new_from_string(value);
dht_runner_put(runner, &key, val, dht_put_done_callback, runner, true);
dht_value_unref(val);
}
else {
printf("Unkown command: %s\n", cmd);
}
}
// Graceful shutdown
printf("Stopping…\n");
struct op_context ctx;
ctx.runner = runner;
atomic_init(&ctx.stop, false);
dht_runner_shutdown(runner, dht_shutdown_callback, &ctx);
// Wait until shutdown callback is called
while (!atomic_load(&ctx.stop)) {
usleep(10000);
}
dht_runner_delete(runner);
return 0;
return EXIT_SUCCESS;
}
+4 -1
View File
@@ -43,7 +43,7 @@ void print_version() {
}
void print_usage() {
std::cout << "Usage: dhtnode [-v [-l logfile]] [-i] [-d] [-n network_id] [-p local_port] [-b bootstrap_host[:port]] [--proxyserver local_port] [--proxyserverssl local_port]" << std::endl << std::endl;
std::cout << "Usage: dhtnode [-v [-l logfile]] [-i] [-d] [-n network_id] [-p local_port] [-b bootstrap_host[:port]] [--proxyserver local_port] [--proxyserverssl local_port] [--bundleid bundleid] [--openpush endpoint]" << std::endl << std::endl;
print_info();
}
@@ -146,6 +146,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
node->getNodeInfo([&](const std::shared_ptr<dht::NodeInfo>& nodeInfo) {
print_node_info(*nodeInfo);
std::cout << nodeInfo->ongoing_ops << " ongoing operations" << std::endl;
std::cout << "Storage has " << nodeInfo->storage_values << " values, using " << (nodeInfo->storage_size/1024) << " KB" << std::endl;
std::cout << "IPv4 stats:" << std::endl;
std::cout << nodeInfo->ipv4.toString() << std::endl;
std::cout << "IPv6 stats:" << std::endl;
@@ -549,6 +550,8 @@ main(int argc, char **argv)
#ifdef OPENDHT_PROXY_SERVER
ProxyServerConfig serverConfig;
serverConfig.pushServer = params.pushserver;
serverConfig.bundleId = params.bundle_id;
serverConfig.address = params.proxy_address;
if (params.proxyserverssl and params.proxy_id.first and params.proxy_id.second){
serverConfig.identity = params.proxy_id;
serverConfig.port = params.proxyserverssl;
+11 -1
View File
@@ -131,8 +131,10 @@ struct dht_params {
in_port_t proxyserver {0};
in_port_t proxyserverssl {0};
std::string proxyclient {};
std::string proxy_address {};
std::string pushserver {};
std::string devicekey {};
std::string bundle_id {};
std::string persist_path {};
dht::crypto::Identity id {};
dht::crypto::Identity proxy_id {};
@@ -223,12 +225,14 @@ static const constexpr struct option long_options[] = {
{"syslog", no_argument , nullptr, 'L'},
{"proxyserver", required_argument, nullptr, 'S'},
{"proxyserverssl", required_argument, nullptr, 'e'},
{"proxy-addr", required_argument, nullptr, 'a'},
{"proxy-certificate", required_argument, nullptr, 'w'},
{"proxy-privkey", required_argument, nullptr, 'K'},
{"proxy-privkey-password", required_argument, nullptr, 'M'},
{"proxyclient", required_argument, nullptr, 'C'},
{"pushserver", required_argument, nullptr, 'y'},
{"devicekey", required_argument, nullptr, 'z'},
{"bundleid", required_argument, nullptr, 'u'},
{"version", no_argument , nullptr, 'V'},
{nullptr, 0 , nullptr, 0}
};
@@ -239,7 +243,7 @@ parseArgs(int argc, char **argv) {
int opt;
std::string privkey;
std::string proxy_privkey;
while ((opt = getopt_long(argc, argv, "hidsvDUPp:n:b:f:l:", long_options, nullptr)) != -1) {
while ((opt = getopt_long(argc, argv, "hidsvODUPp:n:b:f:l:", long_options, nullptr)) != -1) {
switch (opt) {
case 'p': {
int port_arg = atoi(optarg);
@@ -268,6 +272,9 @@ parseArgs(int argc, char **argv) {
case 'D':
params.peer_discovery = true;
break;
case 'a':
params.proxy_address = optarg;
break;
case 'y':
params.pushserver = optarg;
break;
@@ -336,6 +343,9 @@ parseArgs(int argc, char **argv) {
case 'k':
privkey = optarg;
break;
case 'u':
params.bundle_id = optarg;
break;
case 'K':
proxy_privkey = optarg;
break;