Compare commits

..
Author SHA1 Message Date
Adrien Beraud 95f3920ca8 ci/github: cleanup 2023-03-25 18:27:19 -04:00
Adrien Beraud 5f1e7952a4 Revert "more attempts to find msgpackc-cxx in a universal way"
This reverts commit 965fbb43c7.
2023-03-25 18:26:47 -04:00
147 changed files with 2136 additions and 3401 deletions

No files matched your search

+65 -129
View File
@@ -1,13 +1,5 @@
name: C/C++ CI
env:
LLHTTP_VERSION: "v9.2.1"
RESTINIO_VERSION: "0.7.3"
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:
@@ -15,142 +7,86 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- 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 project
run: |
./autogen.sh
./configure --enable-proxy-client
- name: Build
run: make
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
- name: Configure
run: |
./autogen.sh
./configure
- name: Build
run: make
build-ubuntu-meson:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- 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
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt install meson ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
- name: Configure
run: meson setup build .
- name: Build
run: cd build && ninja
build-ubuntu-minimal:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@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
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
- name: Configure
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DOPENDHT_TESTS=On -DOPENDHT_PEER_DISCOVERY=Off -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=Off -DOPENDHT_PROXY_CLIENT=Off
- name: Build
run: cd build && make
- name: Unit tests
run: cd build && ./opendht_unit_tests
build-macos:
name: macOS/Clang build
runs-on: macos-15
runs-on: macos-11
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Dependencies
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl http-parser cppunit
- 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/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz
ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz
cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none .
make -j8 && sudo make install
cd ../../.. && rm -rf restinio
- name: 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: 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 -DOPENDHT_TESTS=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 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*
- 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
+12 -19
View File
@@ -6,33 +6,26 @@ jobs:
name: Clang Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: deps
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev libasio-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev libasio-dev \
llvm llvm-dev clang clang-tools && \
sudo apt remove gcc g++
- name: expected-lite
run: |
sudo mkdir /usr/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/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 .
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && sudo make install \
&& cd ../../.. && rm -rf restinio
- name: cmake
run: |
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+32 -32
View File
@@ -25,10 +25,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -36,12 +36,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDeps
@@ -58,10 +58,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -69,13 +69,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile
@@ -92,10 +92,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -103,12 +103,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDepsLlvm
@@ -125,10 +125,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -136,13 +136,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileLlvm
@@ -159,10 +159,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -170,13 +170,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DHTNODE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDhtnode
@@ -193,10 +193,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -204,16 +204,16 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDepsAlpine
file: docker/DockerfileAlpineDeps
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
@@ -227,10 +227,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -238,13 +238,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileAlpine
@@ -262,7 +262,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: cmake
run: |
@@ -280,14 +280,14 @@ jobs:
- name: build
run: cd build && make dist
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: opendht-wheels-linux
path: build/python/dist/*.whl
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
with:
draft: true
files: build/python/dist/*.whl
+1 -1
View File
@@ -22,10 +22,10 @@
"${workspaceRoot}",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=On",
"-DCMAKE_BUILD_TYPE=Debug",
"-DBUILD_TESTING=On",
"-DOPENDHT_SANITIZE=On",
"-DOPENDHT_PROXY_CLIENT=On",
"-DOPENDHT_PROXY_SERVER=On",
"-DOPENDHT_TESTS=On",
"-DOPENDHT_C=On"
],
"dependsOn": "builddir"
+47 -96
View File
@@ -1,6 +1,9 @@
cmake_minimum_required (VERSION 3.16..3.28)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
cmake_minimum_required (VERSION 3.10..3.20)
if(POLICY CMP0073)
cmake_policy(SET CMP0073 NEW)
endif()
if(POLICY CMP0074)
cmake_policy(SET CMP0074 NEW)
endif()
project (opendht)
@@ -10,10 +13,9 @@ include(CheckIncludeFileCXX)
include(FindPkgConfig)
include(cmake/CheckAtomic.cmake)
include(CTest)
include(FetchContent)
set (opendht_VERSION_MAJOR 3)
set (opendht_VERSION_MINOR 3.0)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 5.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -21,6 +23,7 @@ set (VERSION "${opendht_VERSION}")
# Options
option (BUILD_SHARED_LIBS "Build shared library" ON)
CMAKE_DEPENDENT_OPTION (OPENDHT_STATIC "Build static library" OFF BUILD_SHARED_LIBS ON)
option (OPENDHT_LOG "Build with logs" ON)
option (OPENDHT_PYTHON "Build Python bindings" OFF)
option (OPENDHT_TOOLS "Build DHT tools" ON)
option (OPENDHT_SYSTEMD "Install systemd module" OFF)
@@ -33,7 +36,6 @@ 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)
@@ -46,9 +48,7 @@ set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED on)
# Dependencies
if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB
# For ARM EABI (armel), little-endian MIPS (mipsel), etc.
OR NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
link_libraries (atomic)
endif ()
@@ -59,16 +59,7 @@ if (NOT MSVC)
find_package (PkgConfig REQUIRED)
pkg_search_module (GnuTLS REQUIRED IMPORTED_TARGET gnutls)
pkg_search_module (Nettle REQUIRED IMPORTED_TARGET nettle)
check_include_file_cxx(msgpack.hpp HAVE_MSGPACKCXX)
if (NOT HAVE_MSGPACKCXX)
find_package(msgpack QUIET CONFIG NAMES msgpack msgpackc-cxx)
if (NOT msgpack_FOUND)
find_package(msgpack REQUIRED CONFIG NAMES msgpack-cxx)
set(MSGPACK_TARGET "msgpack-cxx")
else()
set(MSGPACK_TARGET "msgpackc-cxx")
endif()
endif()
find_package (msgpack REQUIRED NAMES msgpackc-cxx msgpack msgpack-cxx)
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
@@ -86,44 +77,15 @@ if (NOT MSVC)
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
message(STATUS "Found ASIO ${ASIO_INCLUDE_DIR}")
else()
message(STATUS "ASIO not required")
endif ()
find_package(fmt)
if (OPENDHT_HTTP)
find_package(Restinio REQUIRED)
# 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)
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()
set(http_lib "-lllhttp")
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
find_library(HTTP_PARSER_LIBRARY http_parser)
add_library(http_parser SHARED IMPORTED)
set(http_parser_lib "-lhttp_parser")
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
@@ -157,23 +119,19 @@ else ()
${WIN32_DEP_DIR}/openssl/include
${WIN32_DEP_DIR}/restinio/dev
${WIN32_DEP_DIR}/fmt/include
${WIN32_DEP_DIR}/llhttp/include
${WIN32_DEP_DIR}/http_parser
)
endif ()
endif ()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
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")
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")
endif ()
else ()
add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS
@@ -188,6 +146,11 @@ endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
add_definitions(-DPACKAGE_VERSION="${opendht_VERSION}")
if (OPENDHT_LOG)
add_definitions(-DOPENDHT_LOG=true)
else ()
add_definitions(-DOPENDHT_LOG=false)
endif()
if (ASIO_INCLUDE_DIR)
include_directories (SYSTEM "${ASIO_INCLUDE_DIR}")
@@ -206,8 +169,8 @@ include_directories (
include (GNUInstallDirs)
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix "\${prefix}")
set (libdir "${CMAKE_INSTALL_FULL_LIBDIR}")
set (includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
set (libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
set (includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
set (bindir "${CMAKE_INSTALL_FULL_BINDIR}")
set (sysconfdir "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
set (top_srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
@@ -241,7 +204,6 @@ list (APPEND opendht_SOURCES
)
list (APPEND opendht_HEADERS
include/opendht.h
include/opendht/def.h
include/opendht/utils.h
include/opendht/sockaddr.h
@@ -261,7 +223,7 @@ list (APPEND opendht_HEADERS
include/opendht/rate_limiter.h
include/opendht/securedht.h
include/opendht/log.h
include/opendht/logger.h
include/opendht/log_enable.h
include/opendht/thread_pool.h
include/opendht/network_utils.h
include/opendht.h
@@ -344,12 +306,12 @@ if (MSVC)
)
if (OPENDHT_HTTP)
add_obj_lib (win32_fmt ${WIN32_DEP_DIR}/fmt/msvc/Release/fmt.lib)
add_obj_lib (win32_llhttp ${WIN32_DEP_DIR}/llhttp/build/Release/llhttp.lib)
add_obj_lib (win32_http_parser ${WIN32_DEP_DIR}/http_parser/x64/Release/http-parser.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_llhttp>
$<TARGET_OBJECTS:win32_http_parser>
$<TARGET_OBJECTS:win32_ssl>
$<TARGET_OBJECTS:win32_crypto>
)
@@ -362,7 +324,7 @@ if (MSVC)
)
list (APPEND win32_Libs
${PROJECT_SOURCE_DIR}/../fmt/msvc/Release/fmt.lib
${PROJECT_SOURCE_DIR}/../llhttp/build/Release/llhttp.lib
${PROJECT_SOURCE_DIR}/../http_parser/x64/Release/http-parser.lib
${PROJECT_SOURCE_DIR}/../openssl/libssl.lib
${PROJECT_SOURCE_DIR}/../openssl/libcrypto.lib
)
@@ -377,43 +339,32 @@ add_library (opendht
${obj_libs}
)
set_target_properties (opendht PROPERTIES OUTPUT_NAME "opendht")
if (NOT HAVE_MSGPACKCXX)
target_link_libraries(opendht PUBLIC ${MSGPACK_TARGET})
target_link_libraries(opendht
PRIVATE
PkgConfig::argon2
PkgConfig::Nettle
${HTTP_PARSER_LIBRARY}
PUBLIC
${CMAKE_THREAD_LIBS_INIT}
PkgConfig::GnuTLS
msgpackc-cxx
${FMT_LIBRARY}
)
if (Jsoncpp_FOUND)
target_link_libraries(opendht PUBLIC PkgConfig::Jsoncpp)
endif()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (APPLE)
target_link_libraries(opendht PRIVATE "-framework CoreFoundation" "-framework Security")
target_link_libraries(opendht PRIVATE SYSTEM "-framework CoreFoundation" "-framework Security")
endif()
if (MSVC)
if (OPENDHT_STATIC)
target_link_libraries(opendht PUBLIC ${Win32_STATIC_LIBRARIES} ${Win32_IMPORT_LIBRARIES})
set_target_properties (opendht PROPERTIES OUTPUT_NAME "libopendht")
endif()
else()
target_link_libraries(opendht
PRIVATE
PkgConfig::argon2
PkgConfig::Nettle
PUBLIC
${CMAKE_THREAD_LIBS_INIT}
PkgConfig::GnuTLS
fmt::fmt
)
if (OPENDHT_HTTP)
target_link_libraries(opendht PUBLIC ${llhttp_target})
endif()
if (Jsoncpp_FOUND)
target_link_libraries(opendht PUBLIC PkgConfig::Jsoncpp)
endif()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (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)
endif()
endif()
endif ()
if (BUILD_SHARED_LIBS)
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
@@ -470,7 +421,7 @@ install (EXPORT opendht DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht FILE o
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/opendht)
# Unit tests
if (BUILD_TESTING AND NOT MSVC)
if (BUILD_TESTING)
pkg_search_module(Cppunit REQUIRED IMPORTED_TARGET cppunit)
# unit testing
list (APPEND test_FILES
+2 -9
View File
@@ -21,11 +21,6 @@ Values are distributed over the network, with redundancy.
## Documentation
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
#### How to run a node
You can help contributing to the public network by running a stable node with a public IP address.
https://github.com/savoirfairelinux/opendht/wiki/Running-a-node-with-dhtnode
#### How-to build and install
Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-library>
@@ -96,19 +91,17 @@ for r in results:
- msgpack-c 1.2+, used for data serialization.
- GnuTLS 3.3+, used for cryptographic operations.
- Nettle 2.4+, a GnuTLS dependency for crypto.
- {fmt} 9.0+, for log formatting.
- (optional) restinio used for the REST API.
- (optional) llhttp used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 7+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2019, 2022
- Build tested with Microsoft Visual Studio 2017, 2019, 2022
## Contact
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-2022 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.
+15 -24
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -132,12 +132,8 @@ 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 dht_value_with_id_new(data, size, 0);
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
}
dht_value* dht_value_new_from_string(const char* str) {
@@ -329,13 +325,12 @@ 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);
@@ -343,18 +338,14 @@ 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.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;
if (conf->server_ca)
config.server_ca = *reinterpret_cast<const CertSp*>(conf->server_ca);
config.client_identity = dht_identity_from_c(&conf->client_identity);
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.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
dht::DhtRunner::Context context;
if (conf->log) {
+1 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -104,7 +104,6 @@ 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*);
@@ -149,7 +148,6 @@ struct OPENDHT_PUBLIC dht_runner_config {
const char* push_token;
const char* push_topic;
const char* push_platform;
const char* proxy_user_agent;
bool peer_discovery;
bool peer_publish;
dht_certificate* server_ca;
+24 -19
View File
@@ -1,6 +1,6 @@
dnl define macros
m4_define([opendht_major_version], 3)
m4_define([opendht_minor_version], 3)
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 5)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -21,10 +21,10 @@ AS_IF([test "x$enable_debug" = "xyes"],
[CXXFLAGS="${CXXFLAGS} -g -Og -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -Wno-deprecated -pedantic-errors"],
[CXXFLAGS="${CXXFLAGS} -O3 -Wno-deprecated -pedantic-errors -fvisibility=hidden"])
CPPFLAGS="${CPPFLAGS} -DOPENDHT_BUILD"
CPPFLAGS+=" -DOPENDHT_BUILD"
AM_CONDITIONAL([OPENDHT_SHARED], [test "x$enable_shared" != xno])
AM_COND_IF(OPENDHT_SHARED, [
CPPFLAGS="${CPPFLAGS} -Dopendht_EXPORTS"
CPPFLAGS+=" -Dopendht_EXPORTS"
])
AM_PROG_AR
@@ -34,6 +34,12 @@ AC_LANG(C++)
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX(17,[noext],[mandatory])
dnl Check for logs
AC_ARG_ENABLE([logs], [AS_HELP_STRING([--disable-logs], [Disable DHT logs])])
AS_IF([test "x$enable_logs" != "xno"], [], [
AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are disabled])
])
dnl Check for C binding
AC_ARG_ENABLE([c], [AS_HELP_STRING([--disable-c], [Disable DHT C binding])])
AM_CONDITIONAL(ENABLE_C, test x$enable_c != "xno")
@@ -147,7 +153,7 @@ AS_IF([test "x$with_jsoncpp" != "xno"],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS="${CPPFLAGS} -DOPENDHT_JSONCPP"
CPPFLAGS+=" -DOPENDHT_JSONCPP"
AC_SUBST(jsoncpp_lib, [", jsoncpp"])
], [
AC_MSG_NOTICE([Not using JsonCpp])
@@ -165,21 +171,20 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_MSG_NOTICE([Not using OpenSSL])
])
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0], [have_fmt=yes], [have_fmt=no])
AS_IF([test "x$have_fmt" = "xyes"], [
AC_MSG_NOTICE([Using libfmt])
], [
AC_MSG_NOTICE([Missing libfmt files])
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp],, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
# llhttp has no pkgconfig, instead we check with:
AC_CHECK_LIB(llhttp, exit,, AC_MSG_ERROR([Missing llhttp library files]))
AC_CHECK_HEADERS([llhttp.h], [llhttp_headers=yes; break;])
AC_SUBST(http_lib, ["-lllhttp"])
AS_IF([test "x$llhttp_headers" != "xyes"], AC_MSG_ERROR([Missing llhttp headers files]))
PKG_CHECK_MODULES([Fmt], [fmt >= 5.3.0], [have_fmt=yes], [have_fmt=no])
AS_IF([test "x$have_fmt" = "xyes"], [
AC_MSG_NOTICE([Using libfmt])
], [
AC_MSG_NOTICE([Missing libfmt files])
])
# http_parser has no pkgconfig, instead we check with:
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
AC_SUBST(http_parser_lib, ["-lhttp_parser"])
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
@@ -194,8 +199,8 @@ AM_COND_IF([ENABLE_TOOLS], [
AM_COND_IF(ENABLE_PROXY_SERVER, AC_DEFINE([OPENDHT_PROXY_SERVER], [], [Building with proxy server]))
AM_COND_IF(ENABLE_PROXY_CLIENT, AC_DEFINE([OPENDHT_PROXY_CLIENT], [], [Building with proxy client]))
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS="${CPPFLAGS} -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS="${CPPFLAGS} -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
dnl Configure setup.py if we build the python module
AC_SUBST(CURRENT_SOURCE_DIR, ".")
+1 -2
View File
@@ -19,7 +19,7 @@
.SH DESCRIPTION
Runs an OpenDHT node, with a CLI (default) or as a daemon (with \fB'-d'\fP or \fB'-s'\fP).
Commands available in the interactive shell are:
.EX
.EE
h, help Print this help message.
q, quit Quit the program.
log Start/stop printing DHT logs.
@@ -39,7 +39,6 @@ Commands available in the interactive shell are:
private key.
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
its public key (if found).
.EE
.SH OPTIONS
.TP
\fB\-h\fP
+2 -3
View File
@@ -2,9 +2,8 @@ FROM ghcr.io/savoirfairelinux/opendht/opendht-deps:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN cd opendht && mkdir build && cd build \
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
+23 -3
View File
@@ -1,7 +1,27 @@
FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-alpine:latest AS build
FROM alpine:3.17 AS build
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN apk add --no-cache \
build-base cmake ninja git wget \
cython python3-dev py3-setuptools \
ncurses-dev readline-dev nettle-dev \
cppunit-dev gnutls-dev jsoncpp-dev \
argon2-dev openssl-dev fmt-dev \
http-parser-dev asio-dev msgpack-cxx-dev \
&& rm -rf /var/cache/apk/*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../.. && rm -rf restinio
COPY . opendht
RUN mkdir /install
@@ -19,7 +39,7 @@ RUN cd opendht && mkdir build && cd build \
-DOPENDHT_SYSTEMD=On \
&& make -j8 && make install
FROM alpine:3.19 AS install
FROM alpine:3.17 AS install
COPY --from=build /install /
RUN apk add --no-cache \
libstdc++ \
@@ -28,8 +48,8 @@ RUN apk add --no-cache \
openssl \
argon2-dev \
jsoncpp \
llhttp \
fmt \
http-parser \
readline \
ncurses
CMD ["dhtnode", "-b", "bootstrap.jami.net", "-p", "4222", "--proxyserver", "8080"]
+23
View File
@@ -0,0 +1,23 @@
FROM alpine:3.17
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN apk add --no-cache \
build-base cmake ninja git wget \
cython python3-dev py3-setuptools \
ncurses-dev readline-dev nettle-dev \
cppunit-dev gnutls-dev jsoncpp-dev \
argon2-dev openssl-dev fmt-dev \
http-parser-dev asio-dev msgpack-cxx-dev \
&& rm -rf /var/cache/apk/*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../.. && rm -rf restinio
+2 -3
View File
@@ -2,9 +2,8 @@ FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN cd opendht && mkdir build && cd build \
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
+10 -16
View File
@@ -10,25 +10,19 @@ RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y \
build-essential pkg-config cmake git wget \
libtool autotools-dev autoconf \
python3-pip python3-dev python3-setuptools python3-build python3-virtualenv \
cython3 python3-dev python3-setuptools python3-build python3-virtualenv \
libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \
libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \
libssl-dev libfmt-dev libasio-dev libmsgpack-dev \
libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/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 . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../.. && rm -rf restinio
-27
View File
@@ -1,27 +0,0 @@
FROM alpine:3.19
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
RUN apk add --no-cache \
build-base cmake ninja git wget \
cython python3-dev py3-setuptools \
ncurses-dev readline-dev nettle-dev \
cppunit-dev gnutls-dev jsoncpp-dev \
argon2-dev openssl-dev fmt-dev \
llhttp-dev asio-dev msgpack-cxx-dev \
&& rm -rf /var/cache/apk/*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/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 . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
+10 -14
View File
@@ -5,12 +5,12 @@ LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendh
RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
RUN apt-get update && apt-get install -y \
apt-transport-https build-essential pkg-config git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
libargon2-0-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libssl-dev python3-pip \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev python3-pip \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install --upgrade cmake meson Cython
RUN pip3 install --upgrade cmake
# libasio-dev (1.10) is too old
RUN echo "** Building a recent version of asio ***" \
@@ -20,17 +20,13 @@ RUN echo "** Building a recent version of asio ***" \
&& make install \
&& cd ../../ && rm -rf asio*
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/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 . \
&& make -j2 && make install \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
+10 -16
View File
@@ -10,25 +10,19 @@ RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y \
build-essential pkg-config cmake git wget \
libtool autotools-dev autoconf \
python3-dev python3-setuptools python3-pip \
cython3 python3-dev python3-setuptools \
libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \
libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \
libssl-dev libfmt-dev libasio-dev libmsgpack-dev \
libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/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 . \
&& make -j2 && make install \
&& cd ../../ && rm -rf restinio*
&& wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \
&& cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../.. && rm -rf restinio
+11 -17
View File
@@ -1,4 +1,4 @@
FROM ubuntu:24.04
FROM ubuntu:22.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -8,31 +8,25 @@ 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 meson pkg-config \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \
libtool git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev python3-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip python3-build python3-virtualenv \
autotools-dev autoconf libssl-dev libargon2-dev \
libfmt-dev libasio-dev \
libfmt-dev libhttp-parser-dev libasio-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install Cython --break-system-packages
ENV CC cc
ENV CXX c++
RUN mkdir /usr/include/nonstd \
&& wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/include/nonstd/expected.hpp
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/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 . \
&& make -j2 && make install \
&& wget https://github.com/aberaud/restinio/archive/bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& ls -l && tar -xzf bbaa034dbcc7555ce67df0f8a1475591a7441733.tar.gz \
&& cd restinio-bbaa034dbcc7555ce67df0f8a1475591a7441733/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
+2 -3
View File
@@ -2,9 +2,8 @@ FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN cd opendht && mkdir build && cd build \
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
+2 -3
View File
@@ -2,9 +2,8 @@ FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-llvm:latest
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
COPY . opendht
RUN cd opendht && mkdir build && cd build \
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \
-DOPENDHT_C=On \
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+4 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -143,9 +143,6 @@ struct OPENDHT_PUBLIC Config {
* - Larger listen refresh time
*/
bool public_stable {false};
/* Client mode, node will not be used by other nodes to store data. */
bool client_mode {false};
};
/**
@@ -163,20 +160,6 @@ 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>;
@@ -187,19 +170,19 @@ using ValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value
using GetCallbackSimple = std::function<bool(std::shared_ptr<Value> value)>;
using ShutdownCallback = std::function<void()>;
using IdentityAnnouncedCb = std::function<void(bool)>;
using PublicAddressChangedCb = std::function<void(std::vector<SockAddr>)>;
using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const InfoHash& pk_id)>;
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
using DoneCallbackSimple = std::function<void(bool success)>;
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
typedef bool (*ValueCallbackRaw)(std::shared_ptr<Value>, bool expired, void *user_data);
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
typedef void (*ShutdownCallbackRaw)(void *user_data);
typedef void (*DoneCallbackSimpleRaw)(bool, void *user_data);
typedef bool (*FilterRaw)(const Value&, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
+93 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -670,6 +670,94 @@ private:
gnutls_x509_trust_list_t trust {nullptr};
};
template <class T>
class OPENDHT_PUBLIC secure_vector
{
public:
secure_vector() {}
secure_vector(secure_vector<T> const&) = default;
secure_vector(secure_vector<T> &&) = default;
explicit secure_vector(unsigned size): data_(size) {}
explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
explicit secure_vector(const std::vector<T>& c): data_(c) {}
secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
~secure_vector() { clean(); }
static secure_vector<T> getRandom(size_t size) {
secure_vector<T> ret(size);
crypto::random_device rdev;
#ifdef _WIN32
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
std::uniform_int_distribution<uint8_t> rand_byte;
#endif
std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
return ret;
}
secure_vector<T>& operator=(const secure_vector<T>& c) {
if (&c == this)
return *this;
clean();
data_ = c.data_;
return *this;
}
secure_vector<T>& operator=(secure_vector<T>&& c) {
if (&c == this)
return *this;
clean();
data_ = std::move(c.data_);
return *this;
}
secure_vector<T>& operator=(std::vector<T>&& c) {
clean();
data_ = std::move(c);
return *this;
}
std::vector<T>& writable() { clean(); return data_; }
const std::vector<T>& makeInsecure() const { return data_; }
const uint8_t* data() const { return data_.data(); }
void clean() {
clean(data_.begin(), data_.end());
}
void clear() { clean(); data_.clear(); }
size_t size() const { return data_.size(); }
bool empty() const { return data_.empty(); }
void swap(secure_vector<T>& other) { data_.swap(other.data_); }
void resize(size_t s) {
if (s == data_.size()) return;
if (s < data_.size()) {
//shrink
clean(data_.begin()+s, data_.end());
data_.resize(s);
} else {
//grow
auto data = std::move(data_); // move protected data
clear();
data_.resize(s);
std::copy(data.begin(), data.end(), data_.begin());
clean(data.begin(), data.end());
}
}
private:
/**
* Securely wipe memory
*/
static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
std::fill(b, e, 0);
}
std::vector<T> data_;
};
using SecureBlob = secure_vector<uint8_t>;
/**
* Generate an RSA key pair (4096 bits) and a certificate.
* @param name the name used in the generated certificate
@@ -684,7 +772,6 @@ OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identi
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
OPENDHT_PUBLIC Identity loadIdentity(const std::string &path,const std::string &privkey_password = {});
/**
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
@@ -705,7 +792,7 @@ OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash,
* that can be transmitted in clear, and will be generated if
* not provided (32 bytes).
*/
OPENDHT_PUBLIC Blob stretchKey(std::string_view password, Blob& salt, size_t key_length = 512/8);
OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
/**
* AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
@@ -714,58 +801,15 @@ OPENDHT_PUBLIC Blob aesEncrypt(const uint8_t* data, size_t data_length, const Bl
OPENDHT_PUBLIC inline Blob aesEncrypt(const Blob& data, const Blob& key) {
return aesEncrypt(data.data(), data.size(), key);
}
/**
* AES-GCM encryption with argon2 key derivation.
* This function uses `stretchKey` to generate an AES key from the password and a random salt.
* The result is a bundle including the salt that can be decrypted with `aesDecrypt(data, password)`.
* If needed, the salt or encrypted data can be individually extracted from the bundle with `aesGetSalt` and `aesGetEncrypted`.
* @param data: data to encrypt
* @param password: password to encrypt the data with
* @param salt: optional salt to use for key derivation. If not provided, a random salt will be generated.
*/
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, std::string_view password, const Blob& salt = {});
OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
/**
* AES-GCM decryption.
*/
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key);
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, const Blob& key) { return aesDecrypt(data.data(), data.size(), key); }
OPENDHT_PUBLIC inline Blob aesDecrypt(std::string_view data, const Blob& key) { return aesDecrypt((uint8_t*)data.data(), data.size(), key); }
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, std::string_view password);
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, std::string_view password) { return aesDecrypt(data.data(), data.size(), password); }
OPENDHT_PUBLIC inline Blob aesDecrypt(std::string_view data, std::string_view password) { return aesDecrypt((uint8_t*)data.data(), data.size(), password); }
/**
* Get raw AES key from password and salt stored with the encrypted data.
*/
OPENDHT_PUBLIC Blob aesGetKey(const uint8_t* data, size_t data_length, std::string_view password);
OPENDHT_PUBLIC Blob inline aesGetKey(const Blob& data, std::string_view password) {
return aesGetKey(data.data(), data.size(), password);
}
/** Get the salt part of data password-encrypted with `aesEncrypt(data, password)` */
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)` */
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());
}
/** Build an encrypted bundle that can be decrypted with aesDecrypt(data, password).
* @param encryptedData: result of `aesEncrypt(data, key)` or `aesGetEncrypted`
* @param salt: should match the encryption key and password so that `stretchKey(password, salk) == key`.
* Can be obtained from an existing bundle with `aesGetSalt`.
**/
OPENDHT_PUBLIC Blob aesBuildEncrypted(const uint8_t* encryptedData, size_t data_length, const Blob& salt);
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(const Blob& encryptedData, const Blob& salt) {
return aesBuildEncrypted(encryptedData.data(), encryptedData.size(), salt);
}
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(std::string_view encryptedData, const Blob& salt) {
return aesBuildEncrypted((const uint8_t*)encryptedData.data(), encryptedData.size(), salt);
}
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, const std::string& password);
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, const std::string& password) { return aesDecrypt(data.data(), data.size(), password); }
}
}
-114
View File
@@ -1,114 +0,0 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <random>
namespace dht {
namespace crypto {
template <class T>
class secure_vector
{
public:
secure_vector() {}
secure_vector(secure_vector<T> const&) = default;
secure_vector(secure_vector<T> &&) = default;
explicit secure_vector(unsigned size): data_(size) {}
explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
explicit secure_vector(const std::vector<T>& c): data_(c) {}
secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
~secure_vector() { clean(); }
static secure_vector<T> getRandom(size_t size) {
secure_vector<T> ret(size);
std::random_device rdev;
#ifdef _WIN32
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
std::uniform_int_distribution<uint8_t> rand_byte;
#endif
std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
return ret;
}
secure_vector<T>& operator=(const secure_vector<T>& c) {
if (&c == this)
return *this;
clean();
data_ = c.data_;
return *this;
}
secure_vector<T>& operator=(secure_vector<T>&& c) {
if (&c == this)
return *this;
clean();
data_ = std::move(c.data_);
return *this;
}
secure_vector<T>& operator=(std::vector<T>&& c) {
clean();
data_ = std::move(c);
return *this;
}
std::vector<T>& writable() { clean(); return data_; }
const std::vector<T>& makeInsecure() const { return data_; }
const uint8_t* data() const { return data_.data(); }
void clean() {
clean(data_.begin(), data_.end());
}
void clear() { clean(); data_.clear(); }
size_t size() const { return data_.size(); }
bool empty() const { return data_.empty(); }
void swap(secure_vector<T>& other) { data_.swap(other.data_); }
void resize(size_t s) {
if (s == data_.size()) return;
if (s < data_.size()) {
//shrink
clean(data_.begin()+s, data_.end());
data_.resize(s);
} else {
//grow
auto data = std::move(data_); // move protected data
clear();
data_.resize(s);
std::copy(data.begin(), data.end(), data_.begin());
clean(data.begin(), data.end());
}
}
private:
/**
* Securely wipe memory
*/
static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
std::fill(b, e, 0);
}
std::vector<T> data_;
};
using SecureBlob = secure_vector<uint8_t>;
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+11 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -65,7 +65,10 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {}, std::unique_ptr<std::mt19937_64>&& rd = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {})
: Dht(std::move(sock), config, std::make_shared<Logger>(l)) {}
virtual ~Dht();
@@ -73,9 +76,6 @@ public:
* Get the ID of the node.
*/
inline const InfoHash& getNodeId() const override { return myid; }
void setOnPublicAddressChanged(PublicAddressChangedCb cb) override {
publicAddressChangedCb_ = std::move(cb);
}
NodeStatus updateStatus(sa_family_t af) override;
@@ -265,6 +265,7 @@ public:
*/
void connectivityChanged(sa_family_t) override;
void connectivityChanged() override {
reported_addr.clear();
connectivityChanged(AF_INET);
connectivityChanged(AF_INET6);
}
@@ -315,9 +316,7 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>&) override {
return PushNotificationResult::IgnoredDisabled;
}
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
void resubscribe(unsigned) {}
private:
@@ -374,7 +373,7 @@ private:
Dht(const Dht&) = delete;
Dht& operator=(const Dht&) = delete;
std::mt19937_64 rd;
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
InfoHash myid {};
@@ -385,14 +384,11 @@ private:
TypeStore types;
using SearchMap = std::map<InfoHash, Sp<Search>>;
using ReportedAddr = std::pair<unsigned, SockAddr>;
struct Kad {
RoutingTable buckets {};
SearchMap searches {};
unsigned pending_pings {0};
NodeStatus status;
std::vector<ReportedAddr> reported_addr;
NodeStatus getStatus(time_point now) const;
NodeStats getNodesStats(time_point now, const InfoHash& myid) const;
@@ -400,7 +396,6 @@ private:
Kad dht4 {};
Kad dht6 {};
PublicAddressChangedCb publicAddressChangedCb_ {};
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
std::chrono::steady_clock::duration bootstrap_period {BOOTSTRAP_PERIOD};
@@ -428,6 +423,8 @@ private:
Sp<Scheduler::Job> nextStorageMaintenance {};
net::NetworkEngine network_engine;
using ReportedAddr = std::pair<unsigned, SockAddr>;
std::vector<ReportedAddr> reported_addr;
std::string persistPath;
@@ -570,7 +567,7 @@ private:
* @param sr The search for which we want to announce a value.
* @param announce The 'announce' structure.
*/
void searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel = TARGET_NODES);
void searchSendAnnounceValue(const Sp<Search>& sr);
/**
* Main process of a Search's operations. This function will demand the
+19 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#pragma once
#include "infohash.h"
#include "logger.h"
#include "log_enable.h"
#include "node_export.h"
#include <queue>
@@ -33,8 +33,8 @@ namespace net {
class OPENDHT_PUBLIC DhtInterface {
public:
DhtInterface() = default;
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {}
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {}
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {};
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {};
virtual ~DhtInterface() = default;
// [[deprecated]]
@@ -45,16 +45,15 @@ public:
/**
* Get the current status of the node for the given family.
*/
virtual NodeStatus updateStatus(sa_family_t af) { return getStatus(af); }
virtual NodeStatus updateStatus(sa_family_t af) { return getStatus(af); };
virtual NodeStatus getStatus(sa_family_t af) const = 0;
virtual NodeStatus getStatus() const = 0;
void addOnConnectedCallback(std::function<void()> cb) {
onConnectCallbacks_.emplace(std::move(cb));
}
virtual void setOnPublicAddressChanged(PublicAddressChangedCb) {}
virtual net::DatagramSocket* getSocket() const { return {}; }
virtual net::DatagramSocket* getSocket() const { return {}; };
/**
* Get the ID of the DHT node.
@@ -233,6 +232,18 @@ public:
virtual std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) = 0;
/**
* Enable or disable logging of DHT internal messages
*/
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
if (logger_) {
logger_->DBG = std::move(debug);
logger_->WARN = std::move(warn);
logger_->ERR = std::move(error);
} else
logger_= std::make_shared<Logger>(std::move(error), std::move(warn), std::move(debug));
}
virtual void setLogger(const Logger& l) {
if (logger_)
*logger_ = l;
@@ -262,7 +273,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
virtual PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
std::shared_ptr<Logger> logger_ {};
+13 -29
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -53,21 +53,19 @@ public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<crypto::Certificate> serverCA,
crypto::Identity clientIdentity,
std::function<void()> loopSignal,
const std::string& serverHost,
const std::string& userAgent = "",
const std::string& pushClientId = "",
const std::string& pushToken = "",
const std::string& pushTopic = "",
const std::string& pushPlatform = "",
std::shared_ptr<Logger> logger = {}
);
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
void setHeaderFields(http::Request& request);
virtual void setPushNotificationToken(const std::string& token) override;
virtual void setPushNotificationToken(const std::string& token) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#else
(void) token;
#endif
}
virtual void setPushNotificationTopic(const std::string& topic) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
@@ -91,9 +89,6 @@ public:
* Get the ID of the node.
*/
inline const InfoHash& getNodeId() const override { return myid; }
void setOnPublicAddressChanged(PublicAddressChangedCb cb) override {
publicAddressChangedCb_ = std::move(cb);
}
/**
* Get the current status of the node for the given family.
@@ -216,7 +211,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
void 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 {
@@ -293,11 +288,6 @@ public:
loopSignal_();
}
void listenKeepIdle(uint32_t seconds) {
listenKeepIdle_ = seconds;
}
inline uint32_t listenKeepIdle() { return listenKeepIdle_; }
private:
/**
* Start the connection with a server.
@@ -353,7 +343,7 @@ private:
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
std::string userAgent_ {"OpenDHT"};
//std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
std::string pushSessionId_;
@@ -367,7 +357,6 @@ private:
SockAddr publicAddressV4_;
SockAddr publicAddressV6_;
std::atomic_bool launchConnectedCbs_ {false};
PublicAddressChangedCb publicAddressChangedCb_ {};
InfoHash myid {};
@@ -398,11 +387,6 @@ private:
size_t listenerToken_ {0};
std::map<InfoHash, ProxySearch> searches_;
/**
* Keepalive idle time for listen
*/
uint32_t listenKeepIdle_ {120};
/**
* Callbacks should be executed in the main thread.
*/
+23 -89
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -46,17 +46,17 @@ enum class PushType {
}
MSGPACK_ADD_ENUM(dht::PushType)
namespace http {
class Request;
struct ListenerSession;
}
namespace Json {
class Value;
}
namespace dht {
namespace http {
class Request;
struct ListenerSession;
}
class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
@@ -87,7 +87,7 @@ public:
*/
DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
const ProxyServerConfig& config = {},
const std::shared_ptr<log::Logger>& logger = {});
const std::shared_ptr<dht::Logger>& logger = {});
virtual ~DhtProxyServer();
@@ -98,32 +98,6 @@ public:
asio::io_context& io_context() const;
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
struct PushStats {
uint64_t highPriorityCount {0};
uint64_t normalPriorityCount {0};
void increment(bool highPriority) {
if (highPriority)
highPriorityCount++;
else
normalPriorityCount++;
}
Json::Value toJson() const {
Json::Value val;
val["highPriorityCount"] = static_cast<Json::UInt64>(highPriorityCount);
val["normalPriorityCount"] = static_cast<Json::UInt64>(normalPriorityCount);
return val;
}
std::string toString() const {
return fmt::format("{} high priority, {} normal priority", highPriorityCount, normalPriorityCount);
}
};
struct ServerStats {
/** Current number of listen operations */
size_t listenCount {0};
@@ -133,39 +107,24 @@ public:
size_t totalPermanentPuts {0};
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount {0};
/** Time at which the server was started */
time_point serverStartTime;
/** Last time at which the stats were updated */
time_point lastUpdated;
/** Total number of push notification requests that the server attempted to
* send since being started, broken down by type and priority level */
PushStats androidPush;
PushStats iosPush;
PushStats unifiedPush;
/** Average requests per second */
double requestRate {0};
/** Node Info **/
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
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);
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
}
return ret;
return ss.str();
}
/**
@@ -177,11 +136,6 @@ public:
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["totalPermanentPuts"] = static_cast<Json::UInt64>(totalPermanentPuts);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["serverStartTime"] = static_cast<Json::LargestInt>(to_time_t(serverStartTime));
result["lastUpdated"] = static_cast<Json::LargestInt>(to_time_t(lastUpdated));
result["androidPush"] = androidPush.toJson();
result["iosPush"] = iosPush.toJson();
result["unifiedPush"] = unifiedPush.toJson();
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
@@ -321,12 +275,6 @@ private:
RequestStatus options(restinio::request_handle_t request,
restinio::router::route_params_t params);
struct PushSessionContext {
std::mutex lock;
std::string sessionId;
PushSessionContext(const std::string& id) : sessionId(id) {}
};
#ifdef OPENDHT_PUSH_NOTIFICATIONS
PushType getTypeFromString(const std::string& type);
std::string getDefaultTopic(PushType type);
@@ -383,24 +331,6 @@ private:
void handleCancelPushListen(const asio::error_code &ec, const std::string pushToken,
const InfoHash key, const std::string clientId);
/**
* Handles a push listen request.
*
* @param infoHash The information hash associated with the push listen request.
* @param pushToken The push token associated with the push listen request.
* @param type The type of the push listen request.
* @param clientId The client ID associated with the push listen request.
* @param sessionCtx The shared pointer to the push session context associated with the push listen request.
* @param topic The topic associated with the push listen request.
* @param values The vector of shared pointers to values associated with the push listen request.
* @param expired A boolean indicating whether the push listen request has expired.
* @return true.
*/
bool handlePushListen(const InfoHash& infoHash, const std::string& pushToken,
PushType type, const std::string& clientId,
const std::shared_ptr<DhtProxyServer::PushSessionContext>& sessionCtx, const std::string& topic,
const std::vector<std::shared_ptr<Value>>& values, bool expired);
#endif //OPENDHT_PUSH_NOTIFICATIONS
void handlePrintStats(const asio::error_code &ec);
@@ -412,6 +342,9 @@ private:
template <typename Is>
void loadState(Is& is, size_t size);
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
std::shared_ptr<asio::io_context> ioContext_;
std::shared_ptr<DhtRunner> dht_;
Json::StreamWriterBuilder jsonBuilder_;
@@ -431,16 +364,11 @@ private:
mutable std::mutex requestLock_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
std::shared_ptr<log::Logger> logger_;
std::shared_ptr<dht::Logger> logger_;
std::shared_ptr<ServerStats> stats_;
std::shared_ptr<NodeInfo> nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
const time_point serverStartTime_;
mutable std::mutex pushStatsMutex_;
PushStats androidPush_;
PushStats iosPush_;
PushStats unifiedPush_;
// Thread-safe access to listeners map.
std::mutex lockListener_;
@@ -448,6 +376,12 @@ private:
std::map<restinio::connection_id_t, http::ListenerSession> listeners_;
// Connection Listener observing conn state changes.
std::shared_ptr<ConnectionListener> connListener_;
struct PushSessionContext {
std::mutex lock;
std::string sessionId;
PushSessionContext(const std::string& id) : sessionId(id) {}
};
struct PermanentPut {
time_point expiration;
std::string pushToken;
+6 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -25,7 +25,7 @@
#include "value.h"
#include "callbacks.h"
#include "sockaddr.h"
#include "logger.h"
#include "log_enable.h"
#include "network_utils.h"
#include "node_export.h"
@@ -64,7 +64,6 @@ public:
std::string push_token {};
std::string push_topic {};
std::string push_platform {};
std::string proxy_user_agent {};
bool peer_discovery {false};
bool peer_publish {false};
std::shared_ptr<dht::crypto::Certificate> server_ca;
@@ -79,8 +78,6 @@ public:
StatusCallback statusChangedCallback {};
CertificateStoreQuery certificateStore {};
IdentityAnnouncedCb identityAnnouncedCb {};
PublicAddressChangedCb publicAddressChangedCb {};
std::unique_ptr<std::mt19937_64> rng {};
Context() {}
};
@@ -352,6 +349,7 @@ public:
void setLogger(const Logger& logger) {
setLogger(std::make_shared<Logger>(logger));
}
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
@@ -410,8 +408,7 @@ public:
void run(const Config& config, Context&& context);
void setOnStatusChanged(StatusCallback&& cb) {
if (cb)
statusCbs.emplace_back(std::move(cb));
statusCb = std::move(cb);
}
/**
@@ -466,7 +463,7 @@ public:
/**
* Insert a push notification to process for OpenDHT
*/
std::future<PushNotificationResult> pushNotificationReceived(const std::map<std::string, std::string>& data);
void pushNotificationReceived(const std::map<std::string, std::string>& data);
/* Proxy server mothods */
void forwardAllMessages(bool forward);
@@ -521,8 +518,7 @@ private:
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
std::vector<StatusCallback> statusCbs {};
StatusCallback statusCb {nullptr};
/** PeerDiscovery Parameters */
std::shared_ptr<PeerDiscovery> peerDiscovery_;
+39 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,20 +29,23 @@
# define snprintf snprintf
#endif
#include <asio/ip/tcp.hpp>
#include <asio/streambuf.hpp>
#include <asio/ssl/context.hpp>
#include <restinio/http_headers.hpp>
#include <restinio/message_builders.hpp>
#include <memory>
#include <queue>
#include <mutex>
#include <future>
namespace Json {
class Value;
}
extern "C" {
struct http_parser;
struct http_parser_settings;
}
namespace restinio {
namespace impl {
class tls_socket_t;
@@ -50,9 +53,7 @@ class tls_socket_t;
}
namespace dht {
namespace log {
struct Logger;
}
namespace crypto {
struct Certificate;
@@ -72,7 +73,7 @@ class OPENDHT_PUBLIC Url
{
public:
Url() = default;
Url(std::string_view url);
Url(const std::string& url);
std::string url;
std::string protocol {"http"};
std::string host;
@@ -87,9 +88,9 @@ public:
class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection>
{
public:
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<log::Logger> l = {});
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<dht::Logger> l = {});
Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certificate> server_ca,
const dht::crypto::Identity& identity, std::shared_ptr<log::Logger> l = {});
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l = {});
~Connection();
inline unsigned int id() const { return id_; };
@@ -113,8 +114,6 @@ public:
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void set_keepalive(uint32_t seconds);
const asio::ip::address& local_address() const;
void timeout(const std::chrono::seconds& timeout, HandlerCb cb = {});
@@ -149,10 +148,21 @@ private:
asio::ip::address local_address_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<log::Logger> logger_;
std::shared_ptr<dht::Logger> logger_;
bool checkOcsp_ {false};
};
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
/* @class Resolver
* @brief The purpose is to only resolve once to avoid mutliple dns requests per operation.
*/
@@ -162,15 +172,15 @@ public:
using ResolverCb = std::function<void(const asio::error_code& ec,
const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<log::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
// use already resolved endpoints with classes using this resolver
Resolver(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint> endpoints,
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& url, std::vector<asio::ip::tcp::endpoint> endpoints,
std::shared_ptr<log::Logger> logger = {});
std::shared_ptr<dht::Logger> logger = {});
~Resolver();
@@ -180,12 +190,10 @@ public:
void add_callback(ResolverCb cb, sa_family_t family = AF_UNSPEC);
std::shared_ptr<log::Logger> getLogger() const {
std::shared_ptr<Logger> getLogger() const {
return logger_;
}
void cancel();
private:
void resolve(const std::string& host, const std::string& service);
@@ -200,7 +208,7 @@ private:
bool completed_ {false};
std::queue<ResolverCb> cbs_;
std::shared_ptr<log::Logger> logger_;
std::shared_ptr<dht::Logger> logger_;
};
class Request;
@@ -232,14 +240,14 @@ public:
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
std::shared_ptr<log::Logger> logger = {});
std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb,
std::shared_ptr<log::Logger> logger = {});
std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<log::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<log::Logger> logger = {});
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger = {});
// user defined resolver
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
@@ -247,7 +255,7 @@ public:
// user defined resolved endpoints
Request(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint>&& endpoints,
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
~Request();
@@ -274,7 +282,7 @@ public:
void set_certificate_authority(std::shared_ptr<dht::crypto::Certificate> certificate);
void set_identity(const dht::crypto::Identity& identity);
void set_logger(std::shared_ptr<log::Logger> logger);
void set_logger(std::shared_ptr<dht::Logger> logger);
/**
* Define the HTTP header/body as per https://tools.ietf.org/html/rfc7230.
@@ -320,11 +328,9 @@ private:
void build();
static std::string url_encode(std::string_view value);
void init_default_headers();
/**
* Initialized and wraps the llhttp callbacks with our user defined callbacks.
* Initialized and wraps the http_parser callbacks with our user defined callbacks.
*/
void init_parser();
@@ -341,7 +347,7 @@ private:
mutable std::mutex mutex_;
std::shared_ptr<log::Logger> logger_;
std::shared_ptr<dht::Logger> logger_;
restinio::http_request_header_t header_;
std::map<restinio::http_field_t, std::string> headers_;
@@ -366,8 +372,8 @@ private:
Response response_ {};
std::string request_;
std::atomic<bool> finishing_ {false};
std::unique_ptr<llhttp_t> parser_;
std::unique_ptr<llhttp_settings_t> parser_s_;
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
// Next request in case of redirect following
std::shared_ptr<Request> next_;
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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 are too many nodes
* We could then delete the last one if there is too much node
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
+2 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,6 @@
#include "rng.h"
#include <msgpack.hpp>
#include <fmt/core.h>
#ifndef _WIN32
#include <netinet/in.h>
@@ -230,11 +229,6 @@ public:
return get(data.data(), data.size());
}
template <size_t H>
static Hash get(const Hash<H>& o) {
return get(o.data(), o.size());
}
/**
* Computes the hash from a given data buffer of size data_len.
*/
@@ -323,7 +317,7 @@ Hash<N>
Hash<N>::getRandom()
{
Hash h;
std::random_device rdev;
crypto::random_device rdev;
std::uniform_int_distribution<uint32_t> rand_int;
auto a = reinterpret_cast<uint32_t*>(h.data());
auto b = reinterpret_cast<uint32_t*>(h.data() + h.size());
@@ -395,10 +389,3 @@ Hash<N>::toString() const
}
}
template <size_t N>
struct fmt::formatter<dht::Hash<N>>: formatter<string_view> {
constexpr auto format(const dht::Hash<N>& c, format_context& ctx) const {
return formatter<string_view>::format(c.to_view(), ctx);
}
};
+38 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -20,7 +20,7 @@
#pragma once
#include "def.h"
#include "logger.h"
#include "log_enable.h"
#include <iostream>
#include <memory>
@@ -34,6 +34,42 @@ class DhtRunner;
*/
namespace log {
/**
* Terminal colors for logging
*/
namespace Color {
enum Code {
FG_RED = 31,
FG_GREEN = 32,
FG_YELLOW = 33,
FG_BLUE = 34,
FG_DEFAULT = 39,
BG_RED = 41,
BG_GREEN = 42,
BG_BLUE = 44,
BG_DEFAULT = 49
};
class Modifier {
const Code code;
public:
constexpr Modifier(Code pCode) : code(pCode) {}
friend std::ostream&
operator<<(std::ostream& os, const Modifier& mod) {
return os << "\033[" << mod.code << 'm';
}
};
}
constexpr const Color::Modifier def(Color::FG_DEFAULT);
constexpr const Color::Modifier red(Color::FG_RED);
constexpr const Color::Modifier yellow(Color::FG_YELLOW);
/**
* Print va_list to std::ostream (used for logging).
*/
OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
OPENDHT_PUBLIC
std::shared_ptr<Logger> getStdLogger();
+191
View File
@@ -0,0 +1,191 @@
/*
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "infohash.h"
#include <cstdarg>
#ifndef OPENDHT_LOG
#define OPENDHT_LOG true
#endif
namespace dht {
// Logging related utility functions
/**
* Wrapper for logging methods
*/
struct LogMethod {
LogMethod() = default;
LogMethod(LogMethod&& l) : func(std::move(l.func)) {}
LogMethod(const LogMethod& l) : func(l.func) {}
LogMethod& operator=(dht::LogMethod&& l) {
func = std::forward<LogMethod>(l.func);
return *this;
}
LogMethod& operator=(const dht::LogMethod& l) {
func = l.func;
return *this;
}
template<typename T>
explicit LogMethod(T&& t) : func(std::forward<T>(t)) {}
template<typename T>
LogMethod(const T& t) : func(t) {}
void operator()(char const* format, ...) const {
va_list args;
va_start(args, format);
func(format, args);
va_end(args);
}
inline void log(char const* format, va_list args) const {
func(format, args);
}
explicit operator bool() const {
return (bool)func;
}
void logPrintable(const uint8_t *buf, size_t buflen) const {
std::string buf_clean(buflen, '\0');
for (size_t i=0; i<buflen; i++)
buf_clean[i] = isprint(buf[i]) ? buf[i] : '.';
(*this)("%s", buf_clean.c_str());
}
private:
std::function<void(char const*, va_list)> func;
};
struct Logger {
LogMethod ERR = {};
LogMethod WARN = {};
LogMethod DBG = {};
Logger() = default;
Logger(LogMethod&& err, LogMethod&& warn, LogMethod&& dbg)
: ERR(std::move(err)), WARN(std::move(warn)), DBG(std::move(dbg)) {}
void setFilter(const InfoHash& f) {
filter_ = f;
filterEnable_ = static_cast<bool>(filter_);
}
inline void log0(const LogMethod& logger, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and not filterEnable_)
logger.log(format, args);
#endif
}
inline void log1(const LogMethod& logger, const InfoHash& f, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f == filter_))
logger.log(format, args);
#endif
}
inline void log2(const LogMethod& logger, const InfoHash& f1, const InfoHash& f2, char const* format, va_list args) const {
#if OPENDHT_LOG
if (logger and (not filterEnable_ or f1 == filter_ or f2 == filter_))
logger.log(format, args);
#endif
}
inline void d(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(DBG, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(DBG, f, format, args);
va_end(args);
#endif
}
inline void d(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(DBG, f1, f2, format, args);
va_end(args);
#endif
}
inline void w(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(WARN, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(WARN, f, format, args);
va_end(args);
#endif
}
inline void w(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(WARN, f1, f2, format, args);
va_end(args);
#endif
}
inline void e(char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log0(ERR, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log1(ERR, f, format, args);
va_end(args);
#endif
}
inline void e(const InfoHash& f1, const InfoHash& f2, char const* format, ...) const {
#if OPENDHT_LOG
va_list args;
va_start(args, format);
log2(ERR, f1, f2, format, args);
va_end(args);
#endif
}
private:
bool filterEnable_ {false};
InfoHash filter_ {};
};
}
-118
View File
@@ -1,118 +0,0 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "infohash.h"
#include <fmt/format.h>
#include <fmt/printf.h>
#include <functional>
#include <string_view>
#include <cstdarg>
namespace dht {
namespace log {
enum class LogLevel {
debug, warning, error
};
using LogMethod = std::function<void(LogLevel, std::string&&)>;
struct OPENDHT_PUBLIC Logger {
Logger() = delete;
Logger(LogMethod&& l)
: logger(std::move(l)) {
if (!logger)
throw std::invalid_argument{"logger and loggerf must be set"};
}
void setFilter(const InfoHash& f) {
filter_ = f;
filterEnable_ = static_cast<bool>(filter_);
}
inline void log0(LogLevel level, fmt::string_view format, fmt::printf_args args) const {
if (not filterEnable_)
logger(level, fmt::vsprintf(format, args));
}
inline void log1(LogLevel level, const InfoHash& f, fmt::string_view format, fmt::printf_args args) const {
if (not filterEnable_ or f == filter_)
logger(level, fmt::vsprintf(format, args));
}
inline void log2(LogLevel level, const InfoHash& f1, const InfoHash& f2, fmt::string_view format, fmt::printf_args args) const {
if (not filterEnable_ or f1 == filter_ or f2 == filter_)
logger(level, fmt::vsprintf(format, args));
}
template<typename S, typename... Args>
inline void debug(S&& format, Args&&... args) const {
logger(LogLevel::debug, fmt::format(format, args...));
}
template<typename S, typename... Args>
inline void warn(S&& format, Args&&... args) const {
logger(LogLevel::warning, fmt::format(format, args...));
}
template<typename S, typename... Args>
inline void error(S&& format, Args&&... args) const {
logger(LogLevel::error, fmt::format(format, args...));
}
template <typename... T>
inline void d(fmt::format_string<T...> format, T&&... args) const {
log0(LogLevel::debug, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void d(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
log1(LogLevel::debug, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void d(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
log2(LogLevel::debug, f1, f2, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(fmt::format_string<T...> format, T&&... args) const {
log0(LogLevel::warning, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
log1(LogLevel::warning, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void w(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
log2(LogLevel::warning, f1, f2, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(fmt::format_string<T...> format, T&&... args) const {
log0(LogLevel::error, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(const InfoHash& f, fmt::format_string<T...> format, T&&... args) const {
log1(LogLevel::error, f, format, fmt::make_printf_args(args...));
}
template <typename... T>
inline void e(const InfoHash& f1, const InfoHash& f2, fmt::format_string<T...> format, T&&... args) const {
log2(LogLevel::error, f1, f2, format, fmt::make_printf_args(args...));
}
private:
LogMethod logger = {};
bool filterEnable_ {false};
InfoHash filter_ {};
};
}
using Logger = log::Logger;
}
+4 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -27,7 +27,7 @@
#include "utils.h"
#include "rng.h"
#include "rate_limiter.h"
#include "logger.h"
#include "log_enable.h"
#include "network_utils.h"
#include <vector>
@@ -52,7 +52,6 @@ struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
bool is_client {false};
};
class DhtProtocolException : public DhtException {
@@ -502,6 +501,8 @@ private:
static constexpr size_t MAX_PACKET_VALUE_SIZE {600};
static constexpr size_t MAX_MESSAGE_VALUE_SIZE {56 * 1024};
static const std::string my_v;
void process(std::unique_ptr<ParsedMessage>&&, const SockAddr& from);
bool rateLimit(const SockAddr& addr);
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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
@@ -21,7 +21,7 @@
#include "sockaddr.h"
#include "utils.h"
#include "logger.h"
#include "log_enable.h"
#ifdef _WIN32
#include <ws2tcpip.h>
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -139,7 +139,7 @@ struct Node {
*/
Tid getNewTid() {
++transaction_id;
return transaction_id ? transaction_id : ++transaction_id;
return transaction_id ? ++transaction_id : transaction_id;
}
std::string toString() const;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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
+16 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -22,10 +22,8 @@
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "logger.h"
#include "utils.h"
#include "log_enable.h"
#include <asio/steady_timer.hpp>
#include <thread>
namespace asio {
@@ -38,34 +36,31 @@ class OPENDHT_PUBLIC PeerDiscovery
{
public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object &&, SockAddr &&)>;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT,
std::shared_ptr<asio::io_context> ioContext = {},
std::shared_ptr<Logger> logger = {});
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned
* or stop is called
*/
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
template <typename T>
void startDiscovery(const std::string &type, std::function<void(T &&, SockAddr &&)> cb) {
startDiscovery(type, [cb](msgpack::object &&ob, SockAddr &&addr) {
template<typename T>
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
cb(ob.as<T>(), std::move(addr));
});
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called
*/
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
template <typename T>
void startPublish(const std::string &type, const T &object) {
template<typename T>
void startPublish(const std::string &type, const T& object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, buf);
@@ -73,24 +68,22 @@ public:
/**
* Thread Stopper
*/
*/
void stop();
/**
* Remove possible callBack to discovery
*/
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
*/
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
void connectivityChanged();
void stopConnectivityChanged();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
@@ -99,4 +92,4 @@ private:
std::thread ioRunnner_;
};
} // namespace dht
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -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-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+96 -41
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -27,49 +27,104 @@
namespace dht {
namespace crypto {
/**
* Generate a seeded random engine.
*/
template<class T = std::mt19937, std::size_t N = T::state_size+1>
auto getSeededRandomEngine() -> typename std::enable_if<!!N, T>::type {
std::array<typename T::result_type, N> random_data;
constexpr auto gen = [](std::random_device& source) -> typename T::result_type {
for (unsigned j=0; j<64; j++) {
try {
return source();
} catch (...) {
std::this_thread::sleep_for(std::chrono::microseconds(500));
}
}
throw std::runtime_error("Can't generate random number");
};
for (unsigned i=0; i<8; i++) {
try {
std::random_device source;
for (auto& r : random_data)
r = gen(source);
std::seed_seq seed(
(std::seed_seq::result_type*)random_data.data(),
(std::seed_seq::result_type*)(random_data.data() + random_data.size()));
return T(seed);
} catch (...) {
std::this_thread::sleep_for(std::chrono::microseconds(500));
}
}
throw std::runtime_error("Can't seed random seed");
}
#ifndef _MSC_VER
#ifdef _WIN32
/**
* Generate a random engine from another source.
* Hardware random number generator using Intel RDRAND/RDSEED,
* API-compatible with std::random_device.
*/
template<class T = std::mt19937, std::size_t N = T::state_size+1>
auto getDerivedRandomEngine(T& source) -> typename std::enable_if<!!N, T>::type {
std::array<typename T::result_type, N> random_data;
std::generate(random_data.begin(), random_data.end(), std::ref(source));
std::seed_seq seed(
(std::seed_seq::result_type*)random_data.data(),
(std::seed_seq::result_type*)(random_data.data() + random_data.size()));
return T(seed);
class random_device {
public:
using result_type = std::random_device::result_type;
using pseudo_engine = std::mt19937_64;
/**
* Current implementation assumption : result_type must be of a size
* supported by Intel RDRAND/RDSEED.
* result_type is unsigned int so this is currently safe.
*/
static_assert(
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 8,
"result_type must be 16, 32 or 64 bits");
random_device();
result_type operator()();
static constexpr result_type min() {
return std::numeric_limits<result_type>::lowest();
}
static constexpr result_type max() {
return std::numeric_limits<result_type>::max();
}
double entropy() const {
if (hasRdrand() or hasRdseed())
return 1.;
return 0.;
}
static bool hasRdrand() {
static const bool hasrdrand = _hasRdrand();
return hasrdrand;
}
static bool hasRdseed() {
static const bool hasrdseed = _hasRdseed();
return hasrdseed;
}
private:
random_device& operator=(random_device&) = delete;
pseudo_engine gen;
std::uniform_int_distribution<result_type> dis {};
static bool hasIntelCpu();
static bool _hasRdrand();
static bool _hasRdseed();
struct CPUIDinfo {
unsigned int EAX;
unsigned int EBX;
unsigned int ECX;
unsigned int EDX;
CPUIDinfo(const unsigned int func, const unsigned int subfunc);
};
bool rdrandStep(result_type* r);
bool rdrand(result_type* r);
bool rdseedStep(result_type* r);
bool rdseed(result_type* r);
};
#else
using random_device = std::random_device;
#endif
#else
using random_device = std::random_device;
#endif
template<class T = std::mt19937, std::size_t N = T::state_size>
auto getSeededRandomEngine () -> typename std::enable_if<!!N, T>::type {
typename T::result_type random_data[N];
for (unsigned i=0; i<256; i++) {
try {
random_device source;
std::generate(std::begin(random_data), std::end(random_data), std::ref(source));
std::seed_seq seeds(std::begin(random_data), std::end(random_data));
T seededEngine (seeds);
return seededEngine;
} catch (...) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
throw std::runtime_error("Can't seed random engine");
}
}} // dht::crypto
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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-2022 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+4 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -149,9 +149,6 @@ public:
void setLocalCertificateStore(CertificateStoreQuery&& query_method) {
localQueryMethod_ = std::move(query_method);
}
void setOnPublicAddressChanged(PublicAddressChangedCb cb) override {
dht_->setOnPublicAddressChanged(cb);
}
/**
* SecureDht to Dht proxy
@@ -328,8 +325,8 @@ public:
* Call linked callback with push_notification
* @param notification to process
*/
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
return dht_->pushNotificationReceived(notification);
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
dht_->pushNotificationReceived(notification);
}
void setLogger(const Logger& logger) override {
@@ -381,7 +378,7 @@ const ValueType CERTIFICATE_TYPE = {
try {
crypto::Certificate crt(v->data);
// TODO check certificate signature
return crt.getPublicKey().getId() == id || InfoHash::get(crt.getPublicKey().getLongId()) == id;
return crt.getPublicKey().getId() == id;
} catch (const std::exception& e) {}
return false;
},
+1 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -20,10 +20,6 @@
#include "def.h"
#include <fmt/core.h>
#include <fmt/format.h>
#include <fmt/ostream.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
@@ -52,7 +48,6 @@ typedef uint16_t in_port_t;
namespace dht {
OPENDHT_PUBLIC void print_addr(std::ostream& os, const sockaddr* sa, socklen_t slen);
OPENDHT_PUBLIC std::string print_addr(const sockaddr* sa, socklen_t slen);
OPENDHT_PUBLIC std::string print_addr(const sockaddr_storage& ss, socklen_t sslen);
@@ -294,11 +289,6 @@ public:
(uint8_t*)b.get()+start, len) < 0;
}
};
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const SockAddr& h) {
print_addr(s, h.get(), h.getLength());
return s;
}
private:
struct free_delete { void operator()(void* p) { ::free(p); } };
std::unique_ptr<sockaddr, free_delete> addr {};
@@ -319,7 +309,3 @@ private:
OPENDHT_PUBLIC bool operator==(const SockAddr& a, const SockAddr& b);
}
#if FMT_VERSION >= 90000
template <> struct fmt::formatter<dht::SockAddr> : ostream_formatter {};
#endif
+3 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -37,7 +37,7 @@ public:
static ThreadPool& io();
ThreadPool();
ThreadPool(unsigned minThreads, unsigned maxThreads = 0);
ThreadPool(size_t maxThreads);
~ThreadPool();
void run(std::function<void()>&& cb);
@@ -61,9 +61,8 @@ public:
return get(std::move(cb));
}
void stop(bool wait = true);
void stop();
void join();
void detach();
private:
std::mutex lock_ {};
@@ -73,12 +72,7 @@ private:
unsigned readyThreads_ {0};
bool running_ {true};
unsigned minThreads_;
const unsigned maxThreads_;
std::chrono::steady_clock::duration threadExpirationDelay {std::chrono::minutes(5)};
double threadDelayRatio_ {2};
void threadEnded(std::thread&);
};
class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this<Executor> {
+23 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,6 @@
#include "def.h"
#include <msgpack.hpp>
#include <fmt/format.h>
#include <chrono>
#include <random>
@@ -61,7 +60,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(std::string_view s);
splitPort(const std::string& s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
@@ -85,23 +84,37 @@ 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 fmt::format("{:.3g} us", std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
} else if (d < std::chrono::seconds(1)) {
return fmt::format("{:.3g} ms", std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else if (d < std::chrono::minutes(1)) {
return fmt::format("{:.3g} s", std::chrono::duration_cast<std::chrono::duration<double>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
} else if (d < std::chrono::hours(1)) {
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());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
} else {
return fmt::format("{:.3g} days", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+17 -170
View File
@@ -1,5 +1,5 @@
project('opendht', 'c', 'cpp', 'cython',
version: '3.3.0',
project('opendht', 'c', 'cpp',
version: '2.5.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
@@ -11,18 +11,17 @@ msgpack = dependency('msgpack-cxx', required : false)
argon2 = dependency('libargon2')
openssl = dependency('openssl', required: get_option('proxy_client'))
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
fmt = dependency('fmt')
llhttp = dependency('llhttp', 'libllhttp', required: get_option('proxy_client'))
io_uring = dependency('liburing', required: false)
deps = [fmt, gnutls, nettle, msgpack, argon2, openssl, jsoncpp, llhttp, io_uring]
conf_data = configuration_data()
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language : 'cpp')
if io_uring.found()
add_project_arguments('-DASIO_HAS_IO_URING', '-DASIO_DISABLE_EPOLL', language : 'cpp')
conf_data.set('iouring_lib', ', liburing')
dirs=[]
if host_machine.system() == 'freebsd'
dirs+='/usr/local/lib'
elif host_machine.system() == 'darwin'
dirs+='/opt/homebrew/lib'
endif
http_parser = meson.get_compiler('c').find_library('http_parser', dirs: dirs, required: get_option('proxy_client'))
deps = [gnutls, nettle, msgpack, argon2, openssl, jsoncpp, http_parser]
add_project_arguments('-DMSGPACK_NO_BOOST', language : 'cpp')
add_project_arguments(['-Wno-return-type','-Wno-deprecated','-Wnon-virtual-dtor','-pedantic-errors','-fvisibility=hidden'], language : 'cpp')
opendht_inc = include_directories('include/opendht')
@@ -42,28 +41,17 @@ opendht_src = [
'src/dhtrunner.cpp',
'src/log.cpp',
'src/op_cache.cpp',
'src/network_utils.cpp',
'src/thread_pool.cpp',
'src/network_utils.cpp'
]
if get_option('indexation').enabled()
opendht_src += 'src/indexation/pht.cpp'
add_project_arguments('-DOPENDHT_INDEXATION', language : 'cpp')
endif
if jsoncpp.found()
opendht_src += ['src/base64.cpp']
add_project_arguments('-DOPENDHT_JSONCPP', language : 'cpp')
conf_data.set('jsoncpp_lib', ', jsoncpp')
endif
if llhttp.found()
if http_parser.found()
opendht_src += ['src/http.cpp', 'src/compat/os_cert.cpp']
if host_machine.system() == 'darwin'
deps+=dependency('appleframeworks', modules : ['CoreFoundation', 'Security'])
endif
conf_data.set('http_lib', '-lllhttp')
endif
if openssl.found()
conf_data.set('openssl_lib', ', openssl')
endif
if get_option('proxy_client').enabled()
opendht_src += ['src/dht_proxy_client.cpp']
@@ -73,169 +61,28 @@ if get_option('proxy_server').enabled()
opendht_src += 'src/dht_proxy_server.cpp'
add_project_arguments('-DOPENDHT_PROXY_SERVER', language : 'cpp')
endif
if get_option('push_notifications').enabled()
add_project_arguments('-DOPENDHT_PUSH_NOTIFICATIONS', language : 'cpp')
endif
if get_option('peer_discovery').enabled()
opendht_src += 'src/peer_discovery.cpp'
add_project_arguments('-DOPENDHT_PEER_DISCOVERY', language : 'cpp')
endif
opendht = library('opendht',
opendht = shared_library('opendht',
opendht_src,
include_directories : opendht_inc,
dependencies : deps,
cpp_args : ['-DOPENHT_BUILD', '-Dopendht_EXPORTS'],
install : true)
conf_data.set('VERSION', meson.project_version())
conf_data.set('prefix', get_option('prefix'))
conf_data.set('exec_prefix', get_option('prefix'))
conf_data.set('libdir', join_paths(get_option('prefix'), get_option('libdir')))
conf_data.set('includedir', join_paths(get_option('prefix'), get_option('includedir')))
conf_data.set('argon2_lib', ', libargon2')
configure_file(input : 'opendht.pc.in',
output : 'opendht.pc',
configuration : conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'))
readline = meson.get_compiler('c').find_library('readline', required: get_option('tools'))
if get_option('c').enabled()
opendht_c = library('opendht-c',
['c/opendht.cpp', 'c/opendht_c.h'],
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [msgpack, jsoncpp, fmt],
cpp_args : ['-DOPENDHT_C_BUILD', '-Dopendht_c_EXPORTS'],
install : true)
configure_file(input : 'opendht-c.pc.in',
output : 'opendht-c.pc',
configuration : conf_data,
install: true,
install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'pkgconfig'))
if get_option('tools').enabled()
dhtcnode = executable('dhtcnode', 'tools/dhtcnode.c',
include_directories : ['c', opendht_interface_inc],
link_with : opendht_c,
dependencies : [readline],
install : true)
endif
endif
if get_option('python').require(get_option('indexation').enabled(), error_message: 'python requires indexation').allowed()
py = import('python').find_installation()
dep_py = py.dependency()
py.extension_module(
'opendht',
'python/opendht.pyx',
include_directories : opendht_interface_inc,
override_options : ['cython_language=cpp'],
link_with : [opendht],
dependencies : [msgpack, jsoncpp, fmt, dep_py],
install : true
)
endif
if get_option('tools').enabled()
dhtnode = executable('dhtnode', 'tools/dhtnode.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
dependencies : [readline, msgpack],
install : true)
dhtchat = executable('dhtchat', 'tools/dhtchat.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
dhtscanner = executable('dhtscanner', 'tools/dhtscanner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [readline, jsoncpp, msgpack, fmt, openssl],
install : true)
if llhttp.found()
if http_parser.found()
durl = executable('durl', 'tools/durl.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [msgpack, openssl])
endif
endif
# Unit tests
if get_option('tests').enabled()
cppunit = dependency('cppunit')
test_infohash = executable('test_infohash',
'tests/infohashtester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('Infohash', test_infohash)
test_value = executable('test_value',
'tests/valuetester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('Value', test_value)
test_crypto = executable('test_crypto',
'tests/cryptotester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('Crypto', test_crypto)
test_dhtrunner = executable('test_dhtrunner',
'tests/dhtrunnertester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('DhtRunner', test_dhtrunner)
test_threadpool = executable('test_threadpool',
'tests/threadpooltester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('ThreadPool', test_threadpool)
if get_option('proxy_client').enabled() or get_option('proxy_server').enabled()
test_http = executable('test_http',
'tests/httptester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('Http', test_http)
endif
if get_option('peer_discovery').enabled()
test_peerdiscovery = executable('test_peerdiscovery',
'tests/peerdiscoverytester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('PeerDiscovery', test_peerdiscovery)
endif
if get_option('proxy_server').enabled()
test_proxy = executable('test_dhtproxy',
'tests/dhtproxytester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('DhtProxy', test_proxy)
if get_option('long_tests').enabled()
test_proxystress = executable('test_dhtproxystress',
'tests/dhtproxy_stress_tester.cpp', 'tests/tests_runner.cpp',
include_directories : opendht_interface_inc,
link_with : opendht,
dependencies : [cppunit, jsoncpp, fmt, openssl, msgpack])
test('DhtProxy Stress', test_proxystress)
endif
dependencies : [msgpack, openssl])
endif
endif
-10
View File
@@ -1,10 +0,0 @@
option('proxy_client', type : 'feature', value : 'disabled')
option('proxy_server', type : 'feature', value : 'disabled')
option('push_notifications', type : 'feature', value : 'disabled')
option('peer_discovery', type : 'feature', value : 'enabled')
option('tools', type : 'feature', value : 'enabled')
option('c', type : 'feature', value : 'enabled')
option('indexation', type : 'feature', value : 'enabled')
option('python', type : 'feature', value : 'enabled')
option('tests', type : 'feature', value : 'enabled')
option('long_tests', type : 'feature', value : 'disabled')
+4
View File
@@ -0,0 +1,4 @@
option('proxy_client', type : 'feature', value : 'disabled')
option('proxy_server', type : 'feature', value : 'disabled')
option('peer_discovery', type : 'feature', value : 'enabled')
option('tools', type : 'feature', value : 'enabled')
+2 -2
View File
@@ -6,7 +6,7 @@ Name: OpenDHT
Description: C++17 Distributed Hash Table library
Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs.private: @http_lib@ -pthread
Libs.private: @http_parser_lib@ -pthread
Requires: gnutls >= 3.3@jsoncpp_lib@@openssl_lib@
Requires.private: nettle >= 2.4@argon2_lib@@iouring_lib@
Requires.private: nettle >= 2.4@argon2_lib@
Cflags: -I${includedir}
+10 -124
View File
@@ -5,7 +5,7 @@
# distutils: libraries = opendht gnutls
# cython: language_level=3
#
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
@@ -42,7 +42,7 @@ cimport opendht_cpp as cpp
import threading
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) noexcept with gil:
cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* values, cpp.Prefix* p, void *user_data) with gil:
cbs = <object>user_data
if 'lookup' in cbs and cbs['lookup']:
vals = []
@@ -52,13 +52,13 @@ cdef inline void lookup_callback(cpp.vector[cpp.shared_ptr[cpp.IndexValue]]* val
vals.append(v)
cbs['lookup'](vals, p.toString())
cdef inline void shutdown_callback(void* user_data) noexcept with gil:
cdef inline void shutdown_callback(void* user_data) with gil:
cbs = <object>user_data
if 'shutdown' in cbs and cbs['shutdown']:
cbs['shutdown']()
ref.Py_DECREF(cbs)
cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) noexcept with gil:
cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) with gil:
cbs = <object>user_data
cb = cbs['get']
f = cbs['filter'] if 'filter' in cbs else None
@@ -66,7 +66,7 @@ cdef inline bool get_callback(shared_ptr[cpp.Value] value, void *user_data) noex
pv._value = value
return cb(pv) if not f or f(pv) else True
cdef inline bool value_callback(shared_ptr[cpp.Value] value, bool expired, void *user_data) noexcept with gil:
cdef inline bool value_callback(shared_ptr[cpp.Value] value, bool expired, void *user_data) with gil:
cbs = <object>user_data
cb = cbs['valcb']
f = cbs['filter'] if 'filter' in cbs else None
@@ -74,7 +74,7 @@ cdef inline bool value_callback(shared_ptr[cpp.Value] value, bool expired, void
pv._value = value
return cb(pv, expired) if not f or f(pv) else True
cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* nodes, void *user_data) noexcept with gil:
cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* nodes, void *user_data) with gil:
node_ids = []
for n in deref(nodes):
h = NodeEntry()
@@ -86,7 +86,7 @@ cdef inline void done_callback(bool done, cpp.vector[shared_ptr[cpp.Node]]* node
cbs['done'](done, node_ids)
ref.Py_DECREF(cbs)
cdef inline void done_callback_simple(bool done, void *user_data) noexcept with gil:
cdef inline void done_callback_simple(bool done, void *user_data) with gil:
cbs = <object>user_data
if 'done' in cbs and cbs['done']:
cbs['done'](done)
@@ -158,15 +158,6 @@ cdef class SockAddr(object):
return self.toString().decode()
def __repr__(self):
return "<%s '%s'>" % (self.__class__.__name__, str(self))
@staticmethod
def resolve(str host, str service=None):
vals = []
result = cpp.SockAddr.resolve(host.encode(), service.encode() if service else b'')
for val in result:
a = SockAddr()
a._addr = val
vals.append(a)
return vals
cdef class Node(_WithID):
cdef shared_ptr[cpp.Node] _node
@@ -462,31 +453,11 @@ cdef class Identity(object):
k._key = self._id.first
return k
def aesEncrypt(bytes data, str password) -> bytes :
cdef size_t d_len = len(data)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>data
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob encrypted = cpp.aesEncrypt(indat, password.encode())
cdef char* encrypted_c_str = <char *>encrypted.data()
cdef Py_ssize_t length = encrypted.size()
return encrypted_c_str[:length]
def aesDecrypt(bytes data, str password) -> bytes :
cdef size_t d_len = len(data)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>data
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob decrypted = cpp.aesDecrypt(indat, password.encode())
cdef char* decrypted_c_str = <char *>decrypted.data()
cdef Py_ssize_t length = decrypted.size()
return decrypted_c_str[:length]
cdef class DhtConfig(object):
cdef cpp.DhtRunnerConfig _config
def __init__(self):
self._config = cpp.DhtRunnerConfig()
self._config.threaded = True
self._config.threaded = True;
def setIdentity(self, Identity id):
self._config.dht_config.id = id._id
def setBootstrapMode(self, bool bootstrap):
@@ -500,20 +471,6 @@ cdef class DhtConfig(object):
def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec):
self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec
self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec
def setProxyInfo(self, str proxy_server, str push_node_id="", str push_token="", str push_topic="", str push_platform="", str user_agent="", Certificate server_ca = Certificate()):
self._config.proxy_server = proxy_server.encode()
self._config.push_node_id = push_node_id.encode()
self._config.push_token = push_token.encode()
self._config.push_topic = push_topic.encode()
self._config.push_platform = push_platform.encode()
self._config.proxy_user_agent = user_agent.encode()
self._config.server_ca = server_ca._cert
def setPeerDiscovery(self, bool peer_discovery, bool peer_publish):
self._config.peer_discovery = peer_discovery
self._config.peer_publish = peer_publish
def setBound(self, SockAddr bind4, SockAddr bind6):
self._config.bind4 = bind4._addr
self._config.bind6 = bind6._addr
cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
@@ -630,8 +587,7 @@ cdef class DhtRunner(_WithID):
while pending > 0:
lock.wait()
return res
def put(self, InfoHash key, Value val, done_cb=None, permanent=False):
def put(self, InfoHash key, Value val, done_cb=None):
"""Publish a new value on the DHT at key.
key -- the DHT key where to put the value
@@ -641,7 +597,7 @@ cdef class DhtRunner(_WithID):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), cpp.time_point.max(), permanent)
self.thisptr.get().put(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj))
else:
lock = threading.Condition()
pending = 0
@@ -658,76 +614,6 @@ cdef class DhtRunner(_WithID):
while pending > 0:
lock.wait()
return ok
def putSigned(self, InfoHash key, Value val, done_cb=None, permanent=False):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().putSigned(key._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent)
else:
lock = threading.Condition()
pending = 0
ok = False
def tmp_done(ok_ret, nodes):
nonlocal pending, ok, lock
with lock:
ok = ok_ret
pending -= 1
lock.notify()
with lock:
pending += 1
self.putSigned(key, val, done_cb=tmp_done)
while pending > 0:
lock.wait()
return ok
def putEncrypted(self, InfoHash key, InfoHash to, Value val, done_cb=None, bool permanent=False):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().putEncrypted(key._infohash, to._infohash, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent)
else:
lock = threading.Condition()
pending = 0
ok = False
def tmp_done(ok_ret, nodes):
nonlocal pending, ok, lock
with lock:
ok = ok_ret
pending -= 1
lock.notify()
with lock:
pending += 1
self.putEncrypted(key, to, val, done_cb=tmp_done, permanent=permanent)
while pending > 0:
lock.wait()
return ok
def putEncrypted(self, InfoHash key, PublicKey to, Value val, done_cb=None, bool permanent=False):
if done_cb:
cb_obj = {'done':done_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().putEncrypted(key._infohash, to._key, val._value, cpp.bindDoneCb(done_callback, <void*>cb_obj), permanent)
else:
lock = threading.Condition()
pending = 0
ok = False
def tmp_done(ok_ret, nodes):
nonlocal pending, ok, lock
with lock:
ok = ok_ret
pending -= 1
lock.notify()
with lock:
pending += 1
self.putEncrypted(key, to, val, done_cb=tmp_done, permanent=permanent)
while pending > 0:
lock.wait()
return ok
def cancelPut(self, InfoHash key, Value val):
self.thisptr.get().cancelPut(key._infohash, val._value)
def listen(self, InfoHash key, value_cb):
t = ListenToken()
t._h = key._infohash
+13 -32
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
@@ -21,13 +21,12 @@ from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp.utility cimport pair
from libcpp.map cimport map
from libcpp.memory cimport shared_ptr, make_shared
from libc.string cimport const_char, const_uchar
ctypedef uint16_t in_port_t
ctypedef unsigned short int sa_family_t;
cdef extern from "<chrono>" namespace "std::chrono" nogil:
cdef extern from "<iostream>" namespace "std::chrono" nogil:
cdef cppclass duration[ulong]:
duration() except +
@@ -35,6 +34,16 @@ cdef extern from "<chrono>" namespace "std::chrono" nogil:
duration seconds(uint64_t) except +
duration seconds()
cdef extern from "<memory>" namespace "std" nogil:
cdef cppclass shared_ptr[T]:
shared_ptr() except +
shared_ptr(T*) except +
T* get()
T operator*()
bool operator bool() const
void reset(T*)
shared_ptr[T] make_shared[T](...) except +
cdef extern from "<functional>" namespace "std" nogil:
cdef cppclass hash[T]:
hash() except +
@@ -50,13 +59,6 @@ cdef extern from "<future>" namespace "std" nogil:
bool valid() const
shared_future[T] share()
cdef extern from "opendht/utils.h" namespace "dht":
cdef cppclass time_point:
@staticmethod
time_point min() const
@staticmethod
time_point max() const
cdef extern from "opendht/infohash.h" namespace "dht":
cdef cppclass InfoHash:
InfoHash() except +
@@ -86,16 +88,12 @@ cdef extern from "opendht/sockaddr.h" namespace "dht":
bool isLoopback() const
bool isPrivate() const
bool isUnspecified() const
@staticmethod
vector[SockAddr] resolve(string host, string service) except +
ctypedef vector[uint8_t] Blob
cdef extern from "opendht/crypto.h" namespace "dht::crypto":
ctypedef pair[shared_ptr[PrivateKey], shared_ptr[Certificate]] Identity
cdef Identity generateIdentity(string name, Identity ca, unsigned bits)
cdef Blob aesEncrypt(Blob data, string password) except +
cdef Blob aesDecrypt(Blob encrypted, string password) except +
cdef cppclass PrivateKey:
PrivateKey()
@@ -241,19 +239,6 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
cppclass Config:
SecureDhtConfig dht_config
bool threaded
string proxy_server
string push_node_id
string push_token
string push_topic
string push_platform
string proxy_user_agent
bool peer_discovery
bool peer_publish
shared_ptr[Certificate] server_ca
Identity client_identity
SockAddr bind4
SockAddr bind6
InfoHash getId() const
InfoHash getNodeId() const
void bootstrap(const_char*, const_char*)
@@ -269,11 +254,7 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
string getRoutingTablesLog(sa_family_t af) const
string getSearchesLog(sa_family_t af) const
void get(InfoHash key, GetCallback get_cb, DoneCallback done_cb, nullptr_t f, Where w)
void put(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb, time_point created, bool permanent)
void putSigned(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void putEncrypted(InfoHash key, InfoHash to, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void putEncrypted(InfoHash key, shared_ptr[PublicKey] to, shared_ptr[Value] val, DoneCallback done_cb, bool permanent)
void cancelPut(InfoHash key, shared_ptr[Value] val)
void put(InfoHash key, shared_ptr[Value] val, DoneCallback done_cb)
ListenToken listen(InfoHash key, ValueCallback get_cb)
void cancelListen(InfoHash key, SharedListenToken token)
vector[unsigned] getNodeMessageStats(bool i)
+6 -3
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2014-2023 Savoir-faire Linux Inc.
# Copyright (C) 2014-2022 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
@@ -32,14 +32,17 @@ setup(name="opendht",
author="Adrien Béraud, Guillaume Roguez, Simon Désaulniers",
license="GPLv3",
classifiers=[
'Development Status :: 5 - Production/Stable',
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Distributed Computing',
'Topic :: System :: Networking'
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
cmdclass = { 'build_ext' : build_ext },
ext_modules = cythonize(Extension(
+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-2022 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) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 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,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2023 Savoir-Faire Linux Inc.
# Copyright (C) 2015-2022 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) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+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-2022 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
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2016-2023 Savoir-faire Linux Inc.
# Copyright (c) 2016-2022 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -72,7 +72,7 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Launch an OpenDHT node with an HTTP control interface')
parser.add_argument('-p', '--port', help='OpenDHT port to bind', type=int, default=4222)
parser.add_argument('-hp', '--http-port', help='HTTP port to bind', type=int, default=8080)
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default="bootstrap.jami.net:4222")
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default="bootstrap.ring.cx:4222")
args = parser.parse_args()
endpoints.serverFromString(reactor, "tcp:"+str(args.http_port)).listen(server.Site(DhtServer(args.port, args.bootstrap)))
reactor.run()
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@ from datetime import datetime
import opendht as dht
parser = argparse.ArgumentParser(description='Create a dht network of -n nodes')
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default='bootstrap.jami.net')
parser.add_argument('-b', '--bootstrap', help='bootstrap address', default='bootstrap.ring.cx')
parser.add_argument('-n', '--num-ops', help='number of concurrent operations on the DHT', type=int, default=8)
parser.add_argument('-p', '--period', help='duration between each test (seconds)', type=int, default=60)
parser.add_argument('-t', '--timeout', help='timeout for a test to complete (seconds)', type=float, default=15)
+3 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,8 @@ config.setRateLimit(-1, -1)
ping_node = dht.DhtRunner()
ping_node.run(config=config)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.jami.net", "4222")
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run(config=config)
#pong_node.enableLogging()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2023 Savoir-faire Linux Inc.
# Copyright (c) 2015-2022 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+5 -5
View File
@@ -2,10 +2,10 @@
name = "opendht"
version = "0.1.0"
authors = ["Sébastien Blin <sebastien.blin@savoirfairelinux.com>"]
edition = "2021"
[dependencies]
libc="0.2"
os_socketaddr="0.2.3"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc="0.2.0"
os_socketaddr="0.2.3"
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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-2022 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-2022 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+9 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -49,7 +49,6 @@ impl DhtRunnerConfig {
push_token: ptr::null(),
push_topic: ptr::null(),
push_platform: ptr::null(),
proxy_user_agent: ptr::null(),
peer_discovery: false,
peer_publish: false,
server_ca: ptr::null_mut(),
@@ -57,7 +56,6 @@ impl DhtRunnerConfig {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
log: true,
});
unsafe {
dht_runner_config_default(&mut *config);
@@ -66,27 +64,23 @@ impl DhtRunnerConfig {
}
pub fn set_proxy_server(&mut self, proxy_server: &str) {
self.proxy_server = CString::new(proxy_server).unwrap().into_raw();
self.proxy_server = CString::new(proxy_server).unwrap().as_ptr();
}
pub fn set_push_node_id(&mut self, push_node_id: &str) {
self.push_node_id = CString::new(push_node_id).unwrap().into_raw();
self.push_node_id = CString::new(push_node_id).unwrap().as_ptr();
}
pub fn set_push_token(&mut self, push_token: &str) {
self.push_token = CString::new(push_token).unwrap().into_raw();
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_push_topic(&mut self, push_topic: &str) {
self.push_topic = CString::new(push_topic).unwrap().into_raw();
self.push_topic = CString::new(push_topic).unwrap().as_ptr();
}
pub fn set_push_platform(&mut self, push_platform: &str) {
self.push_platform = CString::new(push_platform).unwrap().into_raw();
}
pub fn set_proxy_user_agent(&mut self, proxy_user_agent: &str) {
self.proxy_user_agent = CString::new(proxy_user_agent).unwrap().into_raw();
self.push_platform = CString::new(push_platform).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
@@ -99,7 +93,7 @@ impl DhtRunnerConfig {
impl DhtNodeConfig
{
pub fn set_persist_path(&mut self, persist_path: &str) {
self.persist_path = CString::new(persist_path).unwrap().into_raw();
self.persist_path = CString::new(persist_path).unwrap().as_ptr();
}
}
@@ -203,8 +197,8 @@ impl DhtRunner {
pub fn bootstrap(&mut self, host: &str, service: u16) {
unsafe {
dht_runner_bootstrap(&mut *self,
CString::new(host).unwrap().into_raw(),
CString::new(service.to_string()).unwrap().into_raw())
CString::new(host).unwrap().as_ptr(),
CString::new(service.to_string()).unwrap().as_ptr())
}
}
+2 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -120,14 +120,13 @@ pub struct DhtRunnerConfig
pub push_token: *const c_char,
pub push_topic: *const c_char,
pub push_platform: *const c_char,
pub proxy_user_agent: *const c_char,
pub peer_discovery: bool,
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
pub client_identity: DhtIdentity,
pub log: bool,
}
#[link(name = "opendht-c")]
extern {
// dht::Value
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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-2022 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-2022 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-2022 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+5 -2
View File
@@ -29,13 +29,16 @@ libopendht_la_SOURCES = \
network_utils.cpp \
thread_pool.cpp
if WIN32
libopendht_la_SOURCES += rng.cpp
endif
nobase_include_HEADERS = \
../include/opendht.h \
../include/opendht/def.h \
../include/opendht/dht.h \
../include/opendht/callbacks.h \
../include/opendht/node_cache.h \
../include/opendht/node_export.h \
../include/opendht/routing_table.h \
../include/opendht/network_engine.h \
../include/opendht/scheduler.h \
@@ -50,7 +53,7 @@ nobase_include_HEADERS = \
../include/opendht/dhtrunner.h \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/logger.h \
../include/opendht/log_enable.h \
../include/opendht/network_utils.h \
../include/opendht/rng.h \
../include/opendht/thread_pool.h
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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-2022 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-2022 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
-39
View File
@@ -1,39 +0,0 @@
//Code from getifaddrs.3 man
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <asio.hpp>
#include <stdexcept>
namespace dht{
namespace workaround{
asio::ip::address_v4
get_interface(){
struct ifaddrs *ifaddr;
if(getifaddrs(&ifaddr) == -1){
throw std::runtime_error("Can't getifaddrs");
}
for (struct ifaddrs *if1 = ifaddr; if1 != NULL; if1 = if1->ifa_next){
if (if1->ifa_addr == NULL)
continue;
if (if1->ifa_addr->sa_family != AF_INET)
continue;
if((if1->ifa_flags & IFF_MULTICAST) == IFF_MULTICAST){
auto sa_data = reinterpret_cast<uint8_t*>(if1->ifa_addr->sa_data);
uint32_t value = sa_data[2] << 24
| sa_data[3] << 16
| sa_data[4] << 8
| sa_data[5];
freeifaddrs(ifaddr);
return asio::ip::address_v4(value);
}
}
freeifaddrs(ifaddr);
throw std::runtime_error("Can't find a interface which supports multicast");
}
} /* namespace workaround */
} /* namespace dht */
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
+93 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,8 @@
*/
#include "os_cert.h"
#include "logger.h"
#include "log_enable.h"
#ifdef _WIN32
#include <windows.h>
@@ -31,6 +32,96 @@
#include <Security/Security.h>
#endif /*TARGET_OS_OSX*/
#if EMBEDDED_ASN1_TIME_PARSE
#undef X509_NAME
#undef OCSP_REQUEST
#undef OCSP_RESPONSE
#define GENTIME_LENGTH 15
#define UTCTIME_LENGTH 13
#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
extern "C" {
// Taken from libressl/src/crypto/asn1/a_time_tm.c
int
ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
{
size_t i;
int type = 0;
struct tm ltm;
struct tm* lt;
const char* p;
if (bytes == NULL)
return (-1);
/* Constrain to valid lengths. */
if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH)
return (-1);
lt = tm;
if (lt == NULL) {
memset(&ltm, 0, sizeof(ltm));
lt = &ltm;
}
/* Timezone is required and must be GMT (Zulu). */
if (bytes[len - 1] != 'Z')
return (-1);
/* Make sure everything else is digits. */
for (i = 0; i < len - 1; i++) {
if (isdigit((unsigned char) bytes[i]))
continue;
return (-1);
}
/*
* Validate and convert the time
*/
p = bytes;
switch (len) {
case GENTIME_LENGTH:
if (mode == V_ASN1_UTCTIME)
return (-1);
lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */
type = V_ASN1_GENERALIZEDTIME;
/* FALLTHROUGH */
case UTCTIME_LENGTH:
if (type == 0) {
if (mode == V_ASN1_GENERALIZEDTIME)
return (-1);
type = V_ASN1_UTCTIME;
}
lt->tm_year += ATOI2(p); /* yy */
if (type == V_ASN1_UTCTIME) {
if (lt->tm_year < 50)
lt->tm_year += 100;
}
lt->tm_mon = ATOI2(p) - 1; /* mm */
if (lt->tm_mon < 0 || lt->tm_mon > 11)
return (-1);
lt->tm_mday = ATOI2(p); /* dd */
if (lt->tm_mday < 1 || lt->tm_mday > 31)
return (-1);
lt->tm_hour = ATOI2(p); /* HH */
if (lt->tm_hour < 0 || lt->tm_hour > 23)
return (-1);
lt->tm_min = ATOI2(p); /* MM */
if (lt->tm_min < 0 || lt->tm_min > 59)
return (-1);
lt->tm_sec = ATOI2(p); /* SS */
/* Leap second 60 is not accepted. Reconsider later? */
if (lt->tm_sec < 0 || lt->tm_sec > 59)
return (-1);
break;
default:
return (-1);
}
return type;
}
}
#endif /* EMBEDDED_ASN1_TIME_PARSE */
namespace dht {
namespace http {
+32 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,12 +18,42 @@
#pragma once
#include "logger.h"
#include "log_enable.h"
#include <memory>
#include <openssl/x509.h>
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER > 0x20501000L))
#define EMBEDDED_ASN1_TIME_PARSE 0
#else
#define EMBEDDED_ASN1_TIME_PARSE 1
#endif
#if EMBEDDED_ASN1_TIME_PARSE
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
extern "C" {
/*
* Parse an RFC 5280 format ASN.1 time string.
*
* mode must be:
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
*
* Returns:
* -1 if the string was invalid.
* V_ASN1_UTCTIME if the string validated as a UTC time string.
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
*
* Fills in *tm with the corresponding time if tm is non NULL.
*/
int ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode);
}
#endif
namespace dht {
namespace http {
+65 -156
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -43,6 +43,8 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
#define DHT_AES_LEGACY_DECRYPT 1
namespace dht {
namespace crypto {
@@ -90,38 +92,24 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
Blob ret(data_length + GCM_IV_SIZE + GCM_DIGEST_SIZE);
{
std::random_device rdev;
crypto::random_device rdev;
std::generate_n(ret.begin(), GCM_IV_SIZE, std::bind(rand_byte, std::ref(rdev)));
}
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes128_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes192_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes256_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
}
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
return ret;
}
Blob aesEncrypt(const Blob& data, std::string_view password, const Blob& salt)
Blob aesEncrypt(const Blob& data, const std::string& password)
{
Blob salt_actual = salt;
Blob key = stretchKey(password, salt_actual, 256 / 8);
return aesBuildEncrypted(aesEncrypt(data, key), salt_actual);
Blob salt;
Blob key = stretchKey(password, salt, 256 / 8);
Blob encrypted = aesEncrypt(data, key);
encrypted.insert(encrypted.begin(), salt.begin(), salt.end());
return encrypted;
}
Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
@@ -134,78 +122,50 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
std::array<uint8_t, GCM_DIGEST_SIZE> digest;
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, data);
size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE;
Blob ret(data_sz);
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes128_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes192_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes256_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, digest.data());
}
gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE)) {
#if DHT_AES_LEGACY_DECRYPT
//gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
Blob ret_tmp(data_sz);
struct gcm_aes_ctx aes_d;
gcm_aes_set_key(&aes_d, key.size(), key.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data);
gcm_aes_update(&aes_d, ret.size(), ret.data());
gcm_aes_encrypt(&aes_d, ret.size(), ret_tmp.data(), ret.data());
gcm_aes_digest(&aes_d, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE))
throw DecryptError("Can't decrypt data");
#else
throw DecryptError("Can't decrypt data");
#endif
}
return ret;
}
Blob aesDecrypt(const uint8_t* data, size_t data_length, std::string_view password)
Blob aesDecrypt(const uint8_t* data, size_t data_len, const std::string& password)
{
return aesDecrypt(
aesGetEncrypted(data, data_length),
aesGetKey(data, data_length, password)
);
}
Blob aesGetSalt(const uint8_t* data, size_t data_length)
{
if (data_length <= PASSWORD_SALT_LENGTH)
if (data_len <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
return Blob {data, data+PASSWORD_SALT_LENGTH};
Blob salt {data, data+PASSWORD_SALT_LENGTH};
Blob key = stretchKey(password, salt, 256/8);
return aesDecrypt(data+PASSWORD_SALT_LENGTH, data_len - PASSWORD_SALT_LENGTH, key);
}
std::string_view aesGetEncrypted(const uint8_t* data, size_t data_length)
{
if (data_length <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
return std::string_view((const char*)(data+PASSWORD_SALT_LENGTH), data_length - PASSWORD_SALT_LENGTH);
}
Blob aesBuildEncrypted(const uint8_t* data, size_t data_length, const Blob& salt)
{
Blob ret;
ret.reserve(data_length + salt.size());
ret.insert(ret.end(), salt.begin(), salt.end());
ret.insert(ret.end(), data, data + data_length);
return ret;
}
Blob aesGetKey(const uint8_t* data, size_t data_length, std::string_view password)
{
Blob salt = aesGetSalt(data, data_length);
return stretchKey(password, salt, 256/8);
}
Blob stretchKey(std::string_view password, Blob& salt, size_t key_length)
Blob stretchKey(const std::string& password, Blob& salt, size_t key_length)
{
if (salt.empty()) {
salt.resize(PASSWORD_SALT_LENGTH);
std::random_device rdev;
crypto::random_device rdev;
std::generate_n(salt.begin(), salt.size(), std::bind(rand_byte, std::ref(rdev)));
}
Blob res;
@@ -257,7 +217,7 @@ PrivateKey::PrivateKey(const uint8_t* src, size_t src_size, const char* password
throw CryptoException("Can't initialize private key !");
const gnutls_datum_t dt {(uint8_t*)src, static_cast<unsigned>(src_size)};
int flags = (password_ptr == NULL || strlen(password_ptr)==0) ? GNUTLS_PKCS_PLAIN
int flags = password_ptr ? GNUTLS_PKCS_PLAIN
: ( GNUTLS_PKCS_PBES2_AES_128 | GNUTLS_PKCS_PBES2_AES_192 | GNUTLS_PKCS_PBES2_AES_256
| GNUTLS_PKCS_PKCS12_3DES | GNUTLS_PKCS_PKCS12_ARCFOUR | GNUTLS_PKCS_PKCS12_RC2_40);
@@ -321,7 +281,7 @@ PrivateKey::sign(const uint8_t* data, size_t data_length) const
throw CryptoException("Can't sign data: no private key set !");
if (std::numeric_limits<unsigned>::max() < data_length)
throw CryptoException("Can't sign data: too large !");
gnutls_datum_t sig {nullptr, 0};
gnutls_datum_t sig;
const gnutls_datum_t dat {(unsigned char*)data, (unsigned)data_length};
if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't sign data !");
@@ -334,7 +294,7 @@ Blob
PrivateKey::decryptBloc(const uint8_t* src, size_t src_size) const
{
const gnutls_datum_t dat {(uint8_t*)src, (unsigned)src_size};
gnutls_datum_t out {nullptr, 0};
gnutls_datum_t out;
int err = gnutls_privkey_decrypt_data(key, 0, &dat, &out);
if (err != GNUTLS_E_SUCCESS)
throw DecryptError(std::string("Can't decrypt data: ") + gnutls_strerror(err));
@@ -512,7 +472,7 @@ void
PublicKey::encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t dst_size) const
{
const gnutls_datum_t key_dat {(uint8_t*)src, (unsigned)src_size};
gnutls_datum_t encrypted {nullptr, 0};
gnutls_datum_t encrypted;
auto err = gnutls_pubkey_encrypt_data(pk, 0, &key_dat, &encrypted);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Can't encrypt data: ") + gnutls_strerror(err));
@@ -553,7 +513,7 @@ PublicKey::encrypt(const uint8_t* data, size_t data_len) const
throw CryptoException("Key is not long enough for AES128");
Blob key(aes_key_sz);
{
std::random_device rdev;
crypto::random_device rdev;
std::generate_n(key.begin(), key.size(), std::bind(rand_byte, std::ref(rdev)));
}
auto data_encrypted = aesEncrypt(data, data_len, key);
@@ -1015,7 +975,7 @@ Certificate::toString(bool chain) const
std::string
Certificate::print() const
{
gnutls_datum_t out {nullptr, 0};
gnutls_datum_t out;
gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &out);
std::string ret(out.data, out.data+out.size);
gnutls_free(out.data);
@@ -1091,7 +1051,7 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
err = gnutls_ocsp_req_set_nonce(req.get(), 0, &nonce);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
gnutls_datum_t rdata {nullptr, 0};
gnutls_datum_t rdata;
err = gnutls_ocsp_req_export(req.get(), &rdata);
if (err != 0)
throw CryptoException(gnutls_strerror(err));
@@ -1164,47 +1124,14 @@ saveIdentity(const Identity& id, const std::string& path, const std::string& pri
auto ca_key_data = id.first->serialize(privkey_password);
std::ofstream key_file(path + ".pem");
key_file.write((char*)ca_key_data.data(), ca_key_data.size());
// Throw error if the file is not written
if (!key_file)
throw CryptoException("Could not write private key file");
}
{
auto ca_key_data = id.second->getPacked();
std::ofstream crt_file(path + ".crt");
crt_file.write((char*)ca_key_data.data(), ca_key_data.size());
// Throw error if the file is not written
if (!crt_file)
throw CryptoException("Could not write certificate file");
}
}
Identity
loadIdentity(const std::string &path,const std::string &privkey_password)
{
std::ifstream pkStream(path + ".pem", std::ios::in | std::ios::binary);
std::vector<uint8_t> pkContent((std::istreambuf_iterator<char>(pkStream)),
std::istreambuf_iterator<char>());
auto key = std::make_shared<PrivateKey>(pkContent, privkey_password);
pkStream.close();
// Create a certificate
gnutls_x509_crt_t gnuCert;
if (gnutls_x509_crt_init(&gnuCert))
throw std::runtime_error("Failed to initialize gnutls certificate struct");
gnutls_datum_t crtContent {nullptr, 0};
// Read the certificate file
int err = gnutls_load_file((path + ".crt").c_str(), &crtContent);
if (err)
throw CryptoException(gnutls_strerror(err));
err = gnutls_x509_crt_import(gnuCert, &crtContent, GNUTLS_X509_FMT_PEM);
if (err)
throw CryptoException(gnutls_strerror(err));
auto cert = std::make_shared<Certificate>(gnuCert);
return {std::move(key), std::move(cert)};
}
void
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
{
@@ -1220,7 +1147,7 @@ setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
void
setRandomSerial(gnutls_x509_crt_t cert)
{
std::random_device rdev;
random_device rdev;
std::uniform_int_distribution<int64_t> dist{1};
int64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
@@ -1247,49 +1174,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
int err = gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
if(err) {
throw CryptoException(std::string("Error when setting dn by oid ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
err = gnutls_x509_crt_set_ca_status(cert, 1);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_ca_status(cert, 1);
key_usage |= GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN;
} else {
key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_DATA_ENCIPHERMENT;
}
err = gnutls_x509_crt_set_key_usage(cert, key_usage);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_key_usage(cert, key_usage);
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
throw CryptoException("Signing certificate must be CA");
}
err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0);
if (err) {
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
} else {
err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0);
if (err) {
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
@@ -1385,7 +1294,7 @@ std::string
OcspRequest::toString(const bool compact) const
{
int ret;
gnutls_datum_t dat {nullptr, 0};
gnutls_datum_t dat;
ret = gnutls_ocsp_req_print(request, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat);
std::string str;
@@ -1400,7 +1309,7 @@ OcspRequest::toString(const bool compact) const
Blob
OcspRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
gnutls_datum_t dat;
int err = gnutls_ocsp_req_export(request, &dat);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
@@ -1412,7 +1321,7 @@ OcspRequest::pack() const
Blob
OcspRequest::getNonce() const
{
gnutls_datum_t dat {nullptr, 0};
gnutls_datum_t dat;
unsigned critical;
int err = gnutls_ocsp_req_get_nonce(request, &critical, &dat);
if (err < 0)
@@ -1445,7 +1354,7 @@ OcspResponse::~OcspResponse()
Blob
OcspResponse::pack() const
{
gnutls_datum_t dat {nullptr, 0};
gnutls_datum_t dat;
int err = gnutls_ocsp_resp_export(response, &dat);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
@@ -1459,7 +1368,7 @@ OcspResponse::toString(const bool compact) const
{
int ret;
std::string str;
gnutls_datum_t dat {nullptr, 0};
gnutls_datum_t dat;
ret = gnutls_ocsp_resp_print(response, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat);
if (ret == 0)
str = std::string((const char*)dat.data, (size_t)dat.size);
@@ -1494,7 +1403,7 @@ OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce)
if (not nonce.empty()) {
// Ensure no replay attack has been done
gnutls_datum_t rnonce {nullptr, 0};
gnutls_datum_t rnonce;
ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
@@ -1711,7 +1620,7 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration vali
if (number == 0) {
// initialize to a random number
number_sz = sizeof(number);
std::random_device rdev;
random_device rdev;
std::generate_n((uint8_t*)&number, sizeof(number), std::bind(rand_byte, std::ref(rdev)));
} else
number = endian(endian(number) + 1);
@@ -1752,7 +1661,7 @@ RevocationList::getNumber() const
std::string
RevocationList::toString() const
{
gnutls_datum_t out {nullptr, 0};
gnutls_datum_t out;
gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_FULL, &out);
std::string ret(out.data, out.data+out.size);
gnutls_free(out.data);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+130 -158
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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) {
for (auto& cb : a.callbacks) cb(false, {});
if (a.callback) a.callback(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("Shutting down node: %u ops remaining", *remaining);
logger_->w("shuting 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("Shutting down node: after storage, %u ops", *remaining);
logger_->w("shuting down node: after storage, %u ops", *remaining);
if (!*remaining) {
if (cb) cb();
@@ -147,25 +147,17 @@ 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);
}
std::vector<SockAddr>
Dht::getPublicAddress(sa_family_t family)
{
std::sort(reported_addr.begin(), reported_addr.end(), [](const ReportedAddr& a, const ReportedAddr& b) {
return a.first > b.first;
});
std::vector<SockAddr> ret;
if (family == AF_UNSPEC) {
auto& d4 = dht(AF_INET).reported_addr;
auto& d6 = dht(AF_INET6).reported_addr;
ret.reserve(d4.size() + d6.size());
for (const auto& a : d4)
ret.emplace_back(a.second);
for (const auto& a : d6)
ret.emplace_back(a.second);
return ret;
}
auto& reported_addr = dht(family).reported_addr;
ret.reserve(!family ? reported_addr.size() : reported_addr.size()/2);
for (const auto& addr : reported_addr)
if (!family || family == addr.second.getFamily())
@@ -208,8 +200,6 @@ Dht::trySearchInsert(const Sp<Node>& node)
void
Dht::reportedAddr(const SockAddr& addr)
{
auto& reported_addr = dht(addr.getFamily()).reported_addr;
auto firstBefore = reported_addr.empty() ? nullptr : reported_addr.begin()->second.get();
auto it = std::find_if(reported_addr.begin(), reported_addr.end(), [&](const ReportedAddr& a){
return a.second == addr;
});
@@ -218,21 +208,6 @@ Dht::reportedAddr(const SockAddr& addr)
reported_addr.emplace_back(1, addr);
} else
it->first++;
std::sort(reported_addr.begin(), reported_addr.end(), [](const ReportedAddr& a, const ReportedAddr& b) {
return a.first > b.first;
});
if (publicAddressChangedCb_) {
auto firstAfter = reported_addr.begin()->second.get();
if (firstBefore != firstAfter) {
auto& otherDht = dht(addr.getFamily() == AF_INET ? AF_INET6 : AF_INET).reported_addr;
std::vector<SockAddr> v;
v.reserve(otherDht.empty() ? 1 : 2);
v.emplace_back(reported_addr.begin()->second);
if (not otherDht.empty())
v.emplace_back(otherDht.begin()->second);
publicAddressChangedCb_(std::move(v));
}
}
}
/* We just learnt about a node, not necessarily a new one. Confirm is 1 if
@@ -280,7 +255,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 +335,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 +346,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 +356,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 +401,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 +414,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 +428,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
paginate(ws, query, n);
}
/* We only attempt to send one request. Return. */
/* We only try to send one request. return. */
return n;
} while (++cb != sr->callbacks.end());
@@ -462,9 +437,10 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
return nullptr;
}
void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
if (sr->announce.empty())
return;
unsigned i = 0;
std::weak_ptr<Search> ws = sr;
auto onDone = [this,ws](const net::Request& req, net::RequestAnswer&& answer)
@@ -519,7 +495,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 +504,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 +516,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 +534,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;
@@ -576,7 +552,6 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
static const auto PROBE_QUERY = std::make_shared<Query>(Select {}.field(Value::Field::Id).field(Value::Field::SeqNum));
const auto& now = scheduler.time();
unsigned i = 0;
for (auto& np : sr->nodes) {
auto& n = *np;
if (not n.isSynced(now))
@@ -594,7 +569,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 +582,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,
@@ -617,7 +592,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
std::bind(&Dht::searchNodeGetExpired, this, _1, _2, ws, PROBE_QUERY));
n.getStatus[PROBE_QUERY] = std::move(req);
}
if (not n.candidate and ++i == syncLevel)
if (not n.candidate and ++i == TARGET_NODES)
break;
}
}
@@ -634,7 +609,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()) {
@@ -700,13 +675,9 @@ Dht::searchStep(std::weak_ptr<Search> ws)
if (not sr or sr->expired or sr->done) return;
const auto& now = scheduler.time();
auto level = sr->syncLevel(now);
constexpr auto MARGIN = 1;
bool preSynced = level > MARGIN;
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;
@@ -764,21 +735,6 @@ Dht::searchStep(std::weak_ptr<Search> ws)
if (sr->callbacks.empty() && sr->announce.empty() && sr->listeners.empty())
sr->setDone();
} else if (preSynced) {
if (not sr->listeners.empty()) {
auto nl = std::min(syncLevel, LISTEN_NODES);
unsigned i = 0;
for (auto& n : sr->nodes) {
if (not n->isSynced(now))
break;
searchSynchedNodeListen(sr, *n);
if (++i == nl)
break;
}
}
// Announce requests
searchSendAnnounceValue(sr, syncLevel);
}
while (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES and searchSendGetValues(sr));
@@ -787,7 +743,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 +760,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 +772,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 +784,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 +812,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 +826,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 +860,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_duration(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_dt(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("Unable to create search");
throw DhtException("Can't create search");
if (logger_)
logger_->w(id, "[search %s IPv%c] Listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
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 +978,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 +1221,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 +1242,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 +1348,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 +1366,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 +1388,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
@@ -1483,10 +1439,11 @@ Dht::connectivityChanged(sa_family_t af)
{
const auto& now = scheduler.time();
scheduler.edit(nextNodesConfirmation, now);
auto& dht = this->dht(af);
dht.buckets.connectivityChanged(now);
dht.reported_addr.clear();
buckets(af).connectivityChanged(now);
network_engine.connectivityChanged(af);
reported_addr.erase(std::remove_if(reported_addr.begin(), reported_addr.end(), [&](const ReportedAddr& addr){
return addr.second.getFamily() == af;
}), reported_addr.end());
startBootstrap(); // will only happen if disconnected
}
@@ -1603,20 +1560,21 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const
const auto& now = scheduler.time();
const auto& listen_expire = getListenExpiration();
using namespace std::chrono;
fmt::print(out, "Search IPv{} {} gets: {} last step: {}{}{}{}{}\n",
(sr.af == AF_INET6 ? '6' : '4'),
sr.id,
sr.callbacks.size(),
print_time_relative(now, sr.step_time),
(sr.done ? " [done]"sv : ""sv),
(sr.expired ? " [expired]"sv : ""sv),
(sr.isSynced(now) ? " [synced]"sv : " [not synced]"sv),
(sr.isListening(now, listen_expire) ? " [listening]"sv : ""sv)
);
out << std::endl << "Search IPv" << (sr.af == AF_INET6 ? '6' : '4') << ' ' << sr.id << " gets: " << sr.callbacks.size();
out << ", last step: " << print_time_relative(now, sr.step_time);
if (sr.done)
out << " [done]";
if (sr.expired)
out << " [expired]";
bool synced = sr.isSynced(now);
out << (synced ? " [synced]" : " [not synced]");
if (synced && sr.isListening(now, listen_expire))
out << " [listening]";
out << std::endl;
// printing the queries
/*printing the queries*/
if (sr.callbacks.size() + sr.listeners.size() > 0)
fmt::print(out, "Queries:\n");
out << "Queries:" << std::endl;
for (const auto& cb : sr.callbacks) {
out << *cb.second.query << std::endl;
}
@@ -1629,39 +1587,55 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const
out << "Announcement: " << *a.value << (announced ? " [announced]" : "") << std::endl;
}
fmt::print(out, " Common bits InfoHash Conn. Get Ops IP\n");
out << " Common bits InfoHash Conn. Get Ops IP" << std::endl;
auto last_get = sr.getLastGetTime();
for (const auto& np : sr.nodes) {
auto& n = *np;
auto listen = (not sr.listeners.empty() ? (n.listenStatus.empty() ? " " : fmt::format("[{}] ", (n.isListening(now,listen_expire) ? 'l' : (n.pending(n.listenStatus) ? 'f' : ' ')))) : "");
std::string announce;
out << std::setfill (' ') << std::setw(3) << InfoHash::commonBits(sr.id, n.node->id) << ' ' << n.node->id;
out << ' ' << (findNode(n.node->id, sr.af) ? '*' : ' ');
out << " [";
if (auto pendingCount = n.node->getPendingMessageCount())
out << pendingCount;
else
out << ' ';
out << (n.node->isExpired() ? 'x' : ' ') << "]";
// Get status
{
char g_i = n.pending(n.getStatus) ? (n.candidate ? 'c' : 'f') : ' ';
char s_i = n.isSynced(now) ? (n.last_get_reply > last_get ? 'u' : 's') : '-';
out << " [" << s_i << g_i << "] ";
}
// Listen status
if (not sr.listeners.empty()) {
if (n.listenStatus.empty())
out << " ";
else
out << "["
<< (n.isListening(now,listen_expire) ? 'l' : (n.pending(n.listenStatus) ? 'f' : ' ')) << "] ";
}
// Announce status
if (not sr.announce.empty()) {
if (n.acked.empty()) {
announce = std::string(sr.announce.size() + 3, ' ');
out << " ";
for (size_t a=0; a < sr.announce.size(); a++)
out << ' ';
} else {
announce = "[";
out << "[";
for (const auto& a : sr.announce) {
auto ack = n.acked.find(a.value->id);
if (ack == n.acked.end() or not ack->second.req) {
announce += ' ';
out << ' ';
} else {
announce += ack->second.req->getStateChar();
out << ack->second.req->getStateChar();
}
}
announce += "] ";
out << "] ";
}
}
fmt::print(out, "{:3} {} {} [{}{}] {}{}{}\n",
InfoHash::commonBits(sr.id, n.node->id),
n.node->id,
(findNode(n.node->id, sr.af) ? '*' : ' '),
(n.pending(n.getStatus) ? (n.candidate ? 'c' : 'f') : ' '),
(n.isSynced(now) ? (n.last_get_reply > last_get ? 'u' : 's') : '-'),
listen,
announce,
n.node->getAddrStr()
);
out << n.node->getAddrStr() << std::endl;
}
}
@@ -1812,13 +1786,11 @@ fromDhtConfig(const Config& config)
netConf.max_peer_req_per_sec = config.max_peer_req_per_sec
? config.max_peer_req_per_sec
: netConf.max_req_per_sec/8;
netConf.is_client = config.client_mode;
return netConf;
}
Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l, std::unique_ptr<std::mt19937_64>&& rda)
Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l)
: DhtInterface(l),
rd(rda ? std::move(*rda) : crypto::getSeededRandomEngine<std::mt19937_64>()),
myid(config.node_id ? config.node_id : InfoHash::getRandom(rd)),
store(),
store_quota(),
@@ -1868,7 +1840,7 @@ Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, cons
expire();
if (logger_)
logger_->debug("DHT node initialised with ID {:s}", myid);
logger_->d("DHT node initialised with ID %s", myid.toString().c_str());
}
bool
@@ -1900,7 +1872,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 +1926,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 +1951,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 +2005,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("Unable to process message: %s", e.what());
logger_->w("Can't process message: %s", e.what());
}
}
return scheduler.run();
@@ -2087,7 +2059,7 @@ Dht::bootstrap()
}
} catch (const std::exception& e) {
if (logger_)
logger_->e(myid, "Unable to resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
}
}
scheduler.cancel(bootstrapJob);
@@ -2118,12 +2090,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);
}
@@ -2260,7 +2232,7 @@ Dht::pingNode(SockAddr sa, DoneCallbackSimple&& cb)
{
scheduler.syncTime();
if (logger_)
logger_->debug("Sending ping to {}", sa);
logger_->d("Sending ping to %s", sa.toString().c_str());
auto& count = dht(sa.getFamily()).pending_pings;
count++;
network_engine.sendPing(std::move(sa), [&count,cb](const net::Request&, net::RequestAnswer&&) {
@@ -2281,7 +2253,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 +2268,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 +2319,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 +2331,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 +2391,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 +2408,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 +2416,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 +2428,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 +2448,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 +2456,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 +2465,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 +2474,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 +2486,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 +2505,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 +2524,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 +2555,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 +2580,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);
+29 -94
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -23,9 +23,10 @@
#include "op_cache.h"
#include "utils.h"
#include <llhttp.h>
#include <http_parser.h>
#include <deque>
namespace dht {
struct DhtProxyClient::InfoState {
@@ -97,7 +98,7 @@ std::string
getRandomSessionId(size_t length = 8) {
static constexpr const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~";
std::string str(length, 0);
std::random_device rdev;
crypto::random_device rdev;
std::uniform_int_distribution<> dist(0, (sizeof(chars)/sizeof(char)) - 2);
std::generate_n( str.begin(), length, [&]{ return chars[dist(rdev)]; } );
return str;
@@ -106,26 +107,13 @@ getRandomSessionId(size_t length = 8) {
DhtProxyClient::DhtProxyClient() {}
DhtProxyClient::DhtProxyClient(
std::shared_ptr<dht::crypto::Certificate> serverCA,
dht::crypto::Identity clientIdentity,
std::function<void()> signal,
const std::string& serverHost,
const std::string& userAgent,
const std::string& pushClientId,
const std::string& pushToken,
const std::string& pushTopic,
const std::string& pushPlatform,
std::shared_ptr<dht::Logger> logger
)
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
std::function<void()> signal, const std::string& serverHost,
const std::string& pushClientId, std::shared_ptr<dht::Logger> logger)
: DhtInterface(logger)
, proxyUrl_(serverHost)
, clientIdentity_(clientIdentity), serverCertificate_(serverCA)
, userAgent_(userAgent)
, pushClientId_(pushClientId)
, pushSessionId_(getRandomSessionId())
, deviceKey_(pushToken)
, notificationTopic_(pushTopic)
, platform_(pushPlatform)
, pushClientId_(pushClientId), pushSessionId_(getRandomSessionId())
, loopSignal_(signal)
, jsonReader_(Json::CharReaderBuilder{}.newCharReader())
{
@@ -203,12 +191,10 @@ void
DhtProxyClient::stop()
{
if (not isDestroying_.exchange(true)) {
std::shared_ptr<http::Resolver> resolver;
{
std::lock_guard<std::mutex> l(resolverLock_);
resolver = std::move(resolver_);
resolver_.reset();
}
resolver->cancel();
cancelAllListeners();
if (infoState_)
infoState_->cancel = true;
@@ -497,7 +483,7 @@ DhtProxyClient::buildRequest(const std::string& target)
request->set_certificate_authority(serverCertificate_);
if (clientIdentity_.first and clientIdentity_.second)
request->set_identity(clientIdentity_);
request->set_header_field(restinio::http_field_t::user_agent, userAgent_);
request->set_header_field(restinio::http_field_t::user_agent, "RESTinio client");
return request;
}
@@ -505,7 +491,7 @@ void
DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb, time_point /*created*/, bool permanent)
{
if (logger_)
logger_->debug("[proxy:client] [put] [search {}] executing for {}", key, val->toString());
logger_->d("[proxy:client] [put] [search %s] executing for %s", key.to_c_str(), val->toString().c_str());
try {
auto request = buildRequest("/key/" + key.toString());
@@ -553,12 +539,12 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
}
} else {
if (logger_)
logger_->error("[proxy:client] [put] failed to parse value from server: {}", err);
logger_->e("[proxy:client] [status] failed to parse value from server", response.status_code);
}
}
} else {
if (logger_)
logger_->error("[proxy:client] [put] failed with code={:d}", response.status_code);
logger_->e("[proxy:client] [status] failed with code=%i", response.status_code);
if (not response.aborted and response.status_code == 0)
opFailed();
}
@@ -577,8 +563,7 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
}
catch (const std::exception &e){
if (logger_)
logger_->error("[proxy:client] [put {}] error: {}", key, e.what());
opFailed();
logger_->e("[proxy:client] [put %s] error: %s", key.to_c_str(), e.what());
}
}
@@ -736,7 +721,7 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
}
} else {
if (logger_)
logger_->debug("[proxy:client] [info] got proxy reply for {}",
logger_->d("[proxy:client] [info] got proxy reply for %s",
family == AF_INET ? "ipv4" : "ipv6");
try {
myid = InfoHash(proxyInfos["node_id"].asString());
@@ -744,7 +729,6 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
stats6_ = NodeStats(proxyInfos["ipv6"]);
auto publicIp = parsePublicAddress(proxyInfos["public_ip"]);
ipChanged = pubAddress && pubAddress.toString() != publicIp.toString();
bool pub = ipChanged || !pubAddress;
pubAddress = publicIp;
if (proxyInfos.isMember("local_ip")) {
@@ -755,18 +739,6 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
}
}
if (pub && publicAddressChangedCb_) {
std::vector<SockAddr> addresses;
if (publicAddressV4_)
addresses.emplace_back(publicAddressV4_);
if (publicAddressV6_)
addresses.emplace_back(publicAddressV6_);
std::lock_guard<std::mutex> lock(lockCallbacks_);
callbacks_.emplace_back([cb=publicAddressChangedCb_, addresses = std::move(addresses)](){
cb(std::move(addresses));
});
}
if (!ipChanged && stats4_.good_nodes + stats6_.good_nodes)
status = NodeStatus::Connected;
else if (!ipChanged && stats4_.dubious_nodes + stats6_.dubious_nodes)
@@ -813,8 +785,8 @@ SockAddr
DhtProxyClient::parsePublicAddress(const Json::Value& val)
{
auto public_ip = val.asString();
auto [host, service] = splitPort(public_ip);
auto sa = SockAddr::resolve(host);
auto hostAndService = splitPort(public_ip);
auto sa = SockAddr::resolve(hostAndService.first);
if (sa.empty()) return {};
return sa.front().getMappedIPv4();
}
@@ -1023,10 +995,7 @@ DhtProxyClient::handleExpireListener(const asio::error_code &ec, const InfoHash&
}
} else {
// stop the request
if (listener.request) {
listener.request->cancel();
listener.request.reset();
}
listener.request.reset();
}
search->second.listeners.erase(it);
if (logger_)
@@ -1121,12 +1090,6 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t& header,
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->add_on_status_callback([request, seconds = this->listenKeepIdle()] (unsigned status_code) {
if(status_code == 200) {
// increase TCP_KEEPIDLE to save power
request->get_connection()->set_keepalive(seconds);
}
});
request->send();
}
catch (const std::exception &e){
@@ -1178,7 +1141,7 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
std::lock_guard<std::mutex> lock(searchLock_);
for (auto& search : searches_) {
const auto& key = search.first;
auto key = search.first;
for (auto& put : search.second.puts) {
doPut(key, put.second.value, [ok = put.second.ok](bool result){
*ok = result;
@@ -1190,10 +1153,6 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
put.second.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this,
std::placeholders::_1, key, put.first));
}
// Restart failed pending puts
for (auto& pput : search.second.pendingPuts) {
doPut(key, pput, {}, time_point::max(), true);
}
}
if (not deviceKey_.empty()) {
if (logger_)
@@ -1233,10 +1192,9 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
}
}
PushNotificationResult
DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& notification)
void
DhtProxyClient::pushNotificationReceived(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
@@ -1253,7 +1211,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 PushNotificationResult::IgnoredWrongSession;
return;
}
std::lock_guard<std::mutex> lock(searchLock_);
auto timeout = notification.find("timeout");
@@ -1270,12 +1228,10 @@ 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"));
@@ -1284,12 +1240,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()) {
@@ -1302,7 +1258,6 @@ 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;
@@ -1328,25 +1283,22 @@ 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_();
#else
(void) notification;
#endif
return ret;
}
void
DhtProxyClient::resubscribe([[maybe_unused]] const InfoHash& key, [[maybe_unused]] const size_t token, [[maybe_unused]] Listener& listener)
DhtProxyClient::resubscribe(const InfoHash& key, const size_t token, Listener& listener)
{
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (deviceKey_.empty())
@@ -1370,6 +1322,9 @@ DhtProxyClient::resubscribe([[maybe_unused]] const InfoHash& key, [[maybe_unused
std::placeholders::_1, key, token, opstate));
auto vcb = listener.cb;
sendListen(header, vcb, opstate, listener, ListenMethod::RESUBSCRIBE);
#else
(void) key;
(void) listener;
#endif
}
@@ -1403,24 +1358,4 @@ DhtProxyClient::fillBody(bool resubscribe)
}
#endif // OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyClient::setPushNotificationToken([[maybe_unused]] const std::string& token) {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
std::unique_lock<std::mutex> l(lockCurrentProxyInfos_);
if (deviceKey_ != token) {
deviceKey_ = token;
if (statusIpv4_ == NodeStatus::Connected || statusIpv6_ == NodeStatus::Connected) {
if (logger_)
logger_->d("[proxy:client] [push] token changed, resubscribing");
for (auto& search : searches_) {
for (auto& listener : search.second.listeners) {
resubscribe(search.first, listener.first, listener.second);
}
}
}
}
#endif
}
} // namespace dht
+58 -110
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -58,19 +58,6 @@ constexpr const std::chrono::minutes PRINT_STATS_PERIOD {2};
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
namespace http {
/**
* Session value associated with a connection_id_t key.
*/
struct ListenerSession
{
ListenerSession() = default;
dht::InfoHash hash;
std::future<size_t> token;
std::shared_ptr<restinio::response_builder_t<restinio::chunked_output_t>> response;
};
}
class opendht_logger_t
{
public:
@@ -129,7 +116,7 @@ private:
void
DhtProxyServer::ConnectionListener::state_changed(const restinio::connection_state::notice_t& notice) noexcept
{
if (std::holds_alternative<restinio::connection_state::closed_t>(notice.cause())) {
if (restinio::holds_alternative<restinio::connection_state::closed_t>(notice.cause())) {
onClosed_(notice.connection_id());
}
}
@@ -223,7 +210,6 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
: ioContext_(std::make_shared<asio::io_context>()),
dht_(dht), persistPath_(config.persistStatePath), logger_(logger),
printStatsTimer_(std::make_unique<asio::steady_timer>(*ioContext_, 3s)),
serverStartTime_(clock::now()),
connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
pushServer_(config.pushServer),
bundleId_(config.bundleId)
@@ -416,12 +402,31 @@ DhtProxyServer::loadState(Is& is, size_t size) {
for (auto& pushListener : pushListeners_) {
for (auto& listeners : pushListener.second.listeners) {
for (auto& listener : listeners.second) {
// start listening
listener.internalToken = dht_->listen(listeners.first,
[this, infoHash=listeners.first, pushToken=pushListener.first, type=listener.type,
clientId=listener.clientId, sessionCtx = listener.sessionCtx, topic=listener.topic]
(const std::vector<Sp<Value>>& values, bool expired) {
return this->handlePushListen(infoHash, pushToken, type, clientId, sessionCtx, topic, values, expired);
[this, infoHash=listeners.first, pushToken=pushListener.first, type=listener.type, clientId=listener.clientId, sessionCtx = listener.sessionCtx, topic=listener.topic]
(const std::vector<std::shared_ptr<Value>>& values, bool expired) {
// Build message content
Json::Value json;
json["key"] = infoHash.toString();
json["to"] = clientId;
json["t"] = Json::Value::Int64(std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
{
std::lock_guard<std::mutex> l(sessionCtx->lock);
json["s"] = sessionCtx->sessionId;
}
if (expired and values.size() < 2){
std::ostringstream ss;
for(size_t i = 0; i < values.size(); ++i){
if(i != 0) ss << ",";
ss << values[i]->id;
}
json["exp"] = ss.str();
}
auto maxPrio = 1000u;
for (const auto& v : values)
maxPrio = std::min(maxPrio, v->priority);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0, topic);
return true;
}
);
// expire notify
@@ -543,15 +548,7 @@ DhtProxyServer::updateStats(std::shared_ptr<NodeInfo> info) const
stats.requestRate = count / dt.count();
#ifdef OPENDHT_PUSH_NOTIFICATIONS
stats.pushListenersCount = pushListeners_.size();
{
std::lock_guard lk(pushStatsMutex_);
stats.androidPush = androidPush_;
stats.iosPush = iosPush_;
stats.unifiedPush = unifiedPush_;
}
#endif
stats.serverStartTime = serverStartTime_;
stats.lastUpdated = now;
stats.totalPermanentPuts = 0;
std::for_each(puts_.begin(), puts_.end(), [&stats](const auto& put) {
stats.totalPermanentPuts += put.second.puts.size();
@@ -631,8 +628,6 @@ 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
@@ -902,13 +897,13 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
// Send response
if (not newListener) {
if (logger_)
logger_->d("[proxy:server] [subscribe %s] found [client %s]", infoHash.toString().c_str(), listener.clientId.c_str());
logger_->d("[proxy:server] [subscribe] found [client %s]", listener.clientId.c_str());
// Send response header
auto response = std::make_shared<ResponseByPartsBuilder>(initHttpResponse(request->create_response<ResponseByParts>()));
response->flush();
if (!root["refresh"].asBool()) {
// No Refresh
dht_->get(infoHash, [this, response](const Sp<Value>& value) {
dht_->get(infoHash, [this, response](const Sp<Value>& value){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
response->append_chunk(output);
response->flush();
@@ -925,15 +920,33 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
} else {
// =========== No existing listener for an infoHash ============
// Add listen on dht
if (logger_)
logger_->d("[proxy:server] [subscribe %s] new", infoHash.toString().c_str());
listener.internalToken = dht_->listen(infoHash,
[this, infoHash, pushToken, type, clientId, sessionCtx = listener.sessionCtx, topic]
(const std::vector<Sp<Value>>& values, bool expired) {
return this->handlePushListen(infoHash, pushToken, type, clientId, sessionCtx, topic, values, expired);
(const std::vector<std::shared_ptr<Value>>& values, bool expired){
// Build message content
Json::Value json;
json["key"] = infoHash.toString();
json["to"] = clientId;
json["t"] = Json::Value::Int64(std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
{
std::lock_guard<std::mutex> l(sessionCtx->lock);
json["s"] = sessionCtx->sessionId;
}
if (expired and values.size() < 2){
std::ostringstream ss;
for(size_t i = 0; i < values.size(); ++i) {
if(i != 0) ss << ",";
ss << values[i]->id;
}
json["exp"] = ss.str();
}
auto maxPrio = 1000u;
for (const auto& v : values)
maxPrio = std::min(maxPrio, v->priority);
sendPushNotification(pushToken, std::move(json), type, !expired and maxPrio == 0, topic);
return true;
}
);
// Send response header
auto response = initHttpResponse(request->create_response());
response.set_body("{}\n");
return response.done();
@@ -1037,54 +1050,10 @@ DhtProxyServer::handleCancelPushListen(const asio::error_code &ec, const std::st
pushListeners_.erase(pushListener);
}
bool
DhtProxyServer::handlePushListen(const InfoHash& infoHash, const std::string& pushToken, PushType type, const std::string& clientId,
const std::shared_ptr<DhtProxyServer::PushSessionContext>& sessionCtx, const std::string& topic,
const std::vector<std::shared_ptr<Value>>& values, bool expired)
{
Json::Value json;
json["key"] = infoHash.toString();
json["to"] = clientId;
using namespace std::chrono;
json["t"] = Json::Value::Int64(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
{
std::lock_guard<std::mutex> l(sessionCtx->lock);
json["s"] = sessionCtx->sessionId;
}
// Build a comma-separated list of ids from the values. This is intended to be used when
// streaming from the iOS notification extension in order to filter out unwanted values.
std::string ids;
for(const auto& value : values) {
if (!ids.empty()) ids += ",";
ids += std::to_string(value->id);
}
json["ids"] = ids;
// If message is expired copy the value ID to the `exp` field.
// This is presumably used by the Android notification system.
if (expired && values.size() < 2) {
json["exp"] = json["ids"];
}
auto minPriority = 1000u;
for (const auto& v : values)
minPriority = std::min(minPriority, v->priority);
if (logger_)
logger_->d("[proxy:server] [listen %s] [client %s] [session %s] [expired %i] [priority %i] [values %zu]",
infoHash.toString().c_str(), clientId.c_str(), sessionCtx->sessionId.c_str(), expired, minPriority, values.size());
sendPushNotification(pushToken, std::move(json), type, !expired and minPriority == 0, topic);
return true;
}
void
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, PushType type, bool highPriority, const std::string& topic)
{
if (pushServer_.empty() && type != PushType::UnifiedPush)
if (pushServer_.empty())
return;
unsigned reqid = 0;
@@ -1092,7 +1061,7 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
std::shared_ptr<http::Request> request;
http::Url tokenUrl(token);
if (type == PushType::UnifiedPush)
request = std::make_shared<http::Request>(io_context(), tokenUrl.protocol + "://" + tokenUrl.host + (tokenUrl.service.empty() ? "" : (":" + tokenUrl.service)), logger_);
request = std::make_shared<http::Request>(io_context(), tokenUrl.protocol + "://" + tokenUrl.host, logger_);
else
request = std::make_shared<http::Request>(io_context(), pushHostPort_.first, pushHostPort_.second, pushHostPort_.first.find("https://") == 0, logger_);;
reqid = request->id();
@@ -1111,33 +1080,27 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
request->set_body(Json::writeString(jsonBuilder_, std::move(json)));
} else {
// NOTE: see https://github.com/appleboy/gorush
auto isResubscribe = json.isMember("timeout");
Json::Value notification(Json::objectValue);
Json::Value tokens(Json::arrayValue);
tokens[0] = token;
notification["tokens"] = std::move(tokens);
notification["platform"] = type == PushType::Android ? 2 : 1;
notification["data"] = std::move(json);
auto priority = highPriority ? "high" : "normal";
if (type == PushType::Android) {
Json::Value androidConfig(Json::objectValue);
androidConfig["priority"] = priority;
androidConfig["ttl"] = "86400s"; // time to live = 24 hours
notification["android"] = std::move(androidConfig);
} else {
notification["priority"] = priority;
notification["priority"] = highPriority ? "high" : "normal";
if (type == PushType::Android)
notification["time_to_live"] = 3600 * 24; // 24 hours
else {
const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24);
uint32_t exp = std::chrono::duration_cast<std::chrono::seconds>(expiration.time_since_epoch()).count();
notification["expiration"] = exp;
if (!topic.empty())
notification["topic"] = topic;
if (highPriority || isResubscribe) {
if (highPriority) {
Json::Value alert(Json::objectValue);
alert["title"]="hello";
notification["push_type"] = "alert";
notification["alert"] = alert;
notification["mutable_content"] = true;
notification["priority"] = "high";
} else {
notification["push_type"] = "background";
notification["content_available"] = true;
@@ -1166,21 +1129,6 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
requests_[reqid] = request;
}
request->send();
// For monitoring purposes
std::lock_guard lk(pushStatsMutex_);
switch (type) {
case PushType::Android:
androidPush_.increment(highPriority);
break;
case PushType::iOS:
iosPush_.increment(highPriority);
break;
case PushType::UnifiedPush:
unifiedPush_.increment(highPriority);
break;
default:
break;
}
}
catch (const std::exception &e){
if (logger_)
+37 -53
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -93,7 +93,7 @@ DhtRunner::run(const Config& config, Context&& context)
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running)) {
if (context.logger)
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.", fmt::ptr(this));
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.", this);
return;
}
@@ -102,7 +102,7 @@ DhtRunner::run(const Config& config, Context&& context)
auto local6 = config.bind6;
if (not local4 and not local6) {
if (context.logger)
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses", fmt::ptr(this));
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses", this);
local4.setFamily(AF_INET);
local6.setFamily(AF_INET6);
}
@@ -116,14 +116,14 @@ DhtRunner::run(const Config& config, Context&& context)
if (inConfig >> port) {
if (local4.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", fmt::ptr(this), port);
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port);
local4.setPort(port);
}
}
if (inConfig >> port) {
if (local6.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", fmt::ptr(this), port);
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port);
local6.setPort(port);
}
}
@@ -132,7 +132,7 @@ DhtRunner::run(const Config& config, Context&& context)
if (context.logger) {
logger_ = context.logger;
logger_->d("[runner %p] state changed to Running", fmt::ptr(this));
logger_->d("[runner %p] state changed to Running", this);
}
#ifdef OPENDHT_PROXY_CLIENT
@@ -155,7 +155,7 @@ DhtRunner::run(const Config& config, Context&& context)
dropped++;
}
if (dropped and logger_) {
logger_->w("[runner %p] dropped %zu packets: queue is full!", fmt::ptr(this), dropped);
logger_->w("[runner %p] dropped %zu packets: queue is full!", this, dropped);
}
ret = std::move(rcv_free);
}
@@ -167,7 +167,7 @@ DhtRunner::run(const Config& config, Context&& context)
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
auto dht = std::make_unique<Dht>(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger, std::move(context.rng));
auto dht = std::make_unique<Dht>(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger);
dht_ = std::make_unique<SecureDht>(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger);
} else {
enableProxy(true);
@@ -180,15 +180,12 @@ DhtRunner::run(const Config& config, Context&& context)
throw;
}
statusCbs.clear();
if (context.statusChangedCallback)
statusCbs.emplace_back(std::move(context.statusChangedCallback));
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
}
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
}
if (context.publicAddressChangedCb) {
dht_->setOnPublicAddressChanged(std::move(context.publicAddressChangedCb));
}
if (not config.threaded)
return;
@@ -210,7 +207,7 @@ DhtRunner::run(const Config& config, Context&& context)
if (not pending_ops_prio.empty())
return true;
auto s = getStatus();
if (not pending_ops.empty() and (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping))
if (not pending_ops.empty() and (s == NodeStatus::Connected or s == NodeStatus::Disconnected))
return true;
}
return false;
@@ -264,17 +261,6 @@ DhtRunner::run(const Config& config, Context&& context)
}
}
}
if (peerDiscovery_) {
statusCbs.emplace_back([this](NodeStatus status4, NodeStatus status6) {
if (status4 == NodeStatus::Disconnected && status6 == NodeStatus::Disconnected) {
peerDiscovery_->connectivityChanged();
}
else if (status4 != NodeStatus::Connected || status6 != NodeStatus::Connected) {
peerDiscovery_->stopConnectivityChanged();
}
});
}
#endif
}
}
@@ -295,7 +281,7 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
return;
}
if (logger_)
logger_->debug("[runner {:p}] state changed to Stopping, {:d} ongoing ops", fmt::ptr(this), ongoing_ops.load());
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
ongoing_ops++;
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops.emplace([=](SecureDht&) mutable {
@@ -360,7 +346,7 @@ DhtRunner::join()
if (auto sock = dht_->getSocket())
sock->stop();
if (logger_)
logger_->debug("[runner {:p}] state changed to Idle", fmt::ptr(this));
logger_->d("[runner %p] state changed to Idle", this);
}
if (dht_thread.joinable())
@@ -369,7 +355,7 @@ DhtRunner::join()
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (ongoing_ops and logger_) {
logger_->warn("[runner {:p}] stopping with {:d} remaining ops", fmt::ptr(this), ongoing_ops.load());
logger_->w("[runner %p] stopping with %zu remaining ops", this, ongoing_ops.load());
}
pending_ops = decltype(pending_ops)();
pending_ops_prio = decltype(pending_ops_prio)();
@@ -468,6 +454,12 @@ DhtRunner::setLogger(const Sp<Logger>& logger) {
dht_->setLogger(logger);
}
void
DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
Logger logger {std::move(error), std::move(warn), std::move(debug)};
setLogger(logger);
}
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -641,7 +633,7 @@ DhtRunner::loop_()
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto s = getStatus();
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping)) ?
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or s == NodeStatus::Disconnected)) ?
std::move(pending_ops) : std::move(pending_ops_prio);
}
while (not ops.empty()) {
@@ -694,16 +686,15 @@ DhtRunner::loop_()
}
if (dropped && logger_)
logger_->e("[runner %p] Dropped %zu packets with high delay.", fmt::ptr(this), dropped);
logger_->e("[runner %p] Dropped %zu packets with high delay.", this, dropped);
NodeStatus nstatus4 = dht_->updateStatus(AF_INET);
NodeStatus nstatus6 = dht_->updateStatus(AF_INET6);
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
for (auto& cb : statusCbs){
cb(status4, status6);
}
if (statusCb)
statusCb(status4, status6);
}
return wakeup;
@@ -1120,13 +1111,13 @@ DhtRunner::enableProxy(bool proxify)
cv.notify_all();
}
},
config_.proxy_server,
config_.proxy_user_agent,
config_.push_node_id,
config_.push_token,
config_.push_topic,
config_.push_platform,
logger_);
config_.proxy_server, config_.push_node_id, logger_);
if (not config_.push_token.empty())
dht_via_proxy->setPushNotificationToken(config_.push_token);
if (not config_.push_topic.empty())
dht_via_proxy->setPushNotificationTopic(config_.push_topic);
if (not config_.push_platform.empty())
dht_via_proxy->setPushNotificationPlatform(config_.push_platform);
dht_ = std::make_unique<SecureDht>(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_);
// and use it
use_proxy = proxify;
@@ -1186,25 +1177,18 @@ DhtRunner::setPushNotificationPlatform(const std::string& platform) {
#endif
}
std::future<PushNotificationResult>
DhtRunner::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& data)
void
DhtRunner::pushNotificationReceived(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([ret_token, this, data](SecureDht&) {
pending_ops_prio.emplace([=](SecureDht&) {
if (dht_)
ret_token->set_value(dht_->pushNotificationReceived(data));
else
ret_token->set_value(PushNotificationResult::IgnoredStopped);
dht_->pushNotificationReceived(data);
});
cv.notify_all();
return future;
#else
std::promise<PushNotificationResult> p {};
p.set_value(PushNotificationResult::IgnoredDisabled);
return p.get_future();
(void) data;
#endif
}
+184 -198
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,14 +17,14 @@
*/
#include "http.h"
#include "logger.h"
#include "log_enable.h"
#include "crypto.h"
#include "base64.h"
#include "compat/os_cert.h"
#include <asio.hpp>
#include <restinio/impl/tls_socket.hpp>
#include <llhttp.h>
#include <http_parser.h>
#include <json/json.h>
#include <openssl/ocsp.h>
@@ -33,10 +33,6 @@
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <cctype>
#include <iomanip>
#include <sstream>
#define MAXAGE_SEC (14*24*60*60)
#define JITTER_SEC (60)
#define OCSP_MAX_RESPONSE_SIZE (20480)
@@ -54,7 +50,7 @@ constexpr const char HTTPS_PROTOCOL[] = "https://";
constexpr const char ORIGIN_PROTOCOL[] = "//";
constexpr unsigned MAX_REDIRECTS {5};
Url::Url(std::string_view url): url(url)
Url::Url(const std::string& url): url(url)
{
size_t addr_begin = 0;
// protocol
@@ -69,9 +65,10 @@ Url::Url(std::string_view 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 [h, s] = splitPort(url.substr(addr_begin, addr_size));
host = std::move(h);
service = std::move(s);
auto host_service = splitPort(url.substr(addr_begin, addr_size));
host = host_service.first;
if (!host_service.second.empty())
service = host_service.second;
// target, query and fragment
size_t query_begin = url.find("?");
auto addr_end = addr_begin + addr_size;
@@ -114,11 +111,11 @@ newTlsClientContext(const std::shared_ptr<dht::Logger>& logger)
if (char* path = getenv("CA_ROOT_FILE")) {
if (logger)
logger->debug("Using CA file: {}", path);
logger->d("Using CA file: %s", path);
ctx->load_verify_file(path);
} else if (char* path = getenv("CA_ROOT_PATH")) {
if (logger)
logger->debug("Using CA path: {}", path);
logger->d("Using CA path: %s", path);
ctx->add_verify_path(path);
} else {
#ifdef __ANDROID__
@@ -143,12 +140,12 @@ Connection::Connection(asio::io_context& ctx, const bool ssl, std::shared_ptr<dh
ssl_ctx_ = newTlsClientContext(l);
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
if (logger_)
logger_->debug("[connection:{:d}] start https session with system CA", id_);
logger_->d("[connection:%i] start https session with system CA", id_);
}
else {
socket_ = std::make_unique<socket_t>(ctx);
if (logger_)
logger_->debug("[connection:{:d}] start http session", id_);
logger_->d("[connection:%i] start http session", id_);
}
}
@@ -165,11 +162,11 @@ Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certi
if (ec)
throw std::runtime_error("Error adding certificate authority: " + ec.message());
else if (logger_)
logger_->debug("[connection:{:d}] start https with custom CA {:s}", id_, server_ca->getUID());
logger_->d("[connection:%i] start https with custom CA %s", id_, server_ca->getUID().c_str());
} else {
ssl_ctx_ = newTlsClientContext(l);
if (logger_)
logger_->debug("[connection:{:d}] start https session with system CA", id_);
logger_->d("[connection:%i] start https session with system CA", id_);
}
if (identity.first){
auto key = identity.first->serialize();
@@ -184,7 +181,7 @@ Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certi
if (ec)
throw std::runtime_error("Error adding client certificate: " + ec.message());
else if (logger_)
logger_->debug("[connection:{:d}] client certificate {:s}", id_, identity.second->getUID());
logger_->d("[connection:%i] client certificate %s", id_, identity.second->getUID().c_str());
}
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
}
@@ -207,7 +204,7 @@ Connection::close()
socket_->close(ec);
}
if (ec and logger_)
logger_->error("[connection:{:d}] error closing: {:s}", id_, ec.message());
logger_->e("[connection:%i] error closing: %s", id_, ec.message().c_str());
}
bool
@@ -224,25 +221,20 @@ Connection::is_ssl() const
return ssl_ctx_ ? true : false;
}
std::string asn1ToString(ASN1_GENERALIZEDTIME* time) {
if (!time) {
return "(null)";
}
BIO* memBio = BIO_new(BIO_s_mem());
if (!memBio) {
throw std::runtime_error("Failed to create BIO");
}
static time_t
parse_ocsp_time(ASN1_GENERALIZEDTIME* gt)
{
struct tm tm;
time_t rv = -1;
if (ASN1_GENERALIZEDTIME_print(memBio, time) <= 0) {
BIO_free(memBio);
throw std::runtime_error("Failed to print ASN1_GENERALIZEDTIME");
}
char* bioData;
long bioLength = BIO_get_mem_data(memBio, &bioData);
std::string result(bioData, bioLength);
BIO_free(memBio);
return result;
if (gt == nullptr)
return -1;
// RFC 6960 specifies that all times in OCSP must be GENERALIZEDTIME
if (ASN1_time_parse((const char*)gt->data, gt->length, &tm, V_ASN1_GENERALIZEDTIME) == -1)
return -1;
if ((rv = timegm(&tm)) == -1)
return -1;
return rv;
}
static inline X509*
@@ -280,26 +272,26 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
if (sk_X509_num(fullchain) <= 1) {
if (logger)
logger->error("Cert does not contain a cert chain");
logger->e("Cert does not contain a cert chain");
return {};
}
X509* cert = cert_from_chain(fullchain);
if (cert == nullptr) {
if (logger)
logger->error("No certificate found");
logger->e("No certificate found");
return {};
}
X509* issuer = issuer_from_chain(fullchain);
if (issuer == nullptr) {
if (logger)
logger->error("Unable to find issuer for cert");
logger->e("Unable to find issuer for cert");
return {};
}
auto urls = X509_get1_ocsp(cert);
if (urls == nullptr || sk_OPENSSL_STRING_num(urls) <= 0) {
if (logger)
logger->error("Certificate contains no OCSP url");
logger->e("Certificate contains no OCSP url");
return {};
}
auto url = sk_OPENSSL_STRING_value(urls, 0);
@@ -314,12 +306,12 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
OCSP_CERTID* id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
if (id == nullptr) {
if (logger)
logger->error("Unable to get certificate id from cert");
logger->e("Unable to get certificate id from cert");
return {};
}
if (OCSP_request_add0_id(request->req.get(), id) == nullptr) {
if (logger)
logger->error("Unable to add certificate id to request");
logger->e("Unable to add certificate id to request");
return {};
}
@@ -330,12 +322,12 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
uint8_t* data {nullptr};
if ((size = i2d_OCSP_REQUEST(request->req.get(), &data)) <= 0) {
if (logger)
logger->error("Unable to encode ocsp request");
logger->e("Unable to encode ocsp request");
return {};
}
if (data == nullptr) {
if (logger)
logger->error("Unable to allocte memory");
logger->e("Unable to allocte memory");
return {};
}
request->data = std::string((char*)data, (char*)data+size);
@@ -346,32 +338,36 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
bool
ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, const std::string& response, X509_STORE *store, const std::shared_ptr<Logger>& logger)
{
ASN1_GENERALIZEDTIME *revtime = nullptr, *thisupd = nullptr, *nextupd = nullptr;
const uint8_t* p = (const uint8_t*)response.data();
int status, cert_status=0, crl_reason=0;
time_t now, rev_t = -1, this_t, next_t;
X509* cert = cert_from_chain(fullchain);
if (cert == nullptr) {
if (logger)
logger->error("ocsp: no certificate found");
logger->e("No certificate found");
return false;
}
X509* issuer = issuer_from_chain(fullchain);
if (issuer == nullptr) {
if (logger)
logger->error("ocsp: unable to find issuer for cert");
logger->e("Unable to find issuer for cert");
return false;
}
OCSP_CERTID *cidr;
if ((cidr = OCSP_cert_to_id(nullptr, cert, issuer)) == nullptr) {
if (logger)
logger->error("ocsp: unable to get issuer cert/CID");
logger->e("Unable to get issuer cert/CID");
return false;
}
std::unique_ptr<OCSP_CERTID, decltype(&OCSP_CERTID_free)> cid(cidr, &OCSP_CERTID_free);
const uint8_t* resp_data = (const uint8_t*)response.data();
OCSP_RESPONSE *r;
if ((r = d2i_OCSP_RESPONSE(nullptr, &resp_data, response.size())) == nullptr) {
if ((r = d2i_OCSP_RESPONSE(nullptr, &p, response.size())) == nullptr) {
if (logger)
logger->error("OCSP response unserializable");
logger->e("OCSP response unserializable");
return false;
}
std::unique_ptr<OCSP_RESPONSE, decltype(&OCSP_RESPONSE_free)> resp(r, &OCSP_RESPONSE_free);
@@ -379,59 +375,99 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
OCSP_BASICRESP *brespr;
if ((brespr = OCSP_response_get1_basic(resp.get())) == nullptr) {
if (logger)
logger->error("Failed to load OCSP response");
logger->e("Failed to load OCSP response");
return false;
}
std::unique_ptr<OCSP_BASICRESP, decltype(&OCSP_BASICRESP_free)> bresp(brespr, &OCSP_BASICRESP_free);
if (OCSP_basic_verify(bresp.get(), fullchain, store, OCSP_TRUSTOTHER) != 1) {
if (logger)
logger->warn("OCSP verify failed");
logger->w("OCSP verify failed");
return false;
}
printf("OCSP response signature validated\n");
int status = OCSP_response_status(resp.get());
status = OCSP_response_status(resp.get());
if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
if (logger)
logger->warn("OCSP Failure: code {:d} ({:s})", status, OCSP_response_status_str(status));
logger->w("OCSP Failure: code %d (%s)", status, OCSP_response_status_str(status));
return false;
}
// Check the nonce if we sent one
if (OCSP_check_nonce(info.req.get(), bresp.get()) <= 0) {
if (logger)
logger->warn("No OCSP nonce, or mismatch");
logger->w("No OCSP nonce, or mismatch");
return false;
}
ASN1_GENERALIZEDTIME *revtime = nullptr, *thisupd = nullptr, *nextupd = nullptr;
int cert_status=0, crl_reason=0;
if (OCSP_resp_find_status(bresp.get(), cid.get(), &cert_status, &crl_reason,
&revtime, &thisupd, &nextupd) != 1) {
if (logger)
logger->warn("OCSP verify failed: no result for cert");
logger->w("OCSP verify failed: no result for cert");
return false;
}
if (revtime && (rev_t = parse_ocsp_time(revtime)) == -1) {
if (logger)
logger->w("Unable to parse revocation time in OCSP reply");
return false;
}
// Belt and suspenders, Treat it as revoked if there is either
// a revocation time, or status revoked.
if (revtime || cert_status == V_OCSP_CERTSTATUS_REVOKED) {
if (logger) {
logger->warn("OCSP verify failed: certificate revoked since {}", asn1ToString(revtime));
if (rev_t != -1 || cert_status == V_OCSP_CERTSTATUS_REVOKED) {
if (logger)
logger->w("Invalid OCSP reply: certificate is revoked");
if (rev_t != -1) {
if (logger)
logger->w("Certificate revoked at: %s", ctime(&rev_t));
}
return false;
}
if (OCSP_check_validity(thisupd, nextupd, 1, -1) == 0) {
if ((this_t = parse_ocsp_time(thisupd)) == -1) {
if (logger)
logger->warn("OCSP reply is expired or not yet valid");
logger->w("unable to parse this update time in OCSP reply");
return false;
}
if ((next_t = parse_ocsp_time(nextupd)) == -1) {
if (logger)
logger->w("unable to parse next update time in OCSP reply");
return false;
}
// Don't allow this update to precede next update
if (this_t >= next_t) {
if (logger)
logger->w("Invalid OCSP reply: this update >= next update");
return false;
}
now = time(nullptr);
// Check that this update is not more than JITTER seconds in the future.
if (this_t > now + JITTER_SEC) {
if (logger)
logger->e("Invalid OCSP reply: this update is in the future (%s)", ctime(&this_t));
return false;
}
// Check that this update is not more than MAXSEC in the past.
if (this_t < now - MAXAGE_SEC) {
if (logger)
logger->e("Invalid OCSP reply: this update is too old (%s)", ctime(&this_t));
return false;
}
// Check that next update is still valid
if (next_t < now - JITTER_SEC) {
if (logger)
logger->w("Invalid OCSP reply: reply has expired (%s)", ctime(&next_t));
return false;
}
if (logger) {
logger->debug("OCSP response validated");
logger->debug(" This Update: {}", asn1ToString(thisupd));
logger->debug(" Next Update: {}", asn1ToString(nextupd));
logger->d("OCSP response validated");
logger->d(" This Update: %s", ctime(&this_t));
logger->d(" Next Update: %s", ctime(&next_t));
}
return true;
}
@@ -452,7 +488,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
if (logger) {
char subject_name[1024];
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 1024);
logger->debug("[connection:{:d}] verify {:s} compliance to RFC 2818:\n{:s}", id, hostname, subject_name);
logger->d("[connection:%i] verify %s compliance to RFC 2818:\n%s", id, hostname.c_str(), subject_name);
}
// starts from CA and goes down the presented chain
@@ -460,14 +496,14 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
bool verified = verifier(preverified, ctx);
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
logger->error("[http::connection:{:d}] ssl verification error={:d} {}", id, verify_ec, verified);
logger->e("[http::connection:%i] ssl verification error=%i %d", id, verify_ec, verified);
if (verified and checkOcsp) {
std::unique_ptr<stack_st_X509, void(*)(stack_st_X509*)> chain(
X509_STORE_CTX_get1_chain(ctx.native_handle()),
[](stack_st_X509* c){ sk_X509_pop_free(c, X509_free); });
if (auto ocspInfo = ocspRequestFromCert(chain.get(), logger)) {
if (logger)
logger->warn("[http::connection:{:d}] TLS OCSP server: {:s}, request size: {:d}", id, ocspInfo->url, ocspInfo->data.size());
logger->w("[http::connection:%i] TLS OCSP server: %s, request size: %zu", id, ocspInfo->url.c_str(), ocspInfo->data.size());
bool ocspVerified = false;
asio::io_context io_ctx;
auto ocspReq = std::make_shared<Request>(io_ctx, ocspInfo->url, [&](const Response& ocspResp){
@@ -475,7 +511,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
ocspVerified = ocspValidateResponse(*ocspInfo, chain.get(), ocspResp.body, X509_STORE_CTX_get0_store(ctx.native_handle()), logger);
} else {
if (logger)
logger->warn("[http::connection:{:d}] TLS OCSP check error", id);
logger->w("[http::connection:%i] TLS OCSP check error", id);
}
}, logger);
ocspReq->set_method(restinio::http_method_post());
@@ -535,11 +571,48 @@ Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, Conn
#pragma GCC diagnostic ignored "-Wunused-variable"
ConnectHandlerCb wcb = [this, &base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) {
if (!ec) {
auto socket = base.native_handle();
local_address_ = base.local_endpoint().address();
// Once connected, set a keep alive on the TCP socket with 30 seconds delay
// This will generate broken pipes as soon as possible.
// Note this needs to be done once connected to have a valid native_handle()
this->set_keepalive(30);
uint32_t start = 30;
uint32_t interval = 30;
uint32_t cnt = 1;
#ifdef _WIN32
std::string val = "1";
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, val.c_str(), sizeof(val));
// TCP_KEEPIDLE and TCP_KEEPINTVL are available since Win 10 version 1709
// TCP_KEEPCNT since Win 10 version 1703
#ifdef TCP_KEEPIDLE
std::string start_str = std::to_string(start);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE,
start_str.c_str(), sizeof(start_str));
#endif
#ifdef TCP_KEEPINTVL
std::string interval_str = std::to_string(interval);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL,
interval_str.c_str(), sizeof(interval_str));
#endif
#ifdef TCP_KEEPCNT
std::string cnt_str = std::to_string(cnt);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT,
cnt_str.c_str(), sizeof(cnt_str));
#endif
#else
uint32_t val = 1;
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(uint32_t));
#ifdef __APPLE__
// Apple devices only have one parameter
setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &start, sizeof(uint32_t));
#else
// Linux based systems
setsockopt(socket, SOL_TCP, TCP_KEEPIDLE, &start, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(uint32_t));
#endif
#endif
}
if (cb)
cb(ec, endpoint);
@@ -569,11 +642,11 @@ Connection::async_handshake(HandlerCb cb)
if (this_.logger_) {
if (verify_ec == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT /*18*/
|| verify_ec == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN /*19*/)
this_.logger_->debug("[connection:{:d}] self-signed certificate in handshake: {:d}", this_.id_, verify_ec);
this_.logger_->d("[connection:%i] self-signed certificate in handshake: %i", this_.id_, verify_ec);
else if (verify_ec != X509_V_OK)
this_.logger_->error("[connection:{:d}] verify handshake error: {:d}", this_.id_, verify_ec);
this_.logger_->e("[connection:%i] verify handshake error: %i", this_.id_, verify_ec);
else
this_.logger_->warn("[connection:{:d}] verify handshake success", this_.id_);
this_.logger_->w("[connection:%i] verify handshake success", this_.id_);
}
}
if (cb)
@@ -655,64 +728,6 @@ Connection::async_read_some(size_t bytes, BytesHandlerCb cb)
else socket_->async_read_some(buf, onEnd);
}
void
Connection::set_keepalive(uint32_t seconds)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!ssl_socket_ && !socket_) return;
auto& base = ssl_socket_? ssl_socket_->lowest_layer() : *socket_;
auto socket = base.native_handle();
uint32_t interval = 1;
uint32_t cnt = 10;
#ifdef _WIN32
// TCP_KEEPIDLE and TCP_KEEPINTVL are available since Win 10 version 1709
// TCP_KEEPCNT since Win 10 version 1703
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
std::string val = "1";
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, val.c_str(), sizeof(val));
std::string seconds_str = std::to_string(seconds);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE,
seconds_str.c_str(), sizeof(seconds_str));
std::string interval_str = std::to_string(interval);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL,
interval_str.c_str(), sizeof(interval_str));
std::string cnt_str = std::to_string(cnt);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT,
cnt_str.c_str(), sizeof(cnt_str));
#else
struct {
uint32_t onoff;
uint32_t keepalivetime;
uint32_t keepaliveinterval;
} keepalive;
keepalive.onoff = 1;
keepalive.keepalivetime = seconds * 1000;
keepalive.keepaliveinterval = interval * 1000;
int32_t out = 0;
WSAIoctl(socket, SIO_KEEPALIVE_VALS, keepalive, sizeof(tcp_keepalive),
nullptr, 0, &out, nullptr, nullptr);
#endif
#else
uint32_t val = 1;
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(uint32_t));
#ifdef __APPLE__
// Old Apple devices only have one parameter
setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &seconds, sizeof(uint32_t));
#if defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(uint32_t));
setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(uint32_t));
#endif
#else
// Linux based systems
setsockopt(socket, SOL_TCP, TCP_KEEPIDLE, &seconds, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(uint32_t));
#endif
#endif
}
const asio::ip::address&
Connection::local_address() const
{
@@ -730,7 +745,7 @@ Connection::timeout(const std::chrono::seconds& timeout, HandlerCb cb)
return;
else if (ec){
if (logger)
logger->error("[connection:{:d}] timeout error: {:s}", id, ec.message());
logger->e("[connection:%i] timeout error: %s", id, ec.message().c_str());
}
if (cb)
cb(ec);
@@ -780,12 +795,6 @@ Resolver::~Resolver()
*destroyed_ = true;
}
void
Resolver::cancel()
{
resolver_.cancel();
}
inline
std::vector<asio::ip::tcp::endpoint>
filter(const std::vector<asio::ip::tcp::endpoint>& epts, sa_family_t family)
@@ -827,8 +836,9 @@ Resolver::resolve(const std::string& host, const std::string& service)
if (ec == asio::error::operation_aborted or *destroyed)
return;
if (logger_) {
logger_->error("[http:client] [resolver] result for {:s}:{:s}: {:s}",
host, service, ec.message());
if (ec)
logger_->e("[http:client] [resolver] error for %s:%s: %s",
host.c_str(), service.c_str(), ec.message().c_str());
}
decltype(cbs_) cbs;
{
@@ -870,7 +880,7 @@ Request::Request(asio::io_context& ctx, const std::string& url, const Json::Valu
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
logger_->error("[http:request:{:d}] can't parse response to json: {:s}", id_, err);
logger_->e("[http:request:%i] can't parse response to json", id_, err.c_str());
}
if (jsoncb)
jsoncb(std::move(json), response);
@@ -892,7 +902,7 @@ Request::Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb,
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
logger_->error("[http:request:{:d}] can't parse response to json: {:s}", id_, err);
logger_->e("[http:request:%i] can't parse response to json", id_, err.c_str());
}
if (jsoncb)
jsoncb(std::move(json), response);
@@ -960,8 +970,6 @@ Request::init_default_headers()
void
Request::cancel()
{
if (auto r = resolver_)
r->cancel();
if (auto c = conn_)
c->close();
}
@@ -1058,7 +1066,7 @@ Request::build()
break;
case restinio::http_connection_header_t::upgrade:
if (logger_)
logger_->error("Unsupported connection type 'upgrade', fallback to 'close'");
logger_->e("Unsupported connection type 'upgrade', fallback to 'close'");
// fallthrough
case restinio::http_connection_header_t::close:
conn_str = "close"; // default
@@ -1076,30 +1084,6 @@ Request::build()
request_ = request.str();
}
// https://stackoverflow.com/a/17708801
std::string
Request::url_encode(std::string_view value)
{
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (const char& c : value) {
// Keep alphanumeric and other accepted characters intact
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
escaped << std::nouppercase;
}
return escaped.str();
}
void
Request::add_on_status_callback(OnStatusCb cb) {
cbs_.on_status = std::move(cb);
@@ -1136,11 +1120,13 @@ Request::init_parser()
response_.request = shared_from_this();
if (!parser_)
parser_ = std::make_unique<llhttp_t>();
parser_ = std::make_unique<http_parser>();
http_parser_init(parser_.get(), HTTP_RESPONSE);
parser_->data = static_cast<void*>(this);
if (!parser_s_)
parser_s_ = std::make_unique<llhttp_settings_t>();
llhttp_settings_init(parser_s_.get());
parser_s_ = std::make_unique<http_parser_settings>();
http_parser_settings_init(parser_s_.get());
cbs_.on_status = [this, statusCb = std::move(cbs_.on_status)](unsigned int status_code){
response_.status_code = status_code;
@@ -1155,33 +1141,31 @@ Request::init_parser()
response_.headers[*header_field] = std::string(at, length);
};
// llhttp raw c callback (note: no context can be passed into them)
parser_s_->on_status = [](llhttp_t* parser, const char* /*at*/, size_t /*length*/) -> int {
// http_parser raw c callback (note: no context can be passed into them)
parser_s_->on_status = [](http_parser* parser, const char* /*at*/, size_t /*length*/) -> int {
static_cast<Request*>(parser->data)->cbs_.on_status(parser->status_code);
return 0;
};
parser_s_->on_header_field = [](llhttp_t* parser, const char* at, size_t length) -> int {
parser_s_->on_header_field = [](http_parser* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->cbs_.on_header_field(at, length);
return 0;
};
parser_s_->on_header_value = [](llhttp_t* parser, const char* at, size_t length) -> int {
parser_s_->on_header_value = [](http_parser* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->cbs_.on_header_value(at, length);
return 0;
};
parser_s_->on_body = [](llhttp_t* parser, const char* at, size_t length) -> int {
parser_s_->on_body = [](http_parser* parser, const char* at, size_t length) -> int {
static_cast<Request*>(parser->data)->onBody(at, length);
return 0;
};
parser_s_->on_headers_complete = [](llhttp_t* parser) -> int {
parser_s_->on_headers_complete = [](http_parser* parser) -> int {
static_cast<Request*>(parser->data)->onHeadersComplete();
return 0;
};
parser_s_->on_message_complete = [](llhttp_t* parser) -> int {
parser_s_->on_message_complete = [](http_parser* parser) -> int {
static_cast<Request*>(parser->data)->onComplete();
return 0;
};
llhttp_init(parser_.get(), HTTP_RESPONSE, parser_s_.get());
parser_->data = static_cast<void*>(this);
}
void
@@ -1189,7 +1173,7 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
{
if (endpoints.empty()){
if (logger_)
logger_->error("[http:request:{:d}] connect: no endpoints provided", id_);
logger_->e("[http:request:%i] connect: no endpoints provided", id_);
if (cb)
cb(asio::error::connection_aborted);
return;
@@ -1198,7 +1182,7 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
std::string eps = "";
for (const auto& endpoint : endpoints)
eps.append(endpoint.address().to_string() + ":" + std::to_string(endpoint.port()) + " ");
logger_->debug("[http:request:{:d}] connect begin: {:s}", id_, eps);
logger_->d("[http:request:%i] connect begin: %s", id_, eps.c_str());
}
bool isHttps = get_url().protocol == "https";
if (isHttps) {
@@ -1229,7 +1213,7 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
}
else if (ec) {
if (this_.logger_)
this_.logger_->error("[http:request:{:d}] connect failed with all endpoints: {:s}", this_.id_, ec.message());
this_.logger_->e("[http:request:%i] connect failed with all endpoints: %s", this_.id_, ec.message().c_str());
} else {
const auto& url = this_.get_url();
auto port = endpoint.port();
@@ -1245,9 +1229,9 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
if (ec == asio::error::operation_aborted)
return;
if (ec and logger)
logger->error("[http:request:{:d}] handshake error: {:s}", id, ec.message());
logger->e("[http:request:%i] handshake error: %s", id, ec.message().c_str());
//else if (logger)
// logger->d("[http:request:{:d}] handshake success", id);
// logger->d("[http:request:%i] handshake success", id);
if (cb)
cb(ec);
});
@@ -1275,7 +1259,7 @@ Request::send()
std::lock_guard<std::mutex> lock(this_.mutex_);
if (ec){
if (this_.logger_)
this_.logger_->error("[http:request:{:d}] resolve error: {:s}", this_.id_, ec.message());
this_.logger_->e("[http:request:%i] resolve error: %s", this_.id_, ec.message().c_str());
this_.terminate(asio::error::connection_aborted);
}
else if (!this_.conn_ or !this_.conn_->is_open()) {
@@ -1305,7 +1289,7 @@ Request::post()
init_parser();
if (logger_)
logger_->debug("[http:request:{}] sending {} bytes", id_, request_.size());
logger_->d("[http:request:%i] sending %zu bytes", id_, request_.size());
// write the request to buffer
std::ostream request_stream(&conn_->input());
@@ -1333,12 +1317,12 @@ Request::terminate(const asio::error_code& ec)
if (logger_) {
if (ec and ec != asio::error::eof and !response_.aborted)
logger_->error("[http:request:{:d}] end with error: {:s}", id_, ec.message());
logger_->e("[http:request:%i] end with error: %s", id_, ec.message().c_str());
else
logger_->debug("[http:request:{:d}] done with status code {:d}", id_, response_.status_code);
logger_->d("[http:request:%i] done with status code %u", id_, response_.status_code);
}
if (!parser_ or !llhttp_should_keep_alive(parser_.get()))
if (!parser_ or !http_should_keep_alive(parser_.get()))
if (auto c = conn_)
c->close();
notify_state_change(State::DONE);
@@ -1377,15 +1361,17 @@ Request::handle_response(const asio::error_code& ec, size_t /* n_bytes */)
return;
}
auto request = (ec == asio::error::eof) ? std::string{} : conn_->read_bytes();
enum llhttp_errno ret = llhttp_execute(parser_.get(), request.c_str(), request.size());
if (ret != HPE_OK && ret != HPE_PAUSED) {
size_t ret = http_parser_execute(parser_.get(), parser_s_.get(), request.c_str(), request.size());
if (ret != request.size()) {
if (logger_)
logger_->e("Error parsing HTTP: %zu %s %d", (int)ret, llhttp_errno_name(ret), llhttp_get_error_reason(parser_.get()));
logger_->e("Error parsing HTTP: %zu %s %s", ret,
http_errno_name(HTTP_PARSER_ERRNO(parser_)),
http_errno_description(HTTP_PARSER_ERRNO(parser_)));
terminate(asio::error::basic_errors::broken_pipe);
return;
}
if (state_ != State::DONE and parser_ and not llhttp_message_needs_eof(parser_.get())) {
if (state_ != State::DONE and parser_ and not http_body_is_final(parser_.get())) {
auto toRead = parser_->content_length ? std::min<uint64_t>(parser_->content_length, 64 * 1024) : 64 * 1024;
std::weak_ptr<Request> wthis = shared_from_this();
conn_->async_read_some(toRead, [wthis](const asio::error_code& ec, size_t bytes){
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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>
@@ -316,7 +316,7 @@ void Pht::updateCanary(Prefix p) {
dht_->put(p.hash(), std::move(canary_value),
[=](bool){
static std::bernoulli_distribution d(0.5);
std::random_device rd;
crypto::random_device rd;
if (p.size_ and d(rd))
updateCanary(p.getPrefix(-1));
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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
+35 -76
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -20,10 +20,6 @@
#include "log.h"
#include "dhtrunner.h"
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <fmt/printf.h>
#ifndef _WIN32
#include <syslog.h>
#endif
@@ -34,70 +30,46 @@
namespace dht {
namespace log {
/**
* Terminal colors for logging
*/
namespace Color {
enum Code {
FG_RED = 31,
FG_GREEN = 32,
FG_YELLOW = 33,
FG_BLUE = 34,
FG_DEFAULT = 39,
BG_RED = 41,
BG_GREEN = 42,
BG_BLUE = 44,
BG_DEFAULT = 49
};
class Modifier {
const Code code;
public:
constexpr Modifier(Code pCode) : code(pCode) {}
friend std::ostream&
operator<<(std::ostream& os, const Modifier& mod) {
return os << "\033[" << mod.code << 'm';
}
};
}
constexpr const Color::Modifier def(Color::FG_DEFAULT);
constexpr const Color::Modifier red(Color::FG_RED);
constexpr const Color::Modifier yellow(Color::FG_YELLOW);
/**
* Print va_list to std::ostream (used for logging).
*/
void
printfLog(std::ostream& s, const std::string& message) {
printLog(std::ostream& s, char const *m, va_list args) {
// print log to buffer
std::array<char, 8192> buffer;
int ret = vsnprintf(buffer.data(), buffer.size(), m, args);
if (ret <= 0)
return;
// write timestamp
using namespace std::chrono;
using log_precision = microseconds;
auto num = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
constexpr auto den = log_precision::period::den;
fmt::print(s, "[{:06d}.{:06d}] ", num / den, num % den);
s << message << std::endl;
}
void
printLog(std::ostream& s, fmt::string_view format, fmt::format_args args) {
using namespace std::chrono;
using log_precision = microseconds;
auto num = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
constexpr auto den = log_precision::period::den;
fmt::print(s, "[{:06d}.{:06d}] ", num / den, num % den);
fmt::vprint(s, format, args);
s << "[" << std::setfill('0') << std::setw(6) << num / den << "."
<< std::setfill('0') << std::setw(6) << num % den << "]" << " ";
// write log
s.write(buffer.data(), std::min((size_t) ret, buffer.size()));
if ((size_t) ret >= buffer.size())
s << "[[TRUNCATED]]";
s << std::endl;
}
std::shared_ptr<Logger>
getStdLogger() {
return std::make_shared<Logger>(
[](LogLevel level, std::string&& message) {
if (level == LogLevel::error)
std::cerr << red;
else if (level == LogLevel::warning)
std::cerr << yellow;
printfLog(std::cerr, message);
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
std::cerr << def;
}
},
[](char const *m, va_list args) {
std::cout << yellow;
printLog(std::cout, m, args);
std::cout << def;
},
[](char const *m, va_list args) { printLog(std::cout, m, args); }
);
}
@@ -105,28 +77,14 @@ std::shared_ptr<Logger>
getFileLogger(const std::string &path) {
auto logfile = std::make_shared<std::ofstream>();
logfile->open(path, std::ios::out);
return std::make_shared<Logger>(
[logfile](LogLevel /*level*/, std::string&& message) {
printfLog(*logfile, message);
}
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
);
}
#ifndef _WIN32
constexpr
int syslogLevel(LogLevel level) {
switch (level) {
case LogLevel::error:
return LOG_ERR;
case LogLevel::warning:
return LOG_WARNING;
case LogLevel::debug:
return LOG_INFO;
}
return LOG_ERR;
}
#endif
std::shared_ptr<Logger>
getSyslogLogger(const char* name) {
#ifndef _WIN32
@@ -146,11 +104,12 @@ getSyslogLogger(const char* name) {
opened_logfile = logfile;
}
return std::make_shared<Logger>(
[logfile](LogLevel level, std::string&& message) {
syslog(syslogLevel(level), "%s", message.c_str());
});
[logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
);
#else
return getStdLogger();
return std::make_shared<Logger>();
#endif
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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
+41 -102
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -20,12 +20,10 @@
#include "network_engine.h"
#include "request.h"
#include "default_types.h"
#include "logger.h"
#include "log_enable.h"
#include "parsed_message.h"
#include <msgpack.hpp>
#include <chrono>
#include <string_view>
namespace dht {
namespace net {
@@ -43,8 +41,7 @@ constexpr std::chrono::seconds NetworkEngine::UDP_REPLY_TIME;
constexpr std::chrono::seconds NetworkEngine::RX_MAX_PACKET_TIME;
constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
/* OpenDHT User Agent (UA) */
constexpr std::string_view OPENDHT_UA {"o2"};
const std::string NetworkEngine::my_v {"RNG1"};
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
@@ -143,7 +140,7 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -162,13 +159,10 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
}
pk.pack(KEY_Y); pk.pack(version >= 1 ? KEY_Q : KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -197,7 +191,7 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -216,13 +210,10 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
}
pk.pack(KEY_Y); pk.pack(version >= 1 ? KEY_Q : KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -384,6 +375,7 @@ NetworkEngine::isMartian(const SockAddr& addr)
const auto& sin6 = addr.getIPv6();
const uint8_t* address = (const uint8_t*)&sin6.sin6_addr;
return address[0] == 0xFF ||
(address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
memcmp(address, InfoHash::zero().data(), 16) == 0 ||
memcmp(address, v4prefix, 12) == 0;
}
@@ -526,13 +518,8 @@ 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);
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());
}
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
}
else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) {
auto rsocket = node->getSocket(msg->tid);
@@ -595,22 +582,13 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
r.node->authSuccess();
}
r.reply_time = scheduler.time();
try {
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
break;
} else { /* request socket data */
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());
}
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
}
break;
default:
@@ -724,7 +702,7 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
Tid tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -732,13 +710,10 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
pk.pack(KEY_Q); pk.pack(QUERY_PING);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid, node,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -764,7 +739,7 @@ void
NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -772,13 +747,10 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -789,7 +761,7 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -804,13 +776,10 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
pk.pack(KEY_Q); pk.pack(QUERY_FIND);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -837,7 +806,7 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
unsigned sendWant = (want > 0) ? 1 : 0;
@@ -860,14 +829,11 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
pk.pack(KEY_Q); pk.pack(QUERY_GET);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
@@ -984,13 +950,10 @@ NetworkEngine::sendValueParts(Tid tid, const std::vector<Blob>& svals, const Soc
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(3+(config.network?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_V); pk.pack_map(1);
@@ -1011,7 +974,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -1049,13 +1012,10 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
// send response
send(addr, buffer.data(), buffer.size());
@@ -1127,7 +1087,7 @@ NetworkEngine::sendListen(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
auto has_query = not query.where.empty() or not query.select.empty();
pk.pack(KEY_A); pk.pack_map(5 + has_query);
@@ -1143,13 +1103,10 @@ NetworkEngine::sendListen(const Sp<Node>& n,
pk.pack(KEY_Q); pk.pack(QUERY_LISTEN);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1171,7 +1128,7 @@ void
NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1179,13 +1136,10 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1202,7 +1156,7 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
bool add_created = created < scheduler.time();
pk.pack(KEY_A); pk.pack_map(add_created ? 5 : 4);
@@ -1218,13 +1172,10 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
pk.pack(KEY_Q); pk.pack(QUERY_PUT);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1291,7 +1242,7 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 7 : 6));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1308,13 +1259,10 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
pk.pack(KEY_Q); pk.pack(QUERY_UPDATE);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::UpdateValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1339,7 +1287,7 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1350,13 +1298,10 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
pk.pack(KEY_Q); pk.pack(QUERY_REFRESH);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1388,7 +1333,7 @@ void
NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1397,13 +1342,10 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1417,7 +1359,7 @@ NetworkEngine::sendError(const SockAddr& addr,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0));
pk.pack(KEY_E); pk.pack_array(2);
pk.pack(code);
@@ -1430,13 +1372,10 @@ NetworkEngine::sendError(const SockAddr& addr,
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(OPENDHT_UA);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
+17 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2023 Savoir-faire Linux Inc.
* Copyright (C) 2014-2022 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
@@ -25,16 +25,11 @@
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#define _poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#else
#include <sys/select.h>
#include <fcntl.h>
#include <poll.h>
#define _poll(fds, nfds, timeout) poll(fds, nfds, timeout)
#endif
// number of file descriptors to poll in openSockets()
#define NUM_FDS 3
#include <iostream>
namespace dht {
@@ -240,23 +235,23 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
running = true;
rcv_thread = std::thread([this, stop_readfd, ls4=s4, ls6=s6]() mutable {
struct pollfd fds[NUM_FDS];
for (int i = 0; i < NUM_FDS; i++)
fds[i].events = POLLIN;
constexpr size_t stop_readfd_index = 0, ls4_index = 1, ls6_index = 2;
int selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
try {
while (running) {
// ls4 and ls6 can be negative, but this doesn't require any special handling
// because poll() will simply ignore them (and set revents to 0) in that case
fds[stop_readfd_index].fd = stop_readfd;
fds[ls4_index].fd = ls4;
fds[ls6_index].fd = ls6;
fd_set readfds;
int rc = _poll(fds, NUM_FDS, -1);
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
if(ls4 >= 0)
FD_SET(ls4, &readfds);
if(ls6 >= 0)
FD_SET(ls6, &readfds);
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
if (rc < 0) {
if (errno != EINTR) {
if (logger)
logger->e("Poll error: %s", strerror(errno));
logger->e("Select error: %s", strerror(errno));
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
@@ -269,16 +264,16 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
sockaddr_storage from;
socklen_t from_len = sizeof(from);
if (fds[stop_readfd_index].revents & POLLIN) {
if (FD_ISSET(stop_readfd, &readfds)) {
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
if (logger)
logger->e("Got stop packet error: %s", strerror(errno));
break;
}
}
else if (fds[ls4_index].revents & POLLIN)
else if (ls4 >= 0 && FD_ISSET(ls4, &readfds))
rc = recvfrom(ls4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (fds[ls6_index].revents & POLLIN)
else if (ls6 >= 0 && FD_ISSET(ls6, &readfds))
rc = recvfrom(ls6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else
continue;
@@ -321,6 +316,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
break;
s4 = ls4;
s6 = ls6;
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
} else {
break;
}
Loaded 100 of 147 files, more files were not shown because too many files have changed in this diff. Show more