Compare commits

...
29 Commits
Author SHA1 Message Date
Adrien Béraud 9da832c1d1 http: use appropriate string format syntax 2024-08-11 11:44:47 -04:00
liufei 44f6d21c83 DecryptError cause by low level error 2024-07-23 11:37:26 -04:00
AmnaSnene 38454eaf6e peer discovery: add a timer to schedule connectivityChanged with a maximum interval of one minute 2024-07-16 14:25:01 -04:00
Matthew Webb 76a2bd234a Get off of deprecated GCM AES methods
Multiple compiler warnings note that the gcm_aes_* family of functions are deprecated. They have been replaced with gcm_aes<key_length>_*. This change uses the correct set of functions based on the given key size. Resolves #571.

Sample compiler warning:
/home/noviv/opendht/src/crypto.cpp: In function ‘dht::Blob dht::crypto::aesEncrypt(const uint8_t*, size_t, const dht::Blob&)’: /home/noviv/opendht/src/crypto.cpp:97:20: warning: ‘void nettle_gcm_aes_set_key(gcm_aes_ctx*, size_t, const uint8_t*)’ is deprecated [-Wdeprecated-declarations]
   97 |     gcm_aes_set_key(&aes, key.size(), key.data());
         |                    ^
         In file included from /home/noviv/opendht/src/crypto.cpp:27:
         /usr/include/nettle/gcm.h:276:1: note: declared here
           276 | gcm_aes_set_key(struct gcm_aes_ctx *ctx,
                 | ^~~~~~~~~~~~~~~)

https://github.com/gnutls/nettle/commit/6a19845e6f71791ca98765d490ec08e776494bee marked the functions as deprecated.
2024-07-11 10:07:05 -04:00
Adrien Beraud 972d4d28a1 pkgconfig: add optional liburing dependency 2024-07-05 11:38:32 -04:00
Matthew Webb 72e0a4fb6b Fix an unused parameter warning in dhtrunnertester
This change eliminates the following compiler warning without reducing readability:

