mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 20:37:23 +00:00
Compare commits
154
Commits
2.4.1
...
message_split
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95f3920ca8 | ||
|
|
5f1e7952a4 | ||
|
|
41eabc7261 | ||
|
|
424fe61a49 | ||
|
|
02e03771d4 | ||
|
|
e35f8c29ee | ||
|
|
64e3bcf0dc | ||
|
|
a9f3883bfa | ||
|
|
3c3b3dc303 | ||
|
|
970e71d215 | ||
|
|
b6552ec300 | ||
|
|
58bc772256 | ||
|
|
31af08feaa | ||
|
|
9e60a681f3 | ||
|
|
51525d144b | ||
|
|
965fbb43c7 | ||
|
|
133d77d985 | ||
|
|
9451861f51 | ||
|
|
4b489fb7d7 | ||
|
|
7fcaf19ca3 | ||
|
|
c51d59a3a3 | ||
|
|
bcc02837d3 | ||
|
|
611017e187 | ||
|
|
7f7bff6a28 | ||
|
|
b9d7957bf6 | ||
|
|
fa31cec73e | ||
|
|
550a8cf362 | ||
|
|
50996eaf7e | ||
|
|
813c3b43d2 | ||
|
|
4ce9292b28 | ||
|
|
655aa074bf | ||
|
|
2e9c119dca | ||
|
|
7bf2d2a7a9 | ||
|
|
d9a97e2cec | ||
|
|
6395399c2d | ||
|
|
e6971c196b | ||
|
|
b1009a54e3 | ||
|
|
33d73d5d55 | ||
|
|
f42d94da59 | ||
|
|
2418b355d7 | ||
|
|
2cb57251a1 | ||
|
|
446da4b792 | ||
|
|
aa958b0f1d | ||
|
|
58be07a8b0 | ||
|
|
6c61ac53c4 | ||
|
|
6e73a78a8b | ||
|
|
f2623bd51d | ||
|
|
d6a99d0edd | ||
|
|
b9ccc968b2 | ||
|
|
7e33c4fc76 | ||
|
|
39bb520339 | ||
|
|
18e53b9ec8 | ||
|
|
0b5379380a | ||
|
|
b800012c57 | ||
|
|
ebeff20215 | ||
|
|
16ff16bd39 | ||
|
|
0d28a7bdab | ||
|
|
69a1bdfc45 | ||
|
|
af7d88b057 | ||
|
|
abe2e018b6 | ||
|
|
2e79ee4f11 | ||
|
|
8b022d0022 | ||
|
|
5399dbdfbc | ||
|
|
0e3bca1dde | ||
|
|
a992aa1f05 | ||
|
|
1a267418dd | ||
|
|
0f8d891476 | ||
|
|
b9c79a1de5 | ||
|
|
2c7edb695f | ||
|
|
c3ad33687e | ||
|
|
9c5e5cd7b7 | ||
|
|
9048e4a31c | ||
|
|
ba1b3c26c5 | ||
|
|
c6b4e317df | ||
|
|
44267a72de | ||
|
|
8c1c5d09c7 | ||
|
|
acadeb220a | ||
|
|
ff7c80d416 | ||
|
|
577f2a0645 | ||
|
|
48e718ffd8 | ||
|
|
07d25a4140 | ||
|
|
2f7fabf1c7 | ||
|
|
60274655dd | ||
|
|
eace3d91b2 | ||
|
|
86cc41f446 | ||
|
|
3ac5b9466a | ||
|
|
c95c3de136 | ||
|
|
a865d6854c | ||
|
|
52b735b1b9 | ||
|
|
f862305f78 | ||
|
|
ce7ffbf2cd | ||
|
|
687f643059 | ||
|
|
f6e3fc99e6 | ||
|
|
293662a710 | ||
|
|
437252bfcc | ||
|
|
ead21d24a0 | ||
|
|
53de63e829 | ||
|
|
633a03d76a | ||
|
|
3e5fbb0b5c | ||
|
|
6d13e301f9 | ||
|
|
4d356b6dca | ||
|
|
44a251de56 | ||
|
|
1c536a4c51 | ||
|
|
502a649f42 | ||
|
|
12a52c78ac | ||
|
|
df2a775927 | ||
|
|
2c86ccbe15 | ||
|
|
b9321a338b | ||
|
|
dc9a211fb0 | ||
|
|
d49b394eae | ||
|
|
f82c68a871 | ||
|
|
3f4235da69 | ||
|
|
e259cb0847 | ||
|
|
08f9b424de | ||
|
|
d33c3515f8 | ||
|
|
0a70b0f80f | ||
|
|
949cbb9fc7 | ||
|
|
37cfbffdca | ||
|
|
efad2ada89 | ||
|
|
d825f4e5ae | ||
|
|
baa2a5d21c | ||
|
|
b3f9683018 | ||
|
|
6d1819acb9 | ||
|
|
d6ee44b640 | ||
|
|
383c53d71f | ||
|
|
833c647524 | ||
|
|
7f6f50411c | ||
|
|
1c7089c055 | ||
|
|
4641780fe6 | ||
|
|
c67df2ead3 | ||
|
|
5f743344e5 | ||
|
|
56442acc84 | ||
|
|
41c9104b8a | ||
|
|
126f0ca966 | ||
|
|
adeca7fa1f | ||
|
|
5527b6553d | ||
|
|
5a6b9db60c | ||
|
|
8f1c075897 | ||
|
|
fca11e621c | ||
|
|
38a7234ae3 | ||
|
|
115a0c683f | ||
|
|
61b7bed0f8 | ||
|
|
dcd8ec7394 | ||
|
|
51880afcce | ||
|
|
db3a4e52b2 | ||
|
|
af8e66b813 | ||
|
|
9646eb9374 | ||
|
|
0df2fbe5de | ||
|
|
c39eceeddf | ||
|
|
11396c315e | ||
|
|
955af06e29 | ||
|
|
e207e59226 | ||
|
|
0302cee8d5 | ||
|
|
8f4031c8cb |
No files matched your search
+50
-24
@@ -4,53 +4,79 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
name: Ubuntu/GCC build
|
||||
name: Ubuntu/GCC Autotools build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: deps
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
|
||||
sudo apt install libncurses5-dev libreadline-dev nettle-dev libasio-dev \
|
||||
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
|
||||
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
|
||||
- name: autogen
|
||||
run: ./autogen.sh
|
||||
- name: asio
|
||||
- name: Configure
|
||||
run: |
|
||||
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
|
||||
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
|
||||
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
|
||||
&& sudo make install \
|
||||
&& cd ../../ && rm -rf asio*
|
||||
- name: configure
|
||||
run: ./configure
|
||||
- name: make
|
||||
./autogen.sh
|
||||
./configure
|
||||
- name: Build
|
||||
run: make
|
||||
- name: make check
|
||||
run: make check
|
||||
|
||||
build-ubuntu-meson:
|
||||
name: Ubuntu/GCC Meson build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt install meson ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev \
|
||||
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
|
||||
libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
|
||||
- name: Configure
|
||||
run: meson setup build .
|
||||
- name: Build
|
||||
run: cd build && ninja
|
||||
|
||||
build-ubuntu-minimal:
|
||||
name: Ubuntu/GCC minimal build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
|
||||
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
|
||||
- name: Configure
|
||||
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: Build
|
||||
run: cd build && make
|
||||
- name: Unit tests
|
||||
run: cd build && ./opendht_unit_tests
|
||||
|
||||
build-macos:
|
||||
name: macOS/Clang build
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: deps
|
||||
- name: Dependencies
|
||||
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/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/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
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
|
||||
@@ -59,8 +85,8 @@ jobs:
|
||||
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
|
||||
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
|
||||
|
||||
- name: make
|
||||
- name: Build
|
||||
run: cd build && make
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: Clang Static Analysis
|
||||
on:
|
||||
push
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
clang-analyzer:
|
||||
name: Clang Static Analysis
|
||||
@@ -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 . \
|
||||
@@ -30,6 +30,6 @@ jobs:
|
||||
- name: cmake
|
||||
run: |
|
||||
mkdir build && cd build && \
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
|
||||
- name: scan-build
|
||||
run: cd build && scan-build --status-bugs make
|
||||
@@ -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
|
||||
@@ -0,0 +1,293 @@
|
||||
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
|
||||
IMAGE_NAME_ALPINE: ${{ github.repository }}/opendht-alpine
|
||||
IMAGE_NAME_ALPINE_DEPS: ${{ github.repository }}/opendht-deps-alpine
|
||||
|
||||
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-and-push-image-alpine-deps:
|
||||
name: Alpine Deps 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_ALPINE_DEPS }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: docker/DockerfileAlpineDeps
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-and-push-image-alpine:
|
||||
name: Alpine 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_ALPINE }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: docker/DockerfileAlpine
|
||||
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
|
||||
Vendored
+2
@@ -20,7 +20,9 @@
|
||||
"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",
|
||||
|
||||
+71
-122
@@ -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,18 +9,20 @@ project (opendht)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(FindPkgConfig)
|
||||
include(cmake/CheckAtomic.cmake)
|
||||
include(CTest)
|
||||
|
||||
set (opendht_VERSION_MAJOR 2)
|
||||
set (opendht_VERSION_MINOR 4.1)
|
||||
set (opendht_VERSION_MINOR 5.0)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
# Options
|
||||
option (OPENDHT_STATIC "Build static library" ON)
|
||||
option (OPENDHT_SHARED "Build shared library" ON)
|
||||
option (BUILD_SHARED_LIBS "Build shared library" ON)
|
||||
CMAKE_DEPENDENT_OPTION (OPENDHT_STATIC "Build static library" OFF BUILD_SHARED_LIBS ON)
|
||||
option (OPENDHT_LOG "Build with logs" ON)
|
||||
option (OPENDHT_PYTHON "Build Python bindings" OFF)
|
||||
option (OPENDHT_TOOLS "Build DHT tools" ON)
|
||||
@@ -41,13 +37,16 @@ option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
|
||||
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
|
||||
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
|
||||
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
|
||||
option (OPENDHT_TESTS "Add unit tests executable" OFF)
|
||||
option (OPENDHT_TESTS_NETWORK "Enable unit tests that require network access" ON)
|
||||
option (OPENDHT_C "Build C bindings" OFF)
|
||||
|
||||
find_package(Doxygen)
|
||||
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
|
||||
|
||||
# Build flags
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED on)
|
||||
|
||||
# Dependencies
|
||||
if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
|
||||
link_libraries (atomic)
|
||||
@@ -58,16 +57,18 @@ if (NOT MSVC)
|
||||
set (THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package (Threads)
|
||||
find_package (PkgConfig REQUIRED)
|
||||
find_package (GnuTLS 3.3 REQUIRED)
|
||||
pkg_search_module (Nettle REQUIRED nettle)
|
||||
find_package (msgpack REQUIRED)
|
||||
pkg_search_module (GnuTLS REQUIRED IMPORTED_TARGET gnutls)
|
||||
pkg_search_module (Nettle REQUIRED IMPORTED_TARGET nettle)
|
||||
find_package (msgpack REQUIRED NAMES msgpackc-cxx msgpack msgpack-cxx)
|
||||
if (OPENDHT_TOOLS)
|
||||
find_package (Readline 6 REQUIRED)
|
||||
endif ()
|
||||
pkg_search_module(argon2 REQUIRED libargon2)
|
||||
pkg_search_module(Jsoncpp jsoncpp)
|
||||
pkg_search_module(argon2 REQUIRED IMPORTED_TARGET libargon2)
|
||||
set(argon2_lib ", libargon2")
|
||||
pkg_search_module(Jsoncpp IMPORTED_TARGET jsoncpp)
|
||||
if (Jsoncpp_FOUND)
|
||||
add_definitions(-DOPENDHT_JSONCPP)
|
||||
set(jsoncpp_lib ", jsoncpp")
|
||||
list (APPEND opendht_SOURCES
|
||||
src/base64.h
|
||||
src/base64.cpp
|
||||
@@ -84,16 +85,16 @@ if (NOT MSVC)
|
||||
add_library(fmt SHARED IMPORTED)
|
||||
find_library(HTTP_PARSER_LIBRARY http_parser)
|
||||
add_library(http_parser SHARED IMPORTED)
|
||||
set(http_parser_lib "-lhttp_parser")
|
||||
if (NOT Jsoncpp_FOUND)
|
||||
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
|
||||
endif()
|
||||
if (OPENDHT_PROXY_OPENSSL)
|
||||
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
|
||||
pkg_search_module(OPENSSL REQUIRED openssl)
|
||||
pkg_search_module(OPENSSL REQUIRED IMPORTED_TARGET openssl)
|
||||
if (OPENSSL_FOUND)
|
||||
message(STATUS "Found OpenSSL ${OPENSSL_VERSION} ${OPENSSL_INCLUDE_DIRS}")
|
||||
include_direcopendht/ries(SYSTEM ${OPENSSL_INCLUDE_DIRS})
|
||||
link_directories (${OPENSSL_LIBRARY_DIRS})
|
||||
set(openssl_lib ", openssl")
|
||||
else ()
|
||||
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
|
||||
endif()
|
||||
@@ -127,12 +128,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 ()
|
||||
@@ -148,9 +145,6 @@ else ()
|
||||
endif ()
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
add_definitions(-DPACKAGE_VERSION="${opendht_VERSION}")
|
||||
if (OPENDHT_LOG)
|
||||
add_definitions(-DOPENDHT_LOG=true)
|
||||
@@ -158,27 +152,12 @@ else ()
|
||||
add_definitions(-DOPENDHT_LOG=false)
|
||||
endif()
|
||||
|
||||
if (MSGPACK_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${MSGPACK_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
if (GNUTLS_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${GNUTLS_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
if (Nettle_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${Nettle_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
if (ASIO_INCLUDE_DIR)
|
||||
include_directories (SYSTEM "${ASIO_INCLUDE_DIR}")
|
||||
endif ()
|
||||
if (Restinio_INCLUDE_DIR)
|
||||
include_directories (SYSTEM "${Restinio_INCLUDE_DIR}")
|
||||
endif ()
|
||||
if (Jsoncpp_INCLUDE_DIRS)
|
||||
include_directories (SYSTEM "${Jsoncpp_INCLUDE_DIRS}")
|
||||
endif ()
|
||||
link_directories (${Nettle_LIBRARY_DIRS})
|
||||
link_directories (${Jsoncpp_LIBRARY_DIRS})
|
||||
link_directories (${argon2_LIBRARY_DIRS})
|
||||
include_directories (
|
||||
./
|
||||
include/
|
||||
@@ -199,7 +178,6 @@ set (top_srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
# Sources
|
||||
list (APPEND opendht_SOURCES
|
||||
src/utils.cpp
|
||||
src/infohash.cpp
|
||||
src/crypto.cpp
|
||||
src/default_types.cpp
|
||||
src/node.cpp
|
||||
@@ -311,20 +289,8 @@ if (MSVC)
|
||||
endif ()
|
||||
|
||||
# Targets
|
||||
if (OPENDHT_STATIC)
|
||||
if (NOT MSVC)
|
||||
add_library (opendht-static STATIC
|
||||
${opendht_SOURCES}
|
||||
${opendht_HEADERS}
|
||||
)
|
||||
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}
|
||||
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES}
|
||||
${Jsoncpp_STATIC_LIBRARIES} ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}
|
||||
${OPENSSL_STATIC_LIBRARIES})
|
||||
else ()
|
||||
if (MSVC)
|
||||
if (OPENDHT_STATIC)
|
||||
if (OPENDHT_TOOLS)
|
||||
function (add_obj_lib name libfile)
|
||||
add_library(${name} OBJECT IMPORTED)
|
||||
@@ -363,64 +329,59 @@ if (OPENDHT_STATIC)
|
||||
${PROJECT_SOURCE_DIR}/../openssl/libcrypto.lib
|
||||
)
|
||||
endif ()
|
||||
add_library (opendht-static STATIC
|
||||
${opendht_SOURCES}
|
||||
${opendht_HEADERS}
|
||||
${obj_libs}
|
||||
)
|
||||
target_link_libraries(opendht-static PUBLIC ${Win32_STATIC_LIBRARIES} ${Win32_IMPORT_LIBRARIES})
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4006")
|
||||
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "libopendht")
|
||||
endif()
|
||||
install (TARGETS opendht-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_SHARED)
|
||||
add_library (opendht SHARED
|
||||
${opendht_SOURCES}
|
||||
${opendht_HEADERS}
|
||||
)
|
||||
add_library (opendht
|
||||
${opendht_SOURCES}
|
||||
${opendht_HEADERS}
|
||||
${obj_libs}
|
||||
)
|
||||
set_target_properties (opendht PROPERTIES OUTPUT_NAME "opendht")
|
||||
target_link_libraries(opendht
|
||||
PRIVATE
|
||||
PkgConfig::argon2
|
||||
PkgConfig::Nettle
|
||||
${HTTP_PARSER_LIBRARY}
|
||||
PUBLIC
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
PkgConfig::GnuTLS
|
||||
msgpackc-cxx
|
||||
${FMT_LIBRARY}
|
||||
)
|
||||
if (Jsoncpp_FOUND)
|
||||
target_link_libraries(opendht PUBLIC PkgConfig::Jsoncpp)
|
||||
endif()
|
||||
if (OPENDHT_PROXY_OPENSSL)
|
||||
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
|
||||
endif()
|
||||
if (APPLE)
|
||||
target_link_libraries(opendht PRIVATE SYSTEM "-framework CoreFoundation" "-framework Security")
|
||||
endif()
|
||||
if (MSVC)
|
||||
if (OPENDHT_STATIC)
|
||||
target_link_libraries(opendht PUBLIC ${Win32_STATIC_LIBRARIES} ${Win32_IMPORT_LIBRARIES})
|
||||
set_target_properties (opendht PROPERTIES OUTPUT_NAME "libopendht")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
|
||||
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
|
||||
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
|
||||
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
|
||||
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})
|
||||
endif ()
|
||||
|
||||
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
endif ()
|
||||
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
|
||||
|
||||
if (OPENDHT_C)
|
||||
if (OPENDHT_SHARED)
|
||||
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
|
||||
)
|
||||
target_link_libraries(opendht-c-static PRIVATE opendht-static)
|
||||
install (TARGETS opendht-c-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c-static)
|
||||
endif ()
|
||||
add_library (opendht-c
|
||||
c/opendht.cpp
|
||||
c/opendht_c.h
|
||||
)
|
||||
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
|
||||
target_link_libraries(opendht-c PRIVATE opendht)
|
||||
set_target_properties (opendht-c PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
|
||||
install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c)
|
||||
|
||||
# PkgConfig module
|
||||
configure_file (
|
||||
@@ -460,8 +421,8 @@ install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE o
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
|
||||
|
||||
# Unit tests
|
||||
if (OPENDHT_TESTS)
|
||||
pkg_search_module(Cppunit REQUIRED cppunit)
|
||||
if (BUILD_TESTING)
|
||||
pkg_search_module(Cppunit REQUIRED IMPORTED_TARGET cppunit)
|
||||
# unit testing
|
||||
list (APPEND test_FILES
|
||||
tests/infohashtester.h
|
||||
@@ -495,22 +456,10 @@ if (OPENDHT_TESTS)
|
||||
tests/tests_runner.cpp
|
||||
${test_FILES}
|
||||
)
|
||||
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${Cppunit_INCLUDE_DIR})
|
||||
target_link_directories(opendht_unit_tests PRIVATE ${Cppunit_LIBRARY_DIRS})
|
||||
if (OPENDHT_SHARED)
|
||||
target_link_libraries(opendht_unit_tests opendht)
|
||||
else ()
|
||||
target_link_libraries(opendht_unit_tests opendht-static)
|
||||
endif ()
|
||||
target_link_libraries(opendht_unit_tests
|
||||
target_link_libraries(opendht_unit_tests PRIVATE
|
||||
opendht
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${Cppunit_LIBRARIES}
|
||||
${GNUTLS_LIBRARIES}
|
||||
${Jsoncpp_LIBRARIES}
|
||||
PkgConfig::Cppunit
|
||||
)
|
||||
if (OPENDHT_PROXY_OPENSSL)
|
||||
target_link_libraries(opendht_unit_tests ${OPENSSL_LIBRARIES})
|
||||
endif()
|
||||
enable_testing()
|
||||
add_test(TEST opendht_unit_tests)
|
||||
endif()
|
||||
@@ -25,11 +25,6 @@ See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
|
||||
|
||||
Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-library>
|
||||
|
||||
#### How-to build a simple client app
|
||||
```bash
|
||||
g++ main.cpp -std=c++17 -lopendht
|
||||
```
|
||||
|
||||
## Examples
|
||||
### C++ example
|
||||
The `tools` directory includes simple example programs :
|
||||
@@ -117,6 +112,3 @@ See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 l
|
||||
## Acknowledgements
|
||||
This project was originally based on https://github.com/jech/dht by Juliusz Chroboczek.
|
||||
It is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
|
||||
|
||||
## Donations
|
||||
We gratefully accept Bitcoin donations to support OpenDHT development at: `bitcoin:3EykSd1An888efq4Bq3KaV3hJ3JQ4FPnwm`.
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
lib_LTLIBRARIES = libopendht-c.la
|
||||
noinst_HEADERS = opendht_c.h
|
||||
|
||||
AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
|
||||
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
|
||||
|
||||
|
||||
+15
-10
@@ -32,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) {
|
||||
@@ -71,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) {
|
||||
@@ -252,7 +261,7 @@ dht_pkid dht_certificate_get_long_id(const dht_certificate* c) {
|
||||
|
||||
dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
|
||||
const auto& cert = *reinterpret_cast<const CertSp*>(c);
|
||||
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey())));
|
||||
return reinterpret_cast<dht_publickey*>(new PubkeySp(cert->getSharedPublicKey()));
|
||||
}
|
||||
|
||||
// dht::crypto::Identity
|
||||
@@ -333,6 +342,8 @@ 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;
|
||||
|
||||
@@ -495,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;
|
||||
}
|
||||
|
||||
@@ -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,6 +146,8 @@ 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;
|
||||
|
||||
+23
-18
@@ -1,7 +1,7 @@
|
||||
dnl define macros
|
||||
m4_define([opendht_major_version], 2)
|
||||
m4_define([opendht_minor_version], 4)
|
||||
m4_define([opendht_patch_version], 1)
|
||||
m4_define([opendht_minor_version], 5)
|
||||
m4_define([opendht_patch_version], 0)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
|
||||
@@ -18,18 +18,26 @@ 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
|
||||
@@ -106,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)
|
||||
@@ -129,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])
|
||||
])
|
||||
|
||||
@@ -138,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"])
|
||||
|
||||
@@ -167,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"], [
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,57 @@
|
||||
FROM alpine:3.17 AS build
|
||||
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
|
||||
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
|
||||
|
||||
RUN apk add --no-cache \
|
||||
build-base cmake ninja git wget \
|
||||
cython python3-dev py3-setuptools \
|
||||
ncurses-dev readline-dev nettle-dev \
|
||||
cppunit-dev gnutls-dev jsoncpp-dev \
|
||||
argon2-dev openssl-dev fmt-dev \
|
||||
http-parser-dev asio-dev msgpack-cxx-dev \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN echo "*** Downloading RESTinio ***" \
|
||||
&& mkdir restinio && cd restinio \
|
||||
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
|
||||
&& 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 . \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../../.. && rm -rf restinio
|
||||
|
||||
COPY . opendht
|
||||
|
||||
RUN mkdir /install
|
||||
ENV DESTDIR /install
|
||||
|
||||
RUN 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 \
|
||||
-DOPENDHT_SYSTEMD=On \
|
||||
&& make -j8 && make install
|
||||
|
||||
FROM alpine:3.17 AS install
|
||||
COPY --from=build /install /
|
||||
RUN apk add --no-cache \
|
||||
libstdc++ \
|
||||
gnutls \
|
||||
nettle \
|
||||
openssl \
|
||||
argon2-dev \
|
||||
jsoncpp \
|
||||
fmt \
|
||||
http-parser \
|
||||
readline \
|
||||
ncurses
|
||||
CMD ["dhtnode", "-b", "bootstrap.jami.net", "-p", "4222", "--proxyserver", "8080"]
|
||||
EXPOSE 4222/udp
|
||||
EXPOSE 8080/tcp
|
||||
@@ -0,0 +1,23 @@
|
||||
FROM alpine:3.17
|
||||
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
|
||||
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
|
||||
|
||||
RUN apk add --no-cache \
|
||||
build-base cmake ninja git wget \
|
||||
cython python3-dev py3-setuptools \
|
||||
ncurses-dev readline-dev nettle-dev \
|
||||
cppunit-dev gnutls-dev jsoncpp-dev \
|
||||
argon2-dev openssl-dev fmt-dev \
|
||||
http-parser-dev asio-dev msgpack-cxx-dev \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN echo "*** Downloading RESTinio ***" \
|
||||
&& mkdir restinio && cd restinio \
|
||||
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
|
||||
&& 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 . \
|
||||
&& make -j8 && make install \
|
||||
&& cd ../../.. && rm -rf restinio
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential pkg-config cmake git wget \
|
||||
libtool autotools-dev autoconf \
|
||||
cython3 python3-dev python3-setuptools \
|
||||
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 . \
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -11,7 +11,7 @@ RUN apt-get update \
|
||||
&& 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 \
|
||||
@@ -22,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 . \
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
+40
-15
@@ -32,6 +32,9 @@ extern "C" {
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iso646.h>
|
||||
@@ -84,12 +87,13 @@ 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; }
|
||||
bool operator ==(const PublicKey& o) const {
|
||||
return pk == o.pk || getId() == o.getId();
|
||||
return pk == o.pk || getLongId() == o.getLongId();
|
||||
}
|
||||
bool operator !=(const PublicKey& o) const {
|
||||
return !(*this == o);
|
||||
@@ -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;
|
||||
@@ -373,19 +390,21 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
*/
|
||||
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
|
||||
|
||||
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
|
||||
Certificate(Certificate&& o) noexcept
|
||||
: cert(o.cert)
|
||||
, issuer(std::move(o.issuer))
|
||||
, publicKey_(std::move(o.publicKey_))
|
||||
{ o.cert = nullptr; };
|
||||
|
||||
/**
|
||||
* Import certificate (PEM or DER) or certificate chain (PEM),
|
||||
* 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),
|
||||
@@ -483,12 +502,13 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
|
||||
explicit operator bool() const { return cert; }
|
||||
PublicKey getPublicKey() const;
|
||||
const PublicKey& getPublicKey() const;
|
||||
const std::shared_ptr<PublicKey>& getSharedPublicKey() 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 +626,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 {
|
||||
@@ -614,6 +636,9 @@ private:
|
||||
};
|
||||
|
||||
std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
|
||||
|
||||
mutable std::mutex publicKeyMutex_ {};
|
||||
mutable std::shared_ptr<PublicKey> publicKey_ {};
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC TrustList
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
*/
|
||||
void insertNode(const InfoHash& id, const SockAddr&) override;
|
||||
void insertNode(const NodeExport& n) override {
|
||||
insertNode(n.id, SockAddr(n.ss, n.sslen));
|
||||
insertNode(n.id, n.addr);
|
||||
}
|
||||
|
||||
void pingNode(SockAddr, DoneCallbackSimple&& cb={}) override;
|
||||
@@ -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};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "infohash.h"
|
||||
#include "log_enable.h"
|
||||
#include "node_export.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
@@ -221,6 +222,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 +266,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
|
||||
|
||||
@@ -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};
|
||||
@@ -349,6 +368,7 @@ private:
|
||||
* Note: Each context is used in one thread only
|
||||
*/
|
||||
asio::io_context httpContext_;
|
||||
mutable std::mutex resolverLock_;
|
||||
std::shared_ptr<http::Resolver> resolver_;
|
||||
|
||||
mutable std::mutex requestLock_;
|
||||
@@ -399,6 +419,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
|
||||
|
||||
@@ -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,11 @@ private:
|
||||
restinio::router::route_params_t params);
|
||||
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
PushType getTypeFromString(const std::string& type);
|
||||
std::string getDefaultTopic(PushType type);
|
||||
|
||||
RequestStatus pingPush(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t /*params*/);
|
||||
/**
|
||||
* Subscribe to push notifications for an iOS or Android device.
|
||||
* Method: SUBSCRIBE "/{InfoHash: .*}"
|
||||
@@ -300,7 +308,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 +316,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 +391,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 +410,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 +428,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 +439,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 +452,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 +464,6 @@ private:
|
||||
MSGPACK_DEFINE_ARRAY(listeners)
|
||||
};
|
||||
std::map<std::string, PushListener> pushListeners_;
|
||||
proxy::ListenToken tokenPushNotif_ {0};
|
||||
#endif //OPENDHT_PUSH_NOTIFICATIONS
|
||||
};
|
||||
|
||||
|
||||
+17
-18
@@ -27,6 +27,7 @@
|
||||
#include "sockaddr.h"
|
||||
#include "log_enable.h"
|
||||
#include "network_utils.h"
|
||||
#include "node_export.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
@@ -61,6 +62,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;
|
||||
@@ -335,6 +338,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 +375,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 +440,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 +450,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 +486,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 +500,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
@@ -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
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef uint16_t in_port_t;
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -103,13 +104,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 +250,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;
|
||||
@@ -391,25 +388,4 @@ Hash<N>::toString() const
|
||||
return std::string(to_c_str(), N*2);
|
||||
}
|
||||
|
||||
struct OPENDHT_PUBLIC NodeExport {
|
||||
InfoHash id;
|
||||
sockaddr_storage ss;
|
||||
socklen_t sslen;
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const
|
||||
{
|
||||
pk.pack_map(2);
|
||||
pk.pack(std::string("id"));
|
||||
pk.pack(id);
|
||||
pk.pack(std::string("addr"));
|
||||
pk.pack_bin(sslen);
|
||||
pk.pack_bin_body((char*)&ss, sslen);
|
||||
}
|
||||
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const NodeExport& h);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -416,12 +416,19 @@ public:
|
||||
*
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request> sendUpdateValues(const Sp<Node>& n,
|
||||
void sendUpdateValues(const Sp<Node>& n,
|
||||
const InfoHash& infohash,
|
||||
const std::vector<Sp<Value>>& values,
|
||||
std::vector<Sp<Value>>&& values,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
const size_t& sid);
|
||||
size_t sid);
|
||||
Sp<Request> sendUpdateValues(const Sp<Node>& n,
|
||||
const InfoHash& infohash,
|
||||
std::vector<Sp<Value>>::iterator begin,
|
||||
std::vector<Sp<Value>>::iterator end,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
size_t sid);
|
||||
|
||||
/**
|
||||
* Parses a message and calls appropriate callbacks.
|
||||
@@ -492,6 +499,7 @@ private:
|
||||
|
||||
static constexpr size_t MTU {1280};
|
||||
static constexpr size_t MAX_PACKET_VALUE_SIZE {600};
|
||||
static constexpr size_t MAX_MESSAGE_VALUE_SIZE {56 * 1024};
|
||||
|
||||
static const std::string my_v;
|
||||
|
||||
@@ -525,7 +533,10 @@ private:
|
||||
int send(const SockAddr& addr, const char *buf, size_t len, bool confirmed = false);
|
||||
|
||||
void sendValueParts(Tid tid, const std::vector<Blob>& svals, const SockAddr& addr);
|
||||
std::vector<Blob> packValueHeader(msgpack::sbuffer&, const std::vector<Sp<Value>>&);
|
||||
std::vector<Blob> packValueHeader(msgpack::sbuffer&, std::vector<Sp<Value>>::const_iterator, std::vector<Sp<Value>>::const_iterator) const;
|
||||
std::vector<Blob> packValueHeader(msgpack::sbuffer& buf, const std::vector<Sp<Value>>& values) const {
|
||||
return packValueHeader(buf, values.begin(), values.end());
|
||||
}
|
||||
void maintainRxBuffer(Tid tid);
|
||||
|
||||
/*************
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "infohash.h" // includes socket structures
|
||||
#include "utils.h"
|
||||
#include "sockaddr.h"
|
||||
#include "node_export.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -52,7 +53,7 @@ struct Node {
|
||||
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
|
||||
: Node(id, SockAddr(sa, salen), rd) {}
|
||||
|
||||
InfoHash getId() const {
|
||||
const InfoHash& getId() const {
|
||||
return id;
|
||||
}
|
||||
const SockAddr& getAddr() const { return addr; }
|
||||
@@ -92,8 +93,7 @@ struct Node {
|
||||
NodeExport exportNode() const {
|
||||
NodeExport ne;
|
||||
ne.id = id;
|
||||
ne.sslen = addr.getLength();
|
||||
std::memcpy(&ne.ss, addr.get(), ne.sslen);
|
||||
ne.addr = addr;
|
||||
return ne;
|
||||
}
|
||||
sa_family_t getFamily() const { return addr.getFamily(); }
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "def.h"
|
||||
#include "infohash.h"
|
||||
#include "sockaddr.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace dht {
|
||||
using namespace std::literals;
|
||||
|
||||
struct OPENDHT_PUBLIC NodeExport {
|
||||
InfoHash id;
|
||||
SockAddr addr;
|
||||
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const
|
||||
{
|
||||
pk.pack_map(2);
|
||||
pk.pack("id"sv);
|
||||
pk.pack(id);
|
||||
pk.pack("addr"sv);
|
||||
pk.pack_bin(addr.getLength());
|
||||
pk.pack_bin_body((const char*)addr.get(), (size_t)addr.getLength());
|
||||
}
|
||||
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const NodeExport& h);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
+62
-61
@@ -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() {}
|
||||
|
||||
@@ -440,7 +427,7 @@ struct OPENDHT_PUBLIC Value
|
||||
/**
|
||||
* Returns true if value contents are equals (not considering the value ID)
|
||||
*/
|
||||
inline bool contentEquals(const Value& o) {
|
||||
inline bool contentEquals(const Value& o) const {
|
||||
return isEncrypted() ? cypher == o.cypher :
|
||||
((owner == o.owner || (owner and o.owner and *owner == *o.owner))
|
||||
&& type == o.type
|
||||
@@ -449,22 +436,25 @@ struct OPENDHT_PUBLIC Value
|
||||
&& signature == o.signature);
|
||||
}
|
||||
|
||||
inline bool operator== (const Value& o) {
|
||||
inline bool operator== (const Value& o) const {
|
||||
return id == o.id and contentEquals(o);
|
||||
}
|
||||
inline bool operator!= (const Value& o) const {
|
||||
return !(*this == 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 +464,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,8 +474,8 @@ struct OPENDHT_PUBLIC Value
|
||||
/** print value for debugging */
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const Value& v);
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
inline std::string toString() const {
|
||||
std::ostringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
@@ -638,8 +628,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};
|
||||
@@ -776,7 +774,7 @@ struct OPENDHT_PUBLIC Select
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
@@ -809,11 +807,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 +821,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 +835,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 +849,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 +863,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 +876,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_) {
|
||||
@@ -896,7 +897,7 @@ struct OPENDHT_PUBLIC Where
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
@@ -962,7 +963,7 @@ struct OPENDHT_PUBLIC Query
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
project('opendht', 'c', 'cpp',
|
||||
version: '2.5.0',
|
||||
default_options: [
|
||||
'cpp_std=c++17',
|
||||
'warning_level=3'
|
||||
])
|
||||
|
||||
gnutls = dependency('gnutls')
|
||||
nettle = dependency('nettle')
|
||||
msgpack = dependency('msgpack-cxx', required : false)
|
||||
argon2 = dependency('libargon2')
|
||||
openssl = dependency('openssl', required: get_option('proxy_client'))
|
||||
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
|
||||
|
||||
dirs=[]
|
||||
if host_machine.system() == 'freebsd'
|
||||
dirs+='/usr/local/lib'
|
||||
elif host_machine.system() == 'darwin'
|
||||
dirs+='/opt/homebrew/lib'
|
||||
endif
|
||||
http_parser = meson.get_compiler('c').find_library('http_parser', dirs: dirs, required: get_option('proxy_client'))
|
||||
deps = [gnutls, nettle, msgpack, argon2, openssl, jsoncpp, http_parser]
|
||||
|
||||
add_project_arguments('-DMSGPACK_NO_BOOST', language : 'cpp')
|
||||
add_project_arguments(['-Wno-return-type','-Wno-deprecated','-Wnon-virtual-dtor','-pedantic-errors','-fvisibility=hidden'], language : 'cpp')
|
||||
|
||||
opendht_inc = include_directories('include/opendht')
|
||||
opendht_interface_inc = include_directories('include', is_system: true)
|
||||
opendht_src = [
|
||||
'src/utils.cpp',
|
||||
'src/crypto.cpp',
|
||||
'src/default_types.cpp',
|
||||
'src/node.cpp',
|
||||
'src/value.cpp',
|
||||
'src/dht.cpp',
|
||||
'src/callbacks.cpp',
|
||||
'src/routing_table.cpp',
|
||||
'src/node_cache.cpp',
|
||||
'src/network_engine.cpp',
|
||||
'src/securedht.cpp',
|
||||
'src/dhtrunner.cpp',
|
||||
'src/log.cpp',
|
||||
'src/op_cache.cpp',
|
||||
'src/network_utils.cpp'
|
||||
]
|
||||
if jsoncpp.found()
|
||||
opendht_src += ['src/base64.cpp']
|
||||
add_project_arguments('-DOPENDHT_JSONCPP', language : 'cpp')
|
||||
endif
|
||||
if http_parser.found()
|
||||
opendht_src += ['src/http.cpp', 'src/compat/os_cert.cpp']
|
||||
if host_machine.system() == 'darwin'
|
||||
deps+=dependency('appleframeworks', modules : ['CoreFoundation', 'Security'])
|
||||
endif
|
||||
endif
|
||||
if get_option('proxy_client').enabled()
|
||||
opendht_src += ['src/dht_proxy_client.cpp']
|
||||
add_project_arguments('-DOPENDHT_PROXY_CLIENT', language : 'cpp')
|
||||
endif
|
||||
if get_option('proxy_server').enabled()
|
||||
opendht_src += 'src/dht_proxy_server.cpp'
|
||||
add_project_arguments('-DOPENDHT_PROXY_SERVER', language : 'cpp')
|
||||
endif
|
||||
if get_option('peer_discovery').enabled()
|
||||
opendht_src += 'src/peer_discovery.cpp'
|
||||
add_project_arguments('-DOPENDHT_PEER_DISCOVERY', language : 'cpp')
|
||||
endif
|
||||
opendht = shared_library('opendht',
|
||||
opendht_src,
|
||||
include_directories : opendht_inc,
|
||||
dependencies : deps,
|
||||
cpp_args : ['-DOPENHT_BUILD', '-Dopendht_EXPORTS'],
|
||||
install : true)
|
||||
|
||||
readline = meson.get_compiler('c').find_library('readline', required: get_option('tools'))
|
||||
if get_option('tools').enabled()
|
||||
dhtnode = executable('dhtnode', 'tools/dhtnode.cpp',
|
||||
include_directories : opendht_interface_inc,
|
||||
link_with : opendht,
|
||||
dependencies : [readline, msgpack],
|
||||
install : true)
|
||||
if http_parser.found()
|
||||
durl = executable('durl', 'tools/durl.cpp',
|
||||
include_directories : opendht_interface_inc,
|
||||
link_with : opendht,
|
||||
dependencies : [msgpack, openssl])
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,4 @@
|
||||
option('proxy_client', type : 'feature', value : 'disabled')
|
||||
option('proxy_server', type : 'feature', value : 'disabled')
|
||||
option('peer_discovery', type : 'feature', value : 'enabled')
|
||||
option('tools', type : 'feature', value : 'enabled')
|
||||
+3
-2
@@ -3,9 +3,10 @@ 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
|
||||
Requires.private: gnutls >= 3.3, nettle >= 2.4@argon2_lib@@jsoncpp_lib@@openssl_lib@
|
||||
Requires: gnutls >= 3.3@jsoncpp_lib@@openssl_lib@
|
||||
Requires.private: nettle >= 2.4@argon2_lib@
|
||||
Cflags: -I${includedir}
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ["setuptools", "wheel", "Cython"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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
@@ -8,4 +8,4 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc="0.2.0"
|
||||
os_socketaddr="0.1.0"
|
||||
os_socketaddr="0.2.3"
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -19,7 +19,6 @@ libopendht_la_SOURCES = \
|
||||
routing_table.cpp \
|
||||
network_engine.cpp \
|
||||
utils.cpp \
|
||||
infohash.cpp \
|
||||
node.cpp \
|
||||
value.cpp \
|
||||
crypto.cpp \
|
||||
@@ -84,6 +83,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
|
||||
+1
-1
@@ -92,7 +92,7 @@ bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
|
||||
std::string
|
||||
NodeStats::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
ss << "Known nodes: " << good_nodes << " good, " << dubious_nodes << " dubious, " << incoming_nodes << " incoming." << std::endl;
|
||||
ss << searches << " searches, " << node_cache_size << " total cached nodes" << std::endl;
|
||||
if (table_depth > 1) {
|
||||
|
||||
+70
-83
@@ -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_ = std::move(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
|
||||
@@ -839,51 +824,55 @@ Certificate::~Certificate()
|
||||
}
|
||||
}
|
||||
|
||||
PublicKey
|
||||
const PublicKey&
|
||||
Certificate::getPublicKey() const
|
||||
{
|
||||
PublicKey pk_ret;
|
||||
if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
|
||||
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
|
||||
return pk_ret;
|
||||
return *getSharedPublicKey();
|
||||
}
|
||||
|
||||
InfoHash
|
||||
const std::shared_ptr<PublicKey>&
|
||||
Certificate::getSharedPublicKey() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(publicKeyMutex_);
|
||||
if (not publicKey_) {
|
||||
auto pk = std::make_shared<PublicKey>();
|
||||
if (auto err = gnutls_pubkey_import_x509(pk->pk, cert, 0))
|
||||
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
|
||||
publicKey_ = std::move(pk);
|
||||
}
|
||||
return publicKey_;
|
||||
}
|
||||
|
||||
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 +1760,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 {
|
||||
|
||||
+14
-12
@@ -870,7 +870,7 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
|
||||
throw DhtException("Can't create search");
|
||||
if (logger_)
|
||||
logger_->w(id, "[search %s IPv%c] listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
|
||||
return sr->listen(cb, f, q, scheduler);
|
||||
return sr->listen(cb, std::move(f), q, scheduler);
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -889,7 +889,7 @@ Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
|
||||
});
|
||||
|
||||
auto query = std::make_shared<Query>(Select{}, std::move(where));
|
||||
auto filter = f.chain(query->where.getFilter());
|
||||
auto filter = Value::Filter::chain(std::move(f), query->where.getFilter());
|
||||
auto st = store.find(id);
|
||||
if (st == store.end() && store.size() < max_store_keys)
|
||||
st = store.emplace(id, scheduler.time() + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME).first;
|
||||
@@ -1289,10 +1289,11 @@ Dht::storageStore(const InfoHash& id, const Sp<Value>& value, time_point created
|
||||
if (total_store_size > max_store_size) {
|
||||
auto value = vs->data;
|
||||
auto value_diff = store.second.values_diff;
|
||||
auto value_edit = store.second.edited_values;
|
||||
expireStore();
|
||||
storageChanged(id, st->second, value, value_diff > 0);
|
||||
storageChanged(id, st->second, value, value_diff > 0 || value_edit > 0);
|
||||
} else {
|
||||
storageChanged(id, st->second, vs->data, store.second.values_diff > 0);
|
||||
storageChanged(id, st->second, vs->data, store.second.values_diff > 0 || store.second.edited_values > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1641,7 +1642,7 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const
|
||||
void
|
||||
Dht::dumpTables() const
|
||||
{
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
out << "My id " << myid << std::endl;
|
||||
|
||||
out << "Buckets IPv4 :" << std::endl;
|
||||
@@ -1693,7 +1694,7 @@ Dht::getStorageLog(const InfoHash& h) const
|
||||
{
|
||||
auto s = store.find(h);
|
||||
if (s == store.end()) {
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
out << "Storage " << h << " empty" << std::endl;
|
||||
return out.str();
|
||||
}
|
||||
@@ -1703,7 +1704,7 @@ Dht::getStorageLog(const InfoHash& h) const
|
||||
std::string
|
||||
Dht::printStorageLog(const decltype(store)::value_type& s) const
|
||||
{
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
using namespace std::chrono;
|
||||
const auto& st = s.second;
|
||||
out << "Storage " << s.first << " "
|
||||
@@ -1722,7 +1723,7 @@ Dht::printStorageLog(const decltype(store)::value_type& s) const
|
||||
std::string
|
||||
Dht::getRoutingTablesLog(sa_family_t af) const
|
||||
{
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
for (const auto& b : buckets(af))
|
||||
dumpBucket(b, out);
|
||||
return out.str();
|
||||
@@ -1731,7 +1732,7 @@ Dht::getRoutingTablesLog(sa_family_t af) const
|
||||
std::string
|
||||
Dht::getSearchesLog(sa_family_t af) const
|
||||
{
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
auto num_searches = dht4.searches.size() + dht6.searches.size();
|
||||
if (num_searches > 8) {
|
||||
if (not af or af == AF_INET)
|
||||
@@ -1756,7 +1757,7 @@ Dht::getSearchesLog(sa_family_t af) const
|
||||
std::string
|
||||
Dht::getSearchLog(const InfoHash& id, sa_family_t af) const
|
||||
{
|
||||
std::stringstream out;
|
||||
std::ostringstream out;
|
||||
if (af == AF_UNSPEC) {
|
||||
out << getSearchLog(id, AF_INET) << getSearchLog(id, AF_INET6);
|
||||
} else {
|
||||
@@ -1793,7 +1794,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),
|
||||
@@ -2636,7 +2638,7 @@ Dht::loadState(const std::string& path)
|
||||
std::vector<Sp<Node>> tmpNodes;
|
||||
tmpNodes.reserve(state.nodes.size());
|
||||
for (const auto& node : state.nodes)
|
||||
tmpNodes.emplace_back(network_engine.insertNode(node.id, SockAddr(node.ss, node.sslen)));
|
||||
tmpNodes.emplace_back(network_engine.insertNode(node.id, node.addr));
|
||||
importValues(state.values);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
||||
+60
-28
@@ -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_) {
|
||||
@@ -187,7 +191,10 @@ void
|
||||
DhtProxyClient::stop()
|
||||
{
|
||||
if (not isDestroying_.exchange(true)) {
|
||||
resolver_.reset();
|
||||
{
|
||||
std::lock_guard<std::mutex> l(resolverLock_);
|
||||
resolver_.reset();
|
||||
}
|
||||
cancelAllListeners();
|
||||
if (infoState_)
|
||||
infoState_->cancel = true;
|
||||
@@ -311,26 +318,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;
|
||||
@@ -460,7 +471,9 @@ DhtProxyClient::handleRefreshPut(const asio::error_code &ec, InfoHash key, Value
|
||||
std::shared_ptr<http::Request>
|
||||
DhtProxyClient::buildRequest(const std::string& target)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(resolverLock_);
|
||||
auto resolver = resolver_;
|
||||
l.unlock();
|
||||
if (not resolver)
|
||||
resolver = std::make_shared<http::Resolver>(httpContext_, proxyUrl_, logger_);
|
||||
auto request = target.empty()
|
||||
@@ -481,7 +494,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);
|
||||
@@ -626,6 +639,7 @@ DhtProxyClient::getProxyInfos()
|
||||
auto resolver = std::make_shared<http::Resolver>(httpContext_, proxyUrl_, logger_);
|
||||
queryProxyInfo(infoState, resolver, AF_INET);
|
||||
queryProxyInfo(infoState, resolver, AF_INET6);
|
||||
std::lock_guard<std::mutex> l(resolverLock_);
|
||||
resolver_ = resolver;
|
||||
}
|
||||
|
||||
@@ -657,6 +671,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 +708,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 +727,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 +771,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();
|
||||
@@ -776,7 +812,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
auto& search = searches_[key];
|
||||
auto query = std::make_shared<Query>(Select{}, std::move(where));
|
||||
return search.ops.listen(cb, query, filter, [this, key](Sp<Query>, ValueCallback cb, SyncCallback) -> size_t {
|
||||
return search.ops.listen(cb, query, std::move(filter), [this, key](Sp<Query>, ValueCallback cb, SyncCallback) -> size_t {
|
||||
// Find search
|
||||
auto search = searches_.find(key);
|
||||
if (search == searches_.end()) {
|
||||
@@ -838,7 +874,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 +960,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 +1335,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
|
||||
|
||||
+171
-69
@@ -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,
|
||||
@@ -620,6 +631,8 @@ DhtProxyServer::createRestRouter()
|
||||
// key.listen
|
||||
router->http_get("/key/:hash/listen", std::bind(&DhtProxyServer::listen, this, _1, _2));
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
// node.pingPush
|
||||
router->http_post("/node/pingPush", std::bind(&DhtProxyServer::pingPush, this, _1, _2));
|
||||
// key.subscribe
|
||||
router->add_handler(restinio::http_method_subscribe(),
|
||||
"/key/:hash", std::bind(&DhtProxyServer::subscribe, this, _1, _2));
|
||||
@@ -691,7 +704,7 @@ DhtProxyServer::get(restinio::request_handle_t request,
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
dht_->get(infoHash, [this, response](const std::vector<Sp<Value>>& values) {
|
||||
std::stringstream output;
|
||||
std::ostringstream output;
|
||||
for (const auto& value : values) {
|
||||
output << Json::writeString(jsonBuilder_, value->toJson()) << "\n";
|
||||
}
|
||||
@@ -745,6 +758,59 @@ 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::pingPush(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t /*params*/)
|
||||
{
|
||||
requestNum_++;
|
||||
try {
|
||||
std::string err;
|
||||
Json::Value r;
|
||||
auto* char_data = reinterpret_cast<const char*>(request->body().data());
|
||||
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
|
||||
if (!reader->parse(char_data, char_data + request->body().size(), &r, &err)){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_JSON_INCORRECT);
|
||||
return response.done();
|
||||
}
|
||||
const Json::Value& root(r); // parse using const Json so [] never creates element
|
||||
auto pushToken = root["key"].asString();
|
||||
if (pushToken.empty()){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_NO_TOKEN);
|
||||
return response.done();
|
||||
}
|
||||
auto type = getTypeFromString(root["platform"].asString());
|
||||
auto topic = root["topic"].asString();
|
||||
if (topic.empty()) {
|
||||
topic = getDefaultTopic(type);
|
||||
}
|
||||
Json::Value json;
|
||||
json["to"] = root["client_id"];
|
||||
json["pong"] = true;
|
||||
sendPushNotification(pushToken, std::move(json), type, true, topic);
|
||||
} catch (...) {
|
||||
return serverError(*request);
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
RequestStatus
|
||||
DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params)
|
||||
@@ -771,7 +837,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 +872,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 +886,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 +921,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 +933,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 +943,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 +999,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 +1008,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 +1051,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 +1132,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 +1200,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 +1230,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 +1242,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 +1265,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());
|
||||
|
||||
+150
-264
@@ -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,69 +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);
|
||||
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;
|
||||
});
|
||||
|
||||
#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)
|
||||
@@ -240,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
|
||||
@@ -288,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();
|
||||
@@ -298,20 +282,10 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
|
||||
}
|
||||
if (logger_)
|
||||
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
ongoing_ops += 2;
|
||||
#else
|
||||
ongoing_ops++;
|
||||
#endif
|
||||
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);
|
||||
else
|
||||
opEnded();
|
||||
#endif
|
||||
if (dht_)
|
||||
dht_->shutdown(onShutdown, stop);
|
||||
else
|
||||
@@ -418,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{};
|
||||
}
|
||||
|
||||
|
||||
@@ -484,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
|
||||
@@ -501,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
|
||||
@@ -523,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)
|
||||
@@ -539,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();
|
||||
}
|
||||
@@ -572,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();
|
||||
@@ -587,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());
|
||||
@@ -652,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));
|
||||
}
|
||||
@@ -668,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 {};
|
||||
@@ -680,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();
|
||||
}
|
||||
|
||||
@@ -713,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()) {
|
||||
@@ -731,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;
|
||||
@@ -790,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();
|
||||
@@ -829,27 +766,10 @@ DhtRunner::cancelListen(InfoHash h, size_t token)
|
||||
if (running != State::Running)
|
||||
return;
|
||||
ongoing_ops++;
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
pending_ops.emplace([=](SecureDht&) {
|
||||
auto it = listeners_.find(token);
|
||||
if (it != listeners_.end()) {
|
||||
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 (logger_)
|
||||
logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token);
|
||||
}
|
||||
opEnded();
|
||||
});
|
||||
#else
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelListen(h, token);
|
||||
opEnded();
|
||||
});
|
||||
#endif // OPENDHT_PROXY_CLIENT
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -860,28 +780,10 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
|
||||
if (running != State::Running)
|
||||
return;
|
||||
ongoing_ops++;
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht&) {
|
||||
auto token = ftoken.get();
|
||||
auto it = listeners_.find(token);
|
||||
if (it != listeners_.end()) {
|
||||
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 (logger_)
|
||||
logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token);
|
||||
}
|
||||
opEnded();
|
||||
});
|
||||
#else
|
||||
pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht& dht) {
|
||||
dht.cancelListen(h, ftoken.get());
|
||||
opEnded();
|
||||
});
|
||||
#endif // OPENDHT_PROXY_CLIENT
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -1170,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)
|
||||
{
|
||||
@@ -1199,7 +1087,8 @@ 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.");
|
||||
(void) pushNodeId;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1207,54 +1096,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
|
||||
}
|
||||
|
||||
@@ -1262,16 +1134,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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1282,24 +1146,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;
|
||||
|
||||
+28
-21
@@ -87,7 +87,7 @@ Url::Url(const std::string& url): url(url)
|
||||
std::string
|
||||
Url::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
if (not protocol.empty()) {
|
||||
ss << protocol << "://";
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1040,7 +1044,7 @@ Request::set_auth(const std::string& username, const std::string& password)
|
||||
void
|
||||
Request::build()
|
||||
{
|
||||
std::stringstream request;
|
||||
std::ostringstream request;
|
||||
bool append_body = !body_.empty();
|
||||
|
||||
// first header
|
||||
@@ -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]
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace indexation {
|
||||
* @return string that represent the blob into a readable way
|
||||
*/
|
||||
static std::string blobToString(const Blob &bl) {
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
auto bn = bl.size() % 8;
|
||||
auto n = bl.size() / 8;
|
||||
|
||||
@@ -46,7 +46,7 @@ static std::string blobToString(const Blob &bl) {
|
||||
}
|
||||
|
||||
std::string Prefix::toString() const {
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << "Prefix : " << std::endl << "\tContent_ : \"";
|
||||
ss << blobToString(content_);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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 "infohash.h"
|
||||
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace dht {
|
||||
|
||||
const HexMap hex_map = {};
|
||||
|
||||
void
|
||||
NodeExport::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.size < 2)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.ptr[0].key.as<std::string_view>() != "id"sv)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.ptr[1].key.as<std::string_view>() != "addr"sv)
|
||||
throw msgpack::type_error();
|
||||
const auto& addr = o.via.map.ptr[1].val;
|
||||
if (addr.type != msgpack::type::BIN)
|
||||
throw msgpack::type_error();
|
||||
if (addr.via.bin.size > sizeof(sockaddr_storage))
|
||||
throw msgpack::type_error();
|
||||
id.msgpack_unpack(o.via.map.ptr[0].val);
|
||||
sslen = addr.via.bin.size;
|
||||
std::copy_n(addr.via.bin.ptr, addr.via.bin.size, (char*)&ss);
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& s, const NodeExport& h)
|
||||
{
|
||||
msgpack::pack(s, h);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
+45
-15
@@ -124,9 +124,9 @@ NetworkEngine::tellListener(const Sp<Node>& node, Tid socket_id, const InfoHash&
|
||||
auto nnodes = bufferNodes(node->getFamily(), hash, want, nodes, nodes6);
|
||||
try {
|
||||
if (version >= 1) {
|
||||
sendUpdateValues(node, hash, values, scheduler.time(), ntoken, socket_id);
|
||||
sendUpdateValues(node, hash, std::move(values), scheduler.time(), ntoken, socket_id);
|
||||
} else {
|
||||
sendNodesValues(node->getAddr(), socket_id, nnodes.first, nnodes.second, values, query, ntoken);
|
||||
sendNodesValues(node->getAddr(), socket_id, nnodes.first, nnodes.second, std::move(values), query, ntoken);
|
||||
}
|
||||
} catch (const std::overflow_error& e) {
|
||||
if (logger_)
|
||||
@@ -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());
|
||||
@@ -501,9 +501,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
pmsg.last_part = now;
|
||||
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
} else
|
||||
if (logger_)
|
||||
logger_->e("Partial message with given TID already exists");
|
||||
} else if (logger_)
|
||||
logger_->e("Partial message with given TID %u already exists", k);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,12 +911,16 @@ NetworkEngine::deserializeNodes(ParsedMessage& msg, const SockAddr& from) {
|
||||
}
|
||||
|
||||
std::vector<Blob>
|
||||
NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Value>>& st)
|
||||
NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, std::vector<Sp<Value>>::const_iterator b, std::vector<Sp<Value>>::const_iterator e) const
|
||||
{
|
||||
auto svals = serializeValues(st);
|
||||
std::vector<Blob> svals;
|
||||
size_t total_size = 0;
|
||||
for (const auto& v : svals)
|
||||
total_size += v.size();
|
||||
|
||||
svals.reserve(std::distance(b, e));
|
||||
for (; b != e; ++b) {
|
||||
svals.emplace_back(packMsg(*b));
|
||||
total_size += svals.back().size();
|
||||
}
|
||||
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack(KEY_REQ_VALUES);
|
||||
@@ -1155,11 +1158,12 @@ NetworkEngine::sendAnnounceValue(const 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));
|
||||
}
|
||||
@@ -1199,13 +1203,39 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
|
||||
return req;
|
||||
}
|
||||
|
||||
void
|
||||
NetworkEngine::sendUpdateValues(const Sp<Node>& n,
|
||||
const InfoHash& infohash,
|
||||
std::vector<Sp<Value>>&& values,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
size_t socket_id)
|
||||
{
|
||||
size_t total_size = 0;
|
||||
|
||||
auto b = values.begin(), e = values.begin();
|
||||
while (e != values.end()) {
|
||||
if (total_size >= MAX_MESSAGE_VALUE_SIZE) {
|
||||
sendUpdateValues(n, infohash, b, e, created, token, socket_id);
|
||||
b = e;
|
||||
total_size = 0;
|
||||
}
|
||||
total_size += (*e)->size();
|
||||
++e;
|
||||
}
|
||||
if (b != e) {
|
||||
sendUpdateValues(n, infohash, b, e, created, token, socket_id);
|
||||
}
|
||||
}
|
||||
|
||||
Sp<Request>
|
||||
NetworkEngine::sendUpdateValues(const Sp<Node>& n,
|
||||
const InfoHash& infohash,
|
||||
const std::vector<Sp<Value>>& values,
|
||||
std::vector<Sp<Value>>::iterator begin,
|
||||
std::vector<Sp<Value>>::iterator end,
|
||||
time_point created,
|
||||
const Blob& token,
|
||||
const size_t& socket_id)
|
||||
size_t socket_id)
|
||||
{
|
||||
Tid tid (n->getNewTid());
|
||||
Tid sid (socket_id);
|
||||
@@ -1219,7 +1249,7 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
|
||||
pk.pack(KEY_VERSION); pk.pack(1);
|
||||
pk.pack(KEY_REQ_H); pk.pack(infohash);
|
||||
pk.pack(KEY_REQ_SID); pk.pack(sid);
|
||||
auto v = packValueHeader(buffer, values);
|
||||
auto v = packValueHeader(buffer, begin, end);
|
||||
if (created < scheduler.time()) {
|
||||
pk.pack(KEY_REQ_CREATION);
|
||||
pk.pack(to_time_t(created));
|
||||
|
||||
@@ -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;
|
||||
|
||||
+27
-1
@@ -160,7 +160,7 @@ Node::closeSocket(Tid id)
|
||||
std::string
|
||||
Node::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::ostringstream ss;
|
||||
ss << (*this);
|
||||
return ss.str();
|
||||
}
|
||||
@@ -171,4 +171,30 @@ std::ostream& operator<< (std::ostream& s, const Node& h)
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
NodeExport::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.size < 2)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.ptr[0].key.as<std::string_view>() != "id"sv)
|
||||
throw msgpack::type_error();
|
||||
if (o.via.map.ptr[1].key.as<std::string_view>() != "addr"sv)
|
||||
throw msgpack::type_error();
|
||||
const auto& maddr = o.via.map.ptr[1].val;
|
||||
if (maddr.type != msgpack::type::BIN)
|
||||
throw msgpack::type_error();
|
||||
if (maddr.via.bin.size > sizeof(sockaddr_storage))
|
||||
throw msgpack::type_error();
|
||||
id.msgpack_unpack(o.via.map.ptr[0].val);
|
||||
addr = {(const sockaddr*)maddr.via.bin.ptr, (socklen_t)maddr.via.bin.size};
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& s, const NodeExport& h)
|
||||
{
|
||||
msgpack::pack(s, h);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
+8
-2
@@ -28,6 +28,12 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clo
|
||||
auto viop = values.emplace(v->id, v);
|
||||
if (viop.second) {
|
||||
newValues.emplace_back(v);
|
||||
} else if (*viop.first->second.data != *v) {
|
||||
// Special case for edition
|
||||
if (v->seq > viop.first->second.data->seq) {
|
||||
viop.first->second.data = v;
|
||||
newValues.emplace_back(v);
|
||||
}
|
||||
} else {
|
||||
viop.first->second.refCount++;
|
||||
}
|
||||
@@ -169,7 +175,7 @@ SearchCache::getOp(const Sp<Query>& q) const
|
||||
}
|
||||
|
||||
size_t
|
||||
SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
|
||||
SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, Value::Filter&& filter, const OnListen& onListen)
|
||||
{
|
||||
// find exact match
|
||||
auto op = getOp(q);
|
||||
@@ -186,7 +192,7 @@ SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value
|
||||
auto token = nextToken_++;
|
||||
if (nextToken_ == 0)
|
||||
nextToken_++;
|
||||
return op->second->addListener(token, get_cb, q, filter) ? token : 0;
|
||||
return op->second->addListener(token, get_cb, q, std::move(filter)) ? token : 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
+3
-3
@@ -107,12 +107,12 @@ public:
|
||||
void onValuesAdded(const std::vector<Sp<Value>>& vals);
|
||||
void onValuesExpired(const std::vector<Sp<Value>>& vals);
|
||||
|
||||
bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
|
||||
bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, Value::Filter&& filter) {
|
||||
auto cached = cache.get(filter);
|
||||
if (not cached.empty() and not cb(cached, false)) {
|
||||
return false;
|
||||
}
|
||||
listeners.emplace(token, LocalListener{q, filter, cb});
|
||||
listeners.emplace(token, LocalListener{q, std::move(filter), cb});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
SearchCache(SearchCache&&) = default;
|
||||
|
||||
using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
|
||||
size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
|
||||
size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, Value::Filter&& filter, const OnListen& onListen);
|
||||
|
||||
bool cancelListen(size_t gtoken, const time_point& now);
|
||||
void cancelAll(const std::function<void(size_t)>& onCancel);
|
||||
|
||||
@@ -152,9 +152,10 @@ bool
|
||||
ParsedMessage::complete()
|
||||
{
|
||||
for (auto& e : value_parts) {
|
||||
//std::cout << "part " << e.first << ": " << e.second.second.size() << "/" << e.second.first << std::endl;
|
||||
if (e.second.first > e.second.second.size())
|
||||
if (e.second.first > e.second.second.size()) {
|
||||
//std::cout << "uncomplete part " << e.first << ": " << e.second.second.size() << "/" << e.second.first << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto& e : value_parts) {
|
||||
msgpack::unpacked msg;
|
||||
|
||||
@@ -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
@@ -547,9 +547,9 @@ struct Dht::Search {
|
||||
}
|
||||
}
|
||||
|
||||
size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
|
||||
size_t listen(const ValueCallback& cb, Value::Filter&& f, const Sp<Query>& q, Scheduler& scheduler) {
|
||||
//DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
|
||||
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
|
||||
return cache.listen(cb, q, std::move(f), [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
|
||||
done = false;
|
||||
auto token = ++listener_token;
|
||||
listeners.emplace(token, SearchListener{q, vcb, scb});
|
||||
|
||||
+21
-44
@@ -71,33 +71,20 @@ 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 (*o->owner != *n->owner or not n->isSigned()) {
|
||||
if (logger_)
|
||||
logger_->w("Edition forbidden: owner changed.");
|
||||
logger_->w("Edition forbidden: not signed or wrong owner.");
|
||||
return false;
|
||||
}
|
||||
if (!n->signatureChecked) {
|
||||
n->signatureChecked = true;
|
||||
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
|
||||
}
|
||||
if (!n->signatureValid) {
|
||||
if (not n->checkSignature()) {
|
||||
if (logger_)
|
||||
logger_->w("Edition forbidden: signature verification failed.");
|
||||
return false;
|
||||
@@ -134,7 +121,7 @@ Sp<crypto::PublicKey>
|
||||
SecureDht::getPublicKey(const InfoHash& node) const
|
||||
{
|
||||
if (node == getId())
|
||||
return std::make_shared<crypto::PublicKey>(certificate_->getPublicKey());
|
||||
return certificate_->getSharedPublicKey();
|
||||
auto it = nodesPubKeys_.find(node);
|
||||
if (it == nodesPubKeys_.end())
|
||||
return nullptr;
|
||||
@@ -230,7 +217,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
|
||||
}
|
||||
findCertificate(node, [=](const Sp<crypto::Certificate>& crt) {
|
||||
if (crt && *crt) {
|
||||
auto pk = std::make_shared<crypto::PublicKey>(crt->getPublicKey());
|
||||
auto pk = crt->getSharedPublicKey();
|
||||
if (*pk) {
|
||||
nodesPubKeys_[pk->getId()] = pk;
|
||||
if (cb) cb(pk);
|
||||
@@ -253,19 +240,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 +255,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 +329,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 +368,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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -100,6 +100,8 @@ struct Storage {
|
||||
ssize_t values_diff;
|
||||
/** Difference in number of listeners */
|
||||
ssize_t listeners_diff;
|
||||
/** Number of edited values */
|
||||
size_t edited_values;
|
||||
};
|
||||
|
||||
Storage() {}
|
||||
@@ -230,7 +232,7 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
|
||||
sb->insert(id, *value, expiration);
|
||||
it->data = value;
|
||||
total_size += size_diff;
|
||||
return std::make_pair(&(*it), StoreDiff{size_diff, 0, 0});
|
||||
return std::make_pair(&(*it), StoreDiff{size_diff, 0, 0, 1});
|
||||
}
|
||||
} else {
|
||||
//DHT_LOG.DEBUG("Storing %s -> %s", id.toString().c_str(), value->toString().c_str());
|
||||
@@ -240,7 +242,7 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
|
||||
values.back().store_bucket = sb;
|
||||
if (sb)
|
||||
sb->insert(id, *value, expiration);
|
||||
return std::make_pair(&values.back(), StoreDiff{size_new, 1, 0});
|
||||
return std::make_pair(&values.back(), StoreDiff{size_new, 1, 0, 0});
|
||||
}
|
||||
}
|
||||
return std::make_pair(nullptr, StoreDiff{});
|
||||
@@ -272,7 +274,7 @@ Storage::clear()
|
||||
ssize_t tot_size = total_size;
|
||||
values.clear();
|
||||
total_size = 0;
|
||||
return {-tot_size, -num_values, 0};
|
||||
return {-tot_size, -num_values, 0, 0};
|
||||
}
|
||||
|
||||
std::pair<ssize_t, std::vector<Sp<Value>>>
|
||||
|
||||
+32
-25
@@ -26,7 +26,7 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
constexpr const size_t IO_THREADS_MAX {64};
|
||||
constexpr const size_t IO_THREADS_MAX {512};
|
||||
|
||||
ThreadPool&
|
||||
ThreadPool::computation()
|
||||
@@ -65,33 +65,39 @@ ThreadPool::run(std::function<void()>&& cb)
|
||||
|
||||
// launch new thread if necessary
|
||||
if (not readyThreads_ && threads_.size() < maxThreads_) {
|
||||
threads_.emplace_back(std::make_unique<std::thread>([this]() {
|
||||
while (true) {
|
||||
std::function<void()> task;
|
||||
try {
|
||||
threads_.emplace_back(std::make_unique<std::thread>([this]() {
|
||||
while (true) {
|
||||
std::function<void()> task;
|
||||
|
||||
// pick task from queue
|
||||
{
|
||||
std::unique_lock<std::mutex> l(lock_);
|
||||
readyThreads_++;
|
||||
cv_.wait(l, [&](){
|
||||
return not running_ or not tasks_.empty();
|
||||
});
|
||||
readyThreads_--;
|
||||
if (not running_)
|
||||
break;
|
||||
task = std::move(tasks_.front());
|
||||
tasks_.pop();
|
||||
}
|
||||
// pick task from queue
|
||||
{
|
||||
std::unique_lock<std::mutex> l(lock_);
|
||||
readyThreads_++;
|
||||
cv_.wait(l, [&](){
|
||||
return not running_ or not tasks_.empty();
|
||||
});
|
||||
readyThreads_--;
|
||||
if (not running_)
|
||||
break;
|
||||
task = std::move(tasks_.front());
|
||||
tasks_.pop();
|
||||
}
|
||||
|
||||
// run task
|
||||
try {
|
||||
task();
|
||||
} catch (const std::exception& e) {
|
||||
// LOG_ERR("Exception running task: %s", e.what());
|
||||
std::cerr << "Exception running task: " << e.what() << std::endl;
|
||||
// run task
|
||||
try {
|
||||
task();
|
||||
} catch (const std::exception& e) {
|
||||
// LOG_ERR("Exception running task: %s", e.what());
|
||||
std::cerr << "Exception running task: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}));
|
||||
} catch(const std::exception& e) {
|
||||
std::cerr << "Exception starting thread: " << e.what() << std::endl;
|
||||
if (threads_.empty())
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// push task to queue
|
||||
@@ -106,6 +112,7 @@ ThreadPool::stop()
|
||||
{
|
||||
std::lock_guard<std::mutex> l(lock_);
|
||||
running_ = false;
|
||||
tasks_ = {};
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -35,12 +35,14 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
|
||||
|
||||
const char* version() {
|
||||
return PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
const HexMap hex_map = {};
|
||||
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
splitPort(const std::string& s) {
|
||||
if (s.empty())
|
||||
|
||||
+57
-1
@@ -98,7 +98,7 @@ ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const
|
||||
size_t
|
||||
Value::size() const
|
||||
{
|
||||
return cypher.size() + data.size() + signature.size() + user_type.size();
|
||||
return cypher.size() + data.size() + signature.size() + user_type.size();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
+69
-12
@@ -35,6 +35,8 @@ 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(0, config);
|
||||
node2.run(0, config);
|
||||
@@ -92,7 +94,11 @@ 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 putOkCount1(0);
|
||||
unsigned putOkCount2(0);
|
||||
@@ -105,23 +111,36 @@ DhtRunnerTester::testListen() {
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -145,7 +164,7 @@ DhtRunnerTester::testListen() {
|
||||
});
|
||||
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) putOkCount3++;
|
||||
@@ -174,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));
|
||||
@@ -187,6 +209,7 @@ DhtRunnerTester::testIdOps() {
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
unsigned valueCount(0);
|
||||
unsigned valueCountEdit(0);
|
||||
|
||||
dht::DhtRunner::Config config2;
|
||||
config2.dht_config.node_config.max_peer_req_per_sec = -1;
|
||||
@@ -258,10 +281,44 @@ DhtRunnerTester::testIdOps() {
|
||||
return true;
|
||||
});
|
||||
|
||||
auto key2 = dht::InfoHash::get("key2");
|
||||
auto editValue = std::make_shared<dht::Value>("v1");
|
||||
node1.putSigned(key2, editValue, [&](bool ok){
|
||||
CPPUNIT_ASSERT(ok);
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
valueCountEdit++;
|
||||
cv.notify_all();
|
||||
});
|
||||
node2.listen(key2, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired){
|
||||
for (const auto& v : values) {
|
||||
if (v->seq == 0)
|
||||
CPPUNIT_ASSERT_EQUAL("v1"s, dht::unpackMsg<std::string>(v->data));
|
||||
else if (v->seq == 1)
|
||||
CPPUNIT_ASSERT_EQUAL("v2"s, dht::unpackMsg<std::string>(v->data));
|
||||
CPPUNIT_ASSERT_EQUAL(v->owner->getLongId(), node1.getPublicKey()->getLongId());
|
||||
}
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
valueCountEdit += values.size();
|
||||
cv.notify_all();
|
||||
return true;
|
||||
});
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; }));
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7 && valueCountEdit == 2; }));
|
||||
}
|
||||
|
||||
// editValue->data = dht::packMsg("v2");
|
||||
editValue = std::make_shared<dht::Value>(editValue->id);
|
||||
editValue->data = dht::packMsg("v2");
|
||||
node1.putSigned(key2, editValue, [&](bool ok){
|
||||
CPPUNIT_ASSERT(ok);
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
valueCountEdit++;
|
||||
cv.notify_all();
|
||||
});
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 4; }));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -275,7 +332,7 @@ DhtRunnerTester::testListenLotOfBytes() {
|
||||
std::string data(10000, 'a');
|
||||
|
||||
auto foo = dht::InfoHash::get("foo");
|
||||
constexpr unsigned N = 50;
|
||||
constexpr unsigned N = 1024;
|
||||
|
||||
for (unsigned i=0; i<N; i++) {
|
||||
node2.put(foo, data, [&](bool ok) {
|
||||
|
||||
+5
-10
@@ -1,9 +1,4 @@
|
||||
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 (OPENDHT_STATIC)
|
||||
if (MSVC)
|
||||
set (MSC_COMPAT_SOURCES ${MSC_COMPAT_DIR}/wingetopt.c)
|
||||
endif ()
|
||||
@@ -11,8 +6,8 @@ endif ()
|
||||
|
||||
function (configure_tool name extra_files)
|
||||
add_executable (${name} ${name}.cpp ${extra_files})
|
||||
add_dependencies(${name} ${OPENDHT_LIBS})
|
||||
target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS} ${READLINE_LIBRARIES})
|
||||
add_dependencies(${name} opendht)
|
||||
target_link_libraries (${name} LINK_PUBLIC opendht ${READLINE_LIBRARIES})
|
||||
if (MSVC)
|
||||
target_sources(${name} PRIVATE ${MSC_COMPAT_SOURCES})
|
||||
target_include_directories (${name} PRIVATE ${MSC_COMPAT_DIR})
|
||||
@@ -31,8 +26,8 @@ endif ()
|
||||
|
||||
if (OPENDHT_C)
|
||||
add_executable (dhtcnode dhtcnode.c)
|
||||
add_dependencies(dhtcnode ${OPENDHT_C_LIBS})
|
||||
target_link_libraries (dhtcnode LINK_PUBLIC ${OPENDHT_C_LIBS} ${READLINE_LIBRARIES})
|
||||
add_dependencies(dhtcnode opendht-c)
|
||||
target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES})
|
||||
target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c)
|
||||
endif ()
|
||||
|
||||
|
||||
+74
-41
@@ -18,17 +18,17 @@
|
||||
|
||||
#include <opendht_c.h>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <arpa/inet.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;
|
||||
atomic_bool stop;
|
||||
@@ -36,12 +36,18 @@ struct op_context {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -114,25 +120,26 @@ struct dht_params {
|
||||
};
|
||||
|
||||
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'},
|
||||
{NULL, 0 , NULL, 0}
|
||||
{"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;
|
||||
bzero(¶ms, sizeof params);
|
||||
memset(¶ms, 0, sizeof params);
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "hisvDp:n:b:f:l:", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
@@ -163,6 +170,9 @@ parse_args(int argc, char **argv) {
|
||||
case 's':
|
||||
params.service = true;
|
||||
break;
|
||||
case 'V':
|
||||
params.version = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -170,15 +180,30 @@ parse_args(int argc, char **argv) {
|
||||
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)
|
||||
{
|
||||
struct dht_params params = parse_args(argc, argv);
|
||||
|
||||
if (params.version) {
|
||||
printf("OpenDHT version %s\n", dht_version());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
dht_runner* runner = dht_runner_new();
|
||||
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_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);
|
||||
@@ -191,18 +216,18 @@ int main(int argc, char **argv)
|
||||
char cmd[64];
|
||||
char arg[64];
|
||||
char value[256];
|
||||
dht_infohash key;
|
||||
while (true) {
|
||||
const char* line_read = readline("> ");
|
||||
if (line_read && *line_read)
|
||||
add_history(line_read);
|
||||
if (!line_read)
|
||||
break;
|
||||
if (!strcmp(line_read, "\0"))
|
||||
if (!*line_read)
|
||||
continue;
|
||||
add_history(line_read);
|
||||
|
||||
bzero(cmd, sizeof cmd);
|
||||
bzero(arg, sizeof arg);
|
||||
bzero(value, sizeof value);
|
||||
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")) {
|
||||
@@ -217,36 +242,44 @@ int main(int argc, char **argv)
|
||||
}
|
||||
free(addrs);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dht_infohash key;
|
||||
dht_infohash_from_hex(&key, arg);
|
||||
if (dht_infohash_is_zero(&key)) {
|
||||
dht_infohash_get_from_string(&key, arg);
|
||||
printf("Using h(%s) = %s\n", arg, dht_infohash_print(&key));
|
||||
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));
|
||||
}
|
||||
if (!strcmp(cmd, "g")) {
|
||||
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")) {
|
||||
}
|
||||
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")) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
printf("Stopping..\n");
|
||||
|
||||
// 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
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user