Compare commits

...
60 Commits
Author SHA1 Message Date
Adrien Béraud e4622f5e49 dhtrunner: add putEncrypted with PkId 'to' argument 2025-05-31 19:28:30 -04:00
Adrien Béraud 1d86ab8b16 securedht: add putEncrypted with PkId 'to' argument 2025-05-31 19:28:30 -04:00
Adrien Béraud c5edca7508 dhtrunner: allow to find certificates by PkId 2025-05-31 19:28:30 -04:00
Adrien Béraud 767a3721bd securedht: allow to find certificates by PkId 2025-05-31 19:28:30 -04:00
Adrien Béraud e368292546 securedht: put certificate at PkId 2025-05-31 19:28:30 -04:00
Adrien Béraud acae4bc4ff peer_discovery: use string_view for service type 2025-05-31 19:28:30 -04:00
Andrey Vukolov 68dc6a64be Definitions fix for #756 2025-05-30 23:05:59 -04:00
Andrey Vukolov 54a8fef0ee Windows build fixed for tools (wingetopt, signals)
- Addresses https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2089286643
    - Structures wingetopt and win32 compatibility files for builds on Windows with MSVC
    - Adjusts opendht_EXPORTS definition when building tools on MSVC
2025-05-30 23:05:59 -04:00
Andrey Vukolov a722726196 GNUTLS_INTERNAL_BUILD fix
- Removed GNUTLS_INTERNAL_BUILD definition to avoid problems with gnutls_free()
      function (https://github.com/savoirfairelinux/opendht/pull/750#issuecomment-2832005765)
      https://github.com/ShiftMediaProject/gnutls/blob/f78e2e673e84601283fb5ec353bfdd53204becd2/SMP/gnutls/gnutls.h#L2286
2025-05-23 18:24:35 -04:00
Andrey Vukolov b9bd954dfd GnuTLS version handler routine for versions 3.8.7 and later
- Added GnuTLS version handler directives for versions 3.8.7 and later
      https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2089284896
2025-05-23 18:24:35 -04:00
Andrey Vukolov aeb0b163cf MS Visual Studio .gitignore fix for CMake implicit builds
- Addresses review https://github.com/savoirfairelinux/opendht/pull/750#discussion_r2089277264 in #750
    - Allows clean clone and build in MS Visual Studio with different settings
2025-05-23 08:59:14 -04:00
Adrien Béraud c4e75ae66c update copyright year 2025-05-22 19:07:32 -04:00
Adrien Beraud d9afd2631b update version to 3.4.0 2025-05-22 12:05:31 -04:00
Adrien Beraud 405220795b http: check for cb in async_read_until 2025-05-22 11:53:05 -04:00
Adrien Beraud 3e407e65fa storage: remove previous value size from quota when appropriate 2025-05-22 11:53:05 -04:00
Adrien Béraud a2dff6a123 dhtrunner: registerCertificate: take certificate by const ref 2025-05-20 21:55:04 -04:00
Adrien Béraud 8d030f75f6 valuetype: compare certificate using longId 2025-05-19 23:57:09 -04:00
Adrien Béraud 13af7a6002 dhtrunner: registerCertificate: take certificate by const ref 2025-05-19 23:57:09 -04:00
Adrien Béraud 2bc46e9657 build/cmake: search llhttp with pkg_search_module 2025-05-19 23:55:49 -04:00
Adrien Béraud b3b050ca26 build/cmake: declare support for cmake up to 3.31 2025-05-19 23:55:46 -04:00
Adrien Béraud 38b0b2248f crypto: add Certificate::getDN() to read RFC4514 distinguished name 2025-05-19 23:55:42 -04:00
Adrien Béraud 5cfb1c6c9c tests/dhtrunner: wait separately for two conditions 2025-05-19 23:55:37 -04:00
Adrien Béraud 7aad21b7ed value: cleanup 2025-05-19 23:55:31 -04:00
Adrien Béraud c3669cfd36 ci/github: update restinio tag name 2025-04-22 22:37:39 -04:00
Adrien Béraud 45f04a7b6f ci/github: update restinio 2025-04-22 22:33:59 -04:00
Adrien Béraud 33f9570ecb adapt for Asio 1.34 2025-04-22 20:02:37 -04:00
François-Simon Fauteux-Chapleau c2d8b19380 http: fix service name resolution failure 2025-04-14 22:12:56 -04:00
Adrien Béraud 9bd957da48 build/cmake: update CheckAtomic.cmake 2025-04-05 10:29:06 -04:00
Adrien Béraud 352e36500c utils: make HexMap constexpr 2025-04-05 09:49:58 -04:00
Adrien Béraud 7397bd615f infohash: always write end of string terminator 2025-03-24 23:37:07 -04:00
Adrien Béraud 6a264d6f73 infohash: constexpr HexMap constructor 2025-03-24 23:29:32 -04:00
François-Simon Fauteux-Chapleau b0fa19d6f8 Merge pull request #747 from savoirfairelinux/proxy_push_result
proxy client: provide result for pushNotificationReceived
2025-02-20 15:29:58 -05:00
Adrien Beraud b2860e1731 proxy client: provide result for pushNotificationReceived 2025-02-20 14:13:16 -05:00
Adrien Beraud ad65ce872b docker: update llvm image to Ubuntu 24.04 2025-02-14 12:03:55 -05:00
Adrien Beraud 0cdc828953 docker: update restinio 2025-02-14 11:50:46 -05:00
Adrien Beraud 65e13fff4e ci/github: update llhttp 2025-02-14 11:48:42 -05:00
Adrien Beraud 748247d660 ci/github: update actions 2025-02-14 11:46:05 -05:00
Adrien Beraud 456f266be3 update restinio 2025-02-14 11:41:16 -05:00
Adrien Beraud 2c26030108 build/cmake: accept both llhttp and libllhttp 2025-02-14 11:28:50 -05:00
Adrien Beraud efc26245ae update version to 3.3.0 2025-02-11 16:01:27 -05:00
Adrien Beraud b9e00c7a0f tools/cnode: show value ID when put completes 2025-02-11 15:48:59 -05:00
Simon Désaulniers 5bf19c875c c: dht_value_with_id_new for setting an ID
Necessary for cancelling put values. Otherwise, the user doesn't have
the value ID for asking to cancel the permanent put.
2025-02-04 13:24:54 -05:00
Simon Désaulniers 5c18c980aa c/opendht: check for server_ca null 2025-01-25 09:32:15 -05:00
Simon Désaulniers b8d6fdc8eb c/opendht: dht_runner_run_config, consider client_identity 2025-01-25 09:32:15 -05:00
Simon Désaulniers 27bfd547c5 c/opendht: dht_runner_run_config, consider server_ca 2025-01-25 09:32:15 -05:00
ovari 5237f0a3b3 Update dht.cpp 2025-01-05 10:01:40 -05:00
ovari 23af860532 Update pht.h 2024-12-19 15:29:21 -05:00
ovari 4c98f7c8f4 pht.h: cleanup 2024-12-19 15:29:21 -05:00
Adrien Beraud 2a4b357420 ci: update libargon2 on Ubuntu 2024-12-19 15:22:58 -05:00
Adrien Beraud a26ac441ba proxy: cleanup 2024-12-17 16:04:22 -05:00
Adrien Beraud 80cfed38a1 build/cmake: make using io_uring optional 2024-12-17 16:04:22 -05:00
Lucas Dias 83ae498008 Catch exception of DeserializeNodes
Fix calls to DeserializeNodes. They must
catch possible exceptions

Signed-off-by: Lucas Dias <lucas_dias@redes.ufsm.br>
2024-12-17 14:06:36 -05:00
Adrien Béraud 7c184e1c8c Revert "build/cmake: accept both llhttp and libllhttp"
This reverts commit 7cf43f53ac.
2024-11-26 11:22:58 -05:00
Andreas Traczyk 4aa417802f deps: win32: migrate from http_parser to llhttp 2024-11-26 11:09:21 -05:00
Adrien Béraud cdba5b33cc proxy server: add options to listen route 2024-11-20 11:40:12 -05:00
Adrien Béraud 81bd05fe84 proxy node: remove jquery, update for new APIs 2024-11-20 11:40:12 -05:00
Adrien Béraud cf135d18b4 c node: fix typo 2024-11-20 11:40:12 -05:00
Adrien Béraud c7ba7f6703 utils: use fmt::format for time 2024-11-20 11:40:12 -05:00
Adrien Beraud c73c8c77f2 search: combine callbacks in case of multiple equivalent puts 2024-11-20 11:39:19 -05:00
Adrien Beraud c3bb16e92f tests: add testPutDuplicate 2024-11-20 11:39:19 -05:00
122 changed files with 1281 additions and 725 deletions

No files matched your search

+127 -99
View File
@@ -1,5 +1,13 @@
name: C/C++ CI
env:
LLHTTP_VERSION: "v9.2.1"
RESTINIO_VERSION: "0.7.6"
EXPECTED_LITE_URL: "https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp"
UBUNTU_FULL_DEPS: "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 libmsgpack-dev libargon2-dev"
UBUNTU_MESON_DEPS: "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 libmsgpack-dev libargon2-dev"
UBUNTU_MINIMAL_DEPS: "libncurses5-dev libreadline-dev nettle-dev libfmt-dev libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-dev"
on: [push, pull_request]
jobs:
@@ -7,122 +15,142 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- 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 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 \
- uses: actions/checkout@v4
- name: Install Dependencies
run: |
echo "Installing Ubuntu full dependencies:"
sudo apt-get update
sudo apt-get install -y $UBUNTU_FULL_DEPS
- name: Install Cython
run: sudo pip3 install Cython
- name: Build llhttp dependency
run: |
mkdir llhttp
wget "https://github.com/nodejs/llhttp/archive/refs/tags/release/${LLHTTP_VERSION}.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: Install expected-lite header
run: |
sudo mkdir -p /usr/local/include/nonstd
sudo wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Build restinio dependency
run: |
mkdir restinio && cd restinio
wget "https://github.com/Stiffstream/restinio/releases/download/v${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}.tar.bz2"
tar -xjf restinio-${RESTINIO_VERSION}.tar.bz2
cd restinio-${RESTINIO_VERSION}/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 --enable-proxy-client
- name: Build
run: make
sudo make install
cd ../../ && rm -rf restinio*
- name: Configure project
run: |
./autogen.sh
./configure --enable-proxy-client
- name: Build
run: make
build-ubuntu-meson:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- 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 libmsgpack-dev libargon2-0-dev
- name: Python dependencies
run: sudo pip3 install meson Cython
- name: Configure
run: meson setup build .
- name: Build
run: cd build && ninja
- uses: actions/checkout@v4
- name: Install Dependencies
run: |
echo "Installing Ubuntu meson dependencies:"
sudo apt update
sudo apt install -y $UBUNTU_MESON_DEPS
- name: Install Python dependencies
run: sudo pip3 install meson Cython
- name: Configure with Meson
run: meson setup build .
- name: Build with Ninja
run: cd build && ninja
build-ubuntu-minimal:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- 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
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DBUILD_TESTING=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
- uses: actions/checkout@v4
- name: Install Minimal Dependencies
run: |
echo "Installing Ubuntu minimal dependencies:"
sudo apt-get update
sudo apt-get install -y $UBUNTU_MINIMAL_DEPS
- name: Configure project with CMake
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DBUILD_TESTING=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: Run Unit tests
run: cd build && ./opendht_unit_tests
build-macos:
name: macOS/Clang build
runs-on: macOS-15
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Dependencies
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- uses: actions/checkout@v4
- name: expected-lite
run: |
sudo mkdir -p /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: Install Homebrew Dependencies
run: brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- 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 \
- name: Install expected-lite header
run: |
sudo mkdir -p /usr/local/include/nonstd
sudo wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Build restinio dependency
run: |
mkdir restinio && cd restinio
wget "https://github.com/Stiffstream/restinio/releases/download/v${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}.tar.bz2"
tar -xjf restinio-${RESTINIO_VERSION}.tar.bz2
cd restinio-${RESTINIO_VERSION}/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*
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
- name: Configure
run: |
mkdir build && cd build
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
- name: Build
run: cd build && make
- name: Configure project with CMake
run: |
mkdir build && cd build
# Set Homebrew OpenSSL paths
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On \
-DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
- name: Build
run: cd build && make
+4 -4
View File
@@ -12,7 +12,7 @@ jobs:
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 libmsgpack-dev libargon2-0-dev libasio-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev libasio-dev \
llvm llvm-dev clang clang-tools && \
sudo apt remove gcc g++
@@ -25,9 +25,9 @@ jobs:
- 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
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2
ls -l && tar -xjf restinio-0.7.3.tar.bz2
cd restinio-0.7.3/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 .
+6
View File
@@ -52,6 +52,10 @@ Makefile.in
# VSCode
.vscode/*
# Visual Studio
.vs/
CMakeSettings.json
# Eclipse CDT
.cproject
.project
@@ -78,3 +82,5 @@ doc/Doxyfile
build
build_dev
.DS_Store
build-*/
install/
+39 -33
View File
@@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.16..3.28)
cmake_minimum_required (VERSION 3.16..3.31)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
@@ -13,7 +13,7 @@ include(CTest)
include(FetchContent)
set (opendht_VERSION_MAJOR 3)
set (opendht_VERSION_MINOR 2.0)
set (opendht_VERSION_MINOR 4.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -33,6 +33,7 @@ option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp"
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_IO_URING "Use io_uring if available on the system (Linux only)" OFF)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS_NETWORK "Enable unit tests that require network access" ON)
option (OPENDHT_C "Build C bindings" OFF)
@@ -96,33 +97,39 @@ if (NOT MSVC)
find_package(Restinio REQUIRED)
# llhttp
find_path(LLHTTP_INCLUDE_DIR llhttp.h)
find_library(LLHTTP_LIBRARY NAMES llhttp 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)
pkg_search_module(LLHTTP IMPORTED_TARGET llhttp libllhttp)
if (LLHTTP_FOUND)
message(STATUS "Found llhttp ${LLHTTP_INCLUDE_DIRS}")
set(llhttp_target PkgConfig::LLHTTP)
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()
find_path(LLHTTP_INCLUDE_DIR llhttp.h)
find_library(LLHTTP_LIBRARY NAMES llhttp 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.1.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()
endif()
set(http_lib "-lllhttp")
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
@@ -156,20 +163,20 @@ else ()
${WIN32_DEP_DIR}/openssl/include
${WIN32_DEP_DIR}/restinio/dev
${WIN32_DEP_DIR}/fmt/include
${WIN32_DEP_DIR}/http_parser
${WIN32_DEP_DIR}/llhttp/include
)
endif ()
endif ()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
if (UNIX AND NOT APPLE)
if (OPENDHT_IO_URING AND UNIX AND NOT APPLE)
pkg_search_module(liburing IMPORTED_TARGET liburing)
endif ()
endif()
if (NOT MSVC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wno-deprecated -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fstack-protector-strong")
@@ -178,8 +185,7 @@ else ()
add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS
-D_CRT_SECURE_NO_WARNINGS
-DWIN32_LEAN_AND_MEAN
-DSTATIC_GETOPT
-DGNUTLS_INTERNAL_BUILD)
-DSTATIC_GETOPT)
set(DISABLE_MSC_WARNINGS "/wd4101 /wd4244 /wd4267 /wd4273 /wd4804 /wd4834 /wd4996")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_MSC_WARNINGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
@@ -343,12 +349,12 @@ if (MSVC)
)
if (OPENDHT_HTTP)
add_obj_lib (win32_fmt ${WIN32_DEP_DIR}/fmt/msvc/Release/fmt.lib)
add_obj_lib (win32_http_parser ${WIN32_DEP_DIR}/http_parser/x64/Release/http-parser.lib)
add_obj_lib (win32_llhttp ${WIN32_DEP_DIR}/llhttp/build/Release/llhttp.lib)
add_obj_lib (win32_ssl ${WIN32_DEP_DIR}/openssl/libssl_static.lib)
add_obj_lib (win32_crypto ${WIN32_DEP_DIR}/openssl/libcrypto_static.lib)
list (APPEND obj_libs
$<TARGET_OBJECTS:win32_fmt>
$<TARGET_OBJECTS:win32_http_parser>
$<TARGET_OBJECTS:win32_llhttp>
$<TARGET_OBJECTS:win32_ssl>
$<TARGET_OBJECTS:win32_crypto>
)
@@ -361,7 +367,7 @@ if (MSVC)
)
list (APPEND win32_Libs
${PROJECT_SOURCE_DIR}/../fmt/msvc/Release/fmt.lib
${PROJECT_SOURCE_DIR}/../http_parser/x64/Release/http-parser.lib
${PROJECT_SOURCE_DIR}/../llhttp/build/Release/llhttp.lib
${PROJECT_SOURCE_DIR}/../openssl/libssl.lib
${PROJECT_SOURCE_DIR}/../openssl/libcrypto.lib
)
@@ -407,7 +413,7 @@ else()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (liburing_FOUND)
if (OPENDHT_IO_URING AND 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)
+2 -2
View File
@@ -108,7 +108,7 @@ for r in results:
IRC: join us on Libera.chat at [`#opendht`](https://web.libera.chat/#opendht).
## License
Copyright (C) 2014-2023 Savoir-faire Linux Inc.
Copyright (C) 2014-2025 Savoir-faire Linux Inc.
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
@@ -118,4 +118,4 @@ 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.
It is independent from another (now extinct) project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005).
+23 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -132,8 +132,12 @@ void dht_value_set_user_type(dht_value* data, const char* user_type) {
(*reinterpret_cast<ValueSp*>(data))->user_type = user_type;
}
dht_value* dht_value_with_id_new(const uint8_t* data, size_t size, uint64_t value_id) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(dht::ValueType::USER_DATA.id, data, size, value_id)));
}
dht_value* dht_value_new(const uint8_t* data, size_t size) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
return dht_value_with_id_new(data, size, 0);
}
dht_value* dht_value_new_from_string(const char* str) {
@@ -325,12 +329,13 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
try {
dht::DhtRunner::Config config;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.maintain_storage = conf->dht_config.node_config.maintain_storage;
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path) : std::string{};
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path)
: std::string{};
if (conf->dht_config.id.privatekey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privatekey);
@@ -338,15 +343,18 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
if (conf->dht_config.id.certificate)
config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
config.threaded = conf->threaded;
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.threaded = conf->threaded;
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.proxy_user_agent = conf->proxy_user_agent ? std::string(conf->proxy_user_agent) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
if (conf->server_ca)
config.server_ca = *reinterpret_cast<const CertSp*>(conf->server_ca);
config.client_identity = dht_identity_from_c(&conf->client_identity);
dht::DhtRunner::Context context;
if (conf->log) {
+3 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -91,7 +91,7 @@ OPENDHT_C_PUBLIC dht_pkid dht_certificate_get_long_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_publickey* dht_certificate_get_publickey(const dht_certificate*);
OPENDHT_C_PUBLIC void dht_certificate_delete(dht_certificate*);
struct OPENDHT_PUBLIC dht_identity {
struct OPENDHT_C_PUBLIC dht_identity {
dht_privatekey* privatekey;
dht_certificate* certificate;
};
@@ -104,6 +104,7 @@ struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_with_id_new(const uint8_t* data, size_t size, uint64_t value_id);
OPENDHT_C_PUBLIC dht_value* dht_value_new_from_string(const char* str);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
+31 -8
View File
@@ -49,10 +49,15 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
if(HAVE_LIBATOMIC)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
endif()
@@ -65,14 +70,32 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
if(HAVE_CXX_LIBATOMICS64)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
endif()
endif()
endif()
# Set variable LLVM_ATOMIC_LIB specifying flags for linking against libatomic.
if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB)
# Use options --push-state, --as-needed and --pop-state if linker is known to support them.
# Use single option -Wl of compiler driver to avoid incorrect re-ordering of options by CMake.
if(LLVM_LINKER_IS_GNULD OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD OR LLVM_LINKER_IS_MOLD)
set(LLVM_ATOMIC_LIB "-Wl,--push-state,--as-needed,-latomic,--pop-state")
else()
set(LLVM_ATOMIC_LIB "-latomic")
endif()
else()
set(LLVM_ATOMIC_LIB)
endif()
## TODO: This define is only used for the legacy atomic operations in
## llvm's Atomic.h, which should be replaced. Other code simply
## assumes C++11 <atomic> works.
+1 -1
View File
@@ -1,6 +1,6 @@
dnl define macros
m4_define([opendht_major_version], 3)
m4_define([opendht_minor_version], 2)
m4_define([opendht_minor_version], 4)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
+3 -3
View File
@@ -24,9 +24,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading 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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/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 . \
+3 -3
View File
@@ -17,9 +17,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading 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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/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 . \
+3 -3
View File
@@ -26,9 +26,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading 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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/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 . \
+3 -3
View File
@@ -24,9 +24,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading 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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/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 . \
+6 -6
View File
@@ -1,4 +1,4 @@
FROM ubuntu:22.04
FROM ubuntu:24.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake meson pkg-config \
libtool git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev python3-dev \
python3-setuptools libcppunit-dev python3-pip python3-build python3-virtualenv \
@@ -17,7 +17,7 @@ RUN apt-get update \
&& apt-get remove -y gcc g++ && apt-get autoremove -y \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN pip3 install Cython --break-system-packages
ENV CC cc
ENV CXX c++
@@ -28,9 +28,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading 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 \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/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 . \
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+15 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -163,6 +163,20 @@ struct OPENDHT_PUBLIC SecureDhtConfig
bool cert_cache_all {false};
};
enum class OPENDHT_PUBLIC PushNotificationResult: uint8_t {
/* success codes */
PutRefresh,
ListenRefresh,
Values,
ValuesExpired,
/* ignored/error codes */
IgnoredWrongSession = 0x80,
IgnoredNoOp,
IgnoredStopped,
IgnoredDisabled,
Error
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
using ValuesExport = std::pair<InfoHash, Blob>;
+8 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -512,12 +512,18 @@ struct OPENDHT_PUBLIC Certificate {
Blob getSerialNumber() const;
/** Read certificate full DN as described in RFC4514 */
std::string getDN() const;
/** Read certificate Common Name (CN) */
std::string getName() const;
/** Read certificate User ID (UID) */
std::string getUID() const;
/** Read certificate issuer DN as described in RFC4514 */
std::string getIssuerDN() const;
/** Read certificate issuer Common Name (CN) */
std::string getIssuerName() const;
@@ -748,7 +754,7 @@ OPENDHT_PUBLIC Blob aesGetSalt(const uint8_t* data, size_t data_length);
OPENDHT_PUBLIC Blob inline aesGetSalt(const Blob& data) {
return aesGetSalt(data.data(), data.size());
}
/** Get the encrypted data part of data password-encrypted with `aesEncrypt(data, password)` */
/** Get the encrypted data (ciphertext) part of data password-encrypted with `aesEncrypt(data, password)` */
OPENDHT_PUBLIC std::string_view aesGetEncrypted(const uint8_t* data, size_t data_length);
OPENDHT_PUBLIC std::string_view inline aesGetEncrypted(const Blob& data) {
return aesGetEncrypted(data.data(), data.size());
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 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
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+4 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -315,7 +315,9 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>&) override {
return PushNotificationResult::IgnoredDisabled;
}
void resubscribe(unsigned) {}
private:
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -262,7 +262,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
virtual PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
std::shared_ptr<Logger> logger_ {};
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -216,7 +216,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
+11 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -150,22 +150,22 @@ public:
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Push requests in the last " << print_duration(lastUpdated - serverStartTime) << ": "
<< "[Android: " << androidPush.toString() << "], "
<< "[iOS: " << iosPush.toString() << "], "
<< "[Unified: " << unifiedPush.toString() << "]" << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
auto ret = fmt::format("Listens: {}, Puts: {}, PushListeners: {}\n"
"Push requests in the last {}: [Android: {}], [iOS: {}], [Unified: {}]\n"
"Requests: {} per second.",
listenCount, putCount, pushListenersCount,
print_duration(lastUpdated - serverStartTime),
androidPush.toString(), iosPush.toString(), unifiedPush.toString(),
requestRate);
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
}
return ss.str();
return ret;
}
/**
+11 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -268,11 +268,17 @@ public:
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
}
[[deprecated("Use the shared_ptr version instead")]]
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb={}, bool permanent = false);
[[deprecated("Use the shared_ptr version instead")]]
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
void putEncrypted(InfoHash hash, const PkId& to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const PkId& to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
}
/**
* Insert known nodes to the routing table, without necessarly ping them.
@@ -384,7 +390,9 @@ public:
// securedht methods
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void findCertificate(PkId hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void registerCertificate(const std::shared_ptr<crypto::Certificate>& cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
/**
@@ -466,7 +474,7 @@ public:
/**
* Insert a push notification to process for OpenDHT
*/
void pushNotificationReceived(const std::map<std::string, std::string>& data);
std::future<PushNotificationResult> pushNotificationReceived(const std::map<std::string, std::string>& data);
/* Proxy server mothods */
void forwardAllMessages(bool forward);
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -72,7 +72,7 @@ class OPENDHT_PUBLIC Url
{
public:
Url() = default;
Url(const std::string& url);
Url(std::string_view url);
std::string url;
std::string protocol {"http"};
std::string host;
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
@@ -409,7 +409,7 @@ private:
/**
* This mutlimap contains all prefix insert in the tree in time order
* We could then delete the last one if there is too much node
* We could then delete the last one if there are too many nodes
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
+8 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -110,7 +110,7 @@ public:
bool operator!=(const Hash& h) const { return !(*this == h); }
bool operator<(const Hash& o) const {
for(unsigned i = 0; i < N; i++) {
for (unsigned i = 0; i < N; i++) {
if(data_[i] != o.data_[i])
return data_[i] < o.data_[i];
}
@@ -119,7 +119,7 @@ public:
Hash operator^(const Hash& o) const {
Hash result;
for(auto i = 0u; i < N; i++) {
for (auto i = 0u; i < N; i++) {
result[i] = data_[i] ^ o.data_[i];
}
return result;
@@ -345,8 +345,8 @@ Hash<N>::getRandom(Rd& rdev)
}
struct alignas(std::max_align_t) HexMap : public std::array<std::array<char, 2>, 256> {
HexMap() {
for (size_t i=0; i<size(); i++) {
constexpr HexMap() : std::array<std::array<char, 2>, 256>() {
for (size_t i = 0; i < size(); i++) {
auto& e = (*this)[i];
e[0] = hex_digits[(i >> 4) & 0x0F];
e[1] = hex_digits[i & 0x0F];
@@ -356,7 +356,7 @@ private:
static constexpr const char* hex_digits = "0123456789abcdef";
};
OPENDHT_PUBLIC extern const HexMap hex_map;
OPENDHT_PUBLIC constexpr HexMap hex_map = {};
inline std::string
toHex(const uint8_t* data, size_t size) {
@@ -380,10 +380,11 @@ Hash<N>::to_c_str() const
{
alignas(std::max_align_t) thread_local std::array<char, N*2+1> buf;
for (size_t i=0; i<N; i++) {
auto b = buf.data()+i*2;
auto b = buf.data() + i*2;
const auto& m = hex_map[data_[i]];
*((uint16_t*)b) = *((uint16_t*)&m);
}
buf[N*2] = '\0';
return buf.data();
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 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
+9 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -49,10 +49,10 @@ public:
* startDiscovery - Keep Listening data from the sender until node is joinned
* or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
void startDiscovery(std::string_view type, ServiceDiscoveredCallback callback);
template <typename T>
void startDiscovery(const std::string &type, std::function<void(T &&, SockAddr &&)> cb) {
void startDiscovery(std::string_view type, std::function<void(T &&, SockAddr &&)> cb) {
startDiscovery(type, [cb](msgpack::object &&ob, SockAddr &&addr) {
cb(ob.as<T>(), std::move(addr));
});
@@ -61,11 +61,11 @@ public:
/**
* 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);
void startPublish(std::string_view type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, std::string_view type, const msgpack::sbuffer &pack_buf);
template <typename T>
void startPublish(const std::string &type, const T &object) {
void startPublish(std::string_view type, const T &object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, buf);
@@ -79,13 +79,13 @@ public:
/**
* Remove possible callBack to discovery
*/
bool stopDiscovery(const std::string &type);
bool stopDiscovery(std::string_view type);
/**
* Remove different serivce message to send
*/
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
bool stopPublish(std::string_view type);
bool stopPublish(sa_family_t domain, std::string_view type);
void connectivityChanged();
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@ namespace proxy {
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+22 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -115,14 +115,20 @@ public:
* The operation will be immediate if the recipient' public key is known (otherwise it will be retrived first).
*/
void putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
[[deprecated("Use the shared_ptr version instead")]]
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
[[deprecated("Use the shared_ptr version instead")]]
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
void putEncrypted(const InfoHash& hash, const PkId& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
/**
* Take ownership of the value and sign it using our private key.
*/
@@ -135,12 +141,17 @@ public:
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb);
Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
void findCertificate(const PkId& id, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const PkId& id, const std::function<void(const Sp<crypto::PublicKey>)>& cb);
void registerCertificate(const Sp<crypto::Certificate>& cert);
Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
Sp<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
Sp<crypto::Certificate> getCertificate(const PkId& node) const;
Sp<crypto::PublicKey> getPublicKey(const PkId& node) const;
/**
* Allows to set a custom callback called by the library to find a locally-stored certificate.
* The search key used is the public key ID, so there may be multiple certificates retured, signed with
@@ -328,8 +339,8 @@ public:
* Call linked callback with push_notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
dht_->pushNotificationReceived(notification);
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
return dht_->pushNotificationReceived(notification);
}
void setLogger(const Logger& logger) override {
@@ -360,6 +371,9 @@ private:
ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
Sp<crypto::Certificate> registerCertificate(const PkId& node, const Blob& cert);
Sp<crypto::PrivateKey> key_ {};
Sp<crypto::Certificate> certificate_ {};
@@ -369,6 +383,8 @@ private:
// our certificate cache
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, Sp<crypto::PublicKey>> nodesPubKeys_ {};
std::map<PkId, Sp<crypto::Certificate>> nodesCertificatesLong_ {};
std::map<PkId, Sp<crypto::PublicKey>> nodesPubKeysLong_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
@@ -387,7 +403,7 @@ const ValueType CERTIFICATE_TYPE = {
},
[](InfoHash, const Sp<Value>& o, Sp<Value>& n, const InfoHash&, const SockAddr&) {
try {
return crypto::Certificate(o->data).getPublicKey().getId() == crypto::Certificate(n->data).getPublicKey().getId();
return crypto::Certificate(o->data).getPublicKey().getLongId() == crypto::Certificate(n->data).getPublicKey().getLongId();
} catch (const std::exception& e) {}
return false;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+10 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "def.h"
#include <msgpack.hpp>
#include <fmt/format.h>
#include <chrono>
#include <random>
@@ -60,7 +61,7 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
* Split "[host]:port" or "host:port" to pair<"host", "port">.
*/
OPENDHT_PUBLIC std::pair<std::string, std::string>
splitPort(const std::string& s);
splitPort(std::string_view s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
@@ -84,37 +85,23 @@ using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
template <class DT>
static double
print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
template <class DT>
static std::string
print_duration(DT d) {
if (d < std::chrono::seconds(0)) {
return "-" + print_duration(-d);
} else if (d < std::chrono::milliseconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
return fmt::format("{:.3g} us", std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
} else if (d < std::chrono::seconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
return fmt::format("{:.3g} ms", std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
} else if (d < std::chrono::minutes(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
return fmt::format("{:.3g} s", std::chrono::duration_cast<std::chrono::duration<double>>(d).count());
} else if (d < std::chrono::hours(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
return fmt::format("{:.3g} min", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count());
} else if (d < std::chrono::hours(72)) {
return fmt::format("{:.3g} h", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count());
} else {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
return fmt::format("{:.3g} days", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
}
}
+1 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -137,8 +137,6 @@ private:
std::map<ValueType::Id, ValueType> types {};
};
struct CryptoValueCache;
/**
* A "value" is data potentially stored on the Dht, with some metadata.
*
+1 -1
View File
@@ -1,5 +1,5 @@
project('opendht', 'c', 'cpp', 'cython',
version: '3.2.0',
version: '3.4.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2014-2023 Savoir-faire Linux Inc.
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2023 Savoir-faire Linux Inc.
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2023 Savoir-faire Linux Inc.
# Copyright (C) 2014-2025 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 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
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 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
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
File renamed without changes.
File renamed without changes.
+66 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -646,7 +646,7 @@ GnuTLSFromType(NameType type)
}
static std::string
getDN(gnutls_x509_crq_t request, const char* oid)
readDN(gnutls_x509_crq_t request, const char* oid)
{
std::string dn;
dn.resize(512);
@@ -704,13 +704,13 @@ CertificateRequest::setName(const std::string& name)
std::string
CertificateRequest::getName() const
{
return getDN(request, GNUTLS_OID_X520_COMMON_NAME);
return readDN(request, GNUTLS_OID_X520_COMMON_NAME);
}
std::string
CertificateRequest::getUID() const
{
return getDN(request, GNUTLS_OID_LDAP_UID);
return readDN(request, GNUTLS_OID_LDAP_UID);
}
void
@@ -769,7 +769,21 @@ CertificateRequest::toString() const
// Certificate
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
readDN(gnutls_x509_crt_t cert, bool issuer = false)
{
gnutls_datum_t dn;
int err = issuer
? gnutls_x509_crt_get_issuer_dn3(cert, &dn, 0)
: gnutls_x509_crt_get_dn3( cert, &dn, 0);
if (err != GNUTLS_E_SUCCESS)
return {};
std::string ret((const char*)dn.data, dn.size);
gnutls_free(dn.data);
return ret;
}
static std::string
readDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
@@ -927,28 +941,40 @@ Certificate::getSerialNumber() const
return {serial, serial + size};
}
std::string
Certificate::getDN() const
{
return readDN(cert);
}
std::string
Certificate::getName() const
{
return getDN(cert, GNUTLS_OID_X520_COMMON_NAME);
return readDN(cert, GNUTLS_OID_X520_COMMON_NAME);
}
std::string
Certificate::getUID() const
{
return getDN(cert, GNUTLS_OID_LDAP_UID);
return readDN(cert, GNUTLS_OID_LDAP_UID);
}
std::string
Certificate::getIssuerDN() const
{
return readDN(cert, true);
}
std::string
Certificate::getIssuerName() const
{
return getDN(cert, GNUTLS_OID_X520_COMMON_NAME, true);
return readDN(cert, GNUTLS_OID_X520_COMMON_NAME, true);
}
std::string
Certificate::getIssuerUID() const
{
return getDN(cert, GNUTLS_OID_LDAP_UID, true);
return readDN(cert, GNUTLS_OID_LDAP_UID, true);
}
std::vector<std::pair<NameType, std::string>>
@@ -1475,7 +1501,22 @@ OcspResponse::getCertificateStatus() const
{
int ret;
unsigned int status;
// MSVC/vcpkg GnuTLS cast workaround
#if _WIN32 && (GNUTLS_VERSION_NUMBER >= 0x030807)
ret = gnutls_ocsp_resp_get_single(response,
0,
NULL,
NULL,
NULL,
NULL,
reinterpret_cast<gnutls_ocsp_cert_status_t*>(& status),
NULL,
NULL,
NULL,
NULL);
#else
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status, NULL, NULL, NULL, NULL);
#endif
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
return (gnutls_ocsp_cert_status_t) status;
@@ -1533,8 +1574,23 @@ OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce)
throw CryptoException(gnutls_strerror(ret));
// Check certificate revocation status
unsigned status_ocsp;
unsigned int status_ocsp;
// MSVC/vcpkg GnuTLS cast workaround
#if _WIN32 && (GNUTLS_VERSION_NUMBER >= 0x030807)
ret = gnutls_ocsp_resp_get_single(response,
0,
NULL,
NULL,
NULL,
NULL,
reinterpret_cast<gnutls_ocsp_cert_status_t*>(& status_ocsp),
NULL,
NULL,
NULL,
NULL);
#else
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status_ocsp, NULL, NULL, NULL, NULL);
#endif
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
return (gnutls_ocsp_cert_status_t)status_ocsp;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+69 -69
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -93,7 +93,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
r.second.done_cb(false, {});
sr.second->callbacks.clear();
for (const auto& a : sr.second->announce) {
if (a.callback) a.callback(false, {});
for (auto& cb : a.callbacks) cb(false, {});
}
sr.second->announce.clear();
sr.second->listeners.clear();
@@ -113,7 +113,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
auto str_donecb = [=](bool, const std::vector<Sp<Node>>&) {
--*remaining;
if (logger_)
logger_->w("shuting down node: %u ops remaining", *remaining);
logger_->w("Shutting down node: %u ops remaining", *remaining);
if (!*remaining && cb) { cb(); }
};
@@ -121,7 +121,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
*remaining += maintainStorage(str, true, str_donecb);
if (logger_)
logger_->w("shuting down node: after storage, %u ops", *remaining);
logger_->w("Shutting down node: after storage, %u ops", *remaining);
if (!*remaining) {
if (cb) cb();
@@ -147,7 +147,7 @@ Dht::sendCachedPing(Bucket& b)
{
if (b.cached)
if (logger_)
logger_->d(b.cached->id, "[node %s] sending ping to cached node", b.cached->toString().c_str());
logger_->d(b.cached->id, "[node %s] Sending ping to cached node", b.cached->toString().c_str());
b.sendCachedPing(network_engine);
}
@@ -280,7 +280,7 @@ Dht::expireSearches()
auto b = sr.callbacks.empty() && sr.announce.empty() && sr.listeners.empty() && sr.step_time < t;
if (b) {
if (logger_)
logger_->d(srp.first, "[search %s] removing search", srp.first.toString().c_str());
logger_->d(srp.first, "[search %s] Removing search", srp.first.toString().c_str());
sr.clear();
return b;
} else { return false; }
@@ -360,7 +360,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
auto query_for_vid = std::make_shared<Query>(Select {}, Where {}.id(vid));
sn->pagination_queries[query].push_back(query_for_vid);
if (logger_)
logger_->d(id, sn->node->id, "[search %s] [node %s] sending %s",
logger_->d(id, sn->node->id, "[search %s] [node %s] Sending %s",
id.toString().c_str(), sn->node->toString().c_str(), query_for_vid->toString().c_str());
sn->getStatus[query_for_vid] = network_engine.sendGetValues(status.node,
id,
@@ -371,8 +371,8 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
);
} catch (const std::out_of_range&) {
if (logger_)
logger_->e(id, sn->node->id, "[search %s] [node %s] received non-id field in response to "\
"'SELECT id' request...",
logger_->e(id, sn->node->id, "[search %s] [node %s] Received non-id field in response to "\
"'SELECT id' request…",
id.toString().c_str(), sn->node->toString().c_str());
}
}
@@ -381,7 +381,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
n->pagination_queries[query].push_back(select_q);
if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending %s",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending %s",
sr->id.toString().c_str(), n->node->toString().c_str(), select_q->toString().c_str());
n->getStatus[select_q] = network_engine.sendGetValues(n->node,
sr->id,
@@ -426,7 +426,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
return nullptr;
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'find_node'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'find_node'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendFindNode(n->node,
sr->id,
@@ -439,9 +439,9 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
continue;
if (query and not query->select.empty()) {
/* The request contains a select. No need to paginate... */
/* The request contains a select. No need to paginate… */
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'get'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'get'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendGetValues(n->node,
sr->id,
@@ -453,7 +453,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
paginate(ws, query, n);
}
/* We only try to send one request. return. */
/* We only attempt to send one request. Return. */
return n;
} while (++cb != sr->callbacks.end());
@@ -519,7 +519,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
/* only put the value if the node doesn't already have it */
if (not hasValue or seq_no < a.value->seq) {
if (logger_)
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto created = a.permanent ? time_point::max() : a.created;
acked = {
@@ -528,7 +528,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else if (hasValue and a.permanent) {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %016" PRIx64 ")",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Sending 'refresh' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
acked = {
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
@@ -540,7 +540,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
](const net::Request& /*req*/, net::DhtProtocolException&& e){
if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
if (auto sr = ws.lock()) {
if (auto sn = sr->getNode(node)) {
sn->acked[v->id] = {
@@ -558,7 +558,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %016" PRIx64 "). Aborting.",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Already has value (vid: %016" PRIx64 "). Aborting.",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto ack_req = std::make_shared<net::Request>(net::Request::State::COMPLETED);
ack_req->reply_time = now;
@@ -594,7 +594,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
sendQuery = true;
} else {
if (logger_)
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
logger_->w(sr->id, n.node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), n.node->toString().c_str(), a.value->id);
n.acked[a.value->id] = {
network_engine.sendAnnounceValue(n.node, sr->id, a.value, a.created, n.token, onDone, onExpired),
@@ -607,7 +607,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
if (sendQuery) {
n.probe_query = PROBE_QUERY;
if (logger_)
logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending %s",
logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending %s",
sr->id.toString().c_str(), n.node->toString().c_str(), n.probe_query->toString().c_str());
auto req = network_engine.sendGetValues(n.node,
sr->id,
@@ -634,7 +634,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
if (n.getListenTime(r, listenExp) > scheduler.time())
continue;
// if (logger_)
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending 'listen'",
// sr->id.toString().c_str(), n.node->toString().c_str());
if (r == n.listenStatus.end()) {
@@ -706,7 +706,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
auto syncLevel = preSynced ? level - MARGIN : 0;
/*if (auto req_count = sr->currentlySolicitedNodeCount())
if (logger_)
logger_->d(sr->id, "[search %s IPv%c] step (%d requests)",
logger_->d(sr->id, "[search %s IPv%c] Step (%d requests)",
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', req_count);*/
sr->step_time = now;
@@ -787,7 +787,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
if (sr->getNumberOfConsecutiveBadNodes() >= std::min<size_t>(sr->nodes.size(), SEARCH_MAX_BAD_NODES))
{
if (logger_)
logger_->w(sr->id, "[search %s IPv%c] expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
logger_->w(sr->id, "[search %s IPv%c] Expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
sr->expire();
if (not public_stable)
connectivityChanged(sr->af);
@@ -804,7 +804,7 @@ unsigned Dht::refill(Dht::Search& sr) {
if (cached_nodes.empty()) {
if (logger_)
logger_->e(sr.id, "[search %s IPv%c] no nodes from cache while refilling search",
logger_->e(sr.id, "[search %s IPv%c] No nodes from cache while refilling search",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6');
return 0;
}
@@ -816,7 +816,7 @@ unsigned Dht::refill(Dht::Search& sr) {
++inserted;
}
if (logger_)
logger_->d(sr.id, "[search %s IPv%c] refilled search with %u nodes from node cache",
logger_->d(sr.id, "[search %s IPv%c] Refilled search with %u nodes from node cache",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6', inserted);
return inserted;
}
@@ -828,7 +828,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
{
if (!isRunning(af)) {
if (logger_)
logger_->e(id, "[search %s IPv%c] unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] Unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (dcb)
dcb(false, {});
return {};
@@ -856,7 +856,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
}
if (not sr) {
if (logger_)
logger_->e(id, "[search %s IPv%c] maximum number of searches reached !", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] Maximum number of searches reached!", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
return {};
}
}
@@ -870,7 +870,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
sr->nodes.reserve(SEARCH_NODES+1);
sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr<Search>(sr)));
if (logger_)
logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] New search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (search_id == 0)
search_id++;
}
@@ -904,16 +904,16 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
{
if (!isRunning(af))
return 0;
// logger__ERR("[search %s IPv%c] search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_dt(tm-clock::now()));
// logger__ERR("[search %s IPv%c] Search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_duration(tm-clock::now()));
//logger__WARN("listenTo %s", id.toString().c_str());
auto& srs = searches(af);
auto srp = srs.find(id);
Sp<Search> sr = (srp == srs.end()) ? search(id, af) : srp->second;
if (!sr)
throw DhtException("Can't create search");
throw DhtException("Unable to create search");
if (logger_)
logger_->w(id, "[search %s IPv%c] listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] Listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
return sr->listen(cb, std::move(f), q, scheduler);
}
@@ -1022,7 +1022,7 @@ Dht::put(const InfoHash& id, Sp<Value> val, DoneCallback callback, time_point cr
storageStore(id, val, created, {}, permanent);
if (logger_)
logger_->d(id, "put: adding %s -> %s", id.toString().c_str(), val->toString().c_str());
logger_->d(id, "put: adding %s → %s", id.toString().c_str(), val->toString().c_str());
auto op = std::make_shared<OpStatus>();
auto donecb = [callback](const std::vector<Sp<Node>>& nodes, OpStatus& op) {
@@ -1265,7 +1265,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
vals.push_back(v);
if (not vals.empty()) {
if (logger_)
logger_->d(id, "[store %s] sending update local listener with token %lu",
logger_->d(id, "[store %s] Sending update local listener with token %lu",
id.toString().c_str(),
l.first);
cbs.emplace_back(l.second.get_cb, std::move(vals));
@@ -1286,7 +1286,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
if (f and not f(*v))
continue;
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
@@ -1392,7 +1392,7 @@ void
Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>>& values, size_t totalSize)
{
if (logger_)
logger_->d(id, "[store %s] discarded %ld values (%ld bytes)",
logger_->d(id, "[store %s] Discarded %ld values (%ld bytes)",
id.toString().c_str(), values.size(), totalSize);
total_store_size -= totalSize;
@@ -1410,7 +1410,7 @@ Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending expired",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -1432,7 +1432,7 @@ Dht::expireStore()
if (i->second.empty() && i->second.listeners.empty() && i->second.local_listeners.empty()) {
if (logger_)
logger_->d(i->first, "[store %s] discarding empty storage", i->first.toString().c_str());
logger_->d(i->first, "[store %s] Discarding empty storage", i->first.toString().c_str());
i = store.erase(i);
}
else
@@ -1900,7 +1900,7 @@ Dht::neighbourhoodMaintenance(RoutingTable& list)
auto n = q->randomNode(rd);
if (n) {
if (logger_)
logger_->d(id, n->id, "[node %s] sending [find %s] for neighborhood maintenance",
logger_->d(id, n->id, "[node %s] Sending [find %s] for neighborhood maintenance",
n->toString().c_str(), id.toString().c_str());
/* Since our node-id is the same in both DHTs, it's probably
profitable to query both families. */
@@ -1954,14 +1954,14 @@ Dht::bucketMaintenance(RoutingTable& list)
}
if (logger_)
logger_->d(id, n->id, "[node %s] sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
logger_->d(id, n->id, "[node %s] Sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
//auto start = scheduler.time();
network_engine.sendFindNode(n, id, want, nullptr, [this,n](const net::Request&, bool over) {
if (over) {
const auto& end = scheduler.time();
// using namespace std::chrono;
// if (logger_)
// logger_->d(n->id, "[node %s] bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
// logger_->d(n->id, "[node %s] Bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
scheduler.edit(nextNodesConfirmation, end + Node::MAX_RESPONSE_TIME);
}
});
@@ -1979,7 +1979,7 @@ Dht::dataPersistence(InfoHash id)
auto str = store.find(id);
if (str != store.end() and now > str->second.maintenance_time) {
if (logger_)
logger_->d(id, "[storage %s] maintenance (%u values, %u bytes)",
logger_->d(id, "[storage %s] Maintenance (%u values, %u bytes)",
id.toString().c_str(), str->second.valueCount(), str->second.totalSize());
maintainStorage(*str);
str->second.maintenance_time = now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
@@ -2033,7 +2033,7 @@ Dht::periodic(const uint8_t *buf, size_t buflen, SockAddr from, const time_point
network_engine.processMessage(buf, buflen, std::move(from));
} catch (const std::exception& e) {
if (logger_)
logger_->w("Can't process message: %s", e.what());
logger_->w("Unable to process message: %s", e.what());
}
}
return scheduler.run();
@@ -2087,7 +2087,7 @@ Dht::bootstrap()
}
} catch (const std::exception& e) {
if (logger_)
logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
logger_->e(myid, "Unable to resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
}
}
scheduler.cancel(bootstrapJob);
@@ -2118,12 +2118,12 @@ Dht::confirmNodes()
if (dht4.searches.empty() and dht4.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] initial IPv4 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] Initial IPv4 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET);
}
if (dht6.searches.empty() and dht6.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] initial IPv6 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] Initial IPv6 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET6);
}
@@ -2281,7 +2281,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
const auto& node = req->node;
if (e.getCode() == net::DhtProtocolException::UNAUTHORIZED) {
if (logger_)
logger_->e(node->id, "[node %s] token flush", node->toString().c_str());
logger_->e(node->id, "[node %s] Token flush", node->toString().c_str());
node->authError();
for (auto& srp : searches(node->getFamily())) {
auto& sr = srp.second;
@@ -2296,7 +2296,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
}
} else if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
node->cancelRequest(req);
}
}
@@ -2347,7 +2347,7 @@ Dht::onGetValues(Sp<Node> node, const InfoHash& hash, want_t, const Query& query
if (st != store.end() && not st->second.empty()) {
answer.values = st->second.get(query.where.getFilter());
if (logger_)
logger_->d(hash, "[node %s] sending %u values", node->toString().c_str(), answer.values.size());
logger_->d(hash, "[node %s] Sending %u values", node->toString().c_str(), answer.values.size());
}
return answer;
}
@@ -2359,18 +2359,18 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
{
if (not sr) {
if (logger_)
logger_->w("[search unknown] got reply to 'get'. Ignoring.");
logger_->w("[search unknown] Got reply to 'get'. Ignoring.");
return;
}
/* if (logger_)
logger_->d(sr->id, "[search %s] [node %s] got reply to 'get' with %u nodes",
logger_->d(sr->id, "[search %s] [node %s] Got reply to 'get' with %u nodes",
sr->id.toString().c_str(), node->toString().c_str(), a.nodes4.size()+a.nodes6.size());*/
if (not a.ntoken.empty()) {
if (not a.values.empty() or not a.fields.empty()) {
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] found %u values",
logger_->d(sr->id, node->id, "[search %s] [node %s] Found %u values",
sr->id.toString().c_str(), node->toString().c_str(), a.values.size());
for (auto& getp : sr->callbacks) { /* call all callbacks for this search */
auto& get = getp.second;
@@ -2419,7 +2419,7 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
}
} else {
if (logger_)
logger_->w(sr->id, "[node %s] no token provided. Ignoring response content.", node->toString().c_str());
logger_->w(sr->id, "[node %s] No token provided. Ignoring response content.", node->toString().c_str());
network_engine.blacklistNode(node);
}
@@ -2436,7 +2436,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
{
if (not hash) {
if (logger_)
logger_->w(node->id, "[node %s] listen with no info_hash", node->toString().c_str());
logger_->w(node->id, "[node %s] Listen with no info_hash", node->toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::LISTEN_NO_INFOHASH
@@ -2444,7 +2444,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
}
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::LISTEN_WRONG_TOKEN};
}
Query q = query;
@@ -2456,7 +2456,7 @@ void
Dht::onListenDone(const Sp<Node>& /* node */, net::RequestAnswer& /* answer */, Sp<Search>& sr)
{
// if (logger_)
// logger_->d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
// logger_->d(sr->id, node->id, "[search %s] [node %s] Got listen confirmation",
// sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
if (not sr->done) {
@@ -2476,7 +2476,7 @@ Dht::onAnnounce(Sp<Node> n,
auto& node = *n;
if (not hash) {
if (logger_)
logger_->w(node.id, "put with no info_hash");
logger_->w(node.id, "Put with no info_hash");
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_NO_INFOHASH
@@ -2484,7 +2484,7 @@ Dht::onAnnounce(Sp<Node> n,
}
if (!tokenMatch(token, node.getAddr())) {
if (logger_)
logger_->w(hash, node.id, "[node %s] incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
logger_->w(hash, node.id, "[node %s] Incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::PUT_WRONG_TOKEN};
}
{
@@ -2493,7 +2493,7 @@ Dht::onAnnounce(Sp<Node> n,
auto closest_nodes = buckets(node.getFamily()).findClosestNodes(hash, scheduler.time(), SEARCH_NODES);
if (closest_nodes.size() >= TARGET_NODES and hash.xorCmp(closest_nodes.back()->id, myid) < 0) {
if (logger_)
logger_->w(hash, node.id, "[node %s] announce too far from the target. Dropping value.", node.toString().c_str());
logger_->w(hash, node.id, "[node %s] Announce too far from the target. Dropping value.", node.toString().c_str());
return {};
}
}
@@ -2502,7 +2502,7 @@ Dht::onAnnounce(Sp<Node> n,
for (const auto& v : values) {
if (v->id == Value::INVALID_ID) {
if (logger_)
logger_->w(hash, node.id, "[value %s] incorrect value id", hash.toString().c_str());
logger_->w(hash, node.id, "[value %s] Incorrect value id", hash.toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_INVALID_ID
@@ -2514,17 +2514,17 @@ Dht::onAnnounce(Sp<Node> n,
if (*lv == *vc) {
storageRefresh(hash, v->id);
if (logger_)
logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
logger_->d(hash, node.id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
} else {
const auto& type = getType(lv->type);
if (type.editPolicy(hash, lv, vc, node.id, node.getAddr())) {
if (logger_)
logger_->d(hash, node.id, "[store %s] editing %s",
logger_->d(hash, node.id, "[store %s] Editing %s",
hash.toString().c_str(), vc->toString().c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] rejecting edition of %s because of storage policy",
logger_->d(hash, node.id, "[store %s] Rejecting edition of %s because of storage policy",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2533,11 +2533,11 @@ Dht::onAnnounce(Sp<Node> n,
const auto& type = getType(vc->type);
if (type.storePolicy(hash, vc, node.id, node.getAddr())) {
// if (logger_)
// logger_->d(hash, node.id, "[store %s] storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
// logger_->d(hash, node.id, "[store %s] Storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] rejecting storage of %s",
logger_->d(hash, node.id, "[store %s] Rejecting storage of %s",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2552,15 +2552,15 @@ Dht::onRefresh(Sp<Node> node, const InfoHash& hash, const Blob& token, const Val
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
throw DhtProtocolException {DhtProtocolException::UNAUTHORIZED, DhtProtocolException::PUT_WRONG_TOKEN};
}
if (storageRefresh(hash, vid)) {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
logger_->d(hash, node->id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
} else {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] got refresh for unknown value",
logger_->d(hash, node->id, "[store %s] [node %s] Got refresh for unknown value",
hash.toString().c_str(), node->toString().c_str());
throw DhtProtocolException {DhtProtocolException::NOT_FOUND, DhtProtocolException::STORAGE_NOT_FOUND};
}
@@ -2583,7 +2583,7 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending refresh",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending refresh",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -2608,7 +2608,7 @@ void
Dht::onAnnounceDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>& sr)
{
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] got reply to put!",
logger_->d(sr->id, node->id, "[search %s] [node %s] Got reply to put!",
sr->id.toString().c_str(), node->toString().c_str());
searchSendGetValues(sr);
sr->checkAnnounced(answer.vid);
+15 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -813,8 +813,8 @@ SockAddr
DhtProxyClient::parsePublicAddress(const Json::Value& val)
{
auto public_ip = val.asString();
auto hostAndService = splitPort(public_ip);
auto sa = SockAddr::resolve(hostAndService.first);
auto [host, service] = splitPort(public_ip);
auto sa = SockAddr::resolve(host);
if (sa.empty()) return {};
return sa.front().getMappedIPv4();
}
@@ -1233,9 +1233,10 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
}
}
void
PushNotificationResult
DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& notification)
{
auto ret = PushNotificationResult::IgnoredNoOp;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
{
// If a push notification is received, the proxy is up and running
@@ -1252,7 +1253,7 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
if (sessionId != notification.end() and sessionId->second != pushSessionId_) {
if (logger_)
logger_->d("[proxy:client] [push] ignoring push for other session");
return;
return PushNotificationResult::IgnoredWrongSession;
}
std::lock_guard<std::mutex> lock(searchLock_);
auto timeout = notification.find("timeout");
@@ -1269,10 +1270,12 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
else
put.refreshPutTimer->expires_at(std::chrono::steady_clock::now());
put.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, vid));
ret = PushNotificationResult::PutRefresh;
} else {
// Refresh listen
for (auto& list : search.listeners)
resubscribe(key, list.first, list.second);
ret = search.listeners.empty() ? PushNotificationResult::IgnoredNoOp : PushNotificationResult::ListenRefresh;
}
} else {
auto key = InfoHash(notification.at("key"));
@@ -1281,12 +1284,12 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
sendTime = system_clock::time_point(std::chrono::milliseconds(std::stoull(notification.at("t"))));
} catch (...) {}
auto& search = searches_.at(key);
auto expired = notification.find("exp");
for (auto& list : search.listeners) {
if (list.second.opstate->stop)
continue;
if (logger_)
logger_->d("[proxy:client] [push] [search %s] received", key.to_c_str());
auto expired = notification.find("exp");
auto token = list.first;
auto opstate = list.second.opstate;
if (expired == notification.end()) {
@@ -1299,6 +1302,7 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
// present in the new list
cb(oldValues, true, sendTime);
});
ret = PushNotificationResult::Values;
} else {
std::stringstream ss(expired->second);
std::vector<Value::Id> ids;
@@ -1324,16 +1328,21 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
});
}
launchLoop = true;
ret = PushNotificationResult::ValuesExpired;
}
}
}
} catch (const std::out_of_range& e) {
ret = PushNotificationResult::IgnoredNoOp;
} catch (const std::exception& e) {
if (logger_)
logger_->e("[proxy:client] [push] receive error: %s", e.what());
ret = PushNotificationResult::Error;
}
if (launchLoop)
loopSignal_();
#endif
return ret;
}
void
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -631,6 +631,8 @@ DhtProxyServer::createRestRouter()
router->http_get("/key/:hash", std::bind(&DhtProxyServer::get, this, _1, _2));
// key.post
router->http_post("/key/:hash", std::bind(&DhtProxyServer::put, this, _1, _2));
router->add_handler(restinio::http_method_options(),
"/key/:hash/listen", std::bind(&DhtProxyServer::options, this, _1, _2));
// key.listen
router->http_get("/key/:hash/listen", std::bind(&DhtProxyServer::listen, this, _1, _2));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
+53 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -36,7 +36,9 @@
namespace dht {
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
using namespace std::literals;
constexpr auto PEER_DISCOVERY_DHT_SERVICE = "dht"sv;
struct NodeInsertionPack {
dht::InfoHash nodeId;
@@ -619,7 +621,7 @@ DhtRunner::getPublicAddress(std::function<void(std::vector<SockAddr>&&)> cb, sa_
}
void
DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
DhtRunner::registerCertificate(const std::shared_ptr<crypto::Certificate>& cert) {
std::lock_guard<std::mutex> lck(dht_mtx);
dht_->registerCertificate(cert);
}
@@ -888,6 +890,25 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(InfoHash hash, const PkId& to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
@@ -1077,6 +1098,23 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Ce
cv.notify_all();
}
void DhtRunner::findCertificate(PkId hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)> cb)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
return;
}
ongoing_ops++;
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
cb(crt);
opEnded();
});
});
cv.notify_all();
}
void
DhtRunner::resetDht()
{
@@ -1186,18 +1224,25 @@ DhtRunner::setPushNotificationPlatform(const std::string& platform) {
#endif
}
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
std::future<PushNotificationResult>
DhtRunner::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& data)
{
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
auto ret_token = std::make_shared<std::promise<PushNotificationResult>>();
auto future = ret_token->get_future();
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) {
pending_ops_prio.emplace([ret_token, this, data](SecureDht&) {
if (dht_)
dht_->pushNotificationReceived(data);
ret_token->set_value(dht_->pushNotificationReceived(data));
else
ret_token->set_value(PushNotificationResult::IgnoredStopped);
});
cv.notify_all();
return future;
#else
(void) data;
std::promise<PushNotificationResult> p {};
p.set_value(PushNotificationResult::IgnoredDisabled);
return p.get_future();
#endif
}
+29 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -54,7 +54,7 @@ constexpr const char HTTPS_PROTOCOL[] = "https://";
constexpr const char ORIGIN_PROTOCOL[] = "//";
constexpr unsigned MAX_REDIRECTS {5};
Url::Url(const std::string& url): url(url)
Url::Url(std::string_view url): url(url)
{
size_t addr_begin = 0;
// protocol
@@ -69,10 +69,9 @@ Url::Url(const std::string& url): url(url)
size_t addr_size = url.substr(addr_begin).find("/");
if (addr_size == std::string::npos)
addr_size = url.size() - addr_begin;
auto host_service = splitPort(url.substr(addr_begin, addr_size));
host = host_service.first;
if (!host_service.second.empty())
service = host_service.second;
auto [h, s] = splitPort(url.substr(addr_begin, addr_size));
host = std::move(h);
service = std::move(s);
// target, query and fragment
size_t query_begin = url.find("?");
auto addr_end = addr_begin + addr_size;
@@ -457,7 +456,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
}
// starts from CA and goes down the presented chain
auto verifier = asio::ssl::rfc2818_verification(hostname);
auto verifier = asio::ssl::host_name_verification(hostname);
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)
@@ -592,12 +591,12 @@ Connection::async_write(BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
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); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -605,12 +604,12 @@ Connection::async_read_until(const char* delim, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
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); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -618,12 +617,12 @@ Connection::async_read_until(char delim, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
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); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -631,12 +630,12 @@ Connection::async_read(size_t bytes, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
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); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -644,7 +643,7 @@ Connection::async_read_some(size_t bytes, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
auto buf = read_buf_.prepare(bytes);
@@ -819,10 +818,21 @@ Resolver::add_callback(ResolverCb cb, sa_family_t family)
}
void
Resolver::resolve(const std::string& host, const std::string& service)
Resolver::resolve(const std::string& host, const std::string& serviceName)
{
asio::ip::tcp::resolver::query query_(host, service);
resolver_.async_resolve(query_, [this, host, service, destroyed = destroyed_]
auto service = serviceName;
// The async_resolve function used below typically relies on the contents of the
// /etc/services (Linux/POSIX) or c:\windows\system32\drivers\etc\services (Windows)
// file in order to resolve a descriptive service name into a port number. A
// resolution attempt that would otherwise succeed can therefore fail if the file
// is inaccessible or corrupted (which is rare but can happen in practice). We
// hardcode the port numbers for http and https to prevent this failure mode.
if (service == "http") {
service = "80";
} else if (service == "https") {
service = "443";
}
resolver_.async_resolve(host, service, [this, host, service, destroyed = destroyed_]
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
{
if (ec == asio::error::operation_aborted or *destroyed)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+22 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -526,8 +526,13 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find socket", msg->id};
node->received(now, {});
onNewNode(node, 2);
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
}
else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) {
auto rsocket = node->getSocket(msg->tid);
@@ -590,13 +595,22 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
r.node->authSuccess();
}
r.reply_time = scheduler.time();
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
try {
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
break;
} else { /* request socket data */
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
}
break;
default:
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+28 -24
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
@@ -42,13 +42,13 @@ public:
DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext = {}, Sp<Logger> logger = {});
~DomainPeerDiscovery();
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startDiscovery(std::string_view type, ServiceDiscoveredCallback callback);
void startPublish(std::string_view type, const msgpack::sbuffer &pack_buf);
void stop();
bool stopDiscovery(const std::string &type);
bool stopPublish(const std::string &type);
bool stopDiscovery(std::string_view type);
bool stopPublish(std::string_view type);
void connectivityChanged();
@@ -75,7 +75,7 @@ private:
asio::ip::udp::endpoint receiveFrom_;
msgpack::sbuffer sbuf_;
std::map<std::string, msgpack::sbuffer> messages_;
std::map<std::string, msgpack::sbuffer, std::less<>> messages_;
std::map<std::string, ServiceDiscoveredCallback, std::less<>> callbackmap_;
bool lrunning_ {false};
bool drunning_ {false};
@@ -97,7 +97,7 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
, ioContext_(ioContext)
, peerDiscoveryTimer(*ioContext_)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
, sockAddrSend_(asio::ip::make_address(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
{
try {
@@ -133,13 +133,13 @@ PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
}
void
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
PeerDiscovery::DomainPeerDiscovery::startDiscovery(std::string_view type, ServiceDiscoveredCallback callback)
{
std::lock_guard<std::mutex> lck(dmtx_);
callbackmap_[type] = callback;
callbackmap_[std::string(type)] = callback;
if (not drunning_) {
drunning_ = true;
ioContext_->post([this] () {
asio::post(*ioContext_, [this] () {
loopListener();
query(sockAddrSend_);
});
@@ -236,23 +236,25 @@ PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
void
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
PeerDiscovery::DomainPeerDiscovery::startPublish(std::string_view type, const msgpack::sbuffer &pack_buf)
{
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);
messages_[std::string(type)] = std::move(pack_buf_c);
reloadMessages();
lrunning_ = true;
ioContext_->post([this] () { publish(sockAddrSend_); });
asio::post(*ioContext_, [this] () { publish(sockAddrSend_); });
}
bool
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(std::string_view type)
{
std::lock_guard<std::mutex> lck(dmtx_);
if (callbackmap_.erase(type) > 0) {
auto it = callbackmap_.find(type);
if (it != callbackmap_.end()) {
callbackmap_.erase(it);
if (callbackmap_.empty())
stopDiscovery();
return true;
@@ -261,10 +263,12 @@ PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
}
bool
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
PeerDiscovery::DomainPeerDiscovery::stopPublish(std::string_view type)
{
std::lock_guard<std::mutex> lck(mtx_);
if (messages_.erase(type) > 0) {
auto it = messages_.find(type);
if (it != messages_.end()) {
messages_.erase(it);
if (messages_.empty())
stopPublish();
else
@@ -327,7 +331,7 @@ PeerDiscovery::DomainPeerDiscovery::reDiscover()
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
ioContext_->post([this] () {
asio::post(*ioContext_, [this] () {
reDiscover();
publish(sockAddrSend_);
});
@@ -397,21 +401,21 @@ PeerDiscovery::~PeerDiscovery() {
}
void
PeerDiscovery::startDiscovery(const std::string& type, ServiceDiscoveredCallback callback)
PeerDiscovery::startDiscovery(std::string_view type, ServiceDiscoveredCallback callback)
{
if (peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if (peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
}
void
PeerDiscovery::startPublish(const std::string& type, const msgpack::sbuffer& pack_buf)
PeerDiscovery::startPublish(std::string_view type, const msgpack::sbuffer& pack_buf)
{
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string& type, const msgpack::sbuffer& pack_buf)
PeerDiscovery::startPublish(sa_family_t domain, std::string_view type, const msgpack::sbuffer& pack_buf)
{
if (domain == AF_INET) {
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
@@ -428,7 +432,7 @@ PeerDiscovery::stop()
}
bool
PeerDiscovery::stopDiscovery(const std::string &type)
PeerDiscovery::stopDiscovery(std::string_view type)
{
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopDiscovery(type);
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopDiscovery(type);
@@ -436,7 +440,7 @@ PeerDiscovery::stopDiscovery(const std::string &type)
}
bool
PeerDiscovery::stopPublish(const std::string &type)
PeerDiscovery::stopPublish(std::string_view type)
{
bool stopped4 = peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
bool stopped6 = peerDiscovery6_ and peerDiscovery6_->stopPublish(type);
@@ -444,7 +448,7 @@ PeerDiscovery::stopPublish(const std::string &type)
}
bool
PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
PeerDiscovery::stopPublish(sa_family_t domain, std::string_view type)
{
if (domain == AF_INET) {
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+27 -20
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -45,7 +45,7 @@ struct Dht::Announce {
bool permanent;
Sp<Value> value;
time_point created;
DoneCallback callback;
std::vector<DoneCallback> callbacks;
};
struct Dht::SearchNode {
@@ -442,8 +442,9 @@ struct Dht::Search {
g.second.done_cb = {};
}
for (auto& a : announce) {
a.callback(false, {});
a.callback = {};
for (auto& cb : a.callbacks)
cb(false, {});
a.callbacks.clear();
}
}
@@ -627,7 +628,9 @@ struct Dht::Search {
return a.value->id == value->id;
});
if (a_sr == announce.end()) {
announce.emplace_back(Announce {permanent, value, created, callback});
auto& a = announce.emplace_back(Announce {permanent, value, created, {}} );
if (callback)
a.callbacks.emplace_back(std::move(callback));
for (auto& n : nodes) {
n->probe_query.reset();
n->acked[value->id].req.reset();
@@ -635,24 +638,26 @@ struct Dht::Search {
} else {
a_sr->permanent = permanent;
a_sr->created = created;
if (a_sr->value != value) {
if (a_sr->value != value && *a_sr->value != *value) {
// Value is updated, previous ops are failed
a_sr->value = value;
for (auto& n : nodes) {
n->acked[value->id].req.reset();
n->probe_query.reset();
}
}
if (isAnnounced(value->id)) {
if (a_sr->callback)
a_sr->callback(true, {});
a_sr->callback = {};
for (auto& cb: a_sr->callbacks)
cb(false, {});
a_sr->callbacks.clear();
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
} else if (isAnnounced(value->id)) {
// Same value, already announced
if (callback)
callback(true, {});
return;
} else {
if (a_sr->callback)
a_sr->callback(false, {});
a_sr->callback = callback;
// Same value, not announced yet
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
}
}
}
@@ -722,8 +727,8 @@ struct Dht::Search {
std::vector<DoneCallback> a_cbs;
a_cbs.reserve(announce.size());
for (auto ait = announce.begin() ; ait != announce.end(); ) {
if (ait->callback)
a_cbs.emplace_back(std::move(ait->callback));
a_cbs.insert(a_cbs.end(), std::make_move_iterator(ait->callbacks.begin()), std::make_move_iterator(ait->callbacks.end()));
ait->callbacks.clear();
if (not ait->permanent)
ait = announce.erase(ait);
else
@@ -747,9 +752,11 @@ struct Dht::Search {
if (vid != Value::INVALID_ID and (!a.value || a.value->id != vid))
return true;
if (isAnnounced(a.value->id)) {
if (a.callback) {
a.callback(true, getNodes());
a.callback = nullptr;
if (!a.callbacks.empty()) {
const auto& nodes = getNodes();
for (auto& cb : a.callbacks)
cb(true, nodes);
a.callbacks.clear();
}
if (not a.permanent)
return false;
+157 -16
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -50,9 +50,10 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf,
if (certificate_) {
auto certId = certificate_->getId();
if (key_ and certId != key_->getPublicKey().getId())
auto certLongId = certificate_->getLongId();
if (key_ and (certId != key_->getPublicKey().getId() or certLongId != key_->getPublicKey().getLongId()))
throw DhtException("SecureDht: provided certificate doesn't match private key.");
dht_->addOnConnectedCallback([this, certId, cb=std::move(iacb)]{
dht_->addOnConnectedCallback([this, certId, certLongId, cb=std::move(iacb)]{
dht_->put(certId, Value {
CERTIFICATE_TYPE,
*certificate_,
@@ -62,6 +63,15 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf,
if (logger_)
logger_->d(certId, "SecureDht: certificate announcement %s", ok ? "succeeded" : "failed");
}, {}, true);
dht_->put(InfoHash::get(certLongId), Value {
CERTIFICATE_TYPE,
*certificate_,
1
}, [this, cb=std::move(cb)](bool ok) {
if (cb) cb(ok);
if (logger_)
logger_->debug("SecureDht: certificate announcement {}", ok ? "succeeded" : "failed");
}, {}, true);
});
}
}
@@ -131,6 +141,30 @@ SecureDht::getPublicKey(const InfoHash& node) const
return it->second;
}
Sp<crypto::Certificate>
SecureDht::getCertificate(const PkId& node) const
{
if (node == getLongId())
return certificate_;
auto it = nodesCertificatesLong_.find(node);
if (it == nodesCertificatesLong_.end())
return nullptr;
else
return it->second;
}
Sp<crypto::PublicKey>
SecureDht::getPublicKey(const PkId& node) const
{
if (node == getLongId())
return certificate_->getSharedPublicKey();
auto it = nodesPubKeysLong_.find(node);
if (it == nodesPubKeysLong_.end())
return nullptr;
else
return it->second;
}
Sp<crypto::Certificate>
SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
{
@@ -143,25 +177,44 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
InfoHash h = crt->getPublicKey().getId();
if (node == h) {
if (logger_)
logger_->d("Registering certificate for %s", h.toString().c_str());
auto it = nodesCertificates_.find(h);
if (it == nodesCertificates_.end())
std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
else
it->second = std::move(crt);
return it->second;
logger_->debug("Registering certificate for {}", h.toString());
registerCertificate(crt);
return crt;
} else {
if (logger_)
logger_->w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
logger_->w("Certificate {} for node {} does not match node id !", h.toString(), node.toString());
return nullptr;
}
}
Sp<crypto::Certificate>
SecureDht::registerCertificate(const PkId& node, const Blob& data)
{
Sp<crypto::Certificate> crt;
try {
crt = std::make_shared<crypto::Certificate>(data);
} catch (const std::exception& e) {
return nullptr;
}
auto h = crt->getPublicKey().getLongId();
if (node == h) {
if (logger_)
logger_->debug("Registering certificate for {}", h.toString());
registerCertificate(crt);
return crt;
} else {
if (logger_)
logger_->w("Certificate {} for node {} does not match node id !", h.toString(), node.toString());
return nullptr;
}
}
void
SecureDht::registerCertificate(Sp<crypto::Certificate>& cert)
SecureDht::registerCertificate(const Sp<crypto::Certificate>& cert)
{
if (cert)
if (cert) {
nodesCertificates_[cert->getId()] = cert;
nodesCertificatesLong_[cert->getLongId()] = cert;
}
}
void
@@ -222,6 +275,63 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
auto pk = crt->getSharedPublicKey();
if (*pk) {
nodesPubKeys_[pk->getId()] = pk;
nodesPubKeysLong_[pk->getLongId()] = pk;
if (cb) cb(pk);
return;
}
}
if (cb) cb(nullptr);
});
}
void
SecureDht::findCertificate(const PkId& node, const std::function<void(const Sp<crypto::Certificate>)>& cb)
{
Sp<crypto::Certificate> b = getCertificate(node);
if (b && *b) {
if (logger_)
logger_->debug("Using certificate from cache for {}", node.to_c_str());
if (cb)
cb(b);
return;
}
auto found = std::make_shared<bool>(false);
dht_->get(InfoHash::get(node), [cb,node,found,this](const std::vector<Sp<Value>>& vals) {
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->debug("Found certificate for {}", node.to_c_str());
if (cb)
cb(cert);
return false;
}
}
return !*found;
}, [cb,found](bool) {
if (!*found and cb)
cb(nullptr);
}, Value::TypeFilter(CERTIFICATE_TYPE));
}
void
SecureDht::findPublicKey(const PkId& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
if (logger_)
logger_->debug("Found public key from cache for {}", node.to_c_str());
if (cb)
cb(pk);
return;
}
findCertificate(node, [=](const Sp<crypto::Certificate>& crt) {
if (crt && *crt) {
auto pk = crt->getSharedPublicKey();
if (*pk) {
nodesPubKeys_[pk->getId()] = pk;
nodesPubKeysLong_[pk->getLongId()] = pk;
if (cb) cb(pk);
return;
}
@@ -246,8 +356,10 @@ SecureDht::checkValue(const Sp<Value>& v)
auto isDecrypted = v->isDecrypted();
if (auto decrypted_val = v->decrypt(*key_)) {
auto cacheValue = not isDecrypted and decrypted_val->owner;
if (cacheValue)
if (cacheValue) {
nodesPubKeys_[decrypted_val->owner->getId()] = decrypted_val->owner;
nodesPubKeysLong_[decrypted_val->owner->getLongId()] = decrypted_val->owner;
}
return decrypted_val;
}
} catch (const std::exception& e) {
@@ -259,8 +371,10 @@ SecureDht::checkValue(const Sp<Value>& v)
else if (v->isSigned()) {
auto cacheValue = not v->isSignatureChecked() and enableCache_ and v->owner;
if (v->checkSignature()) {
if (cacheValue)
if (cacheValue) {
nodesPubKeys_[v->owner->getId()] = v->owner;
nodesPubKeysLong_[v->owner->getLongId()] = v->owner;
}
return v;
} else if (logger_)
logger_->w("Signature verification failed for %s", v->toString().c_str());
@@ -401,6 +515,33 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const PkId& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp<crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->warn("Encrypting data for PK: {}", pk->getLongId());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp<Value> val, DoneCallback callback, bool permanent)
{
@@ -410,7 +551,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp<Va
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk.getLongId().to_c_str());
logger_->warn("Encrypting data for PK: {}", pk.getLongId());
try {
dht_->put(hash, encrypt(*val, pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -224,7 +224,7 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
//DHT_LOG.DEBUG("Updating %s -> %s", id.toString().c_str(), value->toString().c_str());
// clear quota for previous value
if (it->store_bucket)
it->store_bucket->erase(id, *value, it->expiration);
it->store_bucket->erase(id, *it->data, it->expiration);
it->expiration = expiration;
// update quota for new value
it->store_bucket = sb;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+10 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -39,28 +39,26 @@ 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) {
splitPort(std::string_view s) {
if (s.empty())
return {};
if (s[0] == '[') {
std::size_t closure = s.find_first_of(']');
std::size_t found = s.find_last_of(':');
if (closure == std::string::npos)
return {s, ""};
if (found == std::string::npos or found < closure)
return {s.substr(1,closure-1), ""};
return {s.substr(1,closure-1), s.substr(found+1)};
if (closure == std::string_view::npos)
return {std::string(s), ""};
if (found == std::string_view::npos or found < closure)
return {std::string(s.substr(1,closure-1)), ""};
return {std::string(s.substr(1,closure-1)), std::string(s.substr(found+1))};
}
std::size_t found = s.find_last_of(':');
std::size_t first = s.find_first_of(':');
if (found == std::string::npos or found != first)
return {s, ""};
return {s.substr(0,found), s.substr(found+1)};
if (found == std::string_view::npos or found != first)
return {std::string(s), ""};
return {std::string(s.substr(0,found)), std::string(s.substr(found+1))};
}
std::vector<SockAddr>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 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
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
+56 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -90,6 +90,59 @@ DhtRunnerTester::testGetPut() {
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutDuplicate() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("hey");
val->id = 42;
auto val_data = val->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutOverride() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("meh");
val->id = 42;
auto val2 = std::make_shared<dht::Value>("hey");
val2->id = 42;
CPPUNIT_ASSERT_EQUAL(val->id, val2->id);
auto val_data = val2->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val2, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(!p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testListen() {
std::mutex mutex;
@@ -305,7 +358,8 @@ DhtRunnerTester::testIdOps() {
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7 && valueCountEdit == 2; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCountEdit == 2; }));
}
// editValue->data = dht::packMsg("v2");
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff. Show more