/home/noviv/opendht/tests/dhtrunnertester.cpp: In lambda function:
/home/noviv/opendht/tests/dhtrunnertester.cpp:292:89: warning: unused parameter ‘expired’ [-Wunused-parameter]
  292 |     node2.listen(key2, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired){
      |                                                                                    ~~~~~^~~~~~~
2024-07-03 21:59:07 -04:00
AmnaSnene 3e2fd5e8fa peer discovery: address requested changes 2024-06-25 13:27:35 -04:00
AmnaSnene 8b3f7f2480 peer discovery: re-publish and re-discover immediately when a node disconnects, instead of on the connectivityChanged signal. 2024-06-25 13:27:35 -04:00
AmnaSnene 57c855e1cb peer discovery: post reDiscover() and publish() to the ioContext when connectivity changes. 2024-06-25 13:27:35 -04:00
Adrien Beraud 56e7cd94a5 cmake, meson: allow to use io_uring 2024-06-21 12:09:29 -04:00
Adrien Beraud 074e05cc32 ci/github: update to latest action versions 2024-06-10 16:39:55 -04:00
Lanius-collaris 251f66dfce fix getif_workaround_android.h
char may be signed
2024-06-10 08:21:57 -04:00
Lucas Dias 227a7aa0d9 make crypto error messages more readable
Add verifications to gnutls calls and throw expcetion
with readable messages.
For example, if call loadIdentity and crt file has name
different of private key exception message was
Can't get certificate public key ID: ASN1 parser: Value was not found.

However, the real problem is that crt file was not found.
Now, for the same problem the exception message will be:
Error while reading file.

Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 16:56:29 -03:00
Lucas Dias e12e344a79 make crypto error messages more readable
Add verifications to gnutls calls and throw expcetion
with readable messages.
For example, if call loadIdentity and crt file has name
different of private key exception message was
Can't get certificate public key ID: ASN1 parser: Value was not found.

However, the real problem is that crt file was not found.
Now, for the same problem the exception message will be:
Error while reading file.

Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 16:55:10 -03:00
Lucas Dias d4fc4fd658 Merge branch 'crypto_error_messages' of https://github.com/lucassdiass/opendht into crypto_error_messages
Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 16:53:32 -03:00
Lucas Dias 08d67cc8d8 Merge branch 'crypto_error_messages' of https://github.com/lucassdiass/opendht into crypto_error_messages
Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 16:52:09 -03:00
Lucas Dias 208afd22f2 Merge branch 'crypto_error_messages' of https://github.com/lucassdiass/opendht into crypto_error_messages 2024-06-09 15:55:31 -03:00
Lucas Dias 9eea01202a make crypto error messages more readable
Add verifications to gnutls calls and throw expcetion
with readable messages.
For example, if call loadIdentity and crt file has name
different of private key exception message was
Can't get certificate public key ID: ASN1 parser: Value was not found.

However, the real problem is that crt file was not found.
Now, for the same problem the exception message will be:
Error while reading file.

Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 15:46:34 -03:00
Lucas Dias 304a9992fe make crypto error messages more readable
Add verifications to gnutls calls and throw expcetion
with readable messages.
For example, if call loadIdentity and crt file has name
different of private key exception message was
Can't get certificate public key ID: ASN1 parser: Value was not found.

However, the real problem is that crt file was not found.
Now, for the same problem the exception message will be:
Error while reading file.

Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-06-09 09:45:21 -03:00
Adrien Beraud ae62216bf4 rust: update to 2021, fix memory issues 2024-06-07 10:29:26 -04:00
Adrien Beraud cd92eeaae5 dht: add support to behave as a client node 2024-06-07 09:52:01 -04:00
Adrien Beraud 9dad7c69fd peer discovery: cleanup 2024-06-07 09:31:48 -04:00
Lanius-collaris 5cc5b98aeb fix android workaround 2024-06-07 09:21:05 -04:00
Lanius-collaris c03ce419ca peer_discovery: add a workaround for Android hotspot 2024-06-07 09:21:05 -04:00
Adrien Béraud ceef3f048c README: add llhttp dependency 2024-06-03 08:32:17 -04:00
Adrien Béraud 8dd926182c ci/github: update before install 2024-06-03 08:26:52 -04:00
Adrien Béraud c8b528b3f4 update version to 3.2.0 2024-05-31 06:58:09 -04:00
Adrien Béraud a65148cd08 ci: build proxy client for Autotools build 2024-05-31 06:58:09 -04:00
Adrien Béraud 5a2a20a32f http: migrate from http-parser to llhttp 2024-05-31 06:58:09 -04:00
36 changed files with 602 additions and 257 deletions

No files matched your search

+48 -16
View File
@@ -7,18 +7,42 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Cython
run: sudo pip3 install Cython
- name: llhttp
run: |
mkdir llhttp
wget https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.0.tar.gz -O llhttp.tar.gz
tar -xzf llhttp.tar.gz -C llhttp --strip-components=1
cd llhttp && cmake -DCMAKE_INSTALL_PREFIX=/usr . && make -j2 && sudo make install
cd ../ && rm -rf llhttp*
- name: expected-lite
run: |
sudo mkdir /usr/local/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/local/include/nonstd/expected.hpp
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
sudo make install
cd ../../ && rm -rf restinio*
- name: Configure
run: |
./autogen.sh
./configure
./configure --enable-proxy-client
- name: Build
run: make
@@ -26,12 +50,13 @@ jobs:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools python3-pip \
libcppunit-dev libjsoncpp-dev libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Python dependencies
run: sudo pip3 install meson Cython
- name: Configure
@@ -43,9 +68,10 @@ jobs:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libfmt-dev \
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
- name: Configure
@@ -63,22 +89,28 @@ jobs:
name: macOS/Clang build
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Dependencies
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl http-parser cppunit
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- name: expected-lite
run: |
sudo mkdir /usr/local/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/local/include/nonstd/expected.hpp
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/aberaud/restinio/archive/6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz
ls -l && tar -xzf 6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz
cd restinio-6fd08b65f6f15899dd0de3c801f6a5462b811c64/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
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
- name: Configure
run: |
+18 -11
View File
@@ -6,26 +6,33 @@ jobs:
name: Clang Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: deps
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev libasio-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev libasio-dev \
llvm llvm-dev clang clang-tools && \
sudo apt remove gcc g++
- name: expected-lite
run: |
sudo mkdir /usr/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
- name: restinio
run: |
mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& ls -l && tar -xzf 6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& cd restinio-6fd08b65f6f15899dd0de3c801f6a5462b811c64/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 && sudo make install \
&& cd ../../.. && rm -rf restinio
mkdir restinio && cd restinio
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
- name: cmake
run: |
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+31 -31
View File
@@ -25,10 +25,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -36,12 +36,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileDeps
@@ -58,10 +58,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -69,13 +69,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
@@ -92,10 +92,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -103,12 +103,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileDepsLlvm
@@ -125,10 +125,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -136,13 +136,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileLlvm
@@ -159,10 +159,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -170,13 +170,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DHTNODE }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileDhtnode
@@ -193,10 +193,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -204,13 +204,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileDepsAlpine
@@ -227,10 +227,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -238,13 +238,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
context: .
file: docker/DockerfileAlpine
@@ -262,7 +262,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: cmake
run: |
@@ -280,14 +280,14 @@ jobs:
- name: build
run: cd build && make dist
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: opendht-wheels-linux
path: build/python/dist/*.whl
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
draft: true
files: build/python/dist/*.whl
+49 -5
View File
@@ -1,4 +1,7 @@
cmake_minimum_required (VERSION 3.16..3.28)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
project (opendht)
include(CMakePackageConfigHelpers)
@@ -7,9 +10,10 @@ include(CheckIncludeFileCXX)
include(FindPkgConfig)
include(cmake/CheckAtomic.cmake)
include(CTest)
include(FetchContent)
set (opendht_VERSION_MAJOR 3)
set (opendht_VERSION_MINOR 1.11)
set (opendht_VERSION_MINOR 2.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -81,15 +85,44 @@ if (NOT MSVC)
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
message(STATUS "Found ASIO ${ASIO_INCLUDE_DIR}")
else()
message(STATUS "ASIO not required")
endif ()
find_package(fmt)
if (OPENDHT_HTTP)
find_package(Restinio REQUIRED)
find_library(HTTP_PARSER_LIBRARY http_parser)
add_library(http_parser SHARED IMPORTED)
set(http_parser_lib "-lhttp_parser")
# llhttp
find_path(LLHTTP_INCLUDE_DIR llhttp.h)
find_library(LLHTTP_LIBRARY libllhttp)
if (LLHTTP_INCLUDE_DIR AND LLHTTP_LIBRARY)
message(STATUS "Found llhttp ${LLHTTP_INCLUDE_DIR} ${LLHTTP_LIBRARY}")
add_library(llhttp_static STATIC IMPORTED)
set_target_properties(llhttp_static PROPERTIES
IMPORTED_LOCATION ${LLHTTP_LIBRARY}
INTERFACE_INCLUDE_DIRECTORIES ${LLHTTP_INCLUDE_DIR}
)
set(llhttp_target llhttp_static)
else()
FetchContent_Declare(llhttp-local URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.0.tar.gz")
if (BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "")
else()
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "")
set(BUILD_STATIC_LIBS ON CACHE INTERNAL "")
endif()
FetchContent_MakeAvailable(llhttp-local)
if (BUILD_SHARED_LIBS)
set(llhttp_target llhttp_shared)
else()
set(llhttp_target llhttp_static)
endif()
endif()
set(http_lib "-lllhttp")
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
@@ -130,6 +163,9 @@ endif ()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
if (UNIX AND NOT APPLE)
pkg_search_module(liburing IMPORTED_TARGET liburing)
endif ()
endif()
if (NOT MSVC)
@@ -204,6 +240,7 @@ list (APPEND opendht_SOURCES
)
list (APPEND opendht_HEADERS
include/opendht.h
include/opendht/def.h
include/opendht/utils.h
include/opendht/sockaddr.h
@@ -356,18 +393,25 @@ else()
PRIVATE
PkgConfig::argon2
PkgConfig::Nettle
${HTTP_PARSER_LIBRARY}
PUBLIC
${CMAKE_THREAD_LIBS_INIT}
PkgConfig::GnuTLS
fmt::fmt
)
if (OPENDHT_HTTP)
target_link_libraries(opendht PUBLIC ${llhttp_target})
endif()
if (Jsoncpp_FOUND)
target_link_libraries(opendht PUBLIC PkgConfig::Jsoncpp)
endif()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (liburing_FOUND)
set(iouring_lib ", liburing")
target_link_libraries(opendht PUBLIC PkgConfig::liburing)
target_compile_definitions(opendht PUBLIC ASIO_HAS_IO_URING ASIO_DISABLE_EPOLL)
endif()
endif()
if (BUILD_SHARED_LIBS)
+1
View File
@@ -98,6 +98,7 @@ for r in results:
- Nettle 2.4+, a GnuTLS dependency for crypto.
- {fmt} 9.0+, for log formatting.
- (optional) restinio used for the REST API.
- (optional) llhttp used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 7+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2019, 2022
+7 -7
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 3)
m4_define([opendht_minor_version], 1)
m4_define([opendht_patch_version], 11)
m4_define([opendht_minor_version], 2)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -175,11 +175,11 @@ AS_IF([test "x$have_fmt" = "xyes"], [
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp],, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
# http_parser has no pkgconfig, instead we check with:
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
AC_SUBST(http_parser_lib, ["-lhttp_parser"])
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
# llhttp has no pkgconfig, instead we check with:
AC_CHECK_LIB(llhttp, exit,, AC_MSG_ERROR([Missing llhttp library files]))
AC_CHECK_HEADERS([llhttp.h], [llhttp_headers=yes; break;])
AC_SUBST(http_lib, ["-lllhttp"])
AS_IF([test "x$llhttp_headers" != "xyes"], AC_MSG_ERROR([Missing llhttp headers files]))
])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
+2 -2
View File
@@ -19,7 +19,7 @@ RUN cd opendht && mkdir build && cd build \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install
FROM alpine:3.18 AS install
FROM alpine:3.19 AS install
COPY --from=build /install /
RUN apk add --no-cache \
libstdc++ \
@@ -28,8 +28,8 @@ RUN apk add --no-cache \
openssl \
argon2-dev \
jsoncpp \
llhttp \
fmt \
http-parser \
readline \
ncurses
CMD ["dhtnode", "-b", "bootstrap.jami.net", "-p", "4222", "--proxyserver", "8080"]
+13 -9
View File
@@ -13,18 +13,22 @@ RUN apt-get update && apt-get install -y \
python3-pip 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 \
libssl-dev libfmt-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& ls -l && tar -xzf 6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& cd restinio-6fd08b65f6f15899dd0de3c801f6a5462b811c64/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
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+14 -10
View File
@@ -1,4 +1,4 @@
FROM alpine:3.18
FROM alpine:3.19
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -8,16 +8,20 @@ RUN apk add --no-cache \
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 \
llhttp-dev asio-dev msgpack-cxx-dev \
&& rm -rf /var/cache/apk/*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& tar -xzf 6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& cd restinio-6fd08b65f6f15899dd0de3c801f6a5462b811c64/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
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+12 -8
View File
@@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \
apt-transport-https build-essential pkg-config git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
libargon2-0-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev python3-pip \
autotools-dev autoconf libfmt-dev libmsgpack-dev libssl-dev python3-pip \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install --upgrade cmake meson Cython
@@ -20,13 +20,17 @@ RUN echo "** Building a recent version of asio ***" \
&& make install \
&& cd ../../ && rm -rf asio*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+13 -9
View File
@@ -13,18 +13,22 @@ RUN apt-get update && apt-get install -y \
python3-dev python3-setuptools python3-pip \
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 \
libssl-dev libfmt-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
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
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+12 -8
View File
@@ -13,7 +13,7 @@ RUN apt-get update \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev python3-dev \
python3-setuptools libcppunit-dev python3-pip python3-build python3-virtualenv \
autotools-dev autoconf libssl-dev libargon2-dev \
libfmt-dev libhttp-parser-dev libasio-dev \
libfmt-dev libasio-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
@@ -22,13 +22,17 @@ RUN pip3 install meson Cython
ENV CC cc
ENV CXX c++
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& ls -l && tar -xzf 6fd08b65f6f15899dd0de3c801f6a5462b811c64.tar.gz \
&& cd restinio-6fd08b65f6f15899dd0de3c801f6a5462b811c64/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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+3
View File
@@ -143,6 +143,9 @@ struct OPENDHT_PUBLIC Config {
* - Larger listen refresh time
*/
bool public_stable {false};
/* Client mode, node will not be used by other nodes to store data. */
bool client_mode {false};
};
/**
+5 -5
View File
@@ -46,17 +46,17 @@ enum class PushType {
}
MSGPACK_ADD_ENUM(dht::PushType)
namespace http {
class Request;
struct ListenerSession;
}
namespace Json {
class Value;
}
namespace dht {
namespace http {
class Request;
struct ListenerSession;
}
class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
+4 -2
View File
@@ -409,7 +409,8 @@ public:
void run(const Config& config, Context&& context);
void setOnStatusChanged(StatusCallback&& cb) {
statusCb = std::move(cb);
if (cb)
statusCbs.emplace_back(std::move(cb));
}
/**
@@ -519,7 +520,8 @@ private:
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
StatusCallback statusCb {nullptr};
std::vector<StatusCallback> statusCbs {};
/** PeerDiscovery Parameters */
std::shared_ptr<PeerDiscovery> peerDiscovery_;
+6 -20
View File
@@ -29,23 +29,20 @@
# define snprintf snprintf
#endif
#include <asio/ip/tcp.hpp>
#include <asio/streambuf.hpp>
#include <asio/ssl/context.hpp>
#include <restinio/http_headers.hpp>
#include <restinio/message_builders.hpp>
#include <memory>
#include <queue>
#include <mutex>
#include <future>
namespace Json {
class Value;
}
extern "C" {
struct http_parser;
struct http_parser_settings;
}
namespace restinio {
namespace impl {
class tls_socket_t;
@@ -156,17 +153,6 @@ private:
bool checkOcsp_ {false};
};
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
/* @class Resolver
* @brief The purpose is to only resolve once to avoid mutliple dns requests per operation.
*/
@@ -338,7 +324,7 @@ private:
void init_default_headers();
/**
* Initialized and wraps the http_parser callbacks with our user defined callbacks.
* Initialized and wraps the llhttp callbacks with our user defined callbacks.
*/
void init_parser();
@@ -380,8 +366,8 @@ private:
Response response_ {};
std::string request_;
std::atomic<bool> finishing_ {false};
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
std::unique_ptr<llhttp_t> parser_;
std::unique_ptr<llhttp_settings_t> parser_s_;
// Next request in case of redirect following
std::shared_ptr<Request> next_;
+1
View File
@@ -52,6 +52,7 @@ struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
bool is_client {false};
};
class DhtProtocolException : public DhtException {
+21 -14
View File
@@ -23,7 +23,9 @@
#include "sockaddr.h"
#include "infohash.h"
#include "logger.h"
#include "utils.h"
#include <asio/steady_timer.hpp>
#include <thread>
namespace asio {
@@ -36,31 +38,34 @@ class OPENDHT_PUBLIC PeerDiscovery
{
public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
using ServiceDiscoveredCallback = std::function<void(msgpack::object &&, SockAddr &&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
PeerDiscovery(in_port_t port = DEFAULT_PORT,
std::shared_ptr<asio::io_context> ioContext = {},
std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
* startDiscovery - Keep Listening data from the sender until node is joinned
* or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
template<typename T>
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
template <typename T>
void startDiscovery(const std::string &type, std::function<void(T &&, SockAddr &&)> cb) {
startDiscovery(type, [cb](msgpack::object &&ob, SockAddr &&addr) {
cb(ob.as<T>(), std::move(addr));
});
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called
*/
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
template<typename T>
void startPublish(const std::string &type, const T& object) {
template <typename T>
void startPublish(const std::string &type, const T &object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, buf);
@@ -68,22 +73,24 @@ public:
/**
* Thread Stopper
*/
*/
void stop();
/**
* Remove possible callBack to discovery
*/
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
*/
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
void connectivityChanged();
void stopConnectivityChanged();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
@@ -92,4 +99,4 @@ private:
std::thread ioRunnner_;
};
}
} // namespace dht
+12 -13
View File
@@ -1,5 +1,5 @@
project('opendht', 'c', 'cpp', 'cython',
version: '3.1.11',
version: '3.2.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
@@ -12,17 +12,16 @@ argon2 = dependency('libargon2')
openssl = dependency('openssl', required: get_option('proxy_client'))
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
fmt = dependency('fmt')
llhttp = dependency('llhttp', 'libllhttp', required: get_option('proxy_client'))
io_uring = dependency('liburing', required: false)
dirs=[]
if host_machine.system() == 'freebsd'
dirs+='/usr/local/lib'
elif host_machine.system() == 'darwin'
dirs+='/opt/homebrew/lib'
deps = [fmt, gnutls, nettle, msgpack, argon2, openssl, jsoncpp, llhttp, io_uring]
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language : 'cpp')
if io_uring.found()
add_project_arguments('-DASIO_HAS_IO_URING', '-DASIO_DISABLE_EPOLL', language : 'cpp')
conf_data.set('iouring_lib', ', liburing')
endif
http_parser = meson.get_compiler('c').find_library('http_parser', dirs: dirs, required: get_option('proxy_client'))
deps = [fmt, 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')
@@ -57,12 +56,12 @@ if jsoncpp.found()
add_project_arguments('-DOPENDHT_JSONCPP', language : 'cpp')
conf_data.set('jsoncpp_lib', ', jsoncpp')
endif
if http_parser.found()
if llhttp.found()
opendht_src += ['src/http.cpp', 'src/compat/os_cert.cpp']
if host_machine.system() == 'darwin'
deps+=dependency('appleframeworks', modules : ['CoreFoundation', 'Security'])
endif
conf_data.set('http_lib', '-lhttp_parser')
conf_data.set('http_lib', '-lllhttp')
endif
if openssl.found()
conf_data.set('openssl_lib', ', openssl')
@@ -158,7 +157,7 @@ if get_option('tools').enabled()
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
if http_parser.found()
if llhttp.found()
durl = executable('durl', 'tools/durl.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
+2 -2
View File
@@ -6,7 +6,7 @@ Name: OpenDHT
Description: C++17 Distributed Hash Table library
Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs.private: @http_parser_lib@ -pthread
Libs.private: @http_lib@ -pthread
Requires: gnutls >= 3.3@jsoncpp_lib@@openssl_lib@
Requires.private: nettle >= 2.4@argon2_lib@
Requires.private: nettle >= 2.4@argon2_lib@@iouring_lib@
Cflags: -I${includedir}
+5 -5
View File
@@ -2,10 +2,10 @@
name = "opendht"
version = "0.1.0"
authors = ["Sébastien Blin <sebastien.blin@savoirfairelinux.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
edition = "2021"
[dependencies]
libc="0.2.0"
os_socketaddr="0.2.3"
libc="0.2"
os_socketaddr="0.2.3"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+9 -8
View File
@@ -56,6 +56,7 @@ impl DhtRunnerConfig {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
log: true,
});
unsafe {
dht_runner_config_default(&mut *config);
@@ -64,23 +65,23 @@ impl DhtRunnerConfig {
}
pub fn set_proxy_server(&mut self, proxy_server: &str) {
self.proxy_server = CString::new(proxy_server).unwrap().as_ptr();
self.proxy_server = CString::new(proxy_server).unwrap().into_raw();
}
pub fn set_push_node_id(&mut self, push_node_id: &str) {
self.push_node_id = CString::new(push_node_id).unwrap().as_ptr();
self.push_node_id = CString::new(push_node_id).unwrap().into_raw();
}
pub fn set_push_token(&mut self, push_token: &str) {
self.push_token = CString::new(push_token).unwrap().as_ptr();
self.push_token = CString::new(push_token).unwrap().into_raw();
}
pub fn set_push_topic(&mut self, push_topic: &str) {
self.push_topic = CString::new(push_topic).unwrap().as_ptr();
self.push_topic = CString::new(push_topic).unwrap().into_raw();
}
pub fn set_push_platform(&mut self, push_platform: &str) {
self.push_platform = CString::new(push_platform).unwrap().as_ptr();
self.push_platform = CString::new(push_platform).unwrap().into_raw();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
@@ -93,7 +94,7 @@ impl DhtRunnerConfig {
impl DhtNodeConfig
{
pub fn set_persist_path(&mut self, persist_path: &str) {
self.persist_path = CString::new(persist_path).unwrap().as_ptr();
self.persist_path = CString::new(persist_path).unwrap().into_raw();
}
}
@@ -197,8 +198,8 @@ impl DhtRunner {
pub fn bootstrap(&mut self, host: &str, service: u16) {
unsafe {
dht_runner_bootstrap(&mut *self,
CString::new(host).unwrap().as_ptr(),
CString::new(service.to_string()).unwrap().as_ptr())
CString::new(host).unwrap().into_raw(),
CString::new(service.to_string()).unwrap().into_raw())
}
}
+1 -1
View File
@@ -124,9 +124,9 @@ pub struct DhtRunnerConfig
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
pub client_identity: DhtIdentity,
pub log: bool,
}
#[link(name = "opendht-c")]
extern {
// dht::Value
+39
View File
@@ -0,0 +1,39 @@
//Code from getifaddrs.3 man
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <asio.hpp>
#include <stdexcept>
namespace dht{
namespace workaround{
asio::ip::address_v4
get_interface(){
struct ifaddrs *ifaddr;
if(getifaddrs(&ifaddr) == -1){
throw std::runtime_error("Can't getifaddrs");
}
for (struct ifaddrs *if1 = ifaddr; if1 != NULL; if1 = if1->ifa_next){
if (if1->ifa_addr == NULL)
continue;
if (if1->ifa_addr->sa_family != AF_INET)
continue;
if((if1->ifa_flags & IFF_MULTICAST) == IFF_MULTICAST){
auto sa_data = reinterpret_cast<uint8_t*>(if1->ifa_addr->sa_data);
uint32_t value = sa_data[2] << 24
| sa_data[3] << 16
| sa_data[4] << 8
| sa_data[5];
freeifaddrs(ifaddr);
return asio::ip::address_v4(value);
}
}
freeifaddrs(ifaddr);
throw std::runtime_error("Can't find a interface which supports multicast");
}
} /* namespace workaround */
} /* namespace dht */
+75 -22
View File
@@ -93,11 +93,27 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
std::random_device rdev;
std::generate_n(ret.begin(), GCM_IV_SIZE, std::bind(rand_byte, std::ref(rdev)));
}
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
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);
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes128_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes192_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes256_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
}
return ret;
}
@@ -118,14 +134,28 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
std::array<uint8_t, GCM_DIGEST_SIZE> digest;
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, data);
size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE;
Blob ret(data_sz);
gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes128_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes192_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes256_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, digest.data());
}
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE)) {
throw DecryptError("Can't decrypt data");
@@ -227,7 +257,7 @@ PrivateKey::PrivateKey(const uint8_t* src, size_t src_size, const char* password
throw CryptoException("Can't initialize private key !");
const gnutls_datum_t dt {(uint8_t*)src, static_cast<unsigned>(src_size)};
int flags = password_ptr ? GNUTLS_PKCS_PLAIN
int flags = (password_ptr == NULL || strlen(password_ptr)==0) ? GNUTLS_PKCS_PLAIN
: ( GNUTLS_PKCS_PBES2_AES_128 | GNUTLS_PKCS_PBES2_AES_192 | GNUTLS_PKCS_PBES2_AES_256
| GNUTLS_PKCS_PKCS12_3DES | GNUTLS_PKCS_PKCS12_ARCFOUR | GNUTLS_PKCS_PKCS12_RC2_40);
@@ -1152,12 +1182,19 @@ loadIdentity(const std::string &path,const std::string &privkey_password)
pkStream.close();
// Create a certificate
gnutls_x509_crt_t gnuCert;
if (gnutls_x509_crt_init(&gnuCert) != GNUTLS_E_SUCCESS)
if (gnutls_x509_crt_init(&gnuCert))
throw std::runtime_error("Failed to initialize gnutls certificate struct");
gnutls_datum_t crtContent {nullptr, 0};
// Read the certificate file
gnutls_load_file((path + ".crt").c_str(), &crtContent);
gnutls_x509_crt_import(gnuCert, &crtContent, GNUTLS_X509_FMT_PEM);
int err = gnutls_load_file((path + ".crt").c_str(), &crtContent);
if (err)
throw CryptoException(gnutls_strerror(err));
err = gnutls_x509_crt_import(gnuCert, &crtContent, GNUTLS_X509_FMT_PEM);
if (err)
throw CryptoException(gnutls_strerror(err));
auto cert = std::make_shared<Certificate>(gnuCert);
return {std::move(key), std::move(cert)};
}
@@ -1204,31 +1241,47 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
int err = gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
if(err) {
throw CryptoException(std::string("Error when setting dn by oid ") + gnutls_strerror(err));
}
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
gnutls_x509_crt_set_ca_status(cert, 1);
err = gnutls_x509_crt_set_ca_status(cert, 1);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
key_usage |= GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN;
} else {
key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_DATA_ENCIPHERMENT;
}
gnutls_x509_crt_set_key_usage(cert, key_usage);
err = gnutls_x509_crt_set_key_usage(cert, key_usage);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
throw CryptoException("Signing certificate must be CA");
}
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
if (err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
} else {
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
if (err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
+1
View File
@@ -1812,6 +1812,7 @@ fromDhtConfig(const Config& config)
netConf.max_peer_req_per_sec = config.max_peer_req_per_sec
? config.max_peer_req_per_sec
: netConf.max_req_per_sec/8;
netConf.is_client = config.client_mode;
return netConf;
}
+1 -1
View File
@@ -23,7 +23,7 @@
#include "op_cache.h"
#include "utils.h"
#include <http_parser.h>
#include <llhttp.h>
#include <deque>
namespace dht {
+14 -1
View File
@@ -58,6 +58,19 @@ constexpr const std::chrono::minutes PRINT_STATS_PERIOD {2};
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
namespace http {
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
}
class opendht_logger_t
{
public:
@@ -116,7 +129,7 @@ private:
void
DhtProxyServer::ConnectionListener::state_changed(const restinio::connection_state::notice_t& notice) noexcept
{
if (restinio::holds_alternative<restinio::connection_state::closed_t>(notice.cause())) {
if (std::holds_alternative<restinio::connection_state::closed_t>(notice.cause())) {
onClosed_(notice.connection_id());
}
}
+17 -5
View File
@@ -180,9 +180,9 @@ DhtRunner::run(const Config& config, Context&& context)
throw;
}
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
}
statusCbs.clear();
if (context.statusChangedCallback)
statusCbs.emplace_back(std::move(context.statusChangedCallback));
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
}
@@ -264,6 +264,17 @@ DhtRunner::run(const Config& config, Context&& context)
}
}
}
if (peerDiscovery_) {
statusCbs.emplace_back([this](NodeStatus status4, NodeStatus status6) {
if (status4 == NodeStatus::Disconnected && status6 == NodeStatus::Disconnected) {
peerDiscovery_->connectivityChanged();
}
else if (status4 != NodeStatus::Connected || status6 != NodeStatus::Connected) {
peerDiscovery_->stopConnectivityChanged();
}
});
}
#endif
}
}
@@ -690,8 +701,9 @@ DhtRunner::loop_()
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
if (statusCb)
statusCb(status4, status6);
for (auto& cb : statusCbs){
cb(status4, status6);
}
}
return wakeup;
+19 -21
View File
@@ -24,7 +24,7 @@
#include <asio.hpp>
#include <restinio/impl/tls_socket.hpp>
#include <http_parser.h>
#include <llhttp.h>
#include <json/json.h>
#include <openssl/ocsp.h>
@@ -461,7 +461,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
bool verified = verifier(preverified, ctx);
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
logger->error("[http::connection:{:d}] ssl verification error={:d} %d", id, verify_ec, verified);
logger->error("[http::connection:{:d}] ssl verification error={:d} {}", id, verify_ec, verified);
if (verified and checkOcsp) {
std::unique_ptr<stack_st_X509, void(*)(stack_st_X509*)> chain(
X509_STORE_CTX_get1_chain(ctx.native_handle()),
@@ -1137,13 +1137,11 @@ Request::init_parser()
response_.request = shared_from_this();
if (!parser_)
parser_ = std::make_unique<http_parser>();
http_parser_init(parser_.get(), HTTP_RESPONSE);
parser_->data = static_cast<void*>(this);
parser_ = std::make_unique<llhttp_t>();
if (!parser_s_)
parser_s_ = std::make_unique<http_parser_settings>();
http_parser_settings_init(parser_s_.get());
parser_s_ = std::make_unique<llhttp_settings_t>();
llhttp_settings_init(parser_s_.get());
cbs_.on_status = [this, statusCb = std::move(cbs_.on_status)](unsigned int status_code){
response_.status_code = status_code;
@@ -1158,31 +1156,33 @@ Request::init_parser()
response_.headers[*header_field] = std::string(at, length);
};
// http_parser raw c callback (note: no context can be passed into them)
parser_s_->on_status = [](http_parser* parser, const char* /*at*/, size_t /*length*/) -> int {
// llhttp raw c callback (note: no context can be passed into them)
parser_s_->on_status = [](llhttp_t* parser, const char* /*at*/, size_t /*length*/) -> int {
static_cast<Request*>(parser->data)->cbs_.on_status(parser->status_code);
return 0;
};
parser_s_->on_header_field = [](http_parser* parser, const char* at, size_t length) -> int {
parser_s_->on_header_field = [](llhttp_t* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->cbs_.on_header_field(at, length);
return 0;
};
parser_s_->on_header_value = [](http_parser* parser, const char* at, size_t length) -> int {
parser_s_->on_header_value = [](llhttp_t* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->cbs_.on_header_value(at, length);
return 0;
};
parser_s_->on_body = [](http_parser* parser, const char* at, size_t length) -> int {
parser_s_->on_body = [](llhttp_t* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->onBody(at, length);
return 0;
};
parser_s_->on_headers_complete = [](http_parser* parser) -> int {
parser_s_->on_headers_complete = [](llhttp_t* parser) -> int {
static_cast<Request*>(parser->data)->onHeadersComplete();
return 0;
};
parser_s_->on_message_complete = [](http_parser* parser) -> int {
parser_s_->on_message_complete = [](llhttp_t* parser) -> int {
static_cast<Request*>(parser->data)->onComplete();
return 0;
};
llhttp_init(parser_.get(), HTTP_RESPONSE, parser_s_.get());
parser_->data = static_cast<void*>(this);
}
void
@@ -1339,7 +1339,7 @@ Request::terminate(const asio::error_code& ec)
logger_->debug("[http:request:{:d}] done with status code {:d}", id_, response_.status_code);
}
if (!parser_ or !http_should_keep_alive(parser_.get()))
if (!parser_ or !llhttp_should_keep_alive(parser_.get()))
if (auto c = conn_)
c->close();
notify_state_change(State::DONE);
@@ -1378,17 +1378,15 @@ Request::handle_response(const asio::error_code& ec, size_t /* n_bytes */)
return;
}
auto request = (ec == asio::error::eof) ? std::string{} : conn_->read_bytes();
size_t ret = http_parser_execute(parser_.get(), parser_s_.get(), request.c_str(), request.size());
if (ret != request.size()) {
enum llhttp_errno ret = llhttp_execute(parser_.get(), request.c_str(), request.size());
if (ret != HPE_OK && ret != HPE_PAUSED) {
if (logger_)
logger_->e("Error parsing HTTP: %zu %s %s", ret,
http_errno_name(HTTP_PARSER_ERRNO(parser_)),
http_errno_description(HTTP_PARSER_ERRNO(parser_)));
logger_->e("Error parsing HTTP: %zu %s %d", (int)ret, llhttp_errno_name(ret), llhttp_get_error_reason(parser_.get()));
terminate(asio::error::basic_errors::broken_pipe);
return;
}
if (state_ != State::DONE and parser_ and not http_body_is_final(parser_.get())) {
if (state_ != State::DONE and parser_ and not llhttp_message_needs_eof(parser_.get())) {
auto toRead = parser_->content_length ? std::min<uint64_t>(parser_->content_length, 64 * 1024) : 64 * 1024;
std::weak_ptr<Request> wthis = shared_from_this();
conn_->async_read_some(toRead, [wthis](const asio::error_code& ec, size_t bytes){
+61 -16
View File
@@ -143,7 +143,7 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -166,6 +166,9 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -194,7 +197,7 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -217,6 +220,9 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -704,7 +710,7 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
Tid tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -716,6 +722,9 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid, node,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -741,7 +750,7 @@ void
NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -753,6 +762,9 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -763,7 +775,7 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -782,6 +794,9 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -808,7 +823,7 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
unsigned sendWant = (want > 0) ? 1 : 0;
@@ -835,7 +850,10 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
@@ -952,10 +970,13 @@ NetworkEngine::sendValueParts(Tid tid, const std::vector<Blob>& svals, const Soc
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(config.network?1:0));
pk.pack_map(3+(config.network?1:0)+(config.is_client?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_V); pk.pack_map(1);
@@ -976,7 +997,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -1018,6 +1039,9 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
// send response
send(addr, buffer.data(), buffer.size());
@@ -1089,7 +1113,7 @@ NetworkEngine::sendListen(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
auto has_query = not query.where.empty() or not query.select.empty();
pk.pack(KEY_A); pk.pack_map(5 + has_query);
@@ -1109,6 +1133,9 @@ NetworkEngine::sendListen(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1130,7 +1157,7 @@ void
NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1142,6 +1169,9 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1158,7 +1188,7 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
bool add_created = created < scheduler.time();
pk.pack(KEY_A); pk.pack_map(add_created ? 5 : 4);
@@ -1178,6 +1208,9 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1244,7 +1277,7 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 7 : 6));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1265,6 +1298,9 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::UpdateValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1289,7 +1325,7 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1304,6 +1340,9 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1335,7 +1374,7 @@ void
NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1348,6 +1387,9 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1361,7 +1403,7 @@ NetworkEngine::sendError(const SockAddr& addr,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0));
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack(KEY_E); pk.pack_array(2);
pk.pack(code);
@@ -1378,6 +1420,9 @@ NetworkEngine::sendError(const SockAddr& addr,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
+61 -3
View File
@@ -22,6 +22,10 @@
#include "network_utils.h"
#include "utils.h"
#ifdef __ANDROID__
#include "compat/getif_workaround_android.h"
#endif
#include <asio.hpp>
using namespace std::literals;
@@ -48,6 +52,7 @@ public:
void connectivityChanged();
void stopConnectivityChanged();
private:
Sp<Logger> logger_;
//dmtx_ for callbackmap_ and drunning_ (write)
@@ -55,6 +60,14 @@ private:
//mtx_ for messages_ and lrunning (listen)
std::mutex mtx_;
std::shared_ptr<asio::io_context> ioContext_;
static constexpr dht::duration PeerDiscovery_PERIOD_MAX{
std::chrono::minutes(1)};
static constexpr std::chrono::seconds PeerDiscovery_PERIOD{10};
asio::steady_timer peerDiscoveryTimer;
std::chrono::steady_clock::duration peerDiscovery_period{
PeerDiscovery_PERIOD};
asio::ip::udp::socket sockFd_;
asio::ip::udp::endpoint sockAddrSend_;
@@ -82,6 +95,7 @@ private:
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
: logger_(logger)
, ioContext_(ioContext)
, peerDiscoveryTimer(*ioContext_)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
@@ -91,8 +105,23 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
sockFd_.bind({domain, port});
} catch (const std::exception& e) {
#ifdef __ANDROID__
if(domain.family() == AF_INET && strcmp(e.what(), "set_option: No such device") == 0) {
try{
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
auto mc_interface = workaround::get_interface();
sockFd_.set_option(asio::ip::multicast::outbound_interface(mc_interface));
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address().to_v4(), mc_interface));
sockFd_.bind({domain, port});
} catch(const std::exception& e){
if (logger_)
logger_->error("Can't start peer discovery using android workaround: {}", e.what());
}
}
else
#endif
if (logger_)
logger_->e("Can't start peer discovery for %s: %s",
logger_->error("Can't start peer discovery for {}: {}",
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
}
}
@@ -298,8 +327,30 @@ PeerDiscovery::DomainPeerDiscovery::reDiscover()
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
reDiscover();
publish(sockAddrSend_);
ioContext_->post([this] () {
reDiscover();
publish(sockAddrSend_);
});
if (logger_)
logger_->d("PeerDiscovery: connectivity changed");
if (peerDiscovery_period == PeerDiscovery_PERIOD_MAX ){
peerDiscovery_period = PeerDiscovery_PERIOD;
}
else{
peerDiscoveryTimer.expires_after(peerDiscovery_period);
peerDiscoveryTimer.async_wait([this](const asio::error_code& ec) {
if (ec == asio::error::operation_aborted)
return;
connectivityChanged();
});
peerDiscovery_period = std::min(peerDiscovery_period * 2, PeerDiscovery_PERIOD_MAX);
}
}
void PeerDiscovery::DomainPeerDiscovery::stopConnectivityChanged() {
peerDiscoveryTimer.cancel();
peerDiscovery_period = PeerDiscovery_PERIOD;
}
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
@@ -412,4 +463,11 @@ PeerDiscovery::connectivityChanged()
peerDiscovery6_->connectivityChanged();
}
void PeerDiscovery::stopConnectivityChanged() {
if (peerDiscovery4_)
peerDiscovery4_->stopConnectivityChanged();
if (peerDiscovery6_)
peerDiscovery6_->stopConnectivityChanged();
}
} /* namespace dht */
+21
View File
@@ -239,6 +239,27 @@ void CryptoTester::testAesEncryption() {
CPPUNIT_ASSERT(data2 == decrypted2);
}
void CryptoTester::testAesEncryptionWithMultipleKeySizes() {
auto data = std::vector<uint8_t>(rand(), rand());
// Valid key sizes
for (auto key_length : {16, 24, 32}) {
auto key = std::vector<uint8_t>(key_length, rand());
auto encrypted_data = dht::crypto::aesEncrypt(data, key);
auto decrypted_data = dht::crypto::aesDecrypt(encrypted_data, key);
CPPUNIT_ASSERT(data == decrypted_data);
}
// Invalid key sizes
for (auto key_length : {12, 28, 36}) {
auto key = std::vector<uint8_t>(key_length, rand());
CPPUNIT_ASSERT_THROW(dht::crypto::aesEncrypt(data, key), dht::crypto::DecryptError);
}
}
void
CryptoTester::tearDown() {
+2
View File
@@ -34,6 +34,7 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testCertificateSerialNumber);
CPPUNIT_TEST(testOcsp);
CPPUNIT_TEST(testAesEncryption);
CPPUNIT_TEST(testAesEncryptionWithMultipleKeySizes);
CPPUNIT_TEST_SUITE_END();
public:
@@ -69,6 +70,7 @@ class CryptoTester : public CppUnit::TestFixture {
* Test key streching and aes encryption/decryption
*/
void testAesEncryption();
void testAesEncryptionWithMultipleKeySizes();
};
} // namespace test
+1 -1
View File
@@ -289,7 +289,7 @@ DhtRunnerTester::testIdOps() {
valueCountEdit++;
cv.notify_all();
});
node2.listen(key2, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired){
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));