From b21e9228f565a66fbb1a7d6ffc614b6f48924f65 Mon Sep 17 00:00:00 2001 From: Lucas Dias Date: Tue, 19 Jan 2021 07:19:34 -0300 Subject: [PATCH 1/2] network_engine::process could throw an exception in message type MessageType::ValueUpdate if rsocket does not exist. processMessage called process out of try-catch --- .devcontainer/devcontainer.json | 12 + .github/workflows/ccpp.yml | 50 +++- .github/workflows/clang-analyzer.yml | 35 +++ .gitignore | 5 + .gitmodules | 4 - .travis.yml | 67 ----- .vscode/launch.json | 54 ++++ .vscode/tasks.json | 44 +++ CMakeLists.txt | 121 +++----- Makefile.am | 4 + README.md | 14 +- argon2 | 1 - autogen.sh | 1 - c/Makefile.am | 12 + c/opendht.cpp | 171 ++++++++--- c/opendht_c.h | 40 ++- cmake/CheckAtomic.cmake | 156 +++++----- cmake/DetermineGCCCompatible.cmake | 13 + cmake/FindMsgpack.cmake | 64 ---- configure.ac | 47 +-- docker/Dockerfile | 16 +- docker/DockerfileBionic | 19 +- docker/DockerfileDeps | 13 +- docker/DockerfileDepsBionic | 10 +- docker/DockerfileDepsLlvm | 16 +- docker/DockerfileLlvm | 16 +- docker/DockerfileTravis | 9 - docker/DockerfileTravisLlvm | 7 - docker/DockerfileTravisProxy | 4 - include/opendht.h | 2 +- include/opendht/callbacks.h | 26 +- include/opendht/crypto.h | 62 +++- include/opendht/default_types.h | 14 +- include/opendht/dht.h | 31 +- include/opendht/dht_interface.h | 14 +- include/opendht/dht_proxy_client.h | 28 +- include/opendht/dht_proxy_server.h | 3 +- include/opendht/dhtrunner.h | 57 ++-- include/opendht/http.h | 14 +- include/opendht/indexation/pht.h | 4 +- include/opendht/infohash.h | 63 ++-- include/opendht/log.h | 2 +- include/opendht/log_enable.h | 2 +- include/opendht/network_engine.h | 25 +- include/opendht/network_utils.h | 4 +- include/opendht/node.h | 2 +- include/opendht/node_cache.h | 2 +- include/opendht/peer_discovery.h | 2 +- include/opendht/proxy.h | 2 +- include/opendht/rate_limiter.h | 2 +- include/opendht/rng.h | 2 +- include/opendht/routing_table.h | 2 +- include/opendht/scheduler.h | 31 +- include/opendht/securedht.h | 31 +- include/opendht/sockaddr.h | 14 +- include/opendht/thread_pool.h | 80 ++++- include/opendht/utils.h | 6 +- include/opendht/value.h | 47 +-- m4/ax_cxx_compile_stdcxx.m4 | 64 +++- python/opendht.pyx | 32 +- python/opendht_cpp.pxd | 22 +- python/setup.py.in | 6 +- python/tools/benchmark.py | 2 +- python/tools/dht/network.py | 2 +- python/tools/dht/tests.py | 2 +- python/tools/dht/virtual_network_builder.py | 2 +- python/tools/dhtcluster.py | 2 +- python/tools/http_server.py | 2 +- python/tools/network_monitor.py | 2 +- python/tools/pingpong.py | 2 +- python/tools/scanner.py | 2 +- rust/examples/dhtnode.rs | 2 +- rust/src/blob.rs | 2 +- rust/src/crypto.rs | 2 +- rust/src/dhtrunner.rs | 2 +- rust/src/ffi.rs | 2 +- rust/src/infohash.rs | 2 +- rust/src/lib.rs | 2 +- rust/src/pkid.rs | 2 +- rust/src/value.rs | 2 +- src/Makefile.am | 29 +- src/base64.cpp | 2 +- src/base64.h | 2 +- src/callbacks.cpp | 18 +- src/compat/msvc/unistd.h | 2 +- src/compat/os_cert.cpp | 24 +- src/compat/os_cert.h | 2 +- src/crypto.cpp | 262 +++++++++++----- src/default_types.cpp | 2 +- src/dht.cpp | 309 +++++++++++-------- src/dht_proxy_client.cpp | 49 +-- src/dht_proxy_server.cpp | 121 +++----- src/dhtrunner.cpp | 314 +++++++++++++------- src/http.cpp | 69 ++++- src/indexation/pht.cpp | 2 +- src/infohash.cpp | 8 +- src/listener.h | 2 +- src/log.cpp | 6 +- src/net.h | 2 +- src/network_engine.cpp | 93 +++--- src/network_utils.cpp | 2 +- src/node.cpp | 7 +- src/node_cache.cpp | 2 +- src/op_cache.cpp | 4 +- src/op_cache.h | 24 +- src/parsed_message.h | 93 +++--- src/peer_discovery.cpp | 11 +- src/request.h | 6 +- src/rng.cpp | 2 +- src/routing_table.cpp | 2 +- src/search.h | 125 +++++--- src/securedht.cpp | 61 ++-- src/storage.h | 58 ++-- src/thread_pool.cpp | 37 +-- src/utils.cpp | 4 +- src/value.cpp | 24 +- src/value_cache.h | 31 +- tests/cryptotester.cpp | 16 +- tests/cryptotester.h | 7 +- tests/dhtproxytester.cpp | 47 ++- tests/dhtproxytester.h | 5 +- tests/dhtrunnertester.cpp | 188 ++++++++++-- tests/dhtrunnertester.h | 12 +- tests/httptester.cpp | 2 +- tests/httptester.h | 2 +- tests/infohashtester.cpp | 2 +- tests/infohashtester.h | 2 +- tests/peerdiscoverytester.cpp | 2 +- tests/peerdiscoverytester.h | 2 +- tests/tests_runner.cpp | 2 +- tests/threadpooltester.cpp | 28 +- tests/threadpooltester.h | 4 +- tests/valuetester.cpp | 2 +- tests/valuetester.h | 2 +- tools/CMakeLists.txt | 10 +- tools/Makefile.am | 13 +- tools/dhtchat.cpp | 2 +- tools/dhtcnode.c | 272 +++++++++++++---- tools/dhtnode.cpp | 26 +- tools/dhtscanner.cpp | 2 +- tools/durl.cpp | 2 +- tools/perftest.cpp | 4 +- tools/proxy_loadtester.py | 2 +- tools/tools_common.h | 2 +- 144 files changed, 2719 insertions(+), 1511 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/workflows/clang-analyzer.yml delete mode 100644 .gitmodules delete mode 100644 .travis.yml create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json delete mode 160000 argon2 create mode 100644 c/Makefile.am create mode 100644 cmake/DetermineGCCCompatible.cmake delete mode 100644 cmake/FindMsgpack.cmake delete mode 100644 docker/DockerfileTravis delete mode 100644 docker/DockerfileTravisLlvm delete mode 100644 docker/DockerfileTravisProxy diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..9157472bd --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,12 @@ +{ + "name": "C++", + "build": { + "dockerfile": "../docker/DockerfileDepsLlvm", + }, + "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], + "settings": {}, + "extensions": [ + "ms-vscode.cpptools" + ], + "forwardPorts": [4222], +} diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 8e0321e89..10e1f0a90 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1,24 +1,20 @@ name: C/C++ CI -on: [push] +on: [push, pull_request] jobs: - build: - + build-ubuntu: + name: Ubuntu/GCC build runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: deps run: | sudo apt install libncurses5-dev libreadline-dev nettle-dev \ libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \ - autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev + autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev - name: autogen run: ./autogen.sh - - name: argon2 - run: | - cd argon2 && make && sudo make install && cd .. - name: asio run: | wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \ @@ -32,3 +28,39 @@ jobs: run: make - name: make check run: make check + + build-macos: + name: macOS/Clang build + runs-on: macos-11 + steps: + - uses: actions/checkout@v3 + - name: deps + run: | + brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl http-parser cppunit + + - name: restinio + run: | + mkdir restinio && cd restinio + wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz + ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz + cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev + cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \ + -DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \ + -DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . + make -j8 && sudo make install + cd ../../.. && rm -rf restinio + + - name: cmake + run: | + mkdir build && cd build + export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH" + export LDFLAGS="-L/usr/local/opt/openssl@3/lib" + export CPPFLAGS="-I/usr/local/opt/openssl@3/include" + export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig" + cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \ + -DOPENDHT_C=On -DOPENDHT_TESTS=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \ + -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On + + - name: make + run: cd build && make + diff --git a/.github/workflows/clang-analyzer.yml b/.github/workflows/clang-analyzer.yml new file mode 100644 index 000000000..a86372284 --- /dev/null +++ b/.github/workflows/clang-analyzer.yml @@ -0,0 +1,35 @@ +name: Clang Static Analysis +on: + push +jobs: + clang-analyzer: + name: Clang Static Analysis + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: deps + run: | + sudo apt install libncurses5-dev libreadline-dev nettle-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: restinio + run: | + mkdir restinio && cd restinio \ + && wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ + && ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ + && cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \ + && 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: | + mkdir build && cd build && \ + cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On + - name: scan-build + run: cd build && scan-build --status-bugs make diff --git a/.gitignore b/.gitignore index 016541716..fd367eaaa 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ *.exe *.out *.app +**/dhtnode +**/dhtchat +**/dhtscanner # Autotools /ac @@ -73,3 +76,5 @@ doc/Doxyfile # build dir build +build_dev +.DS_Store diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ef38b69b0..000000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "argon2"] - path = argon2 - url = https://github.com/P-H-C/phc-winner-argon2 - ignore = dirty diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2c45aa22d..000000000 --- a/.travis.yml +++ /dev/null @@ -1,67 +0,0 @@ -dist: xenial -sudo: required - -services: - - docker - -language: cpp - -env: - matrix: - - OPENDHT_TEST_JOB="opendht.classic" - - OPENDHT_TEST_JOB="opendht.llvm" - - OPENDHT_TEST_JOB="opendht.proxyserver" - - OPENDHT_TEST_JOB="opendht.proxyclient" - - OPENDHT_TEST_JOB="opendht.push" - -before_install: - - | - if [[ "$OPENDHT_TEST_JOB" == *"opendht.classic"* ]]; then - docker pull aberaud/opendht-deps-bionic; - fi - if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then - docker pull aberaud/opendht-deps; - fi - if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then - docker pull aberaud/opendht-deps-llvm - fi - -script: - - | - # classic build - if [[ "$OPENDHT_TEST_JOB" == *"opendht.classic"* ]]; then - docker build -t opendht -f docker/DockerfileTravis .; - fi - - - | - # proxy builds - if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]] && [[ "$OPENDHT_TEST_JOB" != *"opendht.classic"* ]]; then - docker build -t opendht-proxy -f docker/DockerfileTravisProxy .; - options='-DOPENDHT_SANITIZE=On '; - if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then - options+='-DOPENDHT_PROXY_SERVER=ON '; - else - options+='-DOPENDHT_PROXY_SERVER=OFF '; - fi - if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then - options+='-DOPENDHT_PROXY_CLIENT=ON '; - else - options+='-DOPENDHT_PROXY_CLIENT=OFF '; - fi - if [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then - options+='-DOPENDHT_PUSH_NOTIFICATIONS=ON '; - else - options+='-DOPENDHT_PUSH_NOTIFICATIONS=OFF '; - fi - docker run opendht-proxy /bin/sh -c "cd /root/opendht && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=ON -DOPENDHT_LTO=ON -DOPENDHT_TESTS=ON $options .. && make -j8 && ./opendht_unit_tests && make install"; - fi - - - | - # llvm build - if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then - docker build -f docker/DockerfileTravisLlvm . - fi - -notifications: - email: - - adrien.beraud@savoirfairelinux.com diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..24364e781 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,54 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "dhtnode", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build_dev/tools/dhtnode", + "args": ["-v", "-p", "4222"], + "cwd": "${workspaceFolder}/build_dev", + "environment": [], + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build", + "linux": { + "MIMode": "gdb", + "externalConsole": false, + }, + "osx": { + "MIMode": "lldb", + "externalConsole": true, + }, + }, + { + "name": "tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build_dev/opendht_unit_tests", + "cwd": "${workspaceFolder}/build_dev", + "environment": [], + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "build", + "linux": { + "MIMode": "gdb", + "externalConsole": false, + }, + "osx": { + "MIMode": "lldb", + "externalConsole": true, + }, + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..f7cfc5f40 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,44 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceRoot}/build_dev" + }, + "command": "make", + "args": ["-j4"], + "dependsOn": "cmake" + }, + { + "label": "cmake", + "type": "shell", + "options": { + "cwd": "${workspaceRoot}/build_dev" + }, + "command": "cmake", + "args": [ + "${workspaceRoot}", + "-DCMAKE_BUILD_TYPE=Debug", + "-DOPENDHT_PROXY_CLIENT=On", + "-DOPENDHT_PROXY_SERVER=On", + "-DOPENDHT_TESTS=On", + "-DOPENDHT_C=On" + ], + "dependsOn": "builddir" + }, + { + "label": "builddir", + "type": "shell", + "options": { + "cwd": "${workspaceRoot}" + }, + "command": "mkdir", + "args": [ + "-p", + "${workspaceRoot}/build_dev" + ] + }, + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fff55d17..69b957e9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,16 @@ -cmake_minimum_required (VERSION 3.1) +cmake_minimum_required (VERSION 3.10) +if(POLICY CMP0065) + cmake_policy(SET CMP0065 NEW) +endif() +if(POLICY CMP0069) + cmake_policy(SET CMP0069 NEW) +endif() +if(POLICY CMP0073) + cmake_policy(SET CMP0073 NEW) +endif() +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() project (opendht) include(CMakePackageConfigHelpers) @@ -7,7 +19,7 @@ include(FindPkgConfig) include(cmake/CheckAtomic.cmake) set (opendht_VERSION_MAJOR 2) -set (opendht_VERSION_MINOR 1.9) +set (opendht_VERSION_MINOR 4.3) set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR}) set (PACKAGE_VERSION ${opendht_VERSION}) set (VERSION "${opendht_VERSION}") @@ -20,15 +32,12 @@ option (OPENDHT_PYTHON "Build Python bindings" OFF) option (OPENDHT_TOOLS "Build DHT tools" ON) option (OPENDHT_SYSTEMD "Install systemd module" OFF) option (OPENDHT_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file") -option (OPENDHT_ARGON2 "Use included argon2 sources" OFF) -option (OPENDHT_LTO "Build with LTO" OFF) option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF) option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF) option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF) option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF) option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF) option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON) -option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF) CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON) option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON) option (OPENDHT_INDEX "Build DHT indexation feature" OFF) @@ -40,28 +49,22 @@ find_package(Doxygen) option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) # Dependencies +if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) + link_libraries (atomic) +endif () + list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if (NOT MSVC) set (THREADS_PREFER_PTHREAD_FLAG TRUE) find_package (Threads) find_package (PkgConfig REQUIRED) find_package (GnuTLS 3.3 REQUIRED) - pkg_search_module (Nettle nettle) - find_package (Msgpack 1.2 REQUIRED) + pkg_search_module (Nettle REQUIRED nettle) + find_package (msgpack REQUIRED) if (OPENDHT_TOOLS) find_package (Readline 6 REQUIRED) endif () - if (NOT OPENDHT_ARGON2) - pkg_search_module(argon2 libargon2) - if (argon2_FOUND) - message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")") - link_directories (${argon2_LIBRARY_DIRS}) - else () - message("Argon2 not found, using included version.") - set(OPENDHT_ARGON2 ON) - endif() - endif () - + pkg_search_module(argon2 REQUIRED libargon2) pkg_search_module(Jsoncpp jsoncpp) if (Jsoncpp_FOUND) add_definitions(-DOPENDHT_JSONCPP) @@ -71,8 +74,11 @@ if (NOT MSVC) ) endif() - if (OPENDHT_HTTP) + if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY) find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED) + endif () + + if (OPENDHT_HTTP) find_package(Restinio REQUIRED) find_library(FMT_LIBRARY fmt) add_library(fmt SHARED IMPORTED) @@ -92,9 +98,6 @@ if (NOT MSVC) message(SEND_ERROR "OpenSSL is required for DHT proxy as specified") endif() endif() - if (OPENDHT_PROXY_HTTP_PARSER_FORK) - add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK) - endif() else () set(OPENDHT_PROXY_OPENSSL OFF) endif () @@ -125,7 +128,7 @@ if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY) endif() # Build flags -set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD 17) set (CMAKE_CXX_STANDARD_REQUIRED on) if (NOT MSVC) @@ -143,7 +146,7 @@ else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_MSC_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") endif () -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT") if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -154,15 +157,6 @@ if (OPENDHT_LOG) else () add_definitions(-DOPENDHT_LOG=false) endif() -if (OPENDHT_LTO AND NOT MSVC) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") - if (CMAKE_COMPILER_IS_GNUCC) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-linker-plugin") - set (CMAKE_AR "gcc-ar") - set (CMAKE_NM "gcc-nm") - set (CMAKE_RANLIB "gcc-ranlib") - endif () -endif () if (MSGPACK_INCLUDE_DIRS) include_directories (SYSTEM "${MSGPACK_INCLUDE_DIRS}") @@ -184,6 +178,7 @@ if (Jsoncpp_INCLUDE_DIRS) endif () link_directories (${Nettle_LIBRARY_DIRS}) link_directories (${Jsoncpp_LIBRARY_DIRS}) +link_directories (${argon2_LIBRARY_DIRS}) include_directories ( ./ include/ @@ -311,23 +306,6 @@ if (OPENDHT_HTTP) ) endif () -if(OPENDHT_ARGON2) - # make sure argon2 submodule is up to date and initialized - message("Initializing Argon2 submodule") - execute_process(COMMAND git submodule update --init) - - # add local argon2 files to build - list (APPEND opendht_SOURCES - argon2/src/argon2.c - argon2/src/core.c - argon2/src/blake2/blake2b.c - argon2/src/thread.c - argon2/src/ref.c - argon2/src/encoding.c - ) - include_directories(argon2/include/) -endif() - if (MSVC) list (APPEND opendht_HEADERS src/compat/msvc/unistd.h) endif () @@ -340,11 +318,7 @@ if (OPENDHT_STATIC) ${opendht_HEADERS} ) set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht") - if (OPENDHT_ARGON2) - target_include_directories(opendht-static SYSTEM PRIVATE argon2) - else () - target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) - endif () + target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) target_link_libraries(opendht-static PRIVATE ${argon2_LIBRARIES} PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES} @@ -409,40 +383,43 @@ if (OPENDHT_SHARED) set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib") set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION}) target_compile_definitions(opendht PRIVATE OPENDHT_BUILD) - if (OPENDHT_ARGON2) - target_include_directories(opendht SYSTEM PRIVATE argon2) - else () - target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES}) - target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) - endif () + target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) if (APPLE) target_link_libraries(opendht PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Jsoncpp_LIBRARIES} - ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} + ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES} SYSTEM "-framework CoreFoundation" "-framework Security") else () target_link_libraries(opendht PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Jsoncpp_LIBRARIES} - ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}) + ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES}) endif () install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht) endif () if (OPENDHT_C) - add_library (opendht-c SHARED - c/opendht.cpp - c/opendht_c.h - ) - target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD) if (OPENDHT_SHARED) - target_link_libraries(opendht-c opendht) - else () - target_link_libraries(opendht-c opendht-static) + add_library (opendht-c SHARED + c/opendht.cpp + c/opendht_c.h + ) + target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD) + target_link_libraries(opendht-c PRIVATE opendht) + install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c) + endif () + + if (OPENDHT_STATIC) + add_library (opendht-c-static STATIC + c/opendht.cpp + c/opendht_c.h + ) + target_link_libraries(opendht-c-static PRIVATE opendht-static) + install (TARGETS opendht-c-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c-static) endif () # PkgConfig module @@ -451,8 +428,8 @@ if (OPENDHT_C) opendht-c.pc @ONLY ) - install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht-c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install (FILES c/opendht_c.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/opendht) endif () if (OPENDHT_TOOLS) diff --git a/Makefile.am b/Makefile.am index 7ba6efbb2..498329ba2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,10 @@ SUBDIRS = SUBDIRS += src +if ENABLE_C +SUBDIRS += c +endif + if ENABLE_TOOLS SUBDIRS += tools endif diff --git a/README.md b/README.md index 34fb21b85..ee5377daa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ OpenDHT -A lightweight C++14 Distributed Hash Table implementation. +A lightweight C++17 Distributed Hash Table implementation. OpenDHT provides an easy to use distributed in-memory data store. Every node in the network can read and write values to the store. @@ -14,7 +14,7 @@ Values are distributed over the network, with redundancy. * High resilience to network disruption * Public key cryptography layer providing optional data signature and encryption (using GnuTLS) * IPv4 and IPv6 support - * Clean and powerful **C++14** map API + * Clean and powerful **C++17** map API * Bindings for **C, Rust & Python 3** * REST API with optional HTTP client+server with push notification support @@ -27,7 +27,7 @@ Build instructions: + * + * 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 . + */ + #include "opendht_c.h" -#include "opendht.h" + +#include +#include using ValueSp = std::shared_ptr; using PrivkeySp = std::shared_ptr; @@ -10,6 +30,13 @@ using CertSp = std::shared_ptr; extern "C" { #endif +#include + +const char* dht_version() +{ + return dht::version(); +} + // dht::InfoHash inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) { @@ -49,7 +76,11 @@ bool dht_infohash_is_zero(const dht_infohash* h) { } void dht_infohash_from_hex(dht_infohash* h, const char* dat) { - *h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2))); + *h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat, HASH_LEN*2))); +} + +void dht_infohash_from_hex_null(dht_infohash* h, const char* dat) { + *h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat))); } const char* dht_pkid_print(const dht_pkid* h) { @@ -97,10 +128,20 @@ const char* dht_value_get_user_type(const dht_value* data) { return vsp->user_type.c_str(); } +void dht_value_set_user_type(dht_value* data, const char* user_type) { + (*reinterpret_cast(data))->user_type = user_type; +} + dht_value* dht_value_new(const uint8_t* data, size_t size) { return reinterpret_cast(new ValueSp(std::make_shared(data, size))); } +dht_value* dht_value_new_from_string(const char* str) { + ValueSp value = std::make_shared((const uint8_t*)str, strlen(str)); + value->user_type = "text/plain"; + return reinterpret_cast(new ValueSp(std::move(value))); +} + dht_value* dht_value_ref(const dht_value* v) { return reinterpret_cast(new ValueSp(*reinterpret_cast(v))); } @@ -144,9 +185,13 @@ bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, si dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) { const auto& pkey = *reinterpret_cast(pk); - auto rdata = new dht::Blob; - *rdata = pkey->encrypt((const uint8_t*)data, data_size); - return (dht_blob*)rdata; + try { + auto rdata = std::make_unique(); + *rdata = pkey->encrypt((const uint8_t*)data, data_size); + return (dht_blob*)rdata.release(); + } catch (...) { + return nullptr; + } } // dht::crypto::PrivateKey @@ -173,7 +218,18 @@ int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) { const auto& key = *reinterpret_cast(k); - return reinterpret_cast(new PubkeySp(std::make_shared(key->getPublicKey()))); + return reinterpret_cast(new PubkeySp(key->getSharedPublicKey())); +} + +dht_blob* dht_privatekey_decrypt(const dht_privatekey* k, const char* data, size_t data_size) { + const auto& key = *reinterpret_cast(k); + try { + auto rdata = std::make_unique(); + *rdata = key->decrypt((const uint8_t*)data, data_size); + return (dht_blob*)rdata.release(); + } catch (...) { + return nullptr; + } } void dht_privatekey_delete(dht_privatekey* pk) { @@ -247,7 +303,7 @@ void dht_runner_config_default(dht_runner_config* config) { } // dht::DhtRunner -dht_runner* dht_runner_new() { +dht_runner* dht_runner_new(void) { return reinterpret_cast(new dht::DhtRunner); } @@ -255,39 +311,60 @@ void dht_runner_delete(dht_runner* runner) { delete reinterpret_cast(runner); } -void dht_runner_run(dht_runner* r, in_port_t port) { +int dht_runner_run(dht_runner* r, in_port_t port) { auto runner = reinterpret_cast(r); - runner->run(port, {}, true); + try { + runner->run(port, {}, true); + } catch(...) { + return ENOTCONN; + } + return 0; } -void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) { +int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) { auto runner = reinterpret_cast(r); - dht::DhtRunner::Config config; - 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(&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(conf->dht_config.id.privatekey); - - if (conf->dht_config.id.certificate) - config.dht_config.id.second = *reinterpret_cast(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.peer_discovery = conf->peer_discovery; - config.peer_publish = conf->peer_publish; - runner->run(port, config); -} - -void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) { + try { + dht::DhtRunner::Config config; + 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(&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(conf->dht_config.id.privatekey); + + if (conf->dht_config.id.certificate) + config.dht_config.id.second = *reinterpret_cast(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.peer_discovery = conf->peer_discovery; + config.peer_publish = conf->peer_publish; + + dht::DhtRunner::Context context; + if (conf->log) { + context.logger = dht::log::getStdLogger(); + } + runner->run(port, config, std::move(context)); + } catch(...) { + return ENOTCONN; + } + return 0; +} + +void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len, dht_done_cb done_cb, void* cb_user_data) { auto runner = reinterpret_cast(r); - runner->bootstrap(dht::SockAddr(addr, addr_len)); + if (done_cb) { + runner->bootstrap(dht::SockAddr(addr, addr_len), [done_cb, cb_user_data](bool ok){ + done_cb(ok, cb_user_data); + }); + } else { + runner->bootstrap(dht::SockAddr(addr, addr_len)); + } } void dht_runner_bootstrap(dht_runner* r, const char* host, const char* service) { @@ -326,8 +403,11 @@ dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_ auto runner = reinterpret_cast(r); auto hash = reinterpret_cast(h); auto fret = new std::future; - auto guard = done_cb ? std::make_shared(done_cb, cb_user_data) : std::shared_ptr{}; - *fret = runner->listen(*hash, [cb,cb_user_data, guard](const std::vector>& values, bool expired) { + *fret = runner->listen(*hash, [ + cb, + cb_user_data, + guard = done_cb ? std::make_shared(done_cb, cb_user_data) : std::shared_ptr{} + ](const std::vector>& values, bool expired) { for (const auto& value : values) { if (not cb(reinterpret_cast(&value), expired, cb_user_data)) return false; @@ -393,6 +473,17 @@ void dht_runner_shutdown(dht_runner* r, dht_shutdown_cb done_cb, void* cb_user_d }); } +bool dht_runner_is_running(const dht_runner* r) { + if (not r) return false; + auto runner = reinterpret_cast(r); + return runner->isRunning(); +} + +in_port_t dht_runner_get_bound_port(const dht_runner* r, sa_family_t af) { + auto runner = reinterpret_cast(r); + return runner->getBoundPort(af); +} + dht_infohash dht_runner_get_node_id(const dht_runner* r) { auto runner = reinterpret_cast(r); dht_infohash ret; @@ -414,9 +505,9 @@ struct sockaddr** dht_runner_get_public_address(const dht_runner* r) { return nullptr; auto ret = (struct sockaddr**)malloc(sizeof(struct sockaddr*) * (addrs.size() + 1)); for (size_t i=0; i + * + * 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 . + */ + #pragma once #ifdef __cplusplus extern "C" { #endif -#include "def.h" +#include #include #include #include @@ -18,6 +36,8 @@ struct OPENDHT_C_PUBLIC dht_data_view { }; typedef struct dht_data_view dht_data_view; +OPENDHT_C_PUBLIC const char* dht_version(); + // dht::Blob struct OPENDHT_C_PUBLIC dht_blob; typedef struct dht_blob dht_blob; @@ -30,6 +50,7 @@ typedef struct dht_infohash dht_infohash; OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h); OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h); OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat); +OPENDHT_C_PUBLIC void dht_infohash_from_hex_null(dht_infohash* h, const char* dat); OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size); OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str); OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h); @@ -58,6 +79,7 @@ OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bit OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password); OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password); OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*); +OPENDHT_C_PUBLIC dht_blob* dht_privatekey_decrypt(const dht_privatekey*, const char* data, size_t data_size); OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*); // dht::crypto::Certificate @@ -82,6 +104,7 @@ struct OPENDHT_C_PUBLIC dht_value; typedef struct dht_value dht_value; typedef uint64_t dht_value_id; OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size); +OPENDHT_C_PUBLIC dht_value* dht_value_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*); OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data); @@ -89,6 +112,7 @@ OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data); OPENDHT_C_PUBLIC dht_publickey* dht_value_get_owner(const dht_value* data); OPENDHT_C_PUBLIC dht_infohash dht_value_get_recipient(const dht_value* data); OPENDHT_C_PUBLIC const char* dht_value_get_user_type(const dht_value* data); +OPENDHT_C_PUBLIC void dht_value_set_user_type(dht_value* data, const char* user_type); // callbacks typedef bool (*dht_get_cb)(const dht_value* value, void* user_data); @@ -126,6 +150,7 @@ struct OPENDHT_PUBLIC dht_runner_config { bool peer_publish; dht_certificate* server_ca; dht_identity client_identity; + bool log; }; typedef struct dht_runner_config dht_runner_config; OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config); @@ -133,11 +158,13 @@ OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config); // dht::DhtRunner struct OPENDHT_C_PUBLIC dht_runner; typedef struct dht_runner dht_runner; -OPENDHT_C_PUBLIC dht_runner* dht_runner_new(); +OPENDHT_C_PUBLIC dht_runner* dht_runner_new(void); OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner); -OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port); -OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config); -OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len); +/* Returns 0 on success, standard error code on failure */ +OPENDHT_C_PUBLIC int dht_runner_run(dht_runner* runner, in_port_t port); +/* Returns 0 on success, standard error code on failure */ +OPENDHT_C_PUBLIC int dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config); +OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len, dht_done_cb done_cb, void* cb_user_data); OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host, const char* service); OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data); OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data); @@ -149,6 +176,9 @@ OPENDHT_C_PUBLIC void dht_runner_cancel_put(dht_runner* runner, const dht_infoha OPENDHT_C_PUBLIC void dht_runner_shutdown(dht_runner* runner, dht_shutdown_cb done_cb, void* cb_user_data); OPENDHT_C_PUBLIC dht_infohash dht_runner_get_node_id(const dht_runner* runner); OPENDHT_C_PUBLIC dht_infohash dht_runner_get_id(const dht_runner* runner); +OPENDHT_C_PUBLIC bool dht_runner_is_running(const dht_runner* runner); +OPENDHT_C_PUBLIC in_port_t dht_runner_get_bound_port(const dht_runner* runner, sa_family_t af); +/** Returns null-terminated array that must be freed after use as well as each element */ OPENDHT_C_PUBLIC struct sockaddr** dht_runner_get_public_address(const dht_runner* runner); #ifdef __cplusplus diff --git a/cmake/CheckAtomic.cmake b/cmake/CheckAtomic.cmake index d4a671109..b6be817d7 100644 --- a/cmake/CheckAtomic.cmake +++ b/cmake/CheckAtomic.cmake @@ -1,95 +1,103 @@ -# University of Illinois/NCSA -# Open Source License -# -# Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign. -# All rights reserved. -# -# Developed by: -# -# LLVM Team -# -# University of Illinois at Urbana-Champaign -# -# http://llvm.org -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal with -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimers. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimers in the -# documentation and/or other materials provided with the distribution. -# -# * Neither the names of the LLVM Team, University of Illinois at -# Urbana-Champaign, nor the names of its contributors may be used to -# endorse or promote products derived from this Software without specific -# prior written permission. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -# SOFTWARE. +# atomic builtins are required for threading support. -include(CheckCXXSourceCompiles) -include(CheckLibraryExists) +INCLUDE(CheckCXXSourceCompiles) +INCLUDE(CheckLibraryExists) +INCLUDE("${CMAKE_CURRENT_LIST_DIR}/DetermineGCCCompatible.cmake") # Sometimes linking against libatomic is required for atomic ops, if # the platform doesn't support lock-free atomics. function(check_working_cxx_atomics varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - get_directory_property(compile_options COMPILE_OPTIONS) - set(CMAKE_REQUIRED_FLAGS ${compile_options}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") CHECK_CXX_SOURCE_COMPILES(" #include -#include -std::atomic v1; -std::atomic v2; -int main(int, char**) { - return v1 + v2; -}" ${varname}) +std::atomic x; +std::atomic y; +std::atomic z; +int main() { + ++z; + ++y; + return ++x; +} +" ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction(check_working_cxx_atomics) +function(check_working_cxx_atomics64 varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") + CHECK_CXX_SOURCE_COMPILES(" +#include +#include +std::atomic x (0); +int main() { + uint64_t i = x.load(std::memory_order_relaxed); + (void)i; + return 0; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics64) -if(NOT DEFINED PROXYGEN_COMPILER_IS_GCC_COMPATIBLE) - if(CMAKE_COMPILER_IS_GNUCXX) - set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) - elseif(MSVC) - set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE OFF) - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") - set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) - endif() -endif() -# This isn't necessary on MSVC, so avoid command-line switch annoyance -# by only running on GCC-like hosts. -if(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE) +# Check for (non-64-bit) atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) +elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") # First check if atomics work without the library. check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) # If not, check if the library exists, and atomics work with it. if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) - check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) - if(HAVE_LIBATOMIC) - list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") - check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) - if (NOT HAVE_CXX_ATOMICS_WITH_LIB) - message(FATAL_ERROR "Host compiler must support std::atomic!") - endif() - list(APPEND CMAKE_CXX_STANDARD_LIBRARIES -latomic) - else() - message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") endif() endif() endif() + +# Check for 64 bit atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) +elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") + # First check if atomics work without the library. + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) + # If not, check if the library exists, and atomics work with it. + if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) + message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") + endif() + endif() +endif() + +## TODO: This define is only used for the legacy atomic operations in +## llvm's Atomic.h, which should be replaced. Other code simply +## assumes C++11 works. +CHECK_CXX_SOURCE_COMPILES(" +#ifdef _MSC_VER +#include +#endif +int main() { +#ifdef _MSC_VER + volatile LONG val = 1; + MemoryBarrier(); + InterlockedCompareExchange(&val, 0, 1); + InterlockedIncrement(&val); + InterlockedDecrement(&val); +#else + volatile unsigned long val = 1; + __sync_synchronize(); + __sync_val_compare_and_swap(&val, 1, 0); + __sync_add_and_fetch(&val, 1); + __sync_sub_and_fetch(&val, 1); +#endif + return 0; + } +" LLVM_HAS_ATOMICS) + +if( NOT LLVM_HAS_ATOMICS ) + message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing") +endif() \ No newline at end of file diff --git a/cmake/DetermineGCCCompatible.cmake b/cmake/DetermineGCCCompatible.cmake new file mode 100644 index 000000000..1369ebe9d --- /dev/null +++ b/cmake/DetermineGCCCompatible.cmake @@ -0,0 +1,13 @@ +# Determine if the compiler has GCC-compatible command-line syntax. + +if(NOT DEFINED LLVM_COMPILER_IS_GCC_COMPATIBLE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) + elseif( MSVC ) + set(LLVM_COMPILER_IS_GCC_COMPATIBLE OFF) + elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) + set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) + elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" ) + set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) + endif() +endif() diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake deleted file mode 100644 index 7d9dd816d..000000000 --- a/cmake/FindMsgpack.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# - Try to find msgpack -# Once done this will define -# MSGPACK_FOUND - System has msgpack -# MSGPACK_INCLUDE_DIRS - The msgpack include directories -# MSGPACK_LIBRARIES - The libraries needed to use msgpack - -if(NOT MSGPACK_USE_BUNDLED) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_search_module(PC_MSGPACK QUIET - msgpackc>=${Msgpack_FIND_VERSION} - msgpack>=${Msgpack_FIND_VERSION}) - endif() -else() - set(PC_MSGPACK_INCLUDEDIR) - set(PC_MSGPACK_INCLUDE_DIRS) - set(PC_MSGPACK_LIBDIR) - set(PC_MSGPACK_LIBRARY_DIRS) - set(LIMIT_SEARCH NO_DEFAULT_PATH) -endif() - -set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER}) - -find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h - HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS} - ${LIMIT_SEARCH}) - -if(MSGPACK_INCLUDE_DIR) - file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h) - string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}") - string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}") - string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}") - set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}") -else() - set(MSGPACK_VERSION_STRING) -endif() - -# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name. -if(MSGPACK_USE_STATIC) - list(APPEND MSGPACK_NAMES - "${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}" - "${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}") -endif() - -list(APPEND MSGPACK_NAMES msgpackc msgpack) - -find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES} - # Check each directory for all names to avoid using headers/libraries from - # different places. - NAMES_PER_DIR - HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS} - ${LIMIT_SEARCH}) - -mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) - -set(MSGPACK_LIBRARIES ${MSGPACK_LIBRARY}) -set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set MSGPACK_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(Msgpack - REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR - VERSION_VAR MSGPACK_VERSION_STRING) diff --git a/configure.ac b/configure.ac index 23a317b77..04119dd94 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl define macros m4_define([opendht_major_version], 2) -m4_define([opendht_minor_version], 1) -m4_define([opendht_patch_version], 9) +m4_define([opendht_minor_version], 4) +m4_define([opendht_patch_version], 3) m4_define([opendht_version], [opendht_major_version.opendht_minor_version.opendht_patch_version]) @@ -32,6 +32,13 @@ AS_IF([test "x$enable_logs" != "xno"], [ AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled]) ]) +dnl Check for C binding +AC_ARG_ENABLE([c], [AS_HELP_STRING([--disable-c], [Disable DHT C binding])]) +AM_CONDITIONAL(ENABLE_C, test x$enable_c != "xno") +AM_COND_IF(ENABLE_C, [ + AC_DEFINE([OPENDHT_C], [], [Define if DHT C biding is enabled]) +]) + dnl Check for indexation AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])]) AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno") @@ -102,7 +109,7 @@ AS_IF([test "x$SYS" = "xandroid"], LT_INIT() LT_LANG(C++) -AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory]) +AX_CXX_COMPILE_STDCXX(17,[noext],[mandatory]) PKG_PROG_PKG_CONFIG() @@ -132,6 +139,8 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro PKG_CHECK_MODULES([Nettle], [nettle >= 2.4]) PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3]) PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2]) +PKG_CHECK_MODULES([Argon2], [libargon2]) +AC_SUBST(argon2_lib, [", libargon2"]) AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support])) AS_IF([test "x$with_jsoncpp" != "xno"], @@ -157,14 +166,6 @@ AS_IF([test "x$have_openssl" = "xyes"], [ AC_MSG_NOTICE([Not using OpenSSL]) ]) -AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API])) -AS_IF([test "x$with_http_parser_fork" = "xyes"],[ - AC_MSG_NOTICE([Using http_parser fork]) - AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork]) -], [ - AC_MSG_NOTICE([Not using http_parser fork]) -]) - AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files])) CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE" @@ -181,28 +182,7 @@ AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files])) ]) -CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT" - -dnl Check for Argon2 -AC_ARG_WITH([argon2], AS_HELP_STRING([--without-argon2], [Use included Argon2])) -AS_IF([test "x$with_argon2" != "xno"], - [PKG_CHECK_MODULES([Argon2], [libargon2], [have_argon2=yes], [have_argon2=no])], - [have_argon2=no]) -AS_IF([test "x$have_argon2" = "xyes"], [ - AC_MSG_NOTICE([Using system Argon2]) - AC_SUBST(argon2_lib, [", libargon2"]) -], [ - AS_IF([test "x$with_argon2" = "xyes"], [ - AC_MSG_ERROR([Argon2 requested but not found]) - ],[ - AC_MSG_NOTICE([Using included Argon2]) - AC_SUBST(Argon2_CFLAGS, "-I\${top_srcdir}/argon2/src -I\${top_srcdir}/argon2/include") - AC_SUBST(Argon2_LIBS, "libargon2.la") - AC_SUBST(Argon2_LDFLAGS, "-L\${abs_top_srcdir}/argon2/src/.libs") - ]) -]) - -AM_CONDITIONAL([WITH_INCLUDED_ARGON2], [test "x$have_argon2" = "xno"]) +CXXFLAGS="${CXXFLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT" AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes) AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes) @@ -225,6 +205,7 @@ AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs") AC_CONFIG_FILES([Makefile src/Makefile + c/Makefile tools/Makefile python/Makefile python/setup.py diff --git a/docker/Dockerfile b/docker/Dockerfile index 2b4a744f2..6e510d685 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,16 @@ -FROM aberaud/opendht-deps -MAINTAINER Adrien Béraud +FROM ghcr.io/savoirfairelinux/opendht/opendht-deps:latest +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht + RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ - && cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \ + && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ + -DOPENDHT_C=On \ + -DOPENDHT_PEER_DISCOVERY=On \ + -DOPENDHT_PYTHON=On \ + -DOPENDHT_TOOLS=On \ + -DOPENDHT_PROXY_SERVER=On \ + -DOPENDHT_PROXY_CLIENT=On \ + && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileBionic b/docker/DockerfileBionic index 4e2c27245..577291226 100644 --- a/docker/DockerfileBionic +++ b/docker/DockerfileBionic @@ -1,13 +1,16 @@ -FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.1.3 -MAINTAINER Adrien Béraud +FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ - -DOPENDHT_PROXY_CLIENT=On \ - -DOPENDHT_PROXY_SERVER=On \ - -DOPENDHT_C=On \ - -DOPENDHT_PYTHON=On \ - -DOPENDHT_LTO=On \ - && make -j8 && make install \ + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ + -DOPENDHT_C=On \ + -DOPENDHT_PEER_DISCOVERY=On \ + -DOPENDHT_PYTHON=On \ + -DOPENDHT_TOOLS=On \ + -DOPENDHT_PROXY_SERVER=On \ + -DOPENDHT_PROXY_CLIENT=On \ + && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileDeps b/docker/DockerfileDeps index 57cb87b41..a031091a3 100644 --- a/docker/DockerfileDeps +++ b/docker/DockerfileDeps @@ -1,5 +1,6 @@ FROM ubuntu:20.04 -MAINTAINER Adrien Béraud +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht RUN apt-get update && apt-get install -y \ dialog apt-utils \ @@ -8,18 +9,18 @@ RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \ build-essential pkg-config cmake git wget \ - autotools-dev autoconf \ + libtool autotools-dev autoconf \ cython3 python3-dev python3-setuptools \ libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \ libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \ libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \ - && apt-get clean + && apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/* RUN echo "*** Downloading RESTinio ***" \ && mkdir restinio && cd restinio \ - && wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ - && ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ - && cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \ + && 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 . \ diff --git a/docker/DockerfileDepsBionic b/docker/DockerfileDepsBionic index ad854587b..559264df0 100644 --- a/docker/DockerfileDepsBionic +++ b/docker/DockerfileDepsBionic @@ -1,14 +1,16 @@ FROM ubuntu:18.04 -MAINTAINER Adrien Béraud +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht 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 cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \ - autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \ - && apt-get clean + libargon2-0-dev \ + 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 apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake +RUN pip3 install --upgrade cmake # libasio-dev (1.10) is too old RUN echo "** Building a recent version of asio ***" \ diff --git a/docker/DockerfileDepsLlvm b/docker/DockerfileDepsLlvm index a207d304c..aaa02e5ea 100644 --- a/docker/DockerfileDepsLlvm +++ b/docker/DockerfileDepsLlvm @@ -1,26 +1,30 @@ FROM ubuntu:20.04 -MAINTAINER Adrien Béraud +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht + RUN apt-get update && apt-get install -y \ dialog apt-utils \ && apt-get clean \ && echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections RUN apt-get update \ - && apt-get install -y llvm llvm-dev clang make cmake pkg-config git wget libncurses5-dev libreadline-dev \ + && apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \ + libtool git wget libncurses5-dev libreadline-dev \ nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \ python3-setuptools libcppunit-dev python3-pip \ autotools-dev autoconf libssl-dev libargon2-dev \ libfmt-dev libhttp-parser-dev libasio-dev \ - && apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean + && apt-get remove -y gcc g++ && apt-get autoremove -y \ + && apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/* ENV CC cc ENV CXX c++ RUN echo "*** Downloading RESTinio ***" \ && mkdir restinio && cd restinio \ - && wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ - && ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ - && cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \ + && 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 . \ diff --git a/docker/DockerfileLlvm b/docker/DockerfileLlvm index 62a08cd4f..ad1917491 100644 --- a/docker/DockerfileLlvm +++ b/docker/DockerfileLlvm @@ -1,6 +1,16 @@ -FROM aberaud/opendht-deps-llvm -MAINTAINER Adrien Béraud +FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-llvm:latest +LABEL maintainer="Adrien Béraud " +LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht + RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ - && cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \ + && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ + -DOPENDHT_C=On \ + -DOPENDHT_PEER_DISCOVERY=On \ + -DOPENDHT_PYTHON=On \ + -DOPENDHT_TOOLS=On \ + -DOPENDHT_PROXY_SERVER=On \ + -DOPENDHT_PROXY_CLIENT=On \ + && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileTravis b/docker/DockerfileTravis deleted file mode 100644 index 625efb7ea..000000000 --- a/docker/DockerfileTravis +++ /dev/null @@ -1,9 +0,0 @@ -FROM aberaud/opendht-deps-bionic -MAINTAINER Adrien Béraud - -RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake - -COPY . /root/opendht -RUN cd /root/opendht && mkdir build && cd build \ - && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \ - && make -j8 && ./opendht_unit_tests && make install diff --git a/docker/DockerfileTravisLlvm b/docker/DockerfileTravisLlvm deleted file mode 100644 index 679e8828c..000000000 --- a/docker/DockerfileTravisLlvm +++ /dev/null @@ -1,7 +0,0 @@ -FROM aberaud/opendht-deps-llvm -MAINTAINER Adrien Béraud - -COPY . /root/opendht -RUN cd /root/opendht && mkdir build && cd build \ - && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \ - && make -j8 && ./opendht_unit_tests && make install diff --git a/docker/DockerfileTravisProxy b/docker/DockerfileTravisProxy deleted file mode 100644 index a4a883589..000000000 --- a/docker/DockerfileTravisProxy +++ /dev/null @@ -1,4 +0,0 @@ -FROM aberaud/opendht-deps -MAINTAINER Adrien Béraud - -COPY . /root/opendht diff --git a/include/opendht.h b/include/opendht.h index bfd6c00ad..937a3acab 100644 --- a/include/opendht.h +++ b/include/opendht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index b45e3f927..88eeff425 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -82,6 +82,8 @@ struct OPENDHT_PUBLIC NodeInfo { NodeStats ipv4 {}; NodeStats ipv6 {}; size_t ongoing_ops {0}; + size_t storage_values {0}; + size_t storage_size {0}; in_port_t bound4 {0}; in_port_t bound6 {0}; @@ -132,7 +134,10 @@ struct OPENDHT_PUBLIC Config { /* If non-0, overrides the default maximum store size. -1 means no limit. */ ssize_t max_store_size {0}; - /** + /* If non-0, overrides the default maximum store key count. -1 means no limit. */ + ssize_t max_store_keys {0}; + + /** * Use appropriate bahavior for a public IP, stable node: * - No connectivity change triggered when a search fails * - Larger listen refresh time @@ -148,7 +153,7 @@ struct OPENDHT_PUBLIC SecureDhtConfig Config node_config {}; crypto::Identity id {}; - /** + /** * Cache all encountered public keys and certificates, * for use by the certificate store, putEncrypted and putSigned */ @@ -164,6 +169,7 @@ using GetCallback = std::function> using ValueCallback = std::function>& values, bool expired)>; using GetCallbackSimple = std::function value)>; using ShutdownCallback = std::function; +using IdentityAnnouncedCb = std::function; using CertificateStoreQuery = std::function>(const InfoHash& pk_id)>; @@ -178,13 +184,13 @@ typedef bool (*FilterRaw)(const Value&, void *user_data); using DoneCallbackSimple = std::function; -OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data); -OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb); -OPENDHT_PUBLIC ValueCallback bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data); -OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data); +OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data); +OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb); +OPENDHT_PUBLIC ValueCallback bindValueCb(ValueCallbackRaw raw_cb, void* user_data); +OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data); OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb); -OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data); -OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data); -OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data); +OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data); +OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data); +OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data); } diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index e3e0a20a0..4c67dbecc 100644 --- a/include/opendht/crypto.h +++ b/include/opendht/crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * Vsevolod Ivanov * @@ -80,6 +80,8 @@ struct OPENDHT_PUBLIC PublicKey * Takes ownership of an existing gnutls_pubkey. */ PublicKey(gnutls_pubkey_t k) : pk(k) {} + + /** Import public key from serialized data */ PublicKey(const uint8_t* dat, size_t dat_size); PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {} PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; }; @@ -106,12 +108,12 @@ struct OPENDHT_PUBLIC PublicKey PkId getLongId() const; bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const; - bool checkSignature(const Blob& data, const Blob& signature) const { + inline bool checkSignature(const Blob& data, const Blob& signature) const { return checkSignature(data.data(), data.size(), signature.data(), signature.size()); } Blob encrypt(const uint8_t* data, size_t data_len) const; - Blob encrypt(const Blob& data) const { + inline Blob encrypt(const Blob& data) const { return encrypt(data.data(), data.size()); } @@ -162,7 +164,9 @@ struct OPENDHT_PUBLIC PrivateKey ~PrivateKey(); explicit operator bool() const { return key; } - PublicKey getPublicKey() const; + const PublicKey& getPublicKey() const; + const std::shared_ptr& getSharedPublicKey() const; + int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const; Blob serialize(const std::string& password = {}) const; @@ -170,14 +174,16 @@ struct OPENDHT_PUBLIC PrivateKey * Sign the provided binary object. * @returns the signature data. */ - Blob sign(const Blob&) const; + Blob sign(const uint8_t* data, size_t data_len) const; + inline Blob sign(const Blob& dat) const { return sign(dat.data(), dat.size()); } /** * Try to decrypt the provided cypher text. * In case of failure a CryptoException is thrown. * @returns the decrypted data. */ - Blob decrypt(const Blob& cypher) const; + Blob decrypt(const uint8_t* cypher, size_t cypher_len) const; + Blob decrypt(const Blob& cypher) const { return decrypt(cypher.data(), cypher.size()); } /** * Generate a new RSA key pair @@ -195,7 +201,7 @@ struct OPENDHT_PUBLIC PrivateKey PrivateKey& operator=(const PrivateKey&) = delete; Blob decryptBloc(const uint8_t* src, size_t src_size) const; - //friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length); + mutable std::shared_ptr publicKey_ {}; }; class OPENDHT_PUBLIC RevocationList @@ -310,6 +316,24 @@ class OPENDHT_PUBLIC CertificateRequest { gnutls_x509_crq_t request {nullptr}; }; +class OPENDHT_PUBLIC OcspRequest +{ +public: + OcspRequest(gnutls_ocsp_req_t r) : request(r) {}; + OcspRequest(const uint8_t* dat_ptr, size_t dat_size); + ~OcspRequest(); + + /* + * Get OCSP Request in readable format. + */ + std::string toString(const bool compact = true) const; + + Blob pack() const; + Blob getNonce() const; +private: + gnutls_ocsp_req_t request; +}; + class OPENDHT_PUBLIC OcspResponse { public: @@ -331,11 +355,11 @@ class OPENDHT_PUBLIC OcspResponse gnutls_ocsp_cert_status_t getCertificateStatus() const; /* - * Verify OCSP response. - * Return OCSP verify reason. + * Verify OCSP response and return OCSP status. + * Throws CryptoException in case of error in the response. * http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t */ - gnutls_ocsp_verify_reason_t verifyDirect(const Certificate& crt, const Blob& nonce); + gnutls_ocsp_cert_status_t verifyDirect(const Certificate& crt, const Blob& nonce); private: gnutls_ocsp_resp_t response; @@ -517,8 +541,8 @@ struct OPENDHT_PUBLIC Certificate { void addRevocationList(RevocationList&&); void addRevocationList(std::shared_ptr); - static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false); - static Certificate generate(const CertificateRequest& request, const Identity& ca); + static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false, int64_t validity = 0); + static Certificate generate(const CertificateRequest& request, const Identity& ca, int64_t validity = 0); gnutls_x509_crt_t getCopy() const { if (not cert) @@ -568,12 +592,20 @@ struct OPENDHT_PUBLIC Certificate { */ std::pair generateOcspRequest(gnutls_x509_crt_t& issuer); + /** + * Change certificate's expiration + */ + void setValidity(const Identity& ca, int64_t validity); + void setValidity(const PrivateKey& key, int64_t validity); + gnutls_x509_crt_t cert {nullptr}; std::shared_ptr issuer {}; std::shared_ptr ocspResponse; private: Certificate(const Certificate&) = delete; Certificate& operator=(const Certificate&) = delete; + mutable InfoHash cachedId_ {}; + mutable PkId cachedLongId_ {}; struct crlNumberCmp { bool operator() (const std::shared_ptr& lhs, const std::shared_ptr& rhs) const { @@ -749,8 +781,10 @@ OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password); /** * AES-GCM decryption. */ -OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key); -OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password); +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 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); } } } diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h index ef3434cfb..0c5ad1f08 100644 --- a/include/opendht/default_types.h +++ b/include/opendht/default_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -66,8 +66,10 @@ class OPENDHT_PUBLIC SignedValue : public Value::Serializable public: virtual void unpackValue(const Value& v) override { - if (v.owner) + if (v.owner) { + owner = v.owner; from = v.owner->getId(); + } BaseClass::unpackValue(v); } @@ -75,6 +77,7 @@ class OPENDHT_PUBLIC SignedValue : public Value::Serializable return [](const Value& v){ return v.isSigned(); }; } + Sp owner; dht::InfoHash from; }; @@ -144,17 +147,18 @@ class OPENDHT_PUBLIC TrustRequest : public EncryptedValue static const ValueType TYPE; TrustRequest() {} - TrustRequest(std::string s) : service(s) {} - TrustRequest(std::string s, const Blob& d) : service(s), payload(d) {} + TrustRequest(std::string s, std::string ci = {}) : service(s), conversationId(ci) {} + TrustRequest(std::string s, std::string ci, const Blob& d) : service(s), conversationId(ci), payload(d) {} static Value::Filter getFilter() { return EncryptedValue::getFilter(); } std::string service; + std::string conversationId; Blob payload; bool confirm {false}; - MSGPACK_DEFINE_MAP(service, payload, confirm) + MSGPACK_DEFINE_MAP(service, conversationId, payload, confirm) }; class OPENDHT_PUBLIC IceCandidates : public EncryptedValue diff --git a/include/opendht/dht.h b/include/opendht/dht.h index 061e22191..f940cc58d 100644 --- a/include/opendht/dht.h +++ b/include/opendht/dht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -61,9 +61,6 @@ struct LocalListener; */ class OPENDHT_PUBLIC Dht final : public DhtInterface { public: - - Dht(); - /** * Initialise the Dht with two open sockets (for IPv4 and IP6) * and an ID for the node. @@ -98,7 +95,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { /** * Performs final operations before quitting. */ - void shutdown(ShutdownCallback cb) override; + void shutdown(ShutdownCallback cb, bool stop = false) override; /** * Returns true if the node is running (have access to an open socket). @@ -117,7 +114,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void addBootstrap(const std::string& host, const std::string& service) override { bootstrap_nodes.emplace_back(host, service); - onDisconnected(); + startBootstrap(); } void clearBootstrap() override { @@ -305,6 +302,9 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override { max_store_size = limit; } + size_t getStorageLimit() const override { + return max_store_size; + } /** * Returns the total memory usage of stored values and the number @@ -343,7 +343,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { static constexpr unsigned LISTEN_NODES {4}; /* The maximum number of hashes we're willing to track. */ - static constexpr unsigned MAX_HASHES {1024 * 1024}; + static constexpr unsigned MAX_HASHES {1024 * 1024 * 1024}; /* The maximum number of searches we keep data about. */ static constexpr unsigned MAX_SEARCHES {1024 * 1024}; @@ -359,6 +359,8 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)}; + static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10}; + static constexpr size_t TOKEN_SIZE {32}; // internal structures @@ -396,7 +398,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { Kad dht6 {}; std::vector> bootstrap_nodes {}; - std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)}; + std::chrono::steady_clock::duration bootstrap_period {BOOTSTRAP_PERIOD}; Sp bootstrapJob {}; std::map store; @@ -448,13 +450,13 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { // Storage void storageAddListener(const InfoHash& id, const Sp& node, size_t tid, Query&& = {}, int version = 0); bool storageStore(const InfoHash& id, const Sp& value, time_point created, const SockAddr& sa = {}, bool permanent = false); - bool storageErase(const InfoHash& id, Value::Id vid); bool storageRefresh(const InfoHash& id, Value::Id vid); void expireStore(); void expireStorage(InfoHash h); void expireStore(decltype(store)::iterator); - void storageChanged(const InfoHash& id, Storage& st, ValueStorage&, bool newValue); + void storageRemoved(const InfoHash& id, Storage& st, const std::vector>& values, size_t totalSize); + void storageChanged(const InfoHash& id, Storage& st, const Sp&, bool newValue); std::string printStorageLog(const decltype(store)::value_type&) const; /** @@ -483,6 +485,9 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void sendCachedPing(Bucket& b); bool bucketMaintenance(RoutingTable&); void dumpBucket(const Bucket& b, std::ostream& out) const; + void bootstrap(); + void startBootstrap(); + void stopBootstrap(); // Nodes void onNewNode(const Sp& node, int confirm); @@ -490,7 +495,6 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { bool trySearchInsert(const Sp& node); // Searches - inline SearchMap& searches(sa_family_t af) { return dht(af).searches; } inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; } @@ -515,6 +519,8 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void confirmNodes(); void expire(); + + void onConnected(); void onDisconnected(); /** @@ -570,7 +576,8 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { * * @param sr The search to execute its operations. */ - void searchStep(Sp); + void searchStep(std::weak_ptr ws); + void searchSynchedNodeListen(const Sp&, SearchNode&); void dumpSearch(const Search& sr, std::ostream& out) const; diff --git a/include/opendht/dht_interface.h b/include/opendht/dht_interface.h index 7a9f2cda7..bb0362f07 100644 --- a/include/opendht/dht_interface.h +++ b/include/opendht/dht_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include "infohash.h" #include "log_enable.h" +#include + namespace dht { namespace net { @@ -46,6 +48,10 @@ class OPENDHT_PUBLIC DhtInterface { virtual NodeStatus getStatus(sa_family_t af) const = 0; virtual NodeStatus getStatus() const = 0; + void addOnConnectedCallback(std::function cb) { + onConnectCallbacks_.emplace(std::move(cb)); + } + virtual net::DatagramSocket* getSocket() const { return {}; }; /** @@ -55,8 +61,10 @@ class OPENDHT_PUBLIC DhtInterface { /** * Performs final operations before quitting. + * stop: if true, cancel ongoing operations and call their 'done' + * callbacks synchronously. */ - virtual void shutdown(ShutdownCallback cb) = 0; + virtual void shutdown(ShutdownCallback cb, bool stop = false) = 0; /** * Returns true if the node is running (have access to an open socket). @@ -213,6 +221,7 @@ class OPENDHT_PUBLIC DhtInterface { * Set the in-memory storage limit in bytes */ virtual void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) = 0; + virtual size_t getStorageLimit() const = 0; /** * Returns the total memory usage of stored values and the number @@ -264,6 +273,7 @@ class OPENDHT_PUBLIC DhtInterface { protected: std::shared_ptr logger_ {}; + std::queue> onConnectCallbacks_ {}; }; } // namespace dht diff --git a/include/opendht/dht_proxy_client.h b/include/opendht/dht_proxy_client.h index 848ea0af6..3c011b43d 100644 --- a/include/opendht/dht_proxy_client.h +++ b/include/opendht/dht_proxy_client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -85,7 +85,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { /** * Performs final operations before quitting. */ - void shutdown(ShutdownCallback cb) override; + void shutdown(ShutdownCallback cb, bool) override; /** * Returns true if the node is running (have access to an open socket). @@ -107,13 +107,13 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { */ virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override; virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override { - get(key, cb, bindDoneCb(donecb), std::forward(f), std::forward(w)); + get(key, cb, bindDoneCb(std::move(donecb)), std::forward(f), std::forward(w)); } virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override { - get(key, bindGetCb(cb), donecb, std::forward(f), std::forward(w)); + get(key, bindGetCb(cb), std::move(donecb), std::forward(f), std::forward(w)); } virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override { - get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward(f), std::forward(w)); + get(key, bindGetCb(cb), bindDoneCb(std::move(donecb)), std::forward(f), std::forward(w)); } /** @@ -134,7 +134,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, v, bindDoneCb(cb), created, permanent); + put(key, v, bindDoneCb(std::move(cb)), created, permanent); } void put(const InfoHash& key, @@ -143,7 +143,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, std::make_shared(std::move(v)), cb, created, permanent); + put(key, std::make_shared(std::move(v)), std::move(cb), created, permanent); } void put(const InfoHash& key, Value&& v, @@ -151,7 +151,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, std::forward(v), bindDoneCb(cb), created, permanent); + put(key, std::forward(v), bindDoneCb(std::move(cb)), created, permanent); } /** @@ -176,14 +176,14 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override; virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override { - return listen(key, [cb](const std::vector>& vals, bool expired){ + return listen(key, [cb=std::move(cb)](const std::vector>& vals, bool expired){ if (not expired) return cb(vals); return true; }, std::forward(f), std::forward(w)); } virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override { - return listen(key, bindGetCb(cb), std::forward(f), std::forward(w)); + return listen(key, bindGetCb(std::move(cb)), std::forward(f), std::forward(w)); } /* * This function relies on the cache implementation. @@ -214,7 +214,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { */ virtual void query(const InfoHash& /*key*/, QueryCallback /*cb*/, DoneCallback /*done_cb*/ = {}, Query&& /*q*/ = {}) override { } virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override { - query(key, cb, bindDoneCb(done_cb), std::forward(q)); + query(key, cb, bindDoneCb(std::move(done_cb)), std::forward(q)); } /** @@ -263,6 +263,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { void dumpTables() const override {} std::vector getNodeMessageStats(bool) override { return {}; } void setStorageLimit(size_t) override {} + virtual size_t getStorageLimit() const { return 0; } void connectivityChanged(sa_family_t) override { getProxyInfos(); } @@ -337,6 +338,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { NodeStats stats6_ {}; SockAddr publicAddressV4_; SockAddr publicAddressV6_; + std::atomic_bool launchConnectedCbs_ {false}; InfoHash myid {}; @@ -378,8 +380,8 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { * Retrieve if we can connect to the proxy (update statusIpvX_) */ void handleProxyConfirm(const asio::error_code &ec); - Sp nextProxyConfirmationTimer_; - Sp listenerRestartTimer_; + std::unique_ptr nextProxyConfirmationTimer_; + std::unique_ptr listenerRestartTimer_; /** * Relaunch LISTEN requests if the client disconnect/reconnect. diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index 5dcc4193c..e1facd70a 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -445,7 +445,6 @@ class OPENDHT_PUBLIC DhtProxyServer std::map> listeners; MSGPACK_DEFINE_ARRAY(listeners) }; - std::mutex lockPushListeners_; std::map pushListeners_; proxy::ListenToken tokenPushNotif_ {0}; #endif //OPENDHT_PUSH_NOTIFICATIONS diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index 41fbd9802..11e3810e7 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -65,6 +65,7 @@ class OPENDHT_PUBLIC DhtRunner { bool peer_publish {false}; std::shared_ptr server_ca; dht::crypto::Identity client_identity; + SockAddr bind4 {}, bind6 {}; }; struct Context { @@ -73,6 +74,7 @@ class OPENDHT_PUBLIC DhtRunner { std::shared_ptr peerDiscovery {}; StatusCallback statusChangedCallback {}; CertificateStoreQuery certificateStore {}; + IdentityAnnouncedCb identityAnnouncedCb {}; Context() {} }; @@ -97,7 +99,7 @@ class OPENDHT_PUBLIC DhtRunner { template void get(InfoHash hash, std::function&&)> cb, DoneCallbackSimple dcb={}) { - get(hash, [=](const std::vector>& vals) { + get(hash, [cb=std::move(cb)](const std::vector>& vals) { return cb(unpackVector(vals)); }, dcb, @@ -106,7 +108,7 @@ class OPENDHT_PUBLIC DhtRunner { template void get(InfoHash hash, std::function cb, DoneCallbackSimple dcb={}) { - get(hash, [=](const std::vector>& vals) { + get(hash, [cb=std::move(cb)](const std::vector>& vals) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v))) @@ -155,7 +157,7 @@ class OPENDHT_PUBLIC DhtRunner { std::future listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {}); std::future listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) { - return listen(key, [cb](const std::vector>& vals, bool expired){ + return listen(key, [cb=std::move(cb)](const std::vector>& vals, bool expired){ if (not expired) return cb(vals); return true; @@ -169,7 +171,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function&&)> cb) { - return listen(hash, [=](const std::vector>& vals) { + return listen(hash, [cb=std::move(cb)](const std::vector>& vals) { return cb(unpackVector(vals)); }, getFilterSet()); @@ -177,7 +179,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function&&, bool)> cb) { - return listen(hash, [=](const std::vector>& vals, bool expired) { + return listen(hash, [cb=std::move(cb)](const std::vector>& vals, bool expired) { return cb(unpackVector(vals), expired); }, getFilterSet()); @@ -186,7 +188,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function cb, Value::Filter f = {}, Where w = {}) { - return listen(hash, [=](const std::vector>& vals) { + return listen(hash, [cb=std::move(cb)](const std::vector>& vals) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v))) @@ -202,7 +204,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function cb, Value::Filter f = {}, Where w = {}) { - return listen(hash, [=](const std::vector>& vals, bool expired) { + return listen(hash, [cb=std::move(cb)](const std::vector>& vals, bool expired) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v), expired)) @@ -255,18 +257,29 @@ class OPENDHT_PUBLIC DhtRunner { } void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false); + void putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallback cb={}, bool permanent = false); + void putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallbackSimple cb, bool permanent = false) { + putEncrypted(hash, to, value, bindDoneCb(cb), permanent); + } + + void putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallback cb={}, bool permanent = false); + void putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallbackSimple cb, bool permanent = false) { + putEncrypted(hash, to, std::forward(value), bindDoneCb(cb), permanent); + } + + /** * Insert known nodes to the routing table, without necessarly ping them. * Usefull to restart a node and get things running fast without putting load on the network. */ - void bootstrap(std::vector nodes, DoneCallbackSimple&& cb={}); - void bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb={}); + void bootstrap(std::vector nodes, DoneCallbackSimple cb={}); + void bootstrap(SockAddr addr, DoneCallbackSimple cb={}); /** * Insert known nodes to the routing table, without necessarly ping them. * Usefull to restart a node and get things running fast without putting load on the network. */ - void bootstrap(const std::vector& nodes); + void bootstrap(std::vector nodes); /** * Add host:service to bootstrap nodes, and ping this node. @@ -301,6 +314,7 @@ class OPENDHT_PUBLIC DhtRunner { * Get the public key fingerprint if an identity is used with this node, 0 otherwise. */ InfoHash getId() const; + std::shared_ptr getPublicKey() const; /** * Get the ID of the DHT node. @@ -321,6 +335,7 @@ class OPENDHT_PUBLIC DhtRunner { std::pair getStoreSize() const; + void getStorageLimit() const; void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT); std::vector exportNodes() const; @@ -359,6 +374,7 @@ class OPENDHT_PUBLIC DhtRunner { std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const; std::vector getPublicAddress(sa_family_t af = AF_UNSPEC); std::vector getPublicAddressStr(sa_family_t af = AF_UNSPEC); + void getPublicAddress(std::function&&)>, sa_family_t af = AF_UNSPEC); // securedht methods @@ -379,22 +395,12 @@ class OPENDHT_PUBLIC DhtRunner { config.threaded = threaded; run(port, config); } - void run(in_port_t port, const Config& config, Context&& context = {}); - - /** - * @param local4: Local IPv4 address and port to bind. Can be null. - * @param local6: Local IPv6 address and port to bind. Can be null. - * You should allways bind to a global IPv6 address. - * @param identity: RSA key pair to use for cryptographic operations. - * @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched. - * @param cb: Optional callback to receive general state information. - */ - void run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context = {}); + void run(in_port_t port, Config& config, Context&& context = {}); /** * Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port). */ - void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {}); + void run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context = {}); void run(const Config& config, Context&& context); @@ -415,7 +421,7 @@ class OPENDHT_PUBLIC DhtRunner { /** * Gracefuly disconnect from network. */ - void shutdown(ShutdownCallback cb = {}); + void shutdown(ShutdownCallback cb = {}, bool stop = false); /** * Quit and wait for all threads to terminate. @@ -451,8 +457,6 @@ class OPENDHT_PUBLIC DhtRunner { void forwardAllMessages(bool forward); private: - static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10}; - enum class State { Idle, Running, @@ -481,6 +485,7 @@ class OPENDHT_PUBLIC DhtRunner { /** Current configuration */ Config config_; + IdentityAnnouncedCb identityAnnouncedCb_; /** * reset dht clients diff --git a/include/opendht/http.h b/include/opendht/http.h index 76ba5f0e5..baeeed2e9 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Vsevolod Ivanov * * This program is free software; you can redistribute it and/or modify @@ -375,15 +375,3 @@ class OPENDHT_PUBLIC Request : public std::enable_shared_from_this } // namespace http } // namespace dht -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK -namespace restinio -{ -/* Custom HTTP-methods for RESTinio > 0.5.0. - * https://github.com/Stiffstream/restinio/issues/26 - */ -constexpr const restinio::http_method_id_t method_listen {HTTP_LISTEN, "LISTEN"}; -constexpr const restinio::http_method_id_t method_stats {HTTP_STATS, "STATS"}; -constexpr const restinio::http_method_id_t method_sign {HTTP_SIGN, "SIGN"}; -constexpr const restinio::http_method_id_t method_encrypt {HTTP_ENCRYPT, "ENCRYPT"}; -} // namespace restinio -#endif diff --git a/include/opendht/indexation/pht.h b/include/opendht/indexation/pht.h index 6113a1780..ae5d2bb41 100644 --- a/include/opendht/indexation/pht.h +++ b/include/opendht/indexation/pht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * Nicolas Reynaud @@ -335,7 +335,7 @@ class OPENDHT_PUBLIC Pht { void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true); void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true) { - lookup(k, [=](std::vector>& values, Prefix) { cb(values); }, done_cb, exact_match); + lookup(k, [cb=std::move(cb)](std::vector>& values, Prefix) { cb(values); }, done_cb, exact_match); } /** diff --git a/include/opendht/infohash.h b/include/opendht/infohash.h index cf774cd61..414c528b8 100644 --- a/include/opendht/infohash.h +++ b/include/opendht/infohash.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -40,10 +40,12 @@ typedef uint16_t in_port_t; #include #include #include +#include #include #include #include #include +#include namespace dht { @@ -54,9 +56,9 @@ namespace crypto { } /** - * Represents an InfoHash. - * An InfoHash is a byte array of HASH_LEN bytes. - * InfoHashes identify nodes and values in the Dht. + * Represents an Hash, + * a byte array of N bytes. + * Hashes identify nodes and values in the Dht. */ template class OPENDHT_PUBLIC Hash { @@ -65,10 +67,10 @@ class OPENDHT_PUBLIC Hash { typedef typename T::iterator iterator; typedef typename T::const_iterator const_iterator; - Hash () noexcept { + Hash() noexcept { data_.fill(0); } - Hash (const uint8_t* h, size_t data_len) { + Hash(const uint8_t* h, size_t data_len) { if (data_len < N) data_.fill(0); else @@ -79,7 +81,12 @@ class OPENDHT_PUBLIC Hash { * hex must be at least 2.HASH_LEN characters long. * If too long, only the first 2.HASH_LEN characters are read. */ - explicit Hash(const std::string& hex); + explicit Hash(std::string_view hex) { + if (hex.size() < 2*N) + data_.fill(0); + else + fromString(hex.data()); + } Hash(const msgpack::object& o) { msgpack_unpack(o); @@ -93,6 +100,8 @@ class OPENDHT_PUBLIC Hash { iterator end() { return data_.end(); } const_iterator cend() const { return data_.cend(); } + static constexpr inline Hash zero() noexcept { return Hash{}; } + bool operator==(const Hash& h) const { auto a = reinterpret_cast(data_.data()); auto b = reinterpret_cast(h.data_.data()); @@ -112,6 +121,14 @@ class OPENDHT_PUBLIC Hash { return false; } + Hash operator^(const Hash& o) const { + Hash result; + for(auto i = 0u; i < N; i++) { + result[i] = data_[i] ^ o.data_[i]; + } + return result; + } + explicit operator bool() const { auto a = reinterpret_cast(data_.data()); auto b = reinterpret_cast(data_.data() + N); @@ -142,10 +159,6 @@ class OPENDHT_PUBLIC Hash { return 8 * i + j; } - /** - * Forget about the ``XOR-metric''. An id is just a path from the - * root of the tree, so bits are numbered from the start. - */ static inline int cmp(const Hash& id1, const Hash& id2) { return std::memcmp(id1.data_.data(), id2.data_.data(), N); } @@ -179,16 +192,12 @@ class OPENDHT_PUBLIC Hash { int xorCmp(const Hash& id1, const Hash& id2) const { - for(unsigned i = 0; i < N; i++) { - uint8_t xor1, xor2; + for (unsigned i = 0; i < N; i++) { if(id1.data_[i] == id2.data_[i]) continue; - xor1 = id1.data_[i] ^ data_[i]; - xor2 = id2.data_[i] ^ data_[i]; - if(xor1 < xor2) - return -1; - else - return 1; + uint8_t xor1 = id1.data_[i] ^ data_[i]; + uint8_t xor2 = id2.data_[i] ^ data_[i]; + return (xor1 < xor2) ? -1 : 1; } return 0; } @@ -217,7 +226,7 @@ class OPENDHT_PUBLIC Hash { return v; } - static inline Hash get(const std::string& data) { + static inline Hash get(std::string_view data) { return get((const uint8_t*)data.data(), data.size()); } @@ -289,14 +298,6 @@ std::istream& operator>> (std::istream& s, Hash& h) return s; } -template -Hash::Hash(const std::string& hex) { - if (hex.size() < 2*N) - data_.fill(0); - else - fromString(hex.c_str()); -} - template void Hash::fromString(const char* in) { @@ -340,7 +341,7 @@ Hash::getRandom(Rd& rdev) return h; } -struct HexMap : public std::array, 256> { +struct alignas(std::max_align_t) HexMap : public std::array, 256> { HexMap() { for (size_t i=0; i const char* Hash::to_c_str() const { - thread_local std::array buf; + alignas(std::max_align_t) thread_local std::array buf; for (size_t i=0; i::toString() const return std::string(to_c_str(), N*2); } -const InfoHash zeroes {}; - struct OPENDHT_PUBLIC NodeExport { InfoHash id; sockaddr_storage ss; diff --git a/include/opendht/log.h b/include/opendht/log.h index f5af1bce9..7369d6d52 100644 --- a/include/opendht/log.h +++ b/include/opendht/log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/include/opendht/log_enable.h b/include/opendht/log_enable.h index 3811e1410..d60c947c5 100644 --- a/include/opendht/log_enable.h +++ b/include/opendht/log_enable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index 3523125f5..4204060b7 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -214,7 +214,6 @@ class NetworkEngine final using RequestErrorCb = std::function; using RequestExpiredCb = std::function; - NetworkEngine(const Sp& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr&& sock); NetworkEngine( InfoHash& myid, NetworkConfig config, @@ -253,12 +252,12 @@ class NetworkEngine final * @param values The values to send. * @param version If version = 1, a request will be used to answer to the listener */ - void tellListener(Sp n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, + void tellListener(const Sp& n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, std::vector>&& nodes, std::vector>&& nodes6, std::vector>&& values, const Query& q, int version); - void tellListenerRefreshed(Sp n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); - void tellListenerExpired(Sp n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); + void tellListenerRefreshed(const Sp& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); + void tellListenerExpired(const Sp& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); bool isRunning(sa_family_t af) const; inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; } @@ -279,7 +278,7 @@ class NetworkEngine final * @return the request with information concerning its success. */ Sp - sendPing(Sp n, RequestCb&& on_done, RequestExpiredCb&& on_expired); + sendPing(const Sp& n, RequestCb&& on_done, RequestExpiredCb&& on_expired); /** * Send a "ping" request to a given node. @@ -293,7 +292,7 @@ class NetworkEngine final */ Sp sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) { - return sendPing(std::make_shared(zeroes, std::move(sa), rd), + return sendPing(std::make_shared(InfoHash::zero(), std::move(sa), rd), std::forward(on_done), std::forward(on_expired)); } @@ -310,7 +309,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendFindNode(Sp n, + Sp sendFindNode(const Sp& n, const InfoHash& hash, want_t want = -1, RequestCb&& on_done = {}, @@ -329,7 +328,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendGetValues(Sp n, + Sp sendGetValues(const Sp& n, const InfoHash& hash, const Query& query, want_t want, @@ -358,7 +357,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendListen(Sp n, + Sp sendListen(const Sp& n, const InfoHash& hash, const Query& query, const Blob& token, @@ -378,7 +377,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendAnnounceValue(Sp n, + Sp sendAnnounceValue(const Sp& n, const InfoHash& hash, const Sp& v, time_point created, @@ -398,7 +397,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendRefreshValue(Sp n, + Sp sendRefreshValue(const Sp& n, const InfoHash& hash, const Value::Id& vid, const Blob& token, @@ -417,7 +416,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendUpdateValues(Sp n, + Sp sendUpdateValues(const Sp& n, const InfoHash& infohash, const std::vector>& values, time_point created, diff --git a/include/opendht/network_utils.h b/include/opendht/network_utils.h index 4559ea303..238b876f1 100644 --- a/include/opendht/network_utils.h +++ b/include/opendht/network_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -42,7 +42,7 @@ namespace dht { namespace net { static const constexpr in_port_t DHT_DEFAULT_PORT = 4222; -static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16; +static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 64; static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650); int bindSocket(const SockAddr& addr, SockAddr& bound); diff --git a/include/opendht/node.h b/include/opendht/node.h index 47c443b3c..615089eb0 100644 --- a/include/opendht/node.h +++ b/include/opendht/node.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * diff --git a/include/opendht/node_cache.h b/include/opendht/node_cache.h index 19a8d3b1c..06897a362 100644 --- a/include/opendht/node_cache.h +++ b/include/opendht/node_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/peer_discovery.h b/include/opendht/peer_discovery.h index 2eedbb273..610e444f4 100644 --- a/include/opendht/peer_discovery.h +++ b/include/opendht/peer_discovery.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Mingrui Zhang * Vsevolod Ivanov * diff --git a/include/opendht/proxy.h b/include/opendht/proxy.h index 2cc292a50..c8ad58cf6 100644 --- a/include/opendht/proxy.h +++ b/include/opendht/proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/rate_limiter.h b/include/opendht/rate_limiter.h index ec71d6439..7ab315215 100644 --- a/include/opendht/rate_limiter.h +++ b/include/opendht/rate_limiter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/rng.h b/include/opendht/rng.h index c1419b766..579e44382 100644 --- a/include/opendht/rng.h +++ b/include/opendht/rng.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/routing_table.h b/include/opendht/routing_table.h index 234488d56..d488cb9c2 100644 --- a/include/opendht/routing_table.h +++ b/include/opendht/routing_table.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * diff --git a/include/opendht/scheduler.h b/include/opendht/scheduler.h index 01cee921a..2b3b83350 100644 --- a/include/opendht/scheduler.h +++ b/include/opendht/scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -36,8 +36,9 @@ namespace dht { class Scheduler { public: struct Job { - Job(std::function&& f) : do_(std::move(f)) {} + Job(std::function&& f, time_point t) : do_(std::move(f)), t_(t) {} std::function do_; + const time_point t_; void cancel() { do_ = {}; } }; @@ -50,17 +51,12 @@ class Scheduler { * @return pointer to the newly scheduled job. */ Sp add(time_point t, std::function&& job_func) { - auto job = std::make_shared(std::move(job_func)); + auto job = std::make_shared(std::move(job_func), t); if (t != time_point::max()) timers.emplace(std::move(t), job); return job; } - void add(const Sp& job, time_point t) { - if (t != time_point::max()) - timers.emplace(std::move(t), job); - } - /** * Reschedules a job. * @@ -68,16 +64,29 @@ class Scheduler { * @param t The time at which the job shall be rescheduled. */ void edit(Sp& job, time_point t) { - if (not job) { + if (not job) return; - } // std::function move doesn't garantee to leave the object empty. // Force clearing old value. auto task = std::move(job->do_); - job->do_ = {}; + cancel(job); job = add(t, std::move(task)); } + bool cancel(Sp& job) { + if (job) { + job->cancel(); + for (auto r = timers.equal_range(job->t_); r.first != r.second; ++r.first) { + if (r.first->second == job) { + timers.erase(r.first); + job.reset(); + return true; + } + } + } + return false; + } + /** * Runs the jobs to do up to now. * diff --git a/include/opendht/securedht.h b/include/opendht/securedht.h index 9f6ff4a2d..f73e5a1d1 100644 --- a/include/opendht/securedht.h +++ b/include/opendht/securedht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -45,15 +45,13 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { return c; } - SecureDht() {} - /** * s, s6: bound socket descriptors for IPv4 and IPv6, respectively. * For the Dht to be initialised, at least one of them must be >= 0. * id: the identity to use for the crypto layer and to compute * our own hash on the Dht. */ - SecureDht(std::unique_ptr dht, Config config); + SecureDht(std::unique_ptr dht, Config config, IdentityAnnouncedCb iacb = {}, const std::shared_ptr& l = {}); virtual ~SecureDht(); @@ -63,6 +61,9 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { PkId getLongId() const { return key_ ? key_->getPublicKey().getLongId() : PkId(); } + Sp getPublicKey() const { + return key_ ? key_->getSharedPublicKey() : Sp{}; + } ValueType secureType(ValueType&& type); @@ -117,6 +118,10 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) { putEncrypted(hash, to, std::make_shared(std::move(v)), callback, permanent); } + void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Sp val, DoneCallback callback, bool permanent = false); + void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Value&& v, DoneCallback callback, bool permanent = false) { + putEncrypted(hash, to, std::make_shared(std::move(v)), callback, permanent); + } /** * Take ownership of the value and sign it using our private key. @@ -128,13 +133,13 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { Value decrypt(const Value& v); void findCertificate(const InfoHash& node, const std::function)>& cb); - void findPublicKey(const InfoHash& node, const std::function)>& cb); + void findPublicKey(const InfoHash& node, const std::function)>& cb); - const Sp registerCertificate(const InfoHash& node, const Blob& cert); + Sp registerCertificate(const InfoHash& node, const Blob& cert); void registerCertificate(Sp& cert); - const Sp getCertificate(const InfoHash& node) const; - const Sp getPublicKey(const InfoHash& node) const; + Sp getCertificate(const InfoHash& node) const; + Sp getPublicKey(const InfoHash& node) const; /** * Allows to set a custom callback called by the library to find a locally-stored certificate. @@ -148,8 +153,8 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { /** * SecureDht to Dht proxy */ - void shutdown(ShutdownCallback cb) override { - dht_->shutdown(cb); + void shutdown(ShutdownCallback cb, bool stop = false) override { + dht_->shutdown(cb, stop); } void dumpTables() const override { dht_->dumpTables(); @@ -168,6 +173,10 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override { dht_->setStorageLimit(limit); } + size_t getStorageLimit() const override { + return dht_->getStorageLimit(); + } + std::vector exportNodes() const override { return dht_->exportNodes(); } @@ -356,7 +365,7 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { // our certificate cache std::map> nodesCertificates_ {}; - std::map> nodesPubKeys_ {}; + std::map> nodesPubKeys_ {}; std::atomic_bool forward_all_ {false}; bool enableCache_ {false}; diff --git a/include/opendht/sockaddr.h b/include/opendht/sockaddr.h index 790204dec..2e3229bcd 100644 --- a/include/opendht/sockaddr.h +++ b/include/opendht/sockaddr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -68,7 +68,7 @@ class OPENDHT_PUBLIC SockAddr { * Build from existing address. */ SockAddr(const sockaddr* sa, socklen_t length) { - if (length > sizeof(sockaddr_storage)) + if (length > static_cast(sizeof(sockaddr_storage))) throw std::runtime_error("Socket address length is too large"); set(sa, length); } @@ -144,7 +144,7 @@ class OPENDHT_PUBLIC SockAddr { if (len) addr.reset((sockaddr*)::calloc(len, 1)); else addr.reset(); } - if (len > sizeof(sa_family_t)) + if (len) addr->sa_family = af; } @@ -223,16 +223,16 @@ class OPENDHT_PUBLIC SockAddr { */ sockaddr* get() { return addr.get(); } - const sockaddr_in& getIPv4() const { + inline const sockaddr_in& getIPv4() const { return *reinterpret_cast(get()); } - const sockaddr_in6& getIPv6() const { + inline const sockaddr_in6& getIPv6() const { return *reinterpret_cast(get()); } - sockaddr_in& getIPv4() { + inline sockaddr_in& getIPv4() { return *reinterpret_cast(get()); } - sockaddr_in6& getIPv6() { + inline sockaddr_in6& getIPv6() { return *reinterpret_cast(get()); } diff --git a/include/opendht/thread_pool.h b/include/opendht/thread_pool.h index d7a2995c7..24ad91dd6 100644 --- a/include/opendht/thread_pool.h +++ b/include/opendht/thread_pool.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -27,6 +27,8 @@ #include #include +#include // fix windows compiler bug + namespace dht { class OPENDHT_PUBLIC ThreadPool { @@ -63,15 +65,14 @@ class OPENDHT_PUBLIC ThreadPool { void join(); private: - struct ThreadState; - std::queue> tasks_ {}; - std::vector> threads_; - unsigned readyThreads_ {0}; std::mutex lock_ {}; std::condition_variable cv_ {}; + std::queue> tasks_ {}; + std::vector> threads_; + unsigned readyThreads_ {0}; + bool running_ {true}; const unsigned maxThreads_; - bool running_ {true}; }; class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this { @@ -93,4 +94,71 @@ class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this { void schedule(); }; +class OPENDHT_PUBLIC ExecutionContext { +public: + ExecutionContext(ThreadPool& pool) + : threadPool_(pool), state_(std::make_shared()) + {} + + ~ExecutionContext() { + state_->destroy(); + } + + /** Wait for ongoing tasks to complete execution and drop other pending tasks */ + void stop() { + state_->destroy(false); + } + + void run(std::function&& task) { + std::lock_guard lock(state_->mtx); + if (state_->shutdown_) return; + state_->pendingTasks++; + threadPool_.get().run([task = std::move(task), state = state_] { + state->run(task); + }); + } + +private: + struct SharedState { + std::mutex mtx {}; + std::condition_variable cv {}; + unsigned pendingTasks {0}; + unsigned ongoingTasks {0}; + /** When true, prevents new tasks to be scheduled */ + bool shutdown_ {false}; + /** When true, prevents scheduled tasks to be executed */ + std::atomic_bool destroyed {false}; + + void destroy(bool wait = true) { + std::unique_lock lock(mtx); + if (destroyed) return; + if (wait) { + cv.wait(lock, [this] { return pendingTasks == 0 && ongoingTasks == 0; }); + } + shutdown_ = true; + if (not wait) { + cv.wait(lock, [this] { return ongoingTasks == 0; }); + } + destroyed = true; + } + + void run(const std::function& task) { + { + std::lock_guard lock(mtx); + pendingTasks--; + ongoingTasks++; + } + if (destroyed) return; + task(); + { + std::lock_guard lock(mtx); + ongoingTasks--; + cv.notify_all(); + } + } + }; + std::reference_wrapper threadPool_; + std::shared_ptr state_; +}; + } diff --git a/include/opendht/utils.h b/include/opendht/utils.h index 93b6e8d98..691e936e5 100644 --- a/include/opendht/utils.h +++ b/include/opendht/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -178,8 +178,8 @@ msgpack::object* findMapValue(const msgpack::object& map, const char* key, size_ inline msgpack::object* findMapValue(const msgpack::object& map, const char* key) { return findMapValue(map, key, strlen(key)); } -inline msgpack::object* findMapValue(const msgpack::object& map, const std::string& key) { - return findMapValue(map, key.c_str(), key.size()); +inline msgpack::object* findMapValue(const msgpack::object& map, std::string_view key) { + return findMapValue(map, key.data(), key.size()); } } // namespace dht diff --git a/include/opendht/value.h b/include/opendht/value.h index 198d5f621..2298a57f6 100644 --- a/include/opendht/value.h +++ b/include/opendht/value.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -42,8 +43,9 @@ #endif namespace dht { +using namespace std::literals; -static const std::string VALUE_KEY_ID("id"); +static constexpr auto VALUE_KEY_ID("id"); static const std::string VALUE_KEY_DAT("dat"); static const std::string VALUE_KEY_PRIO("p"); static const std::string VALUE_KEY_SIGNATURE("sig"); @@ -117,7 +119,7 @@ struct OPENDHT_PUBLIC ValueType { Id id {0}; std::string name {}; - duration expiration {60 * 10}; + duration expiration {std::chrono::minutes(10)}; StorePolicy storePolicy {DEFAULT_STORE_POLICY}; EditPolicy editPolicy {DEFAULT_EDIT_POLICY}; }; @@ -205,7 +207,7 @@ struct OPENDHT_PUBLIC Value } static Filter chainOr(Filter&& f1, Filter&& f2) { if (not f1 or not f2) return {}; - return [f1,f2](const Value& v) { + return [f1=std::move(f1),f2=std::move(f2)](const Value& v) { return f1(v) or f2(v); }; } @@ -231,8 +233,7 @@ struct OPENDHT_PUBLIC Value } static Filter TypeFilter(const ValueType& t) { - const auto tid = t.id; - return [tid](const Value& v) { + return [tid = t.id](const Value& v) { return v.type == tid; }; } @@ -270,8 +271,8 @@ struct OPENDHT_PUBLIC Value }; } - static Filter UserTypeFilter(const std::string& ut) { - return [ut](const Value& v) { + static Filter UserTypeFilter(std::string ut) { + return [ut = std::move(ut)](const Value& v) { return v.user_type == ut; }; } @@ -357,7 +358,7 @@ struct OPENDHT_PUBLIC Value void sign(const crypto::PrivateKey& key) { if (isEncrypted()) throw DhtException("Can't sign encrypted data."); - owner = std::make_shared(key.getPublicKey()); + owner = key.getSharedPublicKey(); signature = key.sign(getToSign()); } @@ -369,8 +370,8 @@ struct OPENDHT_PUBLIC Value return isSigned() and owner->checkSignature(getToSign(), signature); } - std::shared_ptr getOwner() const { - return std::static_pointer_cast(owner); + std::shared_ptr getOwner() const { + return std::static_pointer_cast(owner); } /** @@ -595,7 +596,7 @@ struct OPENDHT_PUBLIC Value /** * Public key of the signer. */ - std::shared_ptr owner {}; + std::shared_ptr owner {}; /** * Hash of the recipient (optional). @@ -660,7 +661,7 @@ struct OPENDHT_PUBLIC FieldValue FieldValue() {} FieldValue(Value::Field f, uint64_t int_value) : field(f), intValue(int_value) {} FieldValue(Value::Field f, InfoHash hash_value) : field(f), hashValue(hash_value) {} - FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(blob_value) {} + FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(std::move(blob_value)) {} bool operator==(const FieldValue& fd) const; @@ -673,9 +674,9 @@ struct OPENDHT_PUBLIC FieldValue template void msgpack_pack(Packer& p) const { p.pack_map(2); - p.pack(std::string("f")); p.pack(static_cast(field)); + p.pack("f"sv); p.pack(static_cast(field)); - p.pack(std::string("v")); + p.pack("v"sv); switch (field) { case Value::Field::Id: case Value::Field::ValueType: @@ -697,12 +698,12 @@ struct OPENDHT_PUBLIC FieldValue hashValue = {}; blobValue.clear(); - if (auto f = findMapValue(msg, "f")) + if (auto f = findMapValue(msg, "f"sv)) field = (Value::Field)f->as(); else throw msgpack::type_error(); - auto v = findMapValue(msg, "v"); + auto v = findMapValue(msg, "v"sv); if (not v) throw msgpack::type_error(); else @@ -742,7 +743,7 @@ struct OPENDHT_PUBLIC FieldValue struct OPENDHT_PUBLIC Select { Select() { } - Select(const std::string& q_str); + Select(std::string_view q_str); bool isSatisfiedBy(const Select& os) const; @@ -797,7 +798,7 @@ struct OPENDHT_PUBLIC Select struct OPENDHT_PUBLIC Where { Where() { } - Where(const std::string& q_str); + Where(std::string_view q_str); bool isSatisfiedBy(const Where& where) const; @@ -864,7 +865,7 @@ struct OPENDHT_PUBLIC Where * * @return the resulting Where instance. */ - Where& userType(std::string user_type) { + Where& userType(std::string_view user_type) { FieldValue fv {Value::Field::UserType, Blob {user_type.begin(), user_type.end()}}; if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end()) filters_.emplace_back(std::move(fv)); @@ -937,11 +938,11 @@ struct OPENDHT_PUBLIC Query * - $string$: a simple string WITHOUT SPACES. * - $integer$: a simple integer. */ - Query(std::string q_str) { + Query(std::string_view q_str) { auto pos_W = q_str.find("WHERE"); auto pos_w = q_str.find("where"); - auto pos = std::min(pos_W != std::string::npos ? pos_W : q_str.size(), - pos_w != std::string::npos ? pos_w : q_str.size()); + auto pos = std::min(pos_W != std::string_view::npos ? pos_W : q_str.size(), + pos_w != std::string_view::npos ? pos_w : q_str.size()); select = q_str.substr(0, pos); where = q_str.substr(pos, q_str.size()-pos); } diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 43087b2e6..51a35054d 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -10,13 +10,13 @@ # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). +# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for +# the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. +# preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -35,13 +35,15 @@ # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# Copyright (c) 2021 Jörn Heusipp # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 11 +#serial 14 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -50,6 +52,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [$1], [20], [ax_cxx_compile_alternatives="20"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], @@ -62,6 +65,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) + m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do @@ -140,7 +153,6 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) - dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], @@ -148,12 +160,24 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) +dnl Test body for checking C++17 support + m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 +) + + dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ @@ -949,3 +973,33 @@ namespace cxx17 #endif // __cplusplus < 201703L ]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L + +]]) diff --git a/python/opendht.pyx b/python/opendht.pyx index c888c0fc1..454deffe7 100644 --- a/python/opendht.pyx +++ b/python/opendht.pyx @@ -1,11 +1,11 @@ # distutils: language = c++ -# distutils: extra_compile_args = -std=c++14 +# distutils: extra_compile_args = -std=c++17 # distutils: include_dirs = ../../include # distutils: library_dirs = ../../src # distutils: libraries = opendht gnutls # cython: language_level=3 # -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author(s): Guillaume Roguez # Adrien Béraud # Simon Désaulniers @@ -36,6 +36,7 @@ from libcpp.memory cimport shared_ptr from cython.parallel import parallel, prange from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec from cpython cimport ref +from datetime import timedelta cimport opendht_cpp as cpp @@ -235,8 +236,9 @@ cdef class Where(object): cdef class Value(object): cdef shared_ptr[cpp.Value] _value - def __init__(self, bytes val=b''): - self._value.reset(new cpp.Value(val, len(val))) + def __init__(self, bytes val=b'', cpp.uint16_t id=0): + self._value.reset(new cpp.Value(id, val, len(val))) + def __str__(self): return self._value.get().toString().decode() property owner: @@ -270,6 +272,14 @@ cdef class Value(object): def __get__(self): return self._value.get().size() +cdef class ValueType(object): + cdef cpp.ValueType * _value + def __init__(self, cpp.uint16_t id, str name, expiration: timedelta): + if not isinstance(expiration, timedelta): + raise TypeError("expiration argument must be of type timedelta") + cdef cpp.seconds duration = cpp.seconds(int(expiration.total_seconds())) + self._value = new cpp.ValueType(id, name.encode(), duration) + cdef class NodeSetIter(object): cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter @@ -319,11 +329,11 @@ cdef class PrivateKey(_WithID): cdef shared_ptr[cpp.PrivateKey] _key def getId(self): h = InfoHash() - h._infohash = self._key.get().getPublicKey().getId() + h._infohash = self._key.get().getSharedPublicKey().get().getId() return h def getPublicKey(self): pk = PublicKey() - pk._key = self._key.get().getPublicKey() + pk._key = self._key.get().getSharedPublicKey() return pk def decrypt(self, bytes dat): cdef size_t d_len = len(dat) @@ -348,17 +358,17 @@ cdef class PrivateKey(_WithID): return k cdef class PublicKey(_WithID): - cdef cpp.PublicKey _key + cdef cpp.shared_ptr[cpp.PublicKey] _key def getId(self): h = InfoHash() - h._infohash = self._key.getId() + h._infohash = self._key.get().getId() return h def encrypt(self, bytes dat): cdef size_t d_len = len(dat) cdef cpp.uint8_t* d_ptr = dat cdef cpp.Blob indat indat.assign(d_ptr, (d_ptr + d_len)) - cdef cpp.Blob encrypted = self._key.encrypt(indat) + cdef cpp.Blob encrypted = self._key.get().encrypt(indat) cdef char* encrypted_c_str = encrypted.data() cdef Py_ssize_t length = encrypted.size() return encrypted_c_str[:length] @@ -430,7 +440,7 @@ cdef class Identity(object): property publickey: def __get__(self): k = PublicKey() - k._key = self._id.first.get().getPublicKey() + k._key = self._id.first.get().getSharedPublicKey() return k property certificate: def __get__(self): @@ -513,6 +523,8 @@ cdef class DhtRunner(_WithID): cb_obj = {'shutdown':shutdown_cb} ref.Py_INCREF(cb_obj) self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, cb_obj)) + def registerType(self, ValueType type): + self.thisptr.get().registerType(deref(type._value)) def enableLogging(self): cpp.enableLogging(self.thisptr.get()[0]) def disableLogging(self): diff --git a/python/opendht_cpp.pxd b/python/opendht_cpp.pxd index 1bc866a0f..98961e7c4 100644 --- a/python/opendht_cpp.pxd +++ b/python/opendht_cpp.pxd @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # @@ -26,6 +26,14 @@ from libc.string cimport const_char, const_uchar ctypedef uint16_t in_port_t ctypedef unsigned short int sa_family_t; +cdef extern from "" namespace "std::chrono" nogil: + cdef cppclass duration[ulong]: + duration() except + + + cdef cppclass seconds: + duration seconds(uint64_t) except + + duration seconds() + cdef extern from "" namespace "std" nogil: cdef cppclass shared_ptr[T]: shared_ptr() except + @@ -89,7 +97,7 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto": cdef cppclass PrivateKey: PrivateKey() - PublicKey getPublicKey() const + shared_ptr[PublicKey] getSharedPublicKey() const Blob decrypt(Blob data) const @staticmethod PrivateKey generate() @@ -131,7 +139,6 @@ cdef extern from "opendht/value.h" namespace "dht::Value": cdef extern from "opendht/value.h" namespace "dht::Value::Field": cdef Field None cdef Field Id - cdef Field ValueType cdef Field OwnerPk cdef Field SeqNum cdef Field UserType @@ -141,7 +148,7 @@ cdef extern from "opendht/value.h" namespace "dht": cdef cppclass Value: Value() except + Value(vector[uint8_t]) except + - Value(const uint8_t* dat_ptr, size_t dat_len) except + + Value(const uint16_t t, const uint8_t* dat_ptr, size_t dat_len) except + string toString() const size_t size() const uint64_t id @@ -150,6 +157,12 @@ cdef extern from "opendht/value.h" namespace "dht": vector[uint8_t] data string user_type + cdef cppclass ValueType: + ValueType(uint16_t id, string name, seconds expiration) except + + uint16_t id + string name + seconds expiration + cdef cppclass Query: Query() except + Query(Select s, Where w) except + @@ -234,6 +247,7 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht": void run(const_char*, const_char*, const_char*, Config config) void join() void shutdown(ShutdownCallback) + void registerType(ValueType& value); bool isRunning() SockAddr getBound(sa_family_t af) const string getStorageLog() const diff --git a/python/setup.py.in b/python/setup.py.in index e72f80be8..168b126ec 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -1,4 +1,4 @@ -# Copyright (C) 2014-2020 Savoir-faire Linux Inc. +# Copyright (C) 2014-2022 Savoir-faire Linux Inc. # Author: Guillaume Roguez # Author: Adrien Béraud # @@ -50,8 +50,8 @@ setup(name="opendht", ["@CURRENT_SOURCE_DIR@/opendht.pyx"], include_dirs = ['@PROJECT_SOURCE_DIR@/include'], language="c++", - extra_compile_args=["-std=c++14"], - extra_link_args=["-std=c++14"], + extra_compile_args=["-std=c++17"], + extra_link_args=["-std=c++17"], libraries=["opendht"], library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@'] )) diff --git a/python/tools/benchmark.py b/python/tools/benchmark.py index b90b4d23d..5856a25a8 100755 --- a/python/tools/benchmark.py +++ b/python/tools/benchmark.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (C) 2014-2020 Savoir-faire Linux Inc. +# Copyright (C) 2014-2022 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # diff --git a/python/tools/dht/network.py b/python/tools/dht/network.py index 6a84d839b..a012c1999 100755 --- a/python/tools/dht/network.py +++ b/python/tools/dht/network.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # diff --git a/python/tools/dht/tests.py b/python/tools/dht/tests.py index 18daa0387..6c1e0cb0b 100644 --- a/python/tools/dht/tests.py +++ b/python/tools/dht/tests.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2015-2019 Savoir-Faire Linux Inc. +# Copyright (C) 2015-2022 Savoir-Faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers diff --git a/python/tools/dht/virtual_network_builder.py b/python/tools/dht/virtual_network_builder.py index 1757770d6..8484dcb5b 100755 --- a/python/tools/dht/virtual_network_builder.py +++ b/python/tools/dht/virtual_network_builder.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/dhtcluster.py b/python/tools/dhtcluster.py index cc3121a49..bb0427654 100755 --- a/python/tools/dhtcluster.py +++ b/python/tools/dhtcluster.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (C) 2014-2020 Savoir-faire Linux Inc. +# Copyright (C) 2014-2022 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/http_server.py b/python/tools/http_server.py index d2da4c0e9..db9d357e9 100755 --- a/python/tools/http_server.py +++ b/python/tools/http_server.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2019 Savoir-faire Linux Inc. +# Copyright (c) 2016-2022 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/network_monitor.py b/python/tools/network_monitor.py index 074bee228..185415d1b 100755 --- a/python/tools/network_monitor.py +++ b/python/tools/network_monitor.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/pingpong.py b/python/tools/pingpong.py index 14c903296..ef0d54aa0 100755 --- a/python/tools/pingpong.py +++ b/python/tools/pingpong.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/scanner.py b/python/tools/scanner.py index 17d9e7cc2..558a46372 100755 --- a/python/tools/scanner.py +++ b/python/tools/scanner.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2019 Savoir-faire Linux Inc. +# Copyright (c) 2015-2022 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/rust/examples/dhtnode.rs b/rust/examples/dhtnode.rs index c491b87f2..d9a96bcf3 100644 --- a/rust/examples/dhtnode.rs +++ b/rust/examples/dhtnode.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/blob.rs b/rust/src/blob.rs index ff2743be9..491cbfa18 100644 --- a/rust/src/blob.rs +++ b/rust/src/blob.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/crypto.rs b/rust/src/crypto.rs index afb6751c6..1d123cdd1 100644 --- a/rust/src/crypto.rs +++ b/rust/src/crypto.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/dhtrunner.rs b/rust/src/dhtrunner.rs index 12d31fe6a..114614d1e 100644 --- a/rust/src/dhtrunner.rs +++ b/rust/src/dhtrunner.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index c2c36f2ec..7470cc26b 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/infohash.rs b/rust/src/infohash.rs index 059128f95..e66c7fa03 100644 --- a/rust/src/infohash.rs +++ b/rust/src/infohash.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/lib.rs b/rust/src/lib.rs index b9040dee7..72d9ac5c5 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/pkid.rs b/rust/src/pkid.rs index 1ce604e21..0c8fe8a31 100644 --- a/rust/src/pkid.rs +++ b/rust/src/pkid.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/value.rs b/rust/src/value.rs index 9276a8ed8..016e5d252 100644 --- a/rust/src/value.rs +++ b/rust/src/value.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/src/Makefile.am b/src/Makefile.am index b41ec421b..2820655ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@ libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@ -libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@ +libopendht_la_LDFLAGS = @LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@ libopendht_la_SOURCES = \ dht.cpp \ storage.h \ @@ -87,30 +87,3 @@ endif clean-local: rm -rf libargon2.la - -###################### -# ARGON2 submodule # -###################### - -if WITH_INCLUDED_ARGON2 -noinst_LTLIBRARIES = libargon2.la -libopendht_la_DEPENDENCIES = libargon2.la - -libargon2_la_CFLAGS = -std=c89 -fPIC -pthread -O3 -Wall -I@top_builddir@/argon2/include -I@top_builddir@/argon2/src -libargon2_la_SOURCES = \ - @top_builddir@/argon2/src/argon2.c \ - @top_builddir@/argon2/src/core.c \ - @top_builddir@/argon2/src/blake2/blake2b.c \ - @top_builddir@/argon2/src/thread.c \ - @top_builddir@/argon2/src/ref.c \ - @top_builddir@/argon2/src/encoding.c - -noinst_HEADERS = \ - @top_builddir@/argon2/include/argon2.h \ - @top_builddir@/argon2/src/blake2/blake2.h \ - @top_builddir@/argon2/src/blake2/blake2-impl.h \ - @top_builddir@/argon2/src/blake2/blamka-round-ref.h \ - @top_builddir@/argon2/src/core.h \ - @top_builddir@/argon2/src/encoding.h \ - @top_builddir@/argon2/src/thread.h -endif diff --git a/src/base64.cpp b/src/base64.cpp index d2406d7c6..faeea68df 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 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 diff --git a/src/base64.h b/src/base64.h index ecd7fd380..a01fa6b5c 100644 --- a/src/base64.h +++ b/src/base64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 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 diff --git a/src/callbacks.cpp b/src/callbacks.cpp index c1e3e1459..ecda4057a 100644 --- a/src/callbacks.cpp +++ b/src/callbacks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ namespace dht { GetCallbackSimple -bindGetCb(const GetCallbackRaw& raw_cb, void* user_data) +bindGetCb(GetCallbackRaw raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](const std::shared_ptr& value) { @@ -35,10 +35,10 @@ bindGetCb(const GetCallbackRaw& raw_cb, void* user_data) } GetCallback -bindGetCb(const GetCallbackSimple& cb) +bindGetCb(GetCallbackSimple cb) { if (not cb) return {}; - return [=](const std::vector>& values) { + return [cb=std::move(cb)](const std::vector>& values) { for (const auto& v : values) if (not cb(v)) return false; @@ -47,7 +47,7 @@ bindGetCb(const GetCallbackSimple& cb) } ValueCallback -bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data) +bindValueCb(ValueCallbackRaw raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](const std::vector>& values, bool expired) { @@ -59,7 +59,7 @@ bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data) } ShutdownCallback -bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data) +bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data) { return [=]() { shutdown_cb_raw(user_data); }; } @@ -69,11 +69,11 @@ bindDoneCb(DoneCallbackSimple donecb) { if (not donecb) return {}; using namespace std::placeholders; - return std::bind(donecb, _1); + return std::bind(std::move(donecb), _1); } DoneCallback -bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data) +bindDoneCb(DoneCallbackRaw raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](bool success, const std::vector>& nodes) { @@ -82,7 +82,7 @@ bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data) } DoneCallbackSimple -bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) { +bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](bool success) { raw_cb(success, user_data); diff --git a/src/compat/msvc/unistd.h b/src/compat/msvc/unistd.h index c164e762a..3146f42af 100644 --- a/src/compat/msvc/unistd.h +++ b/src/compat/msvc/unistd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Andreas Traczyk * diff --git a/src/compat/os_cert.cpp b/src/compat/os_cert.cpp index 9dd9611c4..ea89f12a7 100644 --- a/src/compat/os_cert.cpp +++ b/src/compat/os_cert.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Andreas Traczyk * * This program is free software; you can redistribute it and/or modify @@ -189,19 +189,15 @@ void PEMCache::fillX509Store(SSL_CTX* ctx) { if (logger) - logger->w("adding %d decoded certs to X509 store", pems_.size()); - X509_STORE* store = SSL_CTX_get_cert_store(ctx); - if (store == nullptr) { - if (logger) - logger->e("couldn't get the context cert store"); - return; - } - for (const auto& pem : pems_) { - if (X509_STORE_add_cert(store, pem.get()) == 1) - continue; - if (logger) - logger->d("couldn't add local certificate"); - } + logger->d("adding %d decoded certs to X509 store", pems_.size()); + if (X509_STORE* store = SSL_CTX_get_cert_store(ctx)) { + for (const auto& pem : pems_) { + if (X509_STORE_add_cert(store, pem.get()) != 1) + if (logger) + logger->w("couldn't add local certificate"); + } + } else if (logger) + logger->e("couldn't get the context cert store"); } } /*namespace http*/ diff --git a/src/compat/os_cert.h b/src/compat/os_cert.h index b037037d8..f20bd7292 100644 --- a/src/compat/os_cert.h +++ b/src/compat/os_cert.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Andreas Traczyk * * This program is free software; you can redistribute it and/or modify diff --git a/src/crypto.cpp b/src/crypto.cpp index 9c2800f75..9eb80f6e4 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * Vsevolod Ivanov * @@ -54,7 +54,7 @@ static std::uniform_int_distribution rand_byte; #define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256 #endif -#define DHT_AES_LEGACY_ENCRYPT 1 +#define DHT_AES_LEGACY_ENCRYPT 0 #define DHT_AES_LEGACY_DECRYPT 1 namespace dht { @@ -69,7 +69,7 @@ constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) { GNUTLS_DIG_SHA1)); } -constexpr size_t gnutlsHashSize(int algo) { +constexpr size_t gnutlsHashSize(gnutls_digest_algorithm_t algo) { return (algo == GNUTLS_DIG_SHA512) ? 512/8 : ( (algo == GNUTLS_DIG_SHA256) ? 256/8 : ( (algo == GNUTLS_DIG_SHA1) ? 160/8 : 0 )); @@ -128,37 +128,37 @@ Blob aesEncrypt(const Blob& data, const std::string& password) return encrypted; } -Blob aesDecrypt(const Blob& data, const Blob& key) +Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key) { if (not aesKeySizeGood(key.size())) throw DecryptError("Wrong key size"); - if (data.size() <= GCM_IV_SIZE + GCM_DIGEST_SIZE) + if (data_length <= GCM_IV_SIZE + GCM_DIGEST_SIZE) throw DecryptError("Wrong data size"); std::array digest; struct gcm_aes_ctx aes; gcm_aes_set_key(&aes, key.size(), key.data()); - gcm_aes_set_iv(&aes, GCM_IV_SIZE, data.data()); + gcm_aes_set_iv(&aes, GCM_IV_SIZE, data); - size_t data_sz = data.size() - GCM_IV_SIZE - GCM_DIGEST_SIZE; + size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE; Blob ret(data_sz); - gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE); + 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.end() - GCM_DIGEST_SIZE)) { + 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.data() + GCM_IV_SIZE); + //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.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.end() - GCM_DIGEST_SIZE)) + 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"); @@ -168,14 +168,13 @@ Blob aesDecrypt(const Blob& data, const Blob& key) return ret; } -Blob aesDecrypt(const Blob& data, const std::string& password) +Blob aesDecrypt(const uint8_t* data, size_t data_len, const std::string& password) { - if (data.size() <= PASSWORD_SALT_LENGTH) + if (data_len <= PASSWORD_SALT_LENGTH) throw DecryptError("Wrong data size"); - Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH}; + Blob salt {data, data+PASSWORD_SALT_LENGTH}; Blob key = stretchKey(password, salt, 256/8); - Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()}; - return aesDecrypt(encrypted, key); + return aesDecrypt(data+PASSWORD_SALT_LENGTH, data_len - PASSWORD_SALT_LENGTH, key); } Blob stretchKey(const std::string& password, Blob& salt, size_t key_length) @@ -292,14 +291,14 @@ PrivateKey::operator=(PrivateKey&& o) noexcept } Blob -PrivateKey::sign(const Blob& data) const +PrivateKey::sign(const uint8_t* data, size_t data_length) const { if (!key) throw CryptoException("Can't sign data: no private key set !"); - if (std::numeric_limits::max() < data.size()) + if (std::numeric_limits::max() < data_length) throw CryptoException("Can't sign data: too large !"); gnutls_datum_t sig; - const gnutls_datum_t dat {(unsigned char*)data.data(), (unsigned)data.size()}; + 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 !"); Blob ret(sig.data, sig.data+sig.size); @@ -321,7 +320,7 @@ PrivateKey::decryptBloc(const uint8_t* src, size_t src_size) const } Blob -PrivateKey::decrypt(const Blob& cipher) const +PrivateKey::decrypt(const uint8_t* cypher, size_t cypher_len) const { if (!key) throw CryptoException("Can't decrypt data without private key !"); @@ -334,12 +333,12 @@ PrivateKey::decrypt(const Blob& cipher) const throw CryptoException("Must be an RSA key"); unsigned cypher_block_sz = key_len / 8; - if (cipher.size() < cypher_block_sz) + if (cypher_len < cypher_block_sz) throw DecryptError("Unexpected cipher length"); - else if (cipher.size() == cypher_block_sz) - return decryptBloc(cipher.data(), cypher_block_sz); + else if (cypher_len == cypher_block_sz) + return decryptBloc(cypher, cypher_block_sz); - return aesDecrypt(Blob {cipher.begin() + cypher_block_sz, cipher.end()}, decryptBloc(cipher.data(), cypher_block_sz)); + return aesDecrypt(cypher + cypher_block_sz, cypher_len - cypher_block_sz, decryptBloc(cypher, cypher_block_sz)); } Blob @@ -369,13 +368,22 @@ PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password : gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len); } -PublicKey +const PublicKey& PrivateKey::getPublicKey() const { - PublicKey pk; - if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0)) + return *getSharedPublicKey(); +} + +const std::shared_ptr& +PrivateKey::getSharedPublicKey() const +{ + if (publicKey_) + return publicKey_; + auto pk = std::make_shared(); + if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0)) throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err)); - return pk; + publicKey_ = pk; + return publicKey_; } PublicKey::PublicKey() @@ -541,12 +549,7 @@ PublicKey::getId() const return {}; InfoHash id; size_t sz = id.size(); -#if GNUTLS_VERSION_NUMBER < 0x030401 - const int flags = 0; -#else - const int flags = (id.size() == 32) ? GNUTLS_KEYID_USE_SHA256 : 0; -#endif - if (auto err = gnutls_pubkey_get_key_id(pk, flags, id.data(), &sz)) + if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz)) throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get public key ID: wrong output length."); @@ -711,13 +714,13 @@ CertificateRequest::sign(const PrivateKey& key, const std::string& password) } bool -CertificateRequest::verify() const +CertificateRequest::verify() const { return gnutls_x509_crq_verify(request, 0) >= 0; } -Blob -CertificateRequest::pack() const +Blob +CertificateRequest::pack() const { gnutls_datum_t dat {nullptr, 0}; if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat)) @@ -728,7 +731,7 @@ CertificateRequest::pack() const } std::string -CertificateRequest::toString() const +CertificateRequest::toString() const { gnutls_datum_t dat {nullptr, 0}; if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat)) @@ -850,12 +853,15 @@ Certificate::getId() const { if (not cert) return {}; + if (cachedId_) + return cachedId_; InfoHash id; size_t sz = id.size(); if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz)) throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get certificate public key ID: wrong output length."); + cachedId_ = id; return id; } @@ -864,6 +870,8 @@ Certificate::getLongId() const { if (not cert) return {}; + if (cachedLongId_) + return cachedLongId_; #if GNUTLS_VERSION_NUMBER < 0x030401 throw CryptoException("Can't get certificate 256 bits public key ID: GnuTLS 3.4.1 or higher required."); #else @@ -873,6 +881,7 @@ Certificate::getLongId() const throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length."); + cachedLongId_ = id; return id; #endif } @@ -1048,6 +1057,8 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer) Blob noncebuf(32); gnutls_datum_t nonce = { noncebuf.data(), (unsigned)noncebuf.size() }; err = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size); + if (err < 0) + throw CryptoException(gnutls_strerror(err)); err = gnutls_ocsp_req_set_nonce(req.get(), 0, &nonce); if (err < 0) throw CryptoException(gnutls_strerror(err)); @@ -1148,20 +1159,20 @@ void setRandomSerial(gnutls_x509_crt_t cert) { random_device rdev; - std::uniform_int_distribution dist{}; - uint64_t cert_serial = dist(rdev); + std::uniform_int_distribution dist{1}; + int64_t cert_serial = dist(rdev); gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial)); } Certificate -Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca) +Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca, int64_t validity) { gnutls_x509_crt_t cert; if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) return {}; Certificate ret {cert}; - setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60); + setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity); if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) { throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err)); } @@ -1170,7 +1181,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden } // TODO: compute the subject key using the recommended RFC method - auto pk = key.getPublicKey(); + const auto& pk = key.getPublicKey(); auto pk_id = pk.getId(); const std::string uid_str = pk_id.toString(); @@ -1207,7 +1218,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden } Certificate -Certificate::generate(const CertificateRequest& request, const Identity& ca) +Certificate::generate(const CertificateRequest& request, const Identity& ca, int64_t validity) { gnutls_x509_crt_t cert; if (auto err = gnutls_x509_crt_init(&cert)) @@ -1220,7 +1231,7 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca) throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err)); } - setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60); + setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity); setRandomSerial(cert); if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) { @@ -1231,6 +1242,32 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca) return ret.getPacked(); } +void +Certificate::setValidity(const Identity& ca, int64_t validity) +{ + setValidityPeriod(cert, validity); + setRandomSerial(cert); + if (ca.first && ca.second) { + if (not ca.second->isCA()) { + throw CryptoException("Signing certificate must be CA"); + } + if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) { + throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err)); + } + } +} + +void +Certificate::setValidity(const PrivateKey& key, int64_t validity) +{ + setValidityPeriod(cert, validity); + setRandomSerial(cert); + const auto& pk = key.getPublicKey(); + 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)); + } +} + std::vector> Certificate::getRevocationLists() const { @@ -1241,6 +1278,70 @@ Certificate::getRevocationLists() const return ret; } +// OcspRequest + +OcspRequest::OcspRequest(const uint8_t* dat_ptr, size_t dat_size) +{ + int ret = gnutls_ocsp_req_init(&request); + if (ret < 0) + throw CryptoException(gnutls_strerror(ret)); + gnutls_datum_t dat = {(unsigned char*)dat_ptr,(unsigned int)dat_size}; + ret = gnutls_ocsp_req_import(request, &dat); + if (ret < 0){ + gnutls_ocsp_req_deinit(request); + throw CryptoException(gnutls_strerror(ret)); + } +} + +OcspRequest::~OcspRequest() +{ + if (request) { + gnutls_ocsp_req_deinit(request); + request = nullptr; + } +} + +std::string +OcspRequest::toString(const bool compact) const +{ + int ret; + gnutls_datum_t dat; + ret = gnutls_ocsp_req_print(request, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat); + + std::string str; + if (ret == 0) { + str = std::string((const char*)dat.data, (size_t)dat.size); + gnutls_free(dat.data); + } else + throw CryptoException(gnutls_strerror(ret)); + return str; +} + +Blob +OcspRequest::pack() const +{ + gnutls_datum_t dat; + int err = gnutls_ocsp_req_export(request, &dat); + if (err < 0) + throw CryptoException(gnutls_strerror(err)); + Blob ret {dat.data, dat.data + dat.size}; + gnutls_free(dat.data); + return ret; +} + +Blob +OcspRequest::getNonce() const +{ + gnutls_datum_t dat; + unsigned critical; + int err = gnutls_ocsp_req_get_nonce(request, &critical, &dat); + if (err < 0) + throw CryptoException(gnutls_strerror(err)); + Blob ret {dat.data, dat.data + dat.size}; + gnutls_free(dat.data); + return ret; +} + // OcspResponse OcspResponse::OcspResponse(const uint8_t* dat_ptr, size_t dat_size) @@ -1265,10 +1366,12 @@ Blob OcspResponse::pack() const { gnutls_datum_t dat; - int ret = gnutls_ocsp_resp_export(response, &dat); - if (ret < 0) - throw CryptoException(gnutls_strerror(ret)); - return {dat.data, dat.data + dat.size}; + int err = gnutls_ocsp_resp_export(response, &dat); + if (err < 0) + throw CryptoException(gnutls_strerror(err)); + Blob ret {dat.data, dat.data + dat.size}; + gnutls_free(dat.data); + return ret; } std::string @@ -1298,7 +1401,7 @@ OcspResponse::getCertificateStatus() const return (gnutls_ocsp_cert_status_t) status; } -gnutls_ocsp_verify_reason_t +gnutls_ocsp_cert_status_t OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce) { // Check OCSP response @@ -1309,39 +1412,52 @@ OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce) if (status != GNUTLS_OCSP_RESP_SUCCESSFUL) throw CryptoException("OCSP request unsuccessful: " + std::to_string(ret)); - // Check whether the OCSP response is about the provided certificate. - if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0) - throw CryptoException(gnutls_strerror(ret)); + if (not nonce.empty()) { + // Ensure no replay attack has been done + gnutls_datum_t rnonce; + ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce); + if (ret < 0) + throw CryptoException(gnutls_strerror(ret)); + if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){ + gnutls_free(rnonce.data); + throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); + } + gnutls_free(rnonce.data); + } // Verify signature of the Basic OCSP response against the public key in the issuer certificate. unsigned int verify = 0; ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert, &verify, 0); if (ret < 0) throw CryptoException(gnutls_strerror(ret)); + if (verify) { + if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) + throw CryptoException("Signer cert not found"); + if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) + throw CryptoException("Signer cert keyusage error"); + if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) + throw CryptoException("Signer cert is not trusted"); + if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) + throw CryptoException("Insecure algorithm"); + if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) + throw CryptoException("Signature failure"); + if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) + throw CryptoException("Signer cert not yet activated"); + if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) + throw CryptoException("Signer cert expired"); + throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); + } + + // Check whether the OCSP response is about the provided certificate. + if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0) + throw CryptoException(gnutls_strerror(ret)); // Check certificate revocation status unsigned status_ocsp; ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status_ocsp, NULL, NULL, NULL, NULL); if (ret < 0) throw CryptoException(gnutls_strerror(ret)); - gnutls_ocsp_cert_status_t certStatus = (gnutls_ocsp_cert_status_t)ret; - if (certStatus == GNUTLS_OCSP_CERT_REVOKED) - throw CryptoException("Certificate was revoked"); - else if (certStatus != GNUTLS_OCSP_CERT_GOOD) - throw CryptoException("Certificate is unknown"); - - // Ensure no replay attack has been done - gnutls_datum_t rnonce; - ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce); - if (ret < 0) - throw CryptoException(gnutls_strerror(ret)); - if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){ - gnutls_free(rnonce.data); - throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); - } - gnutls_free(rnonce.data); - - return (gnutls_ocsp_verify_reason_t) verify; + return (gnutls_ocsp_cert_status_t)status_ocsp; } // RevocationList @@ -1359,7 +1475,7 @@ RevocationList::RevocationList(const Blob& b) } catch (const std::exception& e) { gnutls_x509_crl_deinit(crl); crl = nullptr; - throw e; + throw; } } diff --git a/src/default_types.cpp b/src/default_types.cpp index 73ec669de..f5c3ae2ca 100644 --- a/src/default_types.cpp +++ b/src/default_types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/dht.cpp b/src/dht.cpp index ef1748060..946102c2a 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -30,16 +30,20 @@ #include #include +#include + namespace dht { using namespace std::placeholders; constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME; constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME; +constexpr std::chrono::seconds Dht::BOOTSTRAP_PERIOD; constexpr duration Dht::LISTEN_EXPIRE_TIME; constexpr duration Dht::LISTEN_EXPIRE_TIME_PUBLIC; constexpr duration Dht::REANNOUNCE_MARGIN; static constexpr size_t MAX_REQUESTS_PER_SEC {8 * 1024}; +static constexpr duration BOOTSTRAP_PERIOD_MAX {std::chrono::hours(24)}; NodeStatus Dht::updateStatus(sa_family_t af) @@ -49,15 +53,10 @@ Dht::updateStatus(sa_family_t af) d.status = d.getStatus(scheduler.time()); if (d.status != old) { auto& other = dht(af == AF_INET ? AF_INET6 : AF_INET); - if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) + if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) { onDisconnected(); - else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) { - // On connected - if (bootstrapJob) { - bootstrapJob->cancel(); - bootstrapJob.reset(); - } - bootstrap_period = std::chrono::seconds(10); + } else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) { + onConnected(); } } return d.status; @@ -82,11 +81,27 @@ Dht::Kad::getStatus(time_point now) const } void -Dht::shutdown(ShutdownCallback cb) +Dht::shutdown(ShutdownCallback cb, bool stop) { if (not persistPath.empty()) saveState(persistPath); + if (stop) { + for (auto dht : {&dht4, &dht6}) { + for (auto& sr : dht->searches) { + for (const auto& r : sr.second->callbacks) + r.second.done_cb(false, {}); + sr.second->callbacks.clear(); + for (const auto& a : sr.second->announce) { + if (a.callback) a.callback(false, {}); + } + sr.second->announce.clear(); + sr.second->listeners.clear(); + } + } + network_engine.clear(); + } + if (not maintain_storage) { if (cb) cb(); return; @@ -273,7 +288,7 @@ Dht::searchNodeGetDone(const net::Request& req, if (srn->syncJob) scheduler.edit(srn->syncJob, syncTime); else - srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, sr)); + srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, ws)); } onGetValuesDone(req.node, answer, sr, query); } @@ -475,25 +490,27 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { } catch (std::out_of_range&) { } auto next_refresh_time = now + getType(a.value->type).expiration; + auto& acked = sn->acked[a.value->id]; + scheduler.cancel(acked.refresh); /* 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: %d)", + 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; - sn->acked[a.value->id] = { + acked = { network_engine.sendAnnounceValue(sn->node, sr->id, a.value, created, sn->token, onDone, onExpired), next_refresh_time }; } else if (hasValue and a.permanent) { if (logger_) - logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %d)", + 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); - sn->acked[a.value->id] = { + acked = { network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone, - [this, ws, node=sn->node, v=a.value, - onDone, - onExpired, + [this, ws, node=sn->node, v=a.value, + onDone, + onExpired, created = a.permanent ? time_point::max() : a.created, next_refresh_time ](const net::Request& /*req*/, net::DhtProtocolException&& e){ @@ -517,21 +534,17 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { }; } else { if (logger_) - logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %d). 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::State::COMPLETED); ack_req->reply_time = now; - sn->acked[a.value->id] = std::make_pair(std::move(ack_req), next_refresh_time); + acked = {std::move(ack_req), next_refresh_time}; /* step to clear announces */ scheduler.edit(sr->nextSearchStep, now); } if (a.permanent) { - scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, [this,ws] { - if (auto sr = ws.lock()) { - searchStep(sr); - } - }); + acked.refresh = scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, std::bind(&Dht::searchStep, this, ws)); } } }; @@ -556,7 +569,7 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { sendQuery = true; } else { if (logger_) - logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %d)", + 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), @@ -591,7 +604,7 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) std::weak_ptr ws = sr; for (const auto& l : sr->listeners) { const auto& query = l.second.query; - + auto r = n.listenStatus.find(query); if (n.getListenTime(r, listenExp) > scheduler.time()) continue; @@ -629,8 +642,8 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) if (auto sr = ws.lock()) { scheduler.edit(sr->nextSearchStep, scheduler.time()); if (auto sn = sr->getNode(req.node)) { - scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, sr)); - sn->onListenSynced(query); + auto job = scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, ws)); + sn->onListenSynced(query, true, std::move(job)); } onListenDone(req.node, answer, sr); } @@ -656,8 +669,9 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) /* When a search is in progress, we periodically call search_step to send further requests. */ void -Dht::searchStep(Sp sr) +Dht::searchStep(std::weak_ptr ws) { + auto sr = ws.lock(); if (not sr or sr->expired or sr->done) return; const auto& now = scheduler.time(); @@ -725,7 +739,7 @@ Dht::searchStep(Sp sr) while (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES and searchSendGetValues(sr)); - + if (sr->getNumberOfConsecutiveBadNodes() >= std::min(sr->nodes.size(), SEARCH_MAX_BAD_NODES)) { if (logger_) @@ -810,7 +824,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q sr->expired = false; sr->nodes.clear(); sr->nodes.reserve(SEARCH_NODES+1); - sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, sr)); + sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr(sr))); if (logger_) logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6'); if (search_id == 0) @@ -862,6 +876,11 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte size_t Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where) { + if (not id) { + if (logger_) + logger_->w(id, "Listen called with invalid key"); + return 0; + } scheduler.syncTime(); auto token = ++listener_token; @@ -944,7 +963,9 @@ struct GetStatus : public OpStatus { void Dht::put(const InfoHash& id, Sp val, DoneCallback callback, time_point created, bool permanent) { - if (not val) { + if (not id or not val) { + if (logger_) + logger_->w(id, "Put called with invalid key or value"); if (callback) callback(false, {}); return; @@ -1014,6 +1035,13 @@ bool callbackWrapper(Cb get_cb, DoneCallback done_cb, const std::vector>& void Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filter&& filter, Where&& where) { + if (not id) { + if (logger_) + logger_->w(id, "Get called with invalid key"); + if (donecb) + donecb(false, {}); + return; + } scheduler.syncTime(); auto op = std::make_shared>>>(); @@ -1054,6 +1082,13 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Query&& q) { + if (not id) { + if (logger_) + logger_->w(id, "Query called with invalid key"); + if (done_cb) + done_cb(false, {}); + return; + } scheduler.syncTime(); auto op = std::make_shared>>>(); auto f = q.where.getFilter(); @@ -1159,15 +1194,20 @@ Dht::cancelPut(const InfoHash& id, const Value::Id& vid) }; canceled |= sr_cancel_put(dht4.searches); canceled |= sr_cancel_put(dht6.searches); - if (canceled) - storageErase(id, vid); + if (canceled) { + auto st = store.find(id); + if (st != store.end()) { + if (auto value = st->second.remove(id, vid)) + storageRemoved(id, st->second, {value}, value->size()); + } + } return canceled; } // Storage void -Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newValue) +Dht::storageChanged(const InfoHash& id, Storage& st, const Sp& v, bool newValue) { if (newValue) { if (not st.local_listeners.empty()) { @@ -1177,8 +1217,8 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newVa cbs.reserve(st.local_listeners.size()); for (const auto& l : st.local_listeners) { std::vector> vals; - if (not l.second.filter or l.second.filter(*v.data)) - vals.push_back(v.data); + if (not l.second.filter or l.second.filter(*v)) + vals.push_back(v); if (not vals.empty()) { if (logger_) logger_->d(id, "[store %s] sending update local listener with token %lu", @@ -1199,14 +1239,14 @@ Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newVa for (const auto& node_listeners : st.listeners) { for (const auto& l : node_listeners.second) { auto f = l.second.query.where.getFilter(); - if (f and not f(*v.data)) + if (f and not f(*v)) continue; if (logger_) logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update", id.toString().c_str(), node_listeners.first->toString().c_str()); std::vector> vals {}; - vals.push_back(v.data); + vals.push_back(v); Blob ntoken = makeToken(node_listeners.first->getAddr(), false); network_engine.tellListener(node_listeners.first, l.first, id, 0, ntoken, {}, {}, std::move(vals), l.second.query, l.second.version); @@ -1242,30 +1282,23 @@ Dht::storageStore(const InfoHash& id, const Sp& value, time_point created if (auto vs = store.first) { total_store_size += store.second.size_diff; total_values += store.second.values_diff; + scheduler.cancel(vs->expiration_job); if (not permanent) { - scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); + vs->expiration_job = scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); } if (total_store_size > max_store_size) { + auto value = vs->data; + auto value_diff = store.second.values_diff; expireStore(); + storageChanged(id, st->second, value, value_diff > 0); + } else { + storageChanged(id, st->second, vs->data, store.second.values_diff > 0); } - storageChanged(id, st->second, *vs, store.second.values_diff > 0); } return std::get<0>(store); } -bool -Dht::storageErase(const InfoHash& id, Value::Id vid) -{ - auto st = store.find(id); - if (st == store.end()) - return false; - auto ret = st->second.remove(id, vid); - total_store_size += ret.size_diff; - total_values += ret.values_diff; - return ret.values_diff; -} - void Dht::storageAddListener(const InfoHash& id, const Sp& node, size_t socket_id, Query&& query, int version) { @@ -1297,36 +1330,8 @@ Dht::expireStore(decltype(store)::iterator i) const auto& id = i->first; auto& st = i->second; auto stats = st.expire(id, scheduler.time()); - total_store_size += stats.first; - total_values -= stats.second.size(); if (not stats.second.empty()) { - if (logger_) - logger_->d(id, "[store %s] discarded %ld expired values (%ld bytes)", - id.toString().c_str(), stats.second.size(), -stats.first); - - if (not st.listeners.empty()) { - if (logger_) - logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size()); - - std::vector ids; - ids.reserve(stats.second.size()); - for (const auto& v : stats.second) - ids.emplace_back(v->id); - - for (const auto& node_listeners : st.listeners) { - for (const auto& l : node_listeners.second) { - if (logger_) - logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired", - id.toString().c_str(), - node_listeners.first->toString().c_str()); - Blob ntoken = makeToken(node_listeners.first->getAddr(), false); - network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version); - } - } - } - for (const auto& local_listeners : st.local_listeners) { - local_listeners.second.get_cb(stats.second, true); - } + storageRemoved(id, st, stats.second, -stats.first); } } @@ -1338,6 +1343,41 @@ Dht::expireStorage(InfoHash h) expireStore(i); } +void +Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector>& values, size_t totalSize) +{ + if (logger_) + logger_->d(id, "[store %s] discarded %ld values (%ld bytes)", + id.toString().c_str(), values.size(), totalSize); + + total_store_size -= totalSize; + total_values -= values.size(); + + if (not st.listeners.empty()) { + if (logger_) + logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size()); + + std::vector ids; + ids.reserve(values.size()); + for (const auto& v : values) + ids.emplace_back(v->id); + + for (const auto& node_listeners : st.listeners) { + for (const auto& l : node_listeners.second) { + if (logger_) + logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired", + id.toString().c_str(), + node_listeners.first->toString().c_str()); + Blob ntoken = makeToken(node_listeners.first->getAddr(), false); + network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version); + } + } + } + for (const auto& local_listeners : st.local_listeners) { + local_listeners.second.get_cb(values, true); + } +} + void Dht::expireStore() { @@ -1363,23 +1403,23 @@ Dht::expireStore() break; } auto largest = store_quota.begin(); - for (auto it = ++largest; it != store_quota.end(); ++it) { + for (auto it = std::next(largest); it != store_quota.end(); ++it) { if (it->second.size() > largest->second.size()) largest = it; } - if (logger_) - logger_->w("No space left: discarding value of largest consumer %s", largest->first.toString().c_str()); - while (true) { - auto exp_value = largest->second.getOldest(); - auto storage = store.find(exp_value.first); - if (storage != store.end()) { - auto ret = storage->second.remove(exp_value.first, exp_value.second); - total_store_size += ret.size_diff; - total_values += ret.values_diff; - if (logger_) - logger_->w("Discarded %ld bytes, still %ld used", largest->first.toString().c_str(), total_store_size); - if (ret.values_diff) - break; + if (largest != store_quota.end()) { + while (true) { + auto exp_value = largest->second.getOldest(); + auto storage = store.find(exp_value.first); + if (storage != store.end()) { + if (logger_) + logger_->w("Storage quota full: discarding value from %s at %s %016" PRIx64, largest->first.toString().c_str(), exp_value.first.to_c_str(), exp_value.second); + + if (auto value = storage->second.remove(exp_value.first, exp_value.second)) { + storageRemoved(storage->first, storage->second, {value}, value->size()); + break; + } + } } } } @@ -1403,6 +1443,7 @@ Dht::connectivityChanged(sa_family_t 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 } void @@ -1584,10 +1625,10 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const out << "["; for (const auto& a : sr.announce) { auto ack = n.acked.find(a.value->id); - if (ack == n.acked.end() or not ack->second.first) { + if (ack == n.acked.end() or not ack->second.req) { out << ' '; } else { - out << ack->second.first->getStateChar(); + out << ack->second.req->getStateChar(); } } out << "] "; @@ -1627,7 +1668,7 @@ Dht::dumpTables() const std::string Dht::getStorageLog() const { - std::stringstream out; + std::ostringstream out; for (const auto& s : store) out << printStorageLog(s); out << std::endl << std::endl; @@ -1747,14 +1788,13 @@ fromDhtConfig(const Config& config) return netConf; } -Dht::Dht() : store(), network_engine(logger_, rd, scheduler, {}) {} - Dht::Dht(std::unique_ptr&& sock, const Config& config, const Sp& l) : DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom(rd)), store(), store_quota(), - max_store_keys(config.max_store_size ? (int)config.max_store_size : MAX_HASHES), + max_store_keys(config.max_store_keys ? (int)config.max_store_keys : MAX_HASHES), + max_store_size(config.max_store_size ? (int)config.max_store_size : DEFAULT_STORAGE_LIMIT), max_searches(config.max_searches ? (int)config.max_searches : MAX_SEARCHES), network_engine(myid, fromDhtConfig(config), std::move(sock), logger_, rd, scheduler, std::bind(&Dht::onError, this, _1, _2), @@ -1983,8 +2023,26 @@ Dht::expire() scheduler.add(expire_stuff_time, std::bind(&Dht::expire, this)); } +void +Dht::onConnected() +{ + stopBootstrap(); + auto callbacks = std::move(onConnectCallbacks_); + while (not callbacks.empty()) { + callbacks.front()(); + callbacks.pop(); + } +} + void Dht::onDisconnected() +{ + if (not bootstrapJob) + bootstrap(); +} + +void +Dht::bootstrap() { if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected) return; @@ -2003,10 +2061,23 @@ Dht::onDisconnected() logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what()); } } - if (bootstrapJob) - bootstrapJob->cancel(); - bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::onDisconnected, this)); - bootstrap_period *= 2; + scheduler.cancel(bootstrapJob); + bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::bootstrap, this)); + bootstrap_period = std::min(bootstrap_period * 2, BOOTSTRAP_PERIOD_MAX); +} + +void +Dht::startBootstrap() +{ + stopBootstrap(); + bootstrapJob = scheduler.add(scheduler.time(), std::bind(&Dht::bootstrap, this)); +} + +void +Dht::stopBootstrap() +{ + scheduler.cancel(bootstrapJob); + bootstrap_period = BOOTSTRAP_PERIOD; } void @@ -2123,25 +2194,25 @@ Dht::exportNodes() const if (b4 != dht4.buckets.end()) { for (auto& n : b4->nodes) if (n->isGood(now)) - nodes.push_back(n->exportNode()); + nodes.emplace_back(n->exportNode()); } const auto b6 = dht6.buckets.findBucket(myid); if (b6 != dht6.buckets.end()) { for (auto& n : b6->nodes) if (n->isGood(now)) - nodes.push_back(n->exportNode()); + nodes.emplace_back(n->exportNode()); } for (auto b = dht4.buckets.begin(); b != dht4.buckets.end(); ++b) { if (b == b4) continue; for (auto& n : b->nodes) if (n->isGood(now)) - nodes.push_back(n->exportNode()); + nodes.emplace_back(n->exportNode()); } for (auto b = dht6.buckets.begin(); b != dht6.buckets.end(); ++b) { if (b == b6) continue; for (auto& n : b->nodes) if (n->isGood(now)) - nodes.push_back(n->exportNode()); + nodes.emplace_back(n->exportNode()); } return nodes; } @@ -2414,7 +2485,7 @@ Dht::onAnnounce(Sp n, if (*lv == *vc) { storageRefresh(hash, v->id); if (logger_) - logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %s", hash.toString().c_str(), node.toString().c_str(), std::to_string(v->id).c_str()); + 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())) { @@ -2457,7 +2528,7 @@ Dht::onRefresh(Sp node, const InfoHash& hash, const Blob& token, const Val } if (storageRefresh(hash, vid)) { if (logger_) - logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %s", hash.toString().c_str(), node->toString().c_str(), std::to_string(vid).c_str()); + 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", @@ -2492,9 +2563,13 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid) } } - auto expiration = s->second.refresh(now, vid, types); - if (expiration != time_point::max()) - scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); + auto expiration = s->second.refresh(id, now, vid, types); + if (expiration.first) { + scheduler.cancel(expiration.first->expiration_job); + if (expiration.second != time_point::max()) { + expiration.first->expiration_job = scheduler.add(expiration.second, std::bind(&Dht::expireStorage, this, id)); + } + } return true; } return false; @@ -2528,7 +2603,7 @@ Dht::saveState(const std::string& path) const state.nodes = exportNodes(); state.values = exportValues(); std::ofstream file(path); - msgpack::pack(file, state); + msgpack::pack(file, state); } void diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp index e4fea2e8a..71d01aee3 100644 --- a/src/dht_proxy_client.cpp +++ b/src/dht_proxy_client.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -41,15 +41,15 @@ struct DhtProxyClient::OperationState { struct DhtProxyClient::Listener { Listener(OpValueCache&& c): - cache(std::move(c)) - {} + cache(std::move(c)) {} - unsigned callbackId; OpValueCache cache; CacheValueCallback cb; Sp opstate; std::shared_ptr request; +#ifdef OPENDHT_PUSH_NOTIFICATIONS std::unique_ptr refreshSubscriberTimer; +#endif }; struct PermanentPut { @@ -155,10 +155,10 @@ DhtProxyClient::startProxy() if (logger_) logger_->d("[proxy:client] start proxy with %s", proxyUrl_.c_str()); - nextProxyConfirmationTimer_ = std::make_shared(httpContext_, std::chrono::steady_clock::now()); + nextProxyConfirmationTimer_ = std::make_unique(httpContext_, std::chrono::steady_clock::now()); nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1)); - listenerRestartTimer_ = std::make_shared(httpContext_); + listenerRestartTimer_ = std::make_unique(httpContext_); loopSignal_(); } @@ -242,7 +242,7 @@ DhtProxyClient::cancelAllListeners() } void -DhtProxyClient::shutdown(ShutdownCallback cb) +DhtProxyClient::shutdown(ShutdownCallback cb, bool) { stop(); if (cb) @@ -720,9 +720,19 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa } auto newStatus = std::max(statusIpv4_, statusIpv6_); if (newStatus == NodeStatus::Connected) { - if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting) { + if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting || launchConnectedCbs_) { + launchConnectedCbs_ = false; listenerRestartTimer_->expires_at(std::chrono::steady_clock::now()); listenerRestartTimer_->async_wait(std::bind(&DhtProxyClient::restartListeners, this, std::placeholders::_1)); + if (not onConnectCallbacks_.empty()) { + std::lock_guard lock(lockCallbacks_); + callbacks_.emplace_back([cbs = std::move(onConnectCallbacks_)]() mutable { + while (not cbs.empty()) { + cbs.front()(); + cbs.pop(); + } + }); + } } nextProxyConfirmationTimer_->expires_at(std::chrono::steady_clock::now() + std::chrono::minutes(15)); nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1)); @@ -804,6 +814,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt } return false; }; +#ifdef OPENDHT_PUSH_NOTIFICATIONS if (not deviceKey_.empty()) { /* * Relaunch push listeners even if a timeout is not received @@ -816,17 +827,13 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt l->second.refreshSubscriberTimer->async_wait(std::bind(&DhtProxyClient::handleResubscribe, this, std::placeholders::_1, key, token, opstate)); } +#endif ListenMethod method; restinio::http_request_header_t header; if (deviceKey_.empty()){ // listen method = ListenMethod::LISTEN; -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - header.method(restinio::method_listen); - header.request_target("/" + key.toString()); -#else header.method(restinio::http_method_get()); header.request_target("/key/" + key.toString() + "/listen"); -#endif } else { method = ListenMethod::SUBSCRIBE; @@ -1142,13 +1149,8 @@ DhtProxyClient::restartListeners(const asio::error_code &ec) auto cb = listener.cb; // define header restinio::http_request_header_t header; -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - header.method(restinio::method_listen); - header.request_target("/" + search.first.toString()); -#else header.method(restinio::http_method_get()); header.request_target("/key/" + search.first.toString() + "/listen"); -#endif sendListen(header, cb, opstate, listener, ListenMethod::LISTEN); } } @@ -1161,6 +1163,9 @@ DhtProxyClient::pushNotificationReceived(const std::map l(lockCurrentProxyInfos_); + auto oldStatus = std::max(statusIpv4_, statusIpv6_); + if (oldStatus != NodeStatus::Connected) + launchConnectedCbs_ = true; statusIpv4_ = NodeStatus::Connected; statusIpv6_ = NodeStatus::Connected; } @@ -1226,7 +1231,7 @@ DhtProxyClient::pushNotificationReceived(const std::map lock(lockCallbacks_); + std::lock_guard lockCb(lockCallbacks_); callbacks_.emplace_back([this, key, token, opstate, ids, sendTime]() { if (opstate->stop) return; @@ -1266,11 +1271,7 @@ DhtProxyClient::resubscribe(const InfoHash& key, const size_t token, Listener& l logger_->d("[proxy:client] [resubscribe] [search %s]", key.to_c_str()); auto opstate = listener.opstate; - opstate->stop = true; - if (listener.request){ - listener.request.reset(); - } - opstate->stop = false; + listener.request.reset(); // This will update ok to false opstate->ok = true; restinio::http_request_header_t header; diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index d1f801cae..92c514856 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -38,26 +38,7 @@ using namespace std::placeholders; using namespace std::chrono_literals; - -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK -namespace restinio { -struct custom_http_methods_t -{ - static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept { - if(m == method_listen.raw_id()) - return method_listen; - else if(m == method_stats.raw_id()) - return method_stats; - else if(m == method_sign.raw_id()) - return method_sign; - else if(m == method_encrypt.raw_id()) - return method_encrypt; - else - return restinio::default_http_methods_t::from_nodejs(m); - } -}; -} -#endif +using namespace std::literals; namespace dht { constexpr char RESP_MSG_JSON_INCORRECT[] = "{\"err:\":\"Incorrect JSON\"}"; @@ -119,7 +100,7 @@ class DhtProxyServer::ConnectionListener { public: ConnectionListener() {}; - ConnectionListener(std::function onClosed) : onClosed_(std::move(onClosed)) {}; + explicit ConnectionListener(std::function onClosed) : onClosed_(std::move(onClosed)) {}; ~ConnectionListener() {}; /** @@ -156,9 +137,6 @@ DhtProxyServer::onConnectionClosed(restinio::connection_id_t id) struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits_t { using timer_manager_t = restinio::asio_timer_manager_t; -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - using http_methods_mapper_t = restinio::custom_http_methods_t; -#endif using logger_t = opendht_logger_t; using request_handler_t = RestRouter; using connection_state_listener_t = ConnectionListener; @@ -166,9 +144,6 @@ struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t { using timer_manager_t = restinio::asio_timer_manager_t; -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - using http_methods_mapper_t = restinio::custom_http_methods_t; -#endif using logger_t = opendht_logger_t; using request_handler_t = RestRouter; using connection_state_listener_t = ConnectionListener; @@ -177,25 +152,25 @@ struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t void DhtProxyServer::PermanentPut::msgpack_unpack(const msgpack::object& o) { - if (auto cid = findMapValue(o, "cid")) { + if (auto cid = findMapValue(o, "cid"sv)) { clientId = cid->as(); } - if (auto exp = findMapValue(o, "exp")) { + if (auto exp = findMapValue(o, "exp"sv)) { expiration = from_time_t(exp->as()); } - if (auto token = findMapValue(o, "token")) { + if (auto token = findMapValue(o, "token"sv)) { pushToken = token->as(); } - if (auto sid = findMapValue(o, "sid")) { + if (auto sid = findMapValue(o, "sid"sv)) { if (not sessionCtx) sessionCtx = std::make_shared(sid->as()); else sessionCtx->sessionId = sid->as(); } - if (auto t = findMapValue(o, "t")) { + if (auto t = findMapValue(o, "t"sv)) { type = t->as(); } - if (auto val = findMapValue(o, "value")) { + if (auto val = findMapValue(o, "value"sv)) { value = std::make_shared(*val); } } @@ -204,19 +179,19 @@ DhtProxyServer::PermanentPut::msgpack_unpack(const msgpack::object& o) void DhtProxyServer::Listener::msgpack_unpack(const msgpack::object& o) { - if (auto cid = findMapValue(o, "cid")) { + if (auto cid = findMapValue(o, "cid"sv)) { clientId = cid->as(); } - if (auto exp = findMapValue(o, "exp")) { + if (auto exp = findMapValue(o, "exp"sv)) { expiration = from_time_t(exp->as()); } - if (auto sid = findMapValue(o, "sid")) { + if (auto sid = findMapValue(o, "sid"sv)) { if (not sessionCtx) sessionCtx = std::make_shared(sid->as()); else sessionCtx->sessionId = sid->as(); } - if (auto t = findMapValue(o, "t")) { + if (auto t = findMapValue(o, "t"sv)) { type = t->as(); } } @@ -371,7 +346,7 @@ DhtProxyServer::loadState(Is& is, size_t size) { while (pac.next(oh)) { if (oh.get().type != msgpack::type::MAP) continue; - if (auto puts = findMapValue(oh.get(), "puts")) { + if (auto puts = findMapValue(oh.get(), "puts"sv)) { std::lock_guard lock(lockSearchPuts_); puts_ = puts->as(); if (logger_) @@ -408,9 +383,9 @@ DhtProxyServer::loadState(Is& is, size_t size) { logger_->d("No persistent puts in state"); } #ifdef OPENDHT_PUSH_NOTIFICATIONS - if (auto listeners = findMapValue(oh.get(), "pushListeners")) { + if (auto pushListeners = findMapValue(oh.get(), "pushListeners"sv)) { std::lock_guard lock(lockListener_); - pushListeners_ = listeners->as(); + pushListeners_ = pushListeners->as(); if (logger_) logger_->d("Loading %zu push listeners", pushListeners_.size()); for (auto& pushListener : pushListeners_) { @@ -613,11 +588,6 @@ DhtProxyServer::createRestRouter() // **************************** LEGACY ROUTES **************************** // node.info router->http_get("/", std::bind(&DhtProxyServer::getNodeInfo, this, _1, _2)); -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - // node.stats - router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_stats.raw_id()), - "/", std::bind(&DhtProxyServer::getStats, this, _1, _2)); -#endif // key.options router->add_handler(restinio::http_method_options(), "/:hash", std::bind(&DhtProxyServer::options, this, _1, _2)); @@ -625,11 +595,6 @@ DhtProxyServer::createRestRouter() router->http_get("/:hash", std::bind(&DhtProxyServer::get, this, _1, _2)); // key.post router->http_post("/:hash", std::bind(&DhtProxyServer::put, this, _1, _2)); -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - // key.listen - router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_listen.raw_id()), - "/:hash", std::bind(&DhtProxyServer::listen, this, _1, _2)); -#endif #ifdef OPENDHT_PUSH_NOTIFICATIONS // key.subscribe router->add_handler(restinio::http_method_subscribe(), @@ -639,14 +604,6 @@ DhtProxyServer::createRestRouter() "/:hash", std::bind(&DhtProxyServer::unsubscribe, this, _1, _2)); #endif //OPENDHT_PUSH_NOTIFICATIONS #ifdef OPENDHT_PROXY_SERVER_IDENTITY -#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK - // key.sign - router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_sign.raw_id()), - "/:hash", std::bind(&DhtProxyServer::putSigned, this, _1, _2)); - // key.encrypt - router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_encrypt.raw_id()), - "/:hash", std::bind(&DhtProxyServer::putEncrypted, this, _1, _2)); -#endif #endif // OPENDHT_PROXY_SERVER_IDENTITY // **************************** NEW ROUTES **************************** @@ -727,9 +684,9 @@ DhtProxyServer::get(restinio::request_handle_t request, { requestNum_++; try { - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); auto response = std::make_shared( initHttpResponse(request->create_response())); response->flush(); @@ -758,9 +715,9 @@ DhtProxyServer::listen(restinio::request_handle_t request, requestNum_++; try { - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); auto response = std::make_shared( initHttpResponse(request->create_response())); response->flush(); @@ -794,9 +751,9 @@ DhtProxyServer::subscribe(restinio::request_handle_t request, { requestNum_++; try { - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); std::string err; Json::Value r; @@ -822,7 +779,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request, logger_->d("[proxy:server] [subscribe %s] [client %s] [session %s]", infoHash.toString().c_str(), clientId.c_str(), sessionId.c_str()); // Insert new or return existing push listeners of a token - std::lock_guard lock(lockPushListeners_); + std::lock_guard lock(lockListener_); auto& pushListener = pushListeners_[pushToken]; auto& pushListeners = pushListener.listeners[infoHash]; @@ -936,9 +893,9 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request, { requestNum_++; - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); if (logger_) logger_->d("[proxy:server] [unsubscribe %s]", infoHash.toString().c_str()); @@ -1048,7 +1005,13 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso notification["platform"] = type == PushType::Android ? 2 : 1; notification["data"] = std::move(json); notification["priority"] = highPriority ? "high" : "normal"; - notification["time_to_live"] = 600; + 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(expiration.time_since_epoch()).count(); + notification["expiration"] = exp; + } Json::Value notifications(Json::arrayValue); notifications[0] = notification; @@ -1118,9 +1081,9 @@ DhtProxyServer::put(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1259,9 +1222,9 @@ DhtProxyServer::putSigned(restinio::request_handle_t request, restinio::router::route_params_t params) const { requestNum_++; - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1309,9 +1272,9 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - InfoHash infoHash(params["hash"].to_string()); + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1381,10 +1344,10 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - auto value = params["value"].to_string(); - InfoHash infoHash(params["hash"].to_string()); + auto query = params["value"]; + InfoHash infoHash(params["hash"]); if (!infoHash) - infoHash = InfoHash::get(params["hash"].to_string()); + infoHash = InfoHash::get(params["hash"]); try { auto response = std::make_shared( @@ -1399,7 +1362,7 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request, [response] (bool /*ok*/){ response->done(); }, - {}, value); + {}, query); return restinio::request_handling_status_t::accepted; } catch (const std::exception& e){ return serverError(*request); diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp index 2ece5e217..ded8baca9 100644 --- a/src/dhtrunner.cpp +++ b/src/dhtrunner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -36,7 +36,6 @@ namespace dht { -constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD; static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht"; struct DhtRunner::Listener { @@ -76,19 +75,17 @@ DhtRunner::~DhtRunner() } void -DhtRunner::run(in_port_t port, const Config& config, Context&& context) +DhtRunner::run(in_port_t port, Config& config, Context&& context) { - SockAddr sin4; - sin4.setFamily(AF_INET); - sin4.setPort(port); - SockAddr sin6; - sin6.setFamily(AF_INET6); - sin6.setPort(port); - run(sin4, sin6, config, std::move(context)); + config.bind4.setFamily(AF_INET); + config.bind4.setPort(port); + config.bind6.setFamily(AF_INET6); + config.bind6.setPort(port); + run(config, std::move(context)); } void -DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context) +DhtRunner::run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context) { auto res4 = SockAddr::resolve(ip4, service); auto res6 = SockAddr::resolve(ip6, service); @@ -96,84 +93,109 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Conf res4.emplace_back(); if (res6.empty()) res6.emplace_back(); - run(res4.front(), res6.front(), config, std::move(context)); + config.bind4 = std::move(res4.front()); + config.bind6 = std::move(res6.front()); + run(config, std::move(context)); } void -DhtRunner::run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context) +DhtRunner::run(const Config& config, Context&& context) { - if (running == State::Idle) { + std::lock_guard lck(dht_mtx); + 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.", this); + return; + } + + try { + auto local4 = config.bind4; + 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", this); + local4.setFamily(AF_INET); + local6.setFamily(AF_INET6); + } auto state_path = config.dht_config.node_config.persist_path; - if (not state_path.empty()) { + if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) { state_path += "_port.txt"; std::ifstream inConfig(state_path); if (inConfig.is_open()) { in_port_t port; if (inConfig >> port) { - if (context.logger) - context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port); - if (local4.getPort() == 0) + if (local4.getPort() == 0) { + if (context.logger) + context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port); local4.setPort(port); + } } if (inConfig >> port) { - if (context.logger) - context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port); - if (local6.getPort() == 0) + if (local6.getPort() == 0) { + if (context.logger) + context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port); local6.setPort(port); + } } } } - if (not context.sock) + if (context.logger) { + logger_ = context.logger; + } + + if (not context.sock) { context.sock.reset(new net::UdpSocket(local4, local6, context.logger)); + } if (not state_path.empty()) { std::ofstream outConfig(state_path); outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl; outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl; } - run(config, std::move(context)); - } -} -void -DhtRunner::run(const Config& config, Context&& context) -{ - std::lock_guard lck(dht_mtx); - auto expected = State::Idle; - if (not running.compare_exchange_strong(expected, State::Running)) - return; - - if (context.logger) { - logger_ = context.logger; - logger_->d("[runner %p] state changed to Running", this); - } - - context.sock->setOnReceive([&] (net::PacketList&& pkts) { - net::PacketList ret; - { - std::lock_guard lck(sock_mtx); - auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size(); - while (rcv.size() > maxSize) { - if (logger_) - logger_->e("Dropping packet: queue is full!"); - rcv.pop_front(); - } - - rcv.splice(rcv.end(), std::move(pkts)); - ret = std::move(rcv_free); + if (context.logger) { + logger_->d("[runner %p] state changed to Running", this); } - cv.notify_all(); - return ret; - }); - auto dht = std::unique_ptr(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger)); - dht_ = std::unique_ptr(new SecureDht(std::move(dht), config.dht_config)); + context.sock->setOnReceive([&] (net::PacketList&& pkts) { + net::PacketList ret; + { + std::lock_guard lck(sock_mtx); + rcv.splice(rcv.end(), std::move(pkts)); + size_t dropped = 0; + while (rcv.size() > net::RX_QUEUE_MAX_SIZE) { + rcv.pop_front(); + dropped++; + } + if (dropped and logger_) { + logger_->w("[runner %p] dropped %zu packets: queue is full!", this, dropped); + } + ret = std::move(rcv_free); + } + cv.notify_all(); + return ret; + }); #ifdef OPENDHT_PROXY_CLIENT - config_ = config; + config_ = config; + identityAnnouncedCb_ = context.identityAnnouncedCb; +#endif + auto dht = std::make_unique(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger); + dht_ = std::make_unique(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger); + enableProxy(not config.proxy_server.empty()); + } catch(const std::exception& e) { + config_ = {}; + identityAnnouncedCb_ = {}; + dht_.reset(); +#ifdef OPENDHT_PROXY_CLIENT + dht_via_proxy_.reset(); #endif - enableProxy(not config.proxy_server.empty()); + running = State::Idle; + throw; + } + if (context.logger and dht_via_proxy_) { dht_via_proxy_->setLogger(context.logger); } @@ -261,29 +283,39 @@ DhtRunner::run(const Config& config, Context&& context) } void -DhtRunner::shutdown(ShutdownCallback cb) { +DhtRunner::shutdown(ShutdownCallback cb, bool stop) { + std::unique_lock lck(storage_mtx); auto expected = State::Running; if (not running.compare_exchange_strong(expected, State::Stopping)) { if (expected == State::Stopping and ongoing_ops) { - std::lock_guard lck(storage_mtx); shutdownCallbacks_.emplace_back(std::move(cb)); } - else if (cb) cb(); + else if (cb) { + lck.unlock(); + cb(); + } return; } if (logger_) logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load()); - std::lock_guard lck(storage_mtx); +#ifdef OPENDHT_PROXY_CLIENT + ongoing_ops += 2; +#else ongoing_ops++; +#endif shutdownCallbacks_.emplace_back(std::move(cb)); - pending_ops_prio.emplace([=](SecureDht&) mutable { + pending_ops.emplace([=](SecureDht&) mutable { auto onShutdown = [this]{ opEnded(); }; #ifdef OPENDHT_PROXY_CLIENT if (dht_via_proxy_) - dht_via_proxy_->shutdown(onShutdown); + dht_via_proxy_->shutdown(onShutdown, stop); + else + opEnded(); #endif if (dht_) - dht_->shutdown(onShutdown); + dht_->shutdown(onShutdown, stop); + else + opEnded(); }); cv.notify_all(); } @@ -312,11 +344,11 @@ DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) { bool DhtRunner::checkShutdown() { - if (running != State::Stopping or ongoing_ops) - return false; decltype(shutdownCallbacks_) cbs; { std::lock_guard lck(storage_mtx); + if (running != State::Stopping or ongoing_ops) + return false; cbs = std::move(shutdownCallbacks_); } for (auto& cb : cbs) @@ -348,9 +380,13 @@ DhtRunner::join() { std::lock_guard lck(storage_mtx); + if (ongoing_ops and logger_) { + 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)(); ongoing_ops = 0; + shutdownCallbacks_.clear(); } { std::lock_guard lck(dht_mtx); @@ -393,6 +429,14 @@ DhtRunner::getId() const return {}; } +std::shared_ptr +DhtRunner::getPublicKey() const +{ + if (auto dht = activeDht()) + return dht->getPublicKey(); + return {}; +} + InfoHash DhtRunner::getNodeId() const { @@ -528,6 +572,7 @@ DhtRunner::getNodeInfo(std::function)> cb) info.node_id = dht.getNodeId(); info.ipv4 = dht.getNodesStats(AF_INET); info.ipv6 = dht.getNodesStats(AF_INET6); + std::tie(info.storage_size, info.storage_values) = dht.getStoreSize(); if (auto sock = dht.getSocket()) { info.bound4 = sock->getBoundRef(AF_INET).getPort(); info.bound6 = sock->getBoundRef(AF_INET6).getPort(); @@ -593,6 +638,18 @@ DhtRunner::getPublicAddressStr(sa_family_t af) return ret; } +void +DhtRunner::getPublicAddress(std::function&&)> cb, sa_family_t af) +{ + std::lock_guard lck(storage_mtx); + ongoing_ops++; + pending_ops_prio.emplace([cb = std::move(cb), this, af](SecureDht& dht){ + cb(dht.getPublicAddress(af)); + opEnded(); + }); + cv.notify_all(); +} + void DhtRunner::registerCertificate(std::shared_ptr cert) { std::lock_guard lck(dht_mtx); @@ -672,8 +729,8 @@ DhtRunner::loop_() rcv_free.splice(rcv_free.end(), std::move(received_treated)); } - if (dropped) - std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl; + if (dropped && logger_) + logger_->e("[runner %p] Dropped %zu packets with high delay.", this, dropped); NodeStatus nstatus4 = dht->updateStatus(AF_INET); NodeStatus nstatus6 = dht->updateStatus(AF_INET6); @@ -690,11 +747,12 @@ DhtRunner::loop_() void DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (dcb) dcb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=](SecureDht& dht) mutable { dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w)); @@ -709,11 +767,12 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, } void DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (done_cb) done_cb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=](SecureDht& dht) mutable { dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q)); @@ -725,11 +784,12 @@ std::future DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w) { auto ret_token = std::make_shared>(); + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); ret_token->set_value(0); return ret_token->get_future(); } - std::lock_guard lck(storage_mtx); pending_ops.emplace([=](SecureDht& dht) mutable { #ifdef OPENDHT_PROXY_CLIENT auto tokenbGlobal = listener_token_++; @@ -767,19 +827,28 @@ void DhtRunner::cancelListen(InfoHash h, size_t token) { std::lock_guard lck(storage_mtx); + if (running != State::Running) + return; + ongoing_ops++; #ifdef OPENDHT_PROXY_CLIENT pending_ops.emplace([=](SecureDht&) { auto it = listeners_.find(token); - if (it == listeners_.end()) return; - if (it->second.tokenClassicDht) - dht_->cancelListen(h, it->second.tokenClassicDht); - if (it->second.tokenProxyDht and dht_via_proxy_) - dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); - listeners_.erase(it); + if (it != listeners_.end()) { + if (it->second.tokenClassicDht) + dht_->cancelListen(h, it->second.tokenClassicDht); + if (it->second.tokenProxyDht and dht_via_proxy_) + dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); + listeners_.erase(it); + } else { + if (logger_) + logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token); + } + opEnded(); }); #else pending_ops.emplace([=](SecureDht& dht) { dht.cancelListen(h, token); + opEnded(); }); #endif // OPENDHT_PROXY_CLIENT cv.notify_all(); @@ -789,19 +858,29 @@ void DhtRunner::cancelListen(InfoHash h, std::shared_future ftoken) { std::lock_guard lck(storage_mtx); + if (running != State::Running) + return; + ongoing_ops++; #ifdef OPENDHT_PROXY_CLIENT - pending_ops.emplace([=](SecureDht&) { - auto it = listeners_.find(ftoken.get()); - if (it == listeners_.end()) return; - if (it->second.tokenClassicDht) - dht_->cancelListen(h, it->second.tokenClassicDht); - if (it->second.tokenProxyDht and dht_via_proxy_) - dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); - listeners_.erase(it); + pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht&) { + auto token = ftoken.get(); + auto it = listeners_.find(token); + if (it != listeners_.end()) { + if (it->second.tokenClassicDht) + dht_->cancelListen(h, it->second.tokenClassicDht); + if (it->second.tokenProxyDht and dht_via_proxy_) + dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); + listeners_.erase(it); + } else { + if (logger_) + logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token); + } + opEnded(); }); #else - pending_ops.emplace([=](SecureDht& dht) { + pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht& dht) { dht.cancelListen(h, ftoken.get()); + opEnded(); }); #endif // OPENDHT_PROXY_CLIENT cv.notify_all(); @@ -810,11 +889,12 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future ftoken) void DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (cb) cb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -828,13 +908,14 @@ DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created void DhtRunner::put(InfoHash hash, std::shared_ptr value, DoneCallback cb, time_point created, bool permanent) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (cb) cb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; - pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable { + pending_ops.emplace([=, value = std::move(value), cb = std::move(cb)](SecureDht& dht) mutable { dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent); }); cv.notify_all(); @@ -869,11 +950,12 @@ DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr& value) void DhtRunner::putSigned(InfoHash hash, std::shared_ptr value, DoneCallback cb, bool permanent) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (cb) cb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -899,11 +981,12 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c void DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr value, DoneCallback cb, bool permanent) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (cb) cb(false, {}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -926,6 +1009,31 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done putEncrypted(InfoHash::get(key), to, std::forward(value), std::move(cb), permanent); } +void +DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallback cb, bool permanent) +{ + std::unique_lock lck(storage_mtx); + if (running != State::Running) { + lck.unlock(); + if (cb) cb(false, {}); + return; + } + ongoing_ops++; + pending_ops.emplace([=, + cb = std::move(cb), + value = std::move(value) + ] (SecureDht& dht) mutable { + dht.putEncrypted(hash, *to, value, bindOpDoneCallback(std::move(cb)), permanent); + }); + cv.notify_all(); +} + +void +DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallback cb, bool permanent) +{ + putEncrypted(hash, to, std::make_shared(std::move(value)), std::move(cb), permanent); +} + void DhtRunner::bootstrap(const std::string& host, const std::string& service) { @@ -957,7 +1065,7 @@ DhtRunner::clearBootstrap() } void -DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple&& cb) +DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple cb) { if (running != State::Running) { cb(false); @@ -987,15 +1095,16 @@ DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple&& cb) } void -DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb) +DhtRunner::bootstrap(SockAddr addr, DoneCallbackSimple cb) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); if (cb) cb(false); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; - pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable { + pending_ops_prio.emplace([addr = std::move(addr), cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable { dht.pingNode(std::move(addr), std::move(cb)); }); cv.notify_all(); @@ -1004,9 +1113,9 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb) void DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address) { + std::lock_guard lck(storage_mtx); if (running != State::Running) return; - std::unique_lock lck(storage_mtx); pending_ops_prio.emplace([id, address](SecureDht& dht) mutable { dht.insertNode(id, address); }); @@ -1014,12 +1123,12 @@ DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address) } void -DhtRunner::bootstrap(const std::vector& nodes) +DhtRunner::bootstrap(std::vector nodes) { + std::lock_guard lck(storage_mtx); if (running != State::Running) return; - std::lock_guard lck(storage_mtx); - pending_ops_prio.emplace([=](SecureDht& dht) { + pending_ops_prio.emplace([nodes = std::move(nodes)](SecureDht& dht) { for (auto& node : nodes) dht.insertNode(node); }); @@ -1042,11 +1151,12 @@ DhtRunner::connectivityChanged() void DhtRunner::findCertificate(InfoHash hash, std::function&)> cb) { + std::unique_lock lck(storage_mtx); if (running != State::Running) { + lck.unlock(); cb({}); return; } - std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) { dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp& crt){ @@ -1122,7 +1232,7 @@ DhtRunner::enableProxy(bool proxify) if (not config_.push_token.empty()) dht_via_proxy->setPushNotificationToken(config_.push_token); #endif - dht_via_proxy_ = std::unique_ptr(new SecureDht(std::move(dht_via_proxy), config_.dht_config)); + dht_via_proxy_ = std::unique_ptr(new SecureDht(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_)); // add current listeners for (auto& l: listeners_) l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w); diff --git a/src/http.cpp b/src/http.cpp index 983bcc4b2..203b526a8 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Vsevolod Ivanov * * This program is free software; you can redistribute it and/or modify @@ -561,12 +561,63 @@ void Connection::async_connect(std::vector&& endpoints, ConnectHandlerCb cb) { std::lock_guard lock(mutex_); - if (ssl_socket_) - asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(cb))); - else if (socket_) - asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(cb))); - else if (cb) + if (!ssl_socket_ && !socket_) { cb(asio::error::operation_aborted, {}); + return; + } + auto& base = ssl_socket_? ssl_socket_->lowest_layer() : *socket_; + + ConnectHandlerCb wcb = [&base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) { + if (!ec) { + auto socket = base.native_handle(); + // 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() + 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); + }; + if (ssl_socket_) + asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(wcb))); + else + asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(wcb))); } void @@ -1254,9 +1305,11 @@ Request::terminate(const asio::error_code& ec) return; response_.aborted = ec == asio::error::operation_aborted; + if (ec == asio::error::basic_errors::broken_pipe) + response_.status_code = 0U; // Avoid to give a successful answer (happen with a broken pipe, takes the last status) if (logger_) { - if (ec and ec != asio::error::eof and ec != asio::error::operation_aborted) + if (ec and ec != asio::error::eof and !response_.aborted) logger_->e("[http:request:%i] end with error: %s", id_, ec.message().c_str()); else logger_->d("[http:request:%i] done with status code %u", id_, response_.status_code); @@ -1415,7 +1468,7 @@ Request::await() std::unique_lock lock(mtx); std::condition_variable cv; bool ok {false}; - add_on_done_callback([&](const Response& resp){ + add_on_done_callback([&](const Response&){ std::lock_guard lk(mtx); ok = true; cv.notify_all(); diff --git a/src/indexation/pht.cpp b/src/indexation/pht.cpp index 2494365cc..0840c0e3f 100644 --- a/src/indexation/pht.cpp +++ b/src/indexation/pht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * Nicolas Reynaud diff --git a/src/infohash.cpp b/src/infohash.cpp index 69c79b8a9..84d04ae2e 100644 --- a/src/infohash.cpp +++ b/src/infohash.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -22,6 +22,8 @@ #include #include +using namespace std::literals; + namespace dht { const HexMap hex_map = {}; @@ -33,9 +35,9 @@ NodeExport::msgpack_unpack(msgpack::object o) throw msgpack::type_error(); if (o.via.map.size < 2) throw msgpack::type_error(); - if (o.via.map.ptr[0].key.as() != "id") + if (o.via.map.ptr[0].key.as() != "id"sv) throw msgpack::type_error(); - if (o.via.map.ptr[1].key.as() != "addr") + if (o.via.map.ptr[1].key.as() != "addr"sv) throw msgpack::type_error(); const auto& addr = o.via.map.ptr[1].val; if (addr.type != msgpack::type::BIN) diff --git a/src/listener.h b/src/listener.h index 18663f0bb..0087952df 100644 --- a/src/listener.h +++ b/src/listener.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/log.cpp b/src/log.cpp index b9a62204c..100f0f74b 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -38,7 +38,7 @@ printLog(std::ostream& s, char const *m, va_list args) { // print log to buffer std::array buffer; int ret = vsnprintf(buffer.data(), buffer.size(), m, args); - if (ret < 0) + if (ret <= 0) return; // write timestamp @@ -89,7 +89,7 @@ std::shared_ptr getSyslogLogger(const char* name) { #ifndef _WIN32 struct Syslog { - Syslog(const char* n) { + explicit Syslog(const char* n) { openlog(n, LOG_NDELAY, LOG_USER); } ~Syslog() { diff --git a/src/net.h b/src/net.h index dd4b91473..e7bdf3899 100644 --- a/src/net.h +++ b/src/net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/network_engine.cpp b/src/network_engine.cpp index 10991629c..4bfaeb59d 100644 --- a/src/network_engine.cpp +++ b/src/network_engine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -82,10 +82,6 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg) nodes6(std::move(msg.nodes6)) {} -NetworkEngine::NetworkEngine(const Sp& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr&& sock) - : myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler) -{} - NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c, std::unique_ptr&& sock, const Sp& log, @@ -120,7 +116,7 @@ NetworkEngine::~NetworkEngine() { } void -NetworkEngine::tellListener(Sp node, Tid socket_id, const InfoHash& hash, want_t want, +NetworkEngine::tellListener(const Sp& node, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, std::vector>&& nodes, std::vector>&& nodes6, std::vector>&& values, const Query& query, int version) @@ -139,7 +135,7 @@ NetworkEngine::tellListener(Sp node, Tid socket_id, const InfoHash& hash, } void -NetworkEngine::tellListenerRefreshed(Sp n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) +NetworkEngine::tellListenerRefreshed(const Sp& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) { msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -190,7 +186,7 @@ NetworkEngine::tellListenerRefreshed(Sp n, Tid socket_id, const InfoHash&, } void -NetworkEngine::tellListenerExpired(Sp n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) +NetworkEngine::tellListenerExpired(const Sp& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) { msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -223,7 +219,7 @@ NetworkEngine::tellListenerExpired(Sp n, Tid socket_id, const InfoHash&, c Tid tid (n->getNewTid()); pk.pack(KEY_Q); pk.pack(QUERY_UPDATE); - pk.pack(KEY_TID); pk.pack(tid); + pk.pack(KEY_TID); pk.pack(tid); auto req = std::make_shared(MessageType::UpdateValue, tid, n, Blob(buffer.data(), buffer.data() + buffer.size()), @@ -380,7 +376,7 @@ NetworkEngine::isMartian(const SockAddr& addr) const uint8_t* address = (const uint8_t*)&sin6.sin6_addr; return address[0] == 0xFF || (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) || - memcmp(address, zeroes.data(), 16) == 0 || + memcmp(address, InfoHash::zero().data(), 16) == 0 || memcmp(address, v4prefix, 12) == 0; } default: @@ -460,9 +456,13 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f) pmsg_it->second.last_part = now; // check data completion if (pmsg_it->second.msg->complete()) { - // process the full message - process(std::move(pmsg_it->second.msg), from); - partial_messages.erase(pmsg_it); + try { + // process the full message + process(std::move(pmsg_it->second.msg), from); + partial_messages.erase(pmsg_it); + } catch (...) { + return; + } } else scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, msg->tid)); } @@ -485,7 +485,11 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f) } if (msg->value_parts.empty()) { - process(std::move(msg), from); + try { + process(std::move(msg), from); + } catch(...) { + return; + } } else { // starting partial message session auto k = msg->tid; @@ -515,8 +519,15 @@ NetworkEngine::process(std::unique_ptr&& msg, const SockAddr& fro throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find socket", msg->id}; node->received(now, {}); onNewNode(node, 2); - deserializeNodes(*msg, from); - rsocket->on_receive(node, std::move(*msg)); + try { + deserializeNodes(*msg, from); + rsocket->on_receive(node, std::move(*msg)); + } catch (DhtProtocolException &ex) { + if (logIncoming_) + if (logger_) + logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); + return; + } } else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) { auto rsocket = node->getSocket(msg->tid); @@ -579,13 +590,26 @@ NetworkEngine::process(std::unique_ptr&& msg, const SockAddr& fro r.node->authSuccess(); } r.reply_time = scheduler.time(); - - deserializeNodes(*msg, from); - r.setDone(std::move(*msg)); + try { + deserializeNodes(*msg, from); + r.setDone(std::move(*msg)); + } catch (DhtProtocolException &ex) { + if (logIncoming_) + if (logger_) + logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); + return; + } break; } else { /* request socket data */ - deserializeNodes(*msg, from); - rsocket->on_receive(node, std::move(*msg)); + try { + deserializeNodes(*msg, from); + rsocket->on_receive(node, std::move(*msg)); + } catch (DhtProtocolException &ex) { + if (logIncoming_) + if (logger_) + logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); + return; + } } break; default: @@ -695,7 +719,7 @@ NetworkEngine::send(const SockAddr& addr, const char *buf, size_t len, bool conf } Sp -NetworkEngine::sendPing(Sp node, RequestCb&& on_done, RequestExpiredCb&& on_expired) { +NetworkEngine::sendPing(const Sp& node, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (node->getNewTid()); msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -753,7 +777,7 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) { } Sp -NetworkEngine::sendFindNode(Sp n, const InfoHash& target, want_t want, +NetworkEngine::sendFindNode(const Sp& n, const InfoHash& target, want_t want, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (n->getNewTid()); msgpack::sbuffer buffer; @@ -798,7 +822,7 @@ NetworkEngine::sendFindNode(Sp n, const InfoHash& target, want_t want, Sp -NetworkEngine::sendGetValues(Sp n, const InfoHash& info_hash, const Query& query, want_t want, +NetworkEngine::sendGetValues(const Sp& n, const InfoHash& info_hash, const Query& query, want_t want, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (n->getNewTid()); msgpack::sbuffer buffer; @@ -951,8 +975,8 @@ NetworkEngine::sendValueParts(Tid tid, const std::vector& svals, const Soc pk.pack(KEY_TID); pk.pack(tid); pk.pack(KEY_V); pk.pack_map(1); pk.pack(i); pk.pack_map(2); - pk.pack(std::string("o")); pk.pack(start); - pk.pack(std::string("d")); pk.pack_bin(end-start); + pk.pack("o"sv); pk.pack(start); + pk.pack("d"sv); pk.pack_bin(end-start); pk.pack_bin_body((const char*)v.data()+start, end-start); send(addr, buffer.data(), buffer.size()); start = end; @@ -994,8 +1018,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes, auto fields = query.select.getSelection(); pk.pack(KEY_REQ_FIELDS); pk.pack_map(2); - pk.pack(std::string("f")); pk.pack(fields); - pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size()); + pk.pack("f"sv); pk.pack(fields); + pk.pack("v"sv); pk.pack_array(st.size()*fields.size()); for (const auto& v : st) v->msgpack_pack_fields(fields, pk); //DHT_LOG_DBG("sending closest nodes (%d+%d nodes.), %u value headers containing %u fields", @@ -1069,7 +1093,7 @@ NetworkEngine::bufferNodes(sa_family_t af, const InfoHash& id, want_t want, } Sp -NetworkEngine::sendListen(Sp n, +NetworkEngine::sendListen(const Sp& n, const InfoHash& hash, const Query& query, const Blob& token, @@ -1138,7 +1162,7 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) { } Sp -NetworkEngine::sendAnnounceValue(Sp n, +NetworkEngine::sendAnnounceValue(const Sp& n, const InfoHash& infohash, const Sp& value, time_point created, @@ -1151,11 +1175,12 @@ NetworkEngine::sendAnnounceValue(Sp n, msgpack::packer pk(&buffer); pk.pack_map(5+(config.network?1:0)); - pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4)); + bool add_created = created < scheduler.time(); + pk.pack(KEY_A); pk.pack_map(add_created ? 5 : 4); pk.pack(KEY_REQ_ID); pk.pack(myid); pk.pack(KEY_REQ_H); pk.pack(infohash); auto v = packValueHeader(buffer, {value}); - if (created < scheduler.time()) { + if (add_created) { pk.pack(KEY_REQ_CREATION); pk.pack(to_time_t(created)); } @@ -1196,7 +1221,7 @@ NetworkEngine::sendAnnounceValue(Sp n, } Sp -NetworkEngine::sendUpdateValues(Sp n, +NetworkEngine::sendUpdateValues(const Sp& n, const InfoHash& infohash, const std::vector>& values, time_point created, @@ -1242,7 +1267,7 @@ NetworkEngine::sendUpdateValues(Sp n, } Sp -NetworkEngine::sendRefreshValue(Sp n, +NetworkEngine::sendRefreshValue(const Sp& n, const InfoHash& infohash, const Value::Id& vid, const Blob& token, diff --git a/src/network_utils.cpp b/src/network_utils.cpp index b7e3588ad..e9cd4ee5f 100644 --- a/src/network_utils.cpp +++ b/src/network_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/node.cpp b/src/node.cpp index d207cb68f..c444bbe22 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -137,10 +137,7 @@ Node::openSocket(SocketCb&& cb) if (++transaction_id == 0) transaction_id = 1; - auto sock = std::make_shared(std::move(cb)); - auto s = sockets_.emplace(transaction_id, std::move(sock)); - if (not s.second) - s.first->second = std::move(sock); + sockets_[transaction_id] = std::make_shared(std::move(cb)); return transaction_id; } diff --git a/src/node_cache.cpp b/src/node_cache.cpp index dc25b386e..34366c4e0 100644 --- a/src/node_cache.cpp +++ b/src/node_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/op_cache.cpp b/src/op_cache.cpp index 6c6ebb7bc..de2c4606d 100644 --- a/src/op_cache.cpp +++ b/src/op_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -175,7 +175,7 @@ SearchCache::listen(const ValueCallback& get_cb, const Sp& q, const Value auto op = getOp(q); if (op == ops.end()) { // New query - op = ops.emplace(q, std::unique_ptr(new OpCache)).first; + op = ops.emplace(q, std::make_unique()).first; auto& cache = *op->second; cache.searchToken = onListen(q, [&](const std::vector>& values, bool expired){ return cache.onValue(values, expired); diff --git a/src/op_cache.h b/src/op_cache.h index 516681575..a32751fea 100644 --- a/src/op_cache.h +++ b/src/op_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -28,13 +28,13 @@ struct OpCacheValueStorage Sp data {}; unsigned refCount {1}; system_clock::time_point updated {system_clock::time_point::min()}; - OpCacheValueStorage(Sp val) : data(val) {} + explicit OpCacheValueStorage(Sp val) : data(std::move(val)) {} }; class OpValueCache { public: OpValueCache(ValueCallback&& cb) noexcept : callback(std::forward(cb)) {} - OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) { + explicit OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) { o.callback = {}; } @@ -51,8 +51,8 @@ class OpValueCache { } bool onValue(const std::vector>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) { - return expired - ? onValuesExpired(vals, t) + return expired + ? onValuesExpired(vals, t) : onValuesAdded(vals, t); } @@ -74,6 +74,7 @@ class OpValueCache { std::vector> get(const Value::Filter& filter) const; Sp get(Value::Id id) const; std::vector> getValues() const; + size_t size() const { return values.size(); } private: OpValueCache(const OpValueCache&) = delete; @@ -145,7 +146,11 @@ class OpCache { } time_point getExpiration() const; - size_t searchToken; + size_t size() const { + return cache.size(); + } + + size_t searchToken {0}; private: constexpr static const std::chrono::seconds EXPIRATION {60}; OpCache(const OpCache&) = delete; @@ -176,6 +181,13 @@ class SearchCache { std::vector> get(const Value::Filter& filter) const; Sp get(Value::Id id) const; + std::pair size() const { + size_t tot = 0; + for (const auto& c : ops) + tot += c.second->size(); + return {ops.size(), tot}; + } + private: SearchCache(const SearchCache&) = delete; SearchCache& operator=(const SearchCache&) = delete; diff --git a/src/parsed_message.h b/src/parsed_message.h index 70de16d7d..6f5063c06 100644 --- a/src/parsed_message.h +++ b/src/parsed_message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -22,47 +22,50 @@ #include "net.h" #include +#include + +using namespace std::literals; namespace dht { namespace net { -static const std::string KEY_Y {"y"}; -static const std::string KEY_R {"r"}; -static const std::string KEY_U {"u"}; -static const std::string KEY_E {"e"}; -static const std::string KEY_V {"p"}; -static const std::string KEY_TID {"t"}; -static const std::string KEY_UA {"v"}; -static const std::string KEY_NETID {"n"}; -static const std::string KEY_ISCLIENT {"s"}; -static const std::string KEY_Q {"q"}; -static const std::string KEY_A {"a"}; +static constexpr auto KEY_Y = "y"sv; +static constexpr auto KEY_R = "r"sv; +static constexpr auto KEY_U = "u"sv; +static constexpr auto KEY_E = "e"sv; +static constexpr auto KEY_V = "p"sv; +static constexpr auto KEY_TID = "t"sv; +static constexpr auto KEY_UA = "v"sv; +static constexpr auto KEY_NETID = "n"sv; +static constexpr auto KEY_ISCLIENT = "s"sv; +static constexpr auto KEY_Q = "q"sv; +static constexpr auto KEY_A = "a"sv; -static const std::string KEY_REQ_SID {"sid"}; -static const std::string KEY_REQ_ID {"id"}; -static const std::string KEY_REQ_H {"h"}; -static const std::string KEY_REQ_TARGET {"target"}; -static const std::string KEY_REQ_QUERY {"q"}; -static const std::string KEY_REQ_TOKEN {"token"}; -static const std::string KEY_REQ_VALUE_ID {"vid"}; -static const std::string KEY_REQ_NODES4 {"n4"}; -static const std::string KEY_REQ_NODES6 {"n6"}; -static const std::string KEY_REQ_CREATION {"c"}; -static const std::string KEY_REQ_ADDRESS {"sa"}; -static const std::string KEY_REQ_VALUES {"values"}; -static const std::string KEY_REQ_EXPIRED {"exp"}; -static const std::string KEY_REQ_REFRESHED {"re"}; -static const std::string KEY_REQ_FIELDS {"fileds"}; -static const std::string KEY_REQ_WANT {"w"}; -static const std::string KEY_VERSION {"ve"}; +static constexpr auto KEY_REQ_SID = "sid"sv; +static constexpr auto KEY_REQ_ID = "id"sv; +static constexpr auto KEY_REQ_H = "h"sv; +static constexpr auto KEY_REQ_TARGET = "target"sv; +static constexpr auto KEY_REQ_QUERY = "q"sv; +static constexpr auto KEY_REQ_TOKEN = "token"sv; +static constexpr auto KEY_REQ_VALUE_ID = "vid"sv; +static constexpr auto KEY_REQ_NODES4 = "n4"sv; +static constexpr auto KEY_REQ_NODES6 = "n6"sv; +static constexpr auto KEY_REQ_CREATION = "c"sv; +static constexpr auto KEY_REQ_ADDRESS = "sa"sv; +static constexpr auto KEY_REQ_VALUES = "values"sv; +static constexpr auto KEY_REQ_EXPIRED = "exp"sv; +static constexpr auto KEY_REQ_REFRESHED = "re"sv; +static constexpr auto KEY_REQ_FIELDS = "fileds"sv; +static constexpr auto KEY_REQ_WANT = "w"sv; +static constexpr auto KEY_VERSION = "ve"sv; -static const std::string QUERY_PING {"ping"}; -static const std::string QUERY_FIND {"find"}; -static const std::string QUERY_GET {"get"}; -static const std::string QUERY_UPDATE {"update"}; -static const std::string QUERY_PUT {"put"}; -static const std::string QUERY_LISTEN {"listen"}; -static const std::string QUERY_REFRESH {"refresh"}; +static constexpr auto QUERY_PING = "ping"sv; +static constexpr auto QUERY_FIND = "find"sv; +static constexpr auto QUERY_GET = "get"sv; +static constexpr auto QUERY_UPDATE = "update"sv; +static constexpr auto QUERY_PUT = "put"sv; +static constexpr auto QUERY_LISTEN = "listen"sv; +static constexpr auto QUERY_REFRESH = "refresh"sv; Tid unpackTid(const msgpack::object& o) { switch (o.type) { @@ -173,14 +176,14 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) msgpack::object* e; msgpack::object* v; msgpack::object* a; - std::string q; + std::string_view q; } parsed {}; for (unsigned i = 0; i < msg.via.map.size; i++) { auto& o = msg.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; - auto key = o.key.as(); + auto key = o.key.as(); if (key == KEY_Y) parsed.y = &o.val; else if (key == KEY_R) @@ -200,7 +203,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) else if (key == KEY_ISCLIENT) is_client = o.val.as(); else if (key == KEY_Q) - parsed.q = o.val.as(); + parsed.q = o.val.as(); else if (key == KEY_A) parsed.a = &o.val; } @@ -213,7 +216,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) type = MessageType::ValueData; else if (parsed.u) type = MessageType::ValueUpdate; - else if (parsed.y and parsed.y->as() != "q") + else if (parsed.y and parsed.y->as() != "q"sv) throw msgpack::type_error(); else if (parsed.q == QUERY_PING) type = MessageType::Ping; @@ -237,8 +240,8 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) throw msgpack::type_error(); for (size_t i = 0; i < parsed.v->via.map.size; ++i) { auto& vdat = parsed.v->via.map.ptr[i]; - auto o = findMapValue(vdat.val, "o"); - auto d = findMapValue(vdat.val, "d"); + auto o = findMapValue(vdat.val, "o"sv); + auto d = findMapValue(vdat.val, "d"sv); if (not o or not d) continue; value_parts.emplace(vdat.key.as(), std::pair(o->as(), unpackBlob(*d))); @@ -267,7 +270,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) auto& o = req.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; - auto key = o.key.as(); + auto key = o.key.as(); if (key == KEY_REQ_SID) socket_id = unpackTid(o.val); else if (key == KEY_REQ_ID) @@ -341,9 +344,9 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) } } } else if (parsedReq.fields) { - if (auto rfields = findMapValue(*parsedReq.fields, "f")) { + if (auto rfields = findMapValue(*parsedReq.fields, "f"sv)) { auto vfields = rfields->as>(); - if (auto rvalues = findMapValue(*parsedReq.fields, "v")) { + if (auto rvalues = findMapValue(*parsedReq.fields, "v"sv)) { if (rvalues->type != msgpack::type::ARRAY) throw msgpack::type_error(); size_t val_num = rvalues->via.array.size / vfields.size(); diff --git a/src/peer_discovery.cpp b/src/peer_discovery.cpp index 56ccad965..a25da780e 100644 --- a/src/peer_discovery.cpp +++ b/src/peer_discovery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Mingrui Zhang * Vsevolod Ivanov * Adrien Béraud @@ -24,6 +24,8 @@ #include +using namespace std::literals; + namespace dht { // Organization-local Scope multicast @@ -61,7 +63,7 @@ class PeerDiscovery::DomainPeerDiscovery msgpack::sbuffer sbuf_; std::map messages_; - std::map callbackmap_; + std::map> callbackmap_; bool lrunning_ {false}; bool drunning_ {false}; @@ -133,19 +135,18 @@ PeerDiscovery::DomainPeerDiscovery::loopListener() msgpack::object obj = rcv.get(); if (obj.type == msgpack::type::STR) { - if (lrunning_ and obj.as() == "q") + if (lrunning_ and obj.as() == "q"sv) publish(receiveFrom_); } else if (obj.type == msgpack::type::MAP) { for (unsigned i = 0; i < obj.via.map.size; i++) { auto& o = obj.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; - auto key = o.key.as(); ServiceDiscoveredCallback cb; { std::lock_guard lck(dmtx_); if (drunning_) { - auto callback = callbackmap_.find(key); + auto callback = callbackmap_.find(o.key.as()); if (callback != callbackmap_.end()) cb = callback->second; } else diff --git a/src/request.h b/src/request.h index 5c468c04c..318d120a0 100644 --- a/src/request.h +++ b/src/request.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -74,14 +74,14 @@ struct Request { Blob&& msg, std::function on_done, std::function on_expired) : - node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)) { } + node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_expired(std::move(on_expired)), msg(std::move(msg)) { } Request(MessageType type, Tid tid, Sp node, Blob&& msg, std::function on_done, std::function on_error, std::function on_expired) : - node(node), tid(tid), type(type), on_done(on_done), on_error(on_error), on_expired(on_expired), msg(std::move(msg)) { } + node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_error(std::move(on_error)), on_expired(std::move(on_expired)), msg(std::move(msg)) { } Tid getTid() const { return tid; } MessageType getType() const { return type; } diff --git a/src/rng.cpp b/src/rng.cpp index 3ea47db32..da39372a6 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/routing_table.cpp b/src/routing_table.cpp index e8b9ea6d3..6f2846abf 100644 --- a/src/routing_table.cpp +++ b/src/routing_table.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/search.h b/src/search.h index b7a5ffcb5..5ec9160cc 100644 --- a/src/search.h +++ b/src/search.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -49,12 +49,21 @@ struct Dht::Announce { }; struct Dht::SearchNode { + + struct AnnounceStatus { + Sp req {}; + Sp refresh {}; + time_point refresh_time; + AnnounceStatus(){}; + AnnounceStatus(Sp r, time_point t): req(std::move(r)), refresh_time(t) + {} + }; /** * Foreach value id, we keep track of a pair (net::Request, time_point) where the * request is the request returned by the network engine and the time_point * is the next time at which the value must be refreshed. */ - using AnnounceStatus = std::map, time_point>>; + using AnnounceStatusMap = std::map; /** * Foreach Query, we keep track of the request returned by the network * engine when we sent the "get". @@ -63,6 +72,7 @@ struct Dht::SearchNode { struct CachedListenStatus { ValueCache cache; + Sp refresh {}; Sp cacheExpirationJob {}; Sp req {}; Tid socketId {0}; @@ -87,7 +97,7 @@ struct Dht::SearchNode { SyncStatus getStatus {}; /* get/sync status */ NodeListenerStatus listenStatus {}; /* listen status */ - AnnounceStatus acked {}; /* announcement status for a given value id */ + AnnounceStatusMap acked {}; /* announcement status for a given value id */ Blob token {}; /* last token the node sent to us after a get request */ time_point last_get_reply {time_point::min()}; /* last time received valid token */ @@ -124,6 +134,14 @@ struct Dht::SearchNode { return last_get_reply + Node::NODE_EXPIRE_TIME; } + friend std::ostream& operator<< (std::ostream& s, const SearchNode& node) { + s << "getStatus:" << node.getStatus.size() + << " listenStatus:" << node.listenStatus.size() + << " acked:" << node.acked.size() + << " cache:" << (node.listenStatus.empty() ? 0 : node.listenStatus.begin()->second.cache.size()) << std::endl; + return s; + } + /** * Could a particular "get" request be sent to this node now ? * @@ -146,12 +164,12 @@ struct Dht::SearchNode { if (node->isExpired()) return false; - bool pending {false}, + bool is_pending {false}, completed_sq_status {false}, pending_sq_status {false}; for (const auto& s : getStatus) { if (s.second and s.second->pending()) - pending = true; + is_pending = true; if (s.first and q and q->isSatisfiedBy(*s.first) and s.second) { if (s.second->pending()) pending_sq_status = true; @@ -162,7 +180,7 @@ struct Dht::SearchNode { } } - return (not pending and now > last_get_reply + Node::NODE_EXPIRE_TIME) or + return (not is_pending and now > last_get_reply + Node::NODE_EXPIRE_TIME) or not (completed_sq_status or pending_sq_status or hasStartedPagination(q)); } @@ -231,9 +249,12 @@ struct Dht::SearchNode { } } - void onListenSynced(const Sp& q, bool synced = true) { + void onListenSynced(const Sp& q, bool synced = true, Sp refreshJob = {}) { auto l = listenStatus.find(q); if (l != listenStatus.end()) { + if (l->second.refresh) + l->second.refresh->cancel(); + l->second.refresh = std::move(refreshJob); l->second.cache.onSynced(synced); } } @@ -271,7 +292,7 @@ struct Dht::SearchNode { return std::find_if(status.cbegin(), status.cend(), [](const SyncStatus::value_type& r){ return r.second and r.second->pending(); - }) != status.end(); + }) != status.cend(); } static bool pending(const NodeListenerStatus& status) { return std::find_if(status.begin(), status.end(), @@ -284,16 +305,18 @@ struct Dht::SearchNode { bool isAnnounced(Value::Id vid) const { auto ack = acked.find(vid); - if (ack == acked.end() or not ack->second.first) + if (ack == acked.end() or not ack->second.req) return false; - return ack->second.first->completed(); + return ack->second.req->completed(); } void cancelAnnounce() { for (const auto& status : acked) { - const auto& req = status.second.first; + const auto& req = status.second.req; if (req and req->pending()) { node->cancelRequest(req); } + if (status.second.refresh) + status.second.refresh->cancel(); } acked.clear(); } @@ -320,14 +343,21 @@ struct Dht::SearchNode { return listen_status->second.req->reply_time + listen_expire > now; } void cancelListen() { - for (const auto& status : listenStatus) + for (const auto& status : listenStatus) { node->cancelRequest(status.second.req); - listenStatus.clear(); + if (status.second.refresh) + status.second.refresh->cancel(); + if (status.second.cacheExpirationJob) + status.second.cacheExpirationJob->cancel(); + } + listenStatus.clear(); } void cancelListen(const Sp& query) { auto it = listenStatus.find(query); if (it != listenStatus.end()) { node->cancelRequest(it->second.req); + if (it->second.refresh) + it->second.refresh->cancel(); listenStatus.erase(it); } } @@ -337,13 +367,13 @@ struct Dht::SearchNode { */ time_point getAnnounceTime(Value::Id vid) const { const auto& ack = acked.find(vid); - if (ack == acked.cend() or not ack->second.first) { + if (ack == acked.cend() or not ack->second.req) { return time_point::min(); } - if (ack->second.first->completed()) { - return ack->second.second - REANNOUNCE_MARGIN; + if (ack->second.req->completed()) { + return ack->second.refresh_time - REANNOUNCE_MARGIN; } - return ack->second.first->pending() ? time_point::max() : time_point::min(); + return ack->second.req->pending() ? time_point::max() : time_point::min(); } /** @@ -407,23 +437,35 @@ struct Dht::Search { ~Search() { if (opExpirationJob) opExpirationJob->cancel(); - for (auto& get : callbacks) { - get.second.done_cb(false, {}); - get.second.done_cb = {}; + for (auto& g : callbacks) { + g.second.done_cb(false, {}); + g.second.done_cb = {}; } - for (auto& put : announce) { - put.callback(false, {}); - put.callback = {}; + for (auto& a : announce) { + a.callback(false, {}); + a.callback = {}; } } + friend std::ostream& operator<< (std::ostream& s, const Search& sr) { + auto csize = sr.cache.size(); + s << "announce:" << sr.announce.size() + << " gets:" << sr.callbacks.size() + << " listeners:" << sr.listeners.size() + << " cache:" << csize.first << ',' << csize.second << std::endl; + s << "nodes:" << std::endl; + for (const auto& n : sr.nodes) + s << *n; + return s; + } + /** * @returns true if the node was not present and added to the search */ bool insertNode(const Sp& n, time_point now, const Blob& token={}); SearchNode* getNode(const Sp& n) { - auto srn = std::find_if(nodes.begin(), nodes.end(), [&](std::unique_ptr& sn) { + auto srn = std::find_if(nodes.begin(), nodes.end(), [&](const std::unique_ptr& sn) { return n == sn->node; }); return (srn == nodes.end()) ? nullptr : (*srn).get(); @@ -521,17 +563,15 @@ struct Dht::Search { if (not opExpirationJob) opExpirationJob = scheduler.add(time_point::max(), [this,&scheduler]{ auto nextExpire = cache.expire(scheduler.time(), [&](size_t t){ - Sp query; const auto& ll = listeners.find(t); if (ll != listeners.cend()) { - query = ll->second.query; + auto query = ll->second.query; listeners.erase(ll); - } - for (auto& sn : nodes) { - if (listeners.empty()) - sn->cancelListen(); - else if (query) - sn->cancelListen(query); + if (listeners.empty()) { + for (auto& sn : nodes) sn->cancelListen(); + } else if (query) { + for (auto& sn : nodes) sn->cancelListen(query); + } } }); scheduler.edit(opExpirationJob, nextExpire); @@ -568,8 +608,10 @@ struct Dht::Search { for (auto& n : nodes) { auto ackIt = n->acked.find(vid); if (ackIt != n->acked.end()) { - if (ackIt->second.first) - ackIt->second.first->cancel(); + if (ackIt->second.req) + ackIt->second.req->cancel(); + if (ackIt->second.refresh) + ackIt->second.refresh->cancel(); n->acked.erase(ackIt); } } @@ -586,7 +628,7 @@ struct Dht::Search { announce.emplace_back(Announce {permanent, value, created, callback}); for (auto& n : nodes) { n->probe_query.reset(); - n->acked[value->id].first.reset(); + n->acked[value->id].req.reset(); } } else { a_sr->permanent = permanent; @@ -594,7 +636,7 @@ struct Dht::Search { if (a_sr->value != value) { a_sr->value = value; for (auto& n : nodes) { - n->acked[value->id].first.reset(); + n->acked[value->id].req.reset(); n->probe_query.reset(); } } @@ -623,12 +665,11 @@ struct Dht::Search { } unsigned getNumberOfConsecutiveBadNodes() const { unsigned count = 0; - std::find_if(nodes.begin(), nodes.end(), [&count](const std::unique_ptr& sn) { + for (const auto& sn : nodes) { if (not sn->node->isExpired()) - return true; + break; ++count; - return false; - }); + } return count; } @@ -718,8 +759,8 @@ struct Dht::Search { for (auto& n : nodes) { auto ackIt = n->acked.find(it->value->id); if (ackIt != n->acked.end()) { - if (ackIt->second.first) - ackIt->second.first->cancel(); + if (ackIt->second.req) + ackIt->second.req->cancel(); n->acked.erase(ackIt); } } diff --git a/src/securedht.cpp b/src/securedht.cpp index e4dfc2239..daaa3fe0d 100644 --- a/src/securedht.cpp +++ b/src/securedht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -36,8 +36,8 @@ extern "C" { namespace dht { -SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf) -: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all) +SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf, IdentityAnnouncedCb iacb, const std::shared_ptr& l) +: DhtInterface(l), dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all) { if (!dht_) return; for (const auto& type : DEFAULT_TYPES) @@ -52,16 +52,17 @@ SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf) auto certId = certificate_->getId(); if (key_ and certId != key_->getPublicKey().getId()) throw DhtException("SecureDht: provided certificate doesn't match private key."); - - dht_->put(certId, Value { - CERTIFICATE_TYPE, - *certificate_, - 1 - }, [this, certId](bool ok) { - if (ok) + dht_->addOnConnectedCallback([this, certId, cb=std::move(iacb)]{ + dht_->put(certId, Value { + CERTIFICATE_TYPE, + *certificate_, + 1 + }, [this, certId, cb=std::move(cb)](bool ok) { + if (cb) cb(ok); if (logger_) - logger_->d(certId, "SecureDht: public key announced successfully"); - }, {}, true); + logger_->d(certId, "SecureDht: certificate announcement %s", ok ? "succeeded" : "failed"); + }, {}, true); + }); } } @@ -117,7 +118,7 @@ SecureDht::secureType(ValueType&& type) return type; } -const Sp +Sp SecureDht::getCertificate(const InfoHash& node) const { if (node == getId()) @@ -129,7 +130,7 @@ SecureDht::getCertificate(const InfoHash& node) const return it->second; } -const Sp +Sp SecureDht::getPublicKey(const InfoHash& node) const { if (node == getId()) @@ -141,7 +142,7 @@ SecureDht::getPublicKey(const InfoHash& node) const return it->second; } -const Sp +Sp SecureDht::registerCertificate(const InfoHash& node, const Blob& data) { Sp crt; @@ -199,8 +200,6 @@ SecureDht::findCertificate(const InfoHash& node, const std::function(false); dht_->get(node, [cb,node,found,this](const std::vector>& vals) { - if (*found) - return false; for (const auto& v : vals) { if (auto cert = registerCertificate(node, v->data)) { *found = true; @@ -211,7 +210,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function)>& cb) +SecureDht::findPublicKey(const InfoHash& node, const std::function)>& cb) { auto pk = getPublicKey(node); if (pk && *pk) { @@ -229,7 +228,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function crt) { + findCertificate(node, [=](const Sp& crt) { if (crt && *crt) { auto pk = std::make_shared(crt->getPublicKey()); if (*pk) { @@ -404,7 +403,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp val, callback(false, {}); return; } - findPublicKey(to, [=](const Sp& pk) { + findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp& pk) { if(!pk || !*pk) { if (callback) callback(false, {}); @@ -423,6 +422,26 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp val, }); } +void +SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp val, DoneCallback callback, bool permanent) +{ + if (not key_) { + if (callback) + callback(false, {}); + return; + } + if (logger_) + logger_->w("Encrypting data for PK: %s", pk.getLongId().to_c_str()); + try { + dht_->put(hash, encrypt(*val, pk), callback, time_point::max(), permanent); + } catch (const std::exception& e) { + if (logger_) + logger_->e("Error putting encrypted data: %s", e.what()); + if (callback) + callback(false, {}); + } +} + void SecureDht::sign(Value& v) const { diff --git a/src/storage.h b/src/storage.h index c41740f1e..bff04ab5c 100644 --- a/src/storage.h +++ b/src/storage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -37,19 +37,32 @@ class StorageBucket { storedValues_.emplace(expiration, std::pair(id, value.id)); } void erase(const InfoHash& id, const Value& value, time_point expiration) { - auto size = value.size(); - totalSize_ -= size; auto range = storedValues_.equal_range(expiration); for (auto rit = range.first; rit != range.second;) { if (rit->second.first == id && rit->second.second == value.id) { + totalSize_ -= value.size(); storedValues_.erase(rit); - break; + return; } else ++rit; } + // printf("StorageBucket::erase can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id); + } + void refresh(const InfoHash& id, const Value& value, time_point old_expiration, time_point expiration) { + auto range = storedValues_.equal_range(old_expiration); + for (auto rit = range.first; rit != range.second;) { + if (rit->second.first == id && rit->second.second == value.id) { + storedValues_.erase(rit); + storedValues_.emplace(expiration, std::pair(id, value.id)); + return; + } else + ++rit; + } + // printf("StorageBucket::refresh can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id); + insert(id, value, expiration); } size_t size() const { return totalSize_; } - std::pair getOldest() const { return storedValues_.begin()->second; } + std::pair getOldest() const { return storedValues_.empty() ? std::pair{} : storedValues_.begin()->second; } private: std::multimap> storedValues_; size_t totalSize_ {0}; @@ -59,6 +72,7 @@ struct ValueStorage { Sp data {}; time_point created {}; time_point expiration {}; + Sp expiration_job {}; StorageBucket* store_bucket {nullptr}; ValueStorage() {} @@ -74,7 +88,7 @@ struct Storage { size_t listener_token {1}; /* The maximum number of values we store for a given hash. */ - static constexpr unsigned MAX_VALUES {1024}; + static constexpr unsigned MAX_VALUES {64 * 1024}; /** * Changes caused by an operation on the storage. @@ -143,14 +157,18 @@ struct Storage { * @param vid The value id * @return time of the next expiration, time_point::max() if no expiration */ - time_point refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) { + std::pair + refresh(const InfoHash& id, const time_point& now, const Value::Id& vid, const TypeStore& types) { for (auto& vs : values) if (vs.data->id == vid) { vs.created = now; - vs.expiration = std::max(vs.expiration, now + types.getType(vs.data->type).expiration); - return vs.expiration; + auto oldExp = vs.expiration; + vs.expiration = std::max(oldExp, now + types.getType(vs.data->type).expiration); + if (vs.store_bucket) + vs.store_bucket->refresh(id, *vs.data, oldExp, vs.expiration); + return {&vs, vs.expiration}; } - return time_point::max(); + return {nullptr, time_point::max()}; } size_t listen(ValueCallback& cb, Value::Filter& f, const Sp& q); @@ -159,7 +177,7 @@ struct Storage { local_listeners.erase(token); } - StoreDiff remove(const InfoHash& id, Value::Id); + Sp remove(const InfoHash& id, Value::Id); std::pair>> expire(const InfoHash& id, time_point now); @@ -198,9 +216,9 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t if (it != values.end()) { /* Already there, only need to refresh */ it->created = created; - size_t size_old = it->data->size(); - ssize_t size_diff = size_new - (ssize_t)size_old; if (it->data != value) { + size_t size_old = it->data->size(); + ssize_t size_diff = size_new - (ssize_t)size_old; //DHT_LOG.DEBUG("Updating %s -> %s", id.toString().c_str(), value->toString().c_str()); // clear quota for previous value if (it->store_bucket) @@ -214,7 +232,6 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t total_size += size_diff; return std::make_pair(&(*it), StoreDiff{size_diff, 0, 0}); } - return std::make_pair(nullptr, StoreDiff{}); } else { //DHT_LOG.DEBUG("Storing %s -> %s", id.toString().c_str(), value->toString().c_str()); if (values.size() < MAX_VALUES) { @@ -225,11 +242,11 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t sb->insert(id, *value, expiration); return std::make_pair(&values.back(), StoreDiff{size_new, 1, 0}); } - return std::make_pair(nullptr, StoreDiff{}); } + return std::make_pair(nullptr, StoreDiff{}); } -Storage::StoreDiff +Sp Storage::remove(const InfoHash& id, Value::Id vid) { auto it = std::find_if (values.begin(), values.end(), [&](const ValueStorage& vr) { @@ -240,9 +257,12 @@ Storage::remove(const InfoHash& id, Value::Id vid) ssize_t size = it->data->size(); if (it->store_bucket) it->store_bucket->erase(id, *it->data, it->expiration); + if (it->expiration_job) + it->expiration_job->cancel(); total_size -= size; + auto value = it->data; values.erase(it); - return {-size, -1, 0}; + return value; } Storage::StoreDiff @@ -283,11 +303,13 @@ Storage::expire(const InfoHash& id, time_point now) }); std::vector> ret; ret.reserve(std::distance(r, values.end())); - ssize_t size_diff {}; + ssize_t size_diff {0}; std::for_each(r, values.end(), [&](const ValueStorage& v) { size_diff -= v.data->size(); if (v.store_bucket) v.store_bucket->erase(id, *v.data, v.expiration); + if (v.expiration_job) + v.expiration_job->cancel(); ret.emplace_back(std::move(v.data)); }); total_size += size_diff; diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index fb56365b2..1ebb1abd7 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -28,12 +28,6 @@ namespace dht { constexpr const size_t IO_THREADS_MAX {64}; -struct ThreadPool::ThreadState -{ - std::thread thread {}; - std::atomic_bool run {true}; -}; - ThreadPool& ThreadPool::computation() { @@ -67,14 +61,12 @@ void ThreadPool::run(std::function&& cb) { std::unique_lock l(lock_); - if (not running_) return; + if (not cb or not running_) return; // launch new thread if necessary if (not readyThreads_ && threads_.size() < maxThreads_) { - threads_.emplace_back(new ThreadState()); - auto& t = *threads_.back(); - t.thread = std::thread([&]() { - while (t.run) { + threads_.emplace_back(std::make_unique([this]() { + while (true) { std::function task; // pick task from queue @@ -82,10 +74,10 @@ ThreadPool::run(std::function&& cb) std::unique_lock l(lock_); readyThreads_++; cv_.wait(l, [&](){ - return not t.run or not tasks_.empty(); + return not running_ or not tasks_.empty(); }); readyThreads_--; - if (not t.run) + if (not running_) break; task = std::move(tasks_.front()); tasks_.pop(); @@ -93,14 +85,13 @@ ThreadPool::run(std::function&& cb) // run task try { - if (task) - task(); + task(); } catch (const std::exception& e) { // LOG_ERR("Exception running task: %s", e.what()); std::cerr << "Exception running task: " << e.what() << std::endl; } } - }); + })); } // push task to queue @@ -113,12 +104,8 @@ ThreadPool::run(std::function&& cb) void ThreadPool::stop() { - { - std::lock_guard l(lock_); - running_ = false; - } - for (auto& t : threads_) - t->run = false; + std::lock_guard l(lock_); + running_ = false; cv_.notify_all(); } @@ -127,7 +114,7 @@ ThreadPool::join() { stop(); for (auto& t : threads_) - t->thread.join(); + t->join(); threads_.clear(); } @@ -147,7 +134,7 @@ Executor::run_(std::function&& task) { current_++; std::weak_ptr w = shared_from_this(); - threadPool_.get().run([w,task] { + threadPool_.get().run([w,task = std::move(task)] { try { task(); } catch (const std::exception& e) { diff --git a/src/utils.cpp b/src/utils.cpp index be69eac0d..f29a9dd43 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -106,7 +106,7 @@ print_addr(const sockaddr* sa, socklen_t slen) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; - std::stringstream out; + std::ostringstream out; if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { if (sa->sa_family == AF_INET6) out << "[" << hbuf << "]"; diff --git a/src/value.cpp b/src/value.cpp index 6d50412c7..8252b56fe 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -163,7 +163,7 @@ Value::msgpack_unpack_body(const msgpack::object& o) throw msgpack::type_error(); crypto::PublicKey new_owner; new_owner.msgpack_unpack(*rowner); - owner = std::make_shared(std::move(new_owner)); + owner = std::make_shared(std::move(new_owner)); if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) { recipient = rrecipient->as(); } @@ -193,7 +193,7 @@ Value::Value(const Json::Value& json) if (jowner.isString()) { auto ownerStr = jowner.asString(); auto ownerBlob = std::vector(ownerStr.begin(), ownerStr.end()); - owner = std::make_shared(ownerBlob); + owner = std::make_shared(ownerBlob); } const auto& jto = json[VALUE_KEY_TO]; if (jto.isString()) @@ -406,8 +406,8 @@ void trim_str(std::string& str) { str = str.substr(first, last - first + 1); } -Select::Select(const std::string& q_str) { - std::istringstream q_iss {q_str}; +Select::Select(std::string_view q_str) { + std::istringstream q_iss {std::string(q_str)}; std::string token {}; q_iss >> token; @@ -431,8 +431,8 @@ Select::Select(const std::string& q_str) { } } -Where::Where(const std::string& q_str) { - std::istringstream q_iss {q_str}; +Where::Where(std::string_view q_str) { + std::istringstream q_iss {std::string(q_str)}; std::string token {}; q_iss >> token; if (token == "WHERE" or token == "where") { @@ -482,13 +482,13 @@ Query::msgpack_unpack(const msgpack::object& o) if (o.type != msgpack::type::MAP) throw msgpack::type_error(); - auto rfilters = findMapValue(o, "w"); /* unpacking filters */ + auto rfilters = findMapValue(o, "w"sv); /* unpacking filters */ if (rfilters) where.msgpack_unpack(*rfilters); else throw msgpack::type_error(); - auto rfield_selector = findMapValue(o, "s"); /* unpacking field selectors */ + auto rfield_selector = findMapValue(o, "s"sv); /* unpacking field selectors */ if (rfield_selector) select.msgpack_unpack(*rfield_selector); else @@ -496,10 +496,10 @@ Query::msgpack_unpack(const msgpack::object& o) } template -bool subset(std::vector fds, std::vector qfds) +bool subset(const std::vector& fds, const std::vector& qfds) { - for (auto& fd : fds) { - if (std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; }) == qfds.end()) + for (const auto& fd : fds) { + if (std::find_if(qfds.begin(), qfds.end(), [&fd](const T& _vfd) { return fd == _vfd; }) == qfds.end()) return false; } return true; diff --git a/src/value_cache.h b/src/value_cache.h index b168ee6ea..93265eed1 100644 --- a/src/value_cache.h +++ b/src/value_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ using CallbackQueue = std::list>; class ValueCache { public: - ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {}) + explicit ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {}) : callback(std::forward(cb)), syncCallback(std::move(scb)) { if (syncCallback) @@ -53,13 +53,12 @@ class ValueCache { CallbackQueue clear() { std::vector> expired_values; expired_values.reserve(values.size()); - for (const auto& v : values) + for (auto& v : values) expired_values.emplace_back(std::move(v.second.data)); values.clear(); CallbackQueue ret; if (not expired_values.empty() and callback) { - auto cb = callback; - ret.emplace_back([expired_values, cb]{ + ret.emplace_back([expired_values = std::move(expired_values), cb = callback]{ cb(expired_values, true); }); } @@ -103,24 +102,23 @@ class ValueCache { } CallbackQueue ret; if (not expired_values.empty() and callback) { - auto cb = callback; - ret.emplace_back([cb, expired_values]{ - if (cb) cb(expired_values, true); + ret.emplace_back([cb = callback, expired_values = std::move(expired_values)]{ + cb(expired_values, true); }); } return ret; } time_point onValues - (const std::vector>& values, + (const std::vector>& new_values, const std::vector& refreshed_values, const std::vector& expired_values, const TypeStore& types, const time_point& now) { CallbackQueue cbs; time_point ret = time_point::max(); - if (not values.empty()) - cbs.splice(cbs.end(), addValues(values, types, now)); + if (not new_values.empty()) + cbs.splice(cbs.end(), addValues(new_values, types, now)); for (const auto& vid : refreshed_values) refreshValue(vid, types, now); for (const auto& vid : expired_values) @@ -142,6 +140,10 @@ class ValueCache { } } + size_t size() const { + return values.size(); + } + private: // prevent copy ValueCache(const ValueCache&) = delete; @@ -180,11 +182,10 @@ class ValueCache { v->second.expiration = now + types.getType(v->second.data->type).expiration; } } - auto cb = callback; CallbackQueue ret; - if (not nvals.empty()) - ret.emplace_back([cb, nvals]{ - if (cb) cb(nvals, false); + if (callback and not nvals.empty()) + ret.emplace_back([cb = callback, nvals = std::move(nvals)]{ + cb(nvals, false); }); return ret; } diff --git a/tests/cryptotester.cpp b/tests/cryptotester.cpp index bf092c85e..a04f206e8 100644 --- a/tests/cryptotester.cpp +++ b/tests/cryptotester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Vsevolod Ivanov @@ -33,7 +33,7 @@ CryptoTester::setUp() { void CryptoTester::testSignatureEncryption() { auto key = dht::crypto::PrivateKey::generate(); - auto public_key = key.getPublicKey(); + const auto& public_key = key.getPublicKey(); std::vector data1 {5, 10}; std::vector data2(64 * 1024, 10); @@ -44,6 +44,10 @@ CryptoTester::testSignatureEncryption() { // check signature CPPUNIT_ASSERT(public_key.checkSignature(data1, signature1)); CPPUNIT_ASSERT(public_key.checkSignature(data2, signature2)); + signature1[7]++; + signature2[8]--; + CPPUNIT_ASSERT(!public_key.checkSignature(data1, signature1)); + CPPUNIT_ASSERT(!public_key.checkSignature(data2, signature2)); // encrypt data { @@ -161,6 +165,14 @@ void CryptoTester::testCertificateSerialNumber() CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end())); } +void CryptoTester::testOcsp() { + auto ca = dht::crypto::generateIdentity("Test CA"); + auto device = dht::crypto::generateIdentity("Test Device", ca); + auto ocspRequest = device.second->generateOcspRequest(ca.second->cert); + auto req = dht::crypto::OcspRequest((const uint8_t*)ocspRequest.first.data(), ocspRequest.first.size()); + CPPUNIT_ASSERT(ocspRequest.second == req.getNonce()); +} + void CryptoTester::tearDown() { diff --git a/tests/cryptotester.h b/tests/cryptotester.h index 04ce97ce9..06cf290d4 100644 --- a/tests/cryptotester.h +++ b/tests/cryptotester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Vsevolod Ivanov @@ -32,6 +32,7 @@ class CryptoTester : public CppUnit::TestFixture { CPPUNIT_TEST(testCertificateRevocation); CPPUNIT_TEST(testCertificateRequest); CPPUNIT_TEST(testCertificateSerialNumber); + CPPUNIT_TEST(testOcsp); CPPUNIT_TEST_SUITE_END(); public: @@ -59,6 +60,10 @@ class CryptoTester : public CppUnit::TestFixture { * Test certificate serial number extraction */ void testCertificateSerialNumber(); + /** + * Test OCSP + */ + void testOcsp(); }; } // namespace test diff --git a/tests/dhtproxytester.cpp b/tests/dhtproxytester.cpp index 5036c1287..4e6820c53 100644 --- a/tests/dhtproxytester.cpp +++ b/tests/dhtproxytester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Sébastien Blin * Vsevolod Ivanov @@ -71,7 +71,7 @@ DhtProxyTester::tearDown() { cv.notify_all(); }); std::unique_lock lk(cv_m); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 15s, [&]{ return done; })); serverProxy.reset(); nodeProxy.reset(); } @@ -289,4 +289,47 @@ DhtProxyTester::testFuzzy() CPPUNIT_ASSERT(value->data == mtu); } +void +DhtProxyTester::testShutdownStop() +{ + constexpr size_t N = 40000; + constexpr unsigned C = 100; + + // Arrange + auto key = dht::InfoHash::get("testShutdownStop"); + std::vector> values; + std::vector mtu; + mtu.reserve(N); + for (size_t i = 0; i < N; i++) + mtu.emplace_back((i % 2) ? 'T' : 'M'); + + std::atomic_uint callback_count {0}; + + // Act + for (size_t i = 0; i < C; i++) { + auto nodeTest = std::make_shared(); + nodeTest->run(0, clientConfig); + nodeTest->put(key, dht::Value(mtu), [&](bool ok) { + callback_count++; + }); + nodeTest->get(key, [&](const std::vector>& vals){ + values.insert(values.end(), vals.begin(), vals.end()); + return true; + },[&](bool ok){ + callback_count++; + }); + bool done = false; + std::condition_variable cv; + std::mutex cv_m; + nodeTest->shutdown([&]{ + std::lock_guard lk(cv_m); + done = true; + cv.notify_all(); + }, true); + std::unique_lock lk(cv_m); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; })); + } + CPPUNIT_ASSERT_EQUAL(2*C, callback_count.load()); +} + } // namespace test diff --git a/tests/dhtproxytester.h b/tests/dhtproxytester.h index 6937c3e9d..c0fa7b34f 100644 --- a/tests/dhtproxytester.h +++ b/tests/dhtproxytester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Sébastien Blin * @@ -36,6 +36,7 @@ class DhtProxyTester : public CppUnit::TestFixture { CPPUNIT_TEST(testResubscribeGetValues); CPPUNIT_TEST(testPutGet40KChars); CPPUNIT_TEST(testFuzzy); + CPPUNIT_TEST(testShutdownStop); CPPUNIT_TEST_SUITE_END(); public: @@ -68,6 +69,8 @@ class DhtProxyTester : public CppUnit::TestFixture { void testFuzzy(); + void testShutdownStop(); + private: dht::DhtRunner::Config clientConfig {}; dht::DhtRunner nodePeer; diff --git a/tests/dhtrunnertester.cpp b/tests/dhtrunnertester.cpp index 9f3d63ccb..78df451ab 100644 --- a/tests/dhtrunnertester.cpp +++ b/tests/dhtrunnertester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -19,10 +19,13 @@ #include "dhtrunnertester.h" +#include + #include #include #include using namespace std::chrono_literals; +using namespace std::literals; namespace test { CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester); @@ -32,9 +35,11 @@ DhtRunnerTester::setUp() { dht::DhtRunner::Config config; config.dht_config.node_config.max_peer_req_per_sec = -1; config.dht_config.node_config.max_req_per_sec = -1; + config.dht_config.node_config.max_store_size = -1; + config.dht_config.node_config.max_store_keys = -1; - node1.run(42222, config); - node2.run(42232, config); + node1.run(0, config); + node2.run(0, config); node2.bootstrap(node1.getBound()); } @@ -51,15 +56,23 @@ DhtRunnerTester::tearDown() { node1.shutdown(shutdown); node2.shutdown(shutdown); std::unique_lock lk(cv_m); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done == 2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return done == 2u; })); node1.join(); node2.join(); } void DhtRunnerTester::testConstructors() { - CPPUNIT_ASSERT(node1.getBoundPort() == 42222); - CPPUNIT_ASSERT(node2.getBoundPort() == 42232); + CPPUNIT_ASSERT(node1.getBoundPort()); + CPPUNIT_ASSERT_EQUAL(node1.getBoundPort(), node1.getBound().getPort()); + CPPUNIT_ASSERT(node2.getBoundPort()); + CPPUNIT_ASSERT_EQUAL(node2.getBoundPort(), node2.getBound().getPort()); + + dht::DhtRunner::Config config {}; + dht::DhtRunner::Context context {}; + dht::DhtRunner testNode; + testNode.run(config, std::move(context)); + CPPUNIT_ASSERT(testNode.getBoundPort()); } void @@ -83,32 +96,46 @@ DhtRunnerTester::testListen() { std::condition_variable cv; std::atomic_uint valueCount(0); unsigned putCount(0); - unsigned putOkCount(0); + unsigned putOkCount1(0); + unsigned putOkCount2(0); + unsigned putOkCount3(0); auto a = dht::InfoHash::get("234"); auto b = dht::InfoHash::get("2345"); auto c = dht::InfoHash::get("23456"); auto d = dht::InfoHash::get("234567"); - constexpr unsigned N = 256; + constexpr unsigned N = 2048; constexpr unsigned SZ = 56 * 1024; - auto ftokena = node1.listen(a, [&](const std::shared_ptr&) { - valueCount++; + auto ftokena = node1.listen(a, [&](const std::vector>& values, bool expired) { + if (expired) + valueCount -= values.size(); + else + valueCount += values.size(); return true; }); - auto ftokenb = node1.listen(b, [&](const std::shared_ptr&) { - valueCount++; + auto ftokenb = node1.listen(b, [&](const std::vector>& values, bool expired) { + if (expired) + valueCount -= values.size(); + else + valueCount += values.size(); return false; }); - auto ftokenc = node1.listen(c, [&](const std::shared_ptr&) { - valueCount++; + auto ftokenc = node1.listen(c, [&](const std::vector>& values, bool expired) { + if (expired) + valueCount -= values.size(); + else + valueCount += values.size(); return true; }); - auto ftokend = node1.listen(d, [&](const std::shared_ptr&) { - valueCount++; + auto ftokend = node1.listen(d, [&](const std::vector>& values, bool expired) { + if (expired) + valueCount -= values.size(); + else + valueCount += values.size(); return true; }); @@ -121,21 +148,21 @@ DhtRunnerTester::testListen() { node2.put(a, dht::Value("v1"), [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount++; + if (ok) putOkCount1++; cv.notify_all(); }); node2.put(b, dht::Value("v2"), [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount++; + if (ok) putOkCount2++; cv.notify_all(); }); auto bigVal = std::make_shared(); bigVal->data = mtu; - node2.put(c, bigVal, [&](bool ok) { + node2.put(c, std::move(bigVal), [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount++; + if (ok) putOkCount3++; cv.notify_all(); }); } @@ -143,7 +170,9 @@ DhtRunnerTester::testListen() { { std::unique_lock lk(mutex); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 3u; })); - CPPUNIT_ASSERT_EQUAL(N * 3u, putOkCount); + CPPUNIT_ASSERT_EQUAL(N, putOkCount1); + CPPUNIT_ASSERT_EQUAL(N, putOkCount2); + CPPUNIT_ASSERT_EQUAL(N, putOkCount3); } CPPUNIT_ASSERT(ftokena.valid()); @@ -167,6 +196,88 @@ DhtRunnerTester::testListen() { node1.cancelListen(d, tokend); } +void +DhtRunnerTester::testIdOps() { + std::mutex mutex; + std::condition_variable cv; + unsigned valueCount(0); + + dht::DhtRunner::Config config2; + config2.dht_config.node_config.max_peer_req_per_sec = -1; + config2.dht_config.node_config.max_req_per_sec = -1; + config2.dht_config.id = dht::crypto::generateIdentity(); + + dht::DhtRunner::Context context2; + context2.identityAnnouncedCb = [&](bool ok) { + CPPUNIT_ASSERT(ok); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + }; + + node2.join(); + node2.run(42232, config2, std::move(context2)); + node2.bootstrap(node1.getBound()); + + { + std::unique_lock lk(mutex); + CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 1; })); + } + + node1.findCertificate(node2.getId(), [&](const std::shared_ptr& crt){ + CPPUNIT_ASSERT(crt); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + }); + + { + std::unique_lock lk(mutex); + CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 2; })); + } + + dht::DhtRunner::Context context1; + context1.identityAnnouncedCb = [&](bool ok) { + CPPUNIT_ASSERT(ok); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + }; + + config2.dht_config.id = dht::crypto::generateIdentity(); + node1.join(); + node1.run(42222, config2, std::move(context1)); + node1.bootstrap(node2.getBound()); + + auto key = dht::InfoHash::get("key"); + node1.putEncrypted(key, node2.getId(), dht::Value("yo"), [&](bool ok){ + CPPUNIT_ASSERT(ok); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + }); + + node1.putEncrypted(key, node2.getPublicKey(), dht::Value("yo"), [&](bool ok){ + CPPUNIT_ASSERT(ok); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + }); + + node2.listen(key, [&](std::string&& value){ + CPPUNIT_ASSERT_EQUAL("yo"s, value); + std::lock_guard lk(mutex); + valueCount++; + cv.notify_all(); + return true; + }); + + { + std::unique_lock lk(mutex); + CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; })); + } +} + void DhtRunnerTester::testListenLotOfBytes() { std::mutex mutex; @@ -214,4 +325,39 @@ DhtRunnerTester::testListenLotOfBytes() { node3.cancelListen(foo, ftokenfoo.get()); } + +void +DhtRunnerTester::testMultithread() { + std::mutex mutex; + std::condition_variable cv; + unsigned putCount(0); + unsigned putOkCount(0); + + constexpr unsigned N = 2048; + + for (unsigned i=0; i lock(mutex); + putCount++; + if (ok) putOkCount++; + cv.notify_all(); + }); + node2.get(dht::InfoHash::get("123" + std::to_string(N-i-1)), [](const std::shared_ptr&){ + return true; + }, [&](bool ok) { + std::lock_guard lock(mutex); + putCount++; + if (ok) putOkCount++; + cv.notify_all(); + }); + }); + } + std::unique_lock lk(mutex); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == 2*N; })); + CPPUNIT_ASSERT_EQUAL(2*N, putOkCount); + +} + + } // namespace test diff --git a/tests/dhtrunnertester.h b/tests/dhtrunnertester.h index 1d2338205..ea0b93b0d 100644 --- a/tests/dhtrunnertester.h +++ b/tests/dhtrunnertester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -33,6 +33,7 @@ class DhtRunnerTester : public CppUnit::TestFixture { CPPUNIT_TEST(testGetPut); CPPUNIT_TEST(testListen); CPPUNIT_TEST(testListenLotOfBytes); + CPPUNIT_TEST(testIdOps); CPPUNIT_TEST_SUITE_END(); dht::DhtRunner node1 {}; @@ -58,10 +59,19 @@ class DhtRunnerTester : public CppUnit::TestFixture { * Test listen method */ void testListen(); + /** + * Test methods requiring a node identity + */ + void testIdOps(); /** * Test listen method with lot of datas */ void testListenLotOfBytes(); + /** + * Test multithread + */ + void testMultithread(); + }; } // namespace test diff --git a/tests/httptester.cpp b/tests/httptester.cpp index 2f2dc41ca..342b2b95d 100644 --- a/tests/httptester.cpp +++ b/tests/httptester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Vsevolod Ivanov * diff --git a/tests/httptester.h b/tests/httptester.h index 1f50af990..c31905759 100644 --- a/tests/httptester.h +++ b/tests/httptester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Vsevolod Ivanov * diff --git a/tests/infohashtester.cpp b/tests/infohashtester.cpp index 6245c93e2..ba9650268 100644 --- a/tests/infohashtester.cpp +++ b/tests/infohashtester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Sébastien Blin * diff --git a/tests/infohashtester.h b/tests/infohashtester.h index 75d9f402b..52c07acf4 100644 --- a/tests/infohashtester.h +++ b/tests/infohashtester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Sébastien Blin * diff --git a/tests/peerdiscoverytester.cpp b/tests/peerdiscoverytester.cpp index 3f36e44ee..a1dac8d01 100644 --- a/tests/peerdiscoverytester.cpp +++ b/tests/peerdiscoverytester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Mingrui Zhang * diff --git a/tests/peerdiscoverytester.h b/tests/peerdiscoverytester.h index f5bef8595..b27fe4fca 100644 --- a/tests/peerdiscoverytester.h +++ b/tests/peerdiscoverytester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Mingrui Zhang * diff --git a/tests/tests_runner.cpp b/tests/tests_runner.cpp index dc06c70ab..c54b01595 100644 --- a/tests/tests_runner.cpp +++ b/tests/tests_runner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/tests/threadpooltester.cpp b/tests/threadpooltester.cpp index 4295b87bb..b5ddbf6ab 100644 --- a/tests/threadpooltester.cpp +++ b/tests/threadpooltester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -21,6 +21,7 @@ #include "opendht/thread_pool.h" #include +#include namespace test { CPPUNIT_TEST_SUITE_REGISTRATION(ThreadPoolTester); @@ -47,7 +48,7 @@ ThreadPoolTester::testThreadPool() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); pool.join(); - CPPUNIT_ASSERT(count.load() == N); + CPPUNIT_ASSERT_EQUAL(N, count.load()); } void @@ -59,7 +60,7 @@ ThreadPoolTester::testExecutor() auto executor8 = std::make_shared(pool, 8); constexpr unsigned N = 64 * 1024; - std::atomic_uint count1 {0}; + unsigned count1 {0}; std::atomic_uint count4 {0}; std::atomic_uint count8 {0}; for (unsigned i=0; i * @@ -29,6 +29,7 @@ class ThreadPoolTester : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ThreadPoolTester); CPPUNIT_TEST(testThreadPool); CPPUNIT_TEST(testExecutor); + CPPUNIT_TEST(testContext); CPPUNIT_TEST_SUITE_END(); public: @@ -43,6 +44,7 @@ class ThreadPoolTester : public CppUnit::TestFixture { void testThreadPool(); void testExecutor(); + void testContext(); }; } // namespace test diff --git a/tests/valuetester.cpp b/tests/valuetester.cpp index 784bda4ab..90d4995f7 100644 --- a/tests/valuetester.cpp +++ b/tests/valuetester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tests/valuetester.h b/tests/valuetester.h index f14449dae..e71fa4439 100644 --- a/tests/valuetester.h +++ b/tests/valuetester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2e70c3b4a..b56507d0a 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,7 +1,9 @@ if (OPENDHT_SHARED) set (OPENDHT_LIBS opendht) + set (OPENDHT_C_LIBS opendht-c) else () set (OPENDHT_LIBS opendht-static) + set (OPENDHT_C_LIBS opendht-c-static) if (MSVC) set (MSC_COMPAT_SOURCES ${MSC_COMPAT_DIR}/wingetopt.c) endif () @@ -9,8 +11,8 @@ endif () function (configure_tool name extra_files) add_executable (${name} ${name}.cpp ${extra_files}) - target_link_libraries (${name} LINK_PUBLIC ${READLINE_LIBRARIES}) - target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS}) + add_dependencies(${name} ${OPENDHT_LIBS}) + target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS} ${READLINE_LIBRARIES}) if (MSVC) target_sources(${name} PRIVATE ${MSC_COMPAT_SOURCES}) target_include_directories (${name} PRIVATE ${MSC_COMPAT_DIR}) @@ -29,7 +31,9 @@ endif () if (OPENDHT_C) add_executable (dhtcnode dhtcnode.c) - target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES}) + add_dependencies(dhtcnode ${OPENDHT_C_LIBS}) + target_link_libraries (dhtcnode LINK_PUBLIC ${OPENDHT_C_LIBS} ${READLINE_LIBRARIES}) + target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c) endif () if (NOT DEFINED CMAKE_INSTALL_BINDIR) diff --git a/tools/Makefile.am b/tools/Makefile.am index a9c4b1835..c7a175f25 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,10 +4,17 @@ noinst_HEADERS = tools_common.h AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ dhtnode_SOURCES = dhtnode.cpp -dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ +dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ dhtchat_SOURCES = dhtchat.cpp -dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ +dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ dhtscanner_SOURCES = dhtscanner.cpp -dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ +dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ + +if ENABLE_C +bin_PROGRAMS += dhtcnode +dhtcnode_CFLAGS = -std=c11 -isystem @top_srcdir@/c -isystem @top_srcdir@/include +dhtcnode_SOURCES = dhtcnode.c +dhtcnode_LDFLAGS = -lopendht-c -lreadline -L@top_builddir@/c/.libs +endif diff --git a/tools/dhtchat.cpp b/tools/dhtchat.cpp index 66d455ce6..a1b2c0618 100644 --- a/tools/dhtchat.cpp +++ b/tools/dhtchat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/dhtcnode.c b/tools/dhtcnode.c index ab3a4b825..bb693f341 100644 --- a/tools/dhtcnode.c +++ b/tools/dhtcnode.c @@ -1,20 +1,53 @@ -#include +/* + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Author : Adrien Béraud + * + * 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 . + */ + +#include #include #include #include #include +#include + +#include +#include +#include #include struct op_context { dht_runner* runner; - int d; + atomic_bool stop; +}; +struct listen_context { + dht_runner* runner; + dht_op_token* token; + size_t count; }; bool dht_value_callback(const dht_value* value, bool expired, void* user_data) { + struct listen_context* ctx = (struct listen_context*) user_data; + if (expired) + ctx->count--; + else + ctx->count++; dht_data_view data = dht_value_get_data(value); - printf("Value callback %s: %.*s.\n", expired ? "expired" : "new", (int)data.size, data.data); + printf("Listen: %s value: %.*s (total %zu).\n", expired ? "expired" : "new", (int)data.size, data.data, ctx->count); return true; } @@ -26,16 +59,30 @@ bool dht_get_callback(const dht_value* value, void* user_data) return true; } -void dht_done_callback(bool ok, void* user_data) +void dht_get_done_callback(bool ok, void* user_data) +{ + dht_runner* runner = (dht_runner*)user_data; + printf("Get completed: %s\n", ok ? "success !" : "failure :-("); +} + +void dht_put_done_callback(bool ok, void* user_data) { dht_runner* runner = (dht_runner*)user_data; - printf("Done callback. %s\n", ok ? "Success !" : "Failure :-("); + printf("Put completed: %s\n", ok ? "success !" : "failure :-("); } -void op_context_free(void* user_data) +void dht_shutdown_callback(void* user_data) { + printf("Stopped.\n"); struct op_context* ctx = (struct op_context*)user_data; - printf("op_context_free %d.\n", ctx->d); + atomic_store(&ctx->stop, true); +} + +void listen_context_free(void* user_data) +{ + printf("listen_context_free.\n"); + struct listen_context* ctx = (struct listen_context*)user_data; + dht_op_token_delete(ctx->token); free(ctx); } @@ -60,66 +107,181 @@ char* print_addr(const struct sockaddr* addr) { return s; } -int main() -{ - dht_identity id = dht_identity_generate("testNode", NULL); - dht_infohash cert_id = dht_certificate_get_id(id.certificate); - printf("Cert ID: %s\n", dht_infohash_print(&cert_id)); - - dht_publickey* pk = dht_certificate_get_publickey(id.certificate); - dht_infohash pk_id = dht_publickey_get_id(pk); - printf("PK ID: %s\n", dht_infohash_print(&pk_id)); - dht_publickey_delete(pk); - - pk = dht_privatekey_get_publickey(id.privatekey); - pk_id = dht_publickey_get_id(pk); - printf("Key ID: %s\n", dht_infohash_print(&pk_id)); - dht_publickey_delete(pk); - - dht_identity_delete(&id); +struct dht_params { + bool help; + bool version; + bool generate_identity; + bool service; + bool peer_discovery; + bool log; + const char* bootstrap; + unsigned network; + in_port_t port; +}; - dht_runner* runner = dht_runner_new(); - dht_runner_run(runner, 4040); +static const struct option long_options[] = { + {"help", no_argument , NULL, 'h'}, + {"port", required_argument, NULL, 'p'}, + {"net", required_argument, NULL, 'n'}, + {"bootstrap", required_argument, NULL, 'b'}, + {"identity", no_argument , NULL, 'i'}, + {"verbose", no_argument , NULL, 'v'}, + {"service", no_argument , NULL, 's'}, + {"peer-discovery", no_argument , NULL, 'D'}, + {"no-rate-limit", no_argument , NULL, 'U'}, + {"persist", required_argument, NULL, 'f'}, + {"logfile", required_argument, NULL, 'l'}, + {"syslog", no_argument , NULL, 'L'}, + {"version", no_argument , NULL, 'V'}, + {NULL, 0 , NULL, 0} +}; - dht_infohash h; - dht_infohash_random(&h); +struct dht_params +parse_args(int argc, char **argv) { + struct dht_params params; + memset(¶ms, 0, sizeof params); + int opt; + while ((opt = getopt_long(argc, argv, "hisvDp:n:b:f:l:", long_options, NULL)) != -1) { + switch (opt) { + case 'p': { + int port_arg = atoi(optarg); + if (port_arg >= 0 && port_arg < 0x10000) + params.port = port_arg; + } + break; + case 'D': + params.peer_discovery = true; + break; + case 'n': + params.network = strtoul(optarg, NULL, 0); + break; + case 'b': + params.bootstrap = (optarg[0] == '=') ? optarg+1 : optarg; + break; + case 'h': + params.help = true; + break; + case 'v': + params.log = true; + break; + case 'i': + params.generate_identity = true; + break; + case 's': + params.service = true; + break; + case 'V': + params.version = true; + break; + default: + break; + } + } + return params; +} - printf("random hash: %s\n", dht_infohash_print(&h)); +dht_infohash parse_key(const char* key_str) { + dht_infohash key; + dht_infohash_from_hex_null(&key, key_str); + if (dht_infohash_is_zero(&key)) { + dht_infohash_get_from_string(&key, key_str); + printf("Using h(%s) = %s\n", key_str, dht_infohash_print(&key)); + } + return key; +} - // Put data - const char* data_str = "yo, this is some data"; - dht_value* val = dht_value_new(data_str, strlen(data_str)); - dht_runner_put(runner, &h, val, dht_done_callback, runner, false); - dht_value_unref(val); +int main(int argc, char **argv) +{ + struct dht_params params = parse_args(argc, argv); - // Get data - dht_runner_get(runner, &h, dht_get_callback, dht_done_callback, runner); + if (params.version) { + printf("OpenDHT version %s\n", dht_version()); + return EXIT_SUCCESS; + } - // Listen for data - struct op_context* ctx = malloc(sizeof(struct op_context)); - ctx->runner = runner; - ctx->d = 42; - dht_op_token* token = dht_runner_listen(runner, &h, dht_value_callback, op_context_free, ctx); + dht_runner* runner = dht_runner_new(); + dht_runner_config dht_config; + dht_runner_config_default(&dht_config); + dht_config.peer_discovery = params.peer_discovery; // Look for other peers on the network + dht_config.peer_publish = params.peer_discovery; // Publish our own peer info + dht_config.dht_config.node_config.network = params.network; + dht_config.log = params.log; + dht_runner_run_config(runner, params.port, &dht_config); - sleep(1); + if (params.bootstrap) { + printf("Bootstrap using %s\n", params.bootstrap); + dht_runner_bootstrap(runner, params.bootstrap, NULL); + } - dht_runner_bootstrap(runner, "bootstrap.jami.net", NULL); + char cmd[64]; + char arg[64]; + char value[256]; + dht_infohash key; + while (true) { + const char* line_read = readline("> "); + if (!line_read) + break; + if (!*line_read) + continue; + add_history(line_read); - sleep(2); + memset(cmd, 0, sizeof cmd); + memset(arg, 0, sizeof arg); + memset(value, 0, sizeof value); + sscanf(line_read, "%64s %64s %256s", cmd, arg, value); - struct sockaddr** addrs = dht_runner_get_public_address(runner); - for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) { - struct sockaddr* addr = *addrIt; - char* addr_str = print_addr(addr); - free(addr); - printf("Found public address: %s\n", addr_str); - free(addr_str); + if (!strcmp(cmd, "la")) { + struct sockaddr** addrs = dht_runner_get_public_address(runner); + if (addrs) { + for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) { + struct sockaddr* addr = *addrIt; + char* addr_str = print_addr(addr); + free(addr); + printf("Found public address: %s\n", addr_str); + free(addr_str); + } + free(addrs); + } + continue; + } + else if (!strcmp(cmd, "ll")) { + dht_infohash key = dht_runner_get_node_id(runner); + printf("DHT node %s running on port %u\n", dht_infohash_print(&key), dht_runner_get_bound_port(runner, AF_INET)); + continue; + } + else if (!strcmp(cmd, "g")) { + key = parse_key(arg); + dht_runner_get(runner, &key, dht_get_callback, dht_get_done_callback, runner); + } + else if (!strcmp(cmd, "l")) { + key = parse_key(arg); + struct listen_context* ctx = malloc(sizeof(struct listen_context)); + ctx->runner = runner; + ctx->count = 0; + ctx->token = dht_runner_listen(runner, &key, dht_value_callback, listen_context_free, ctx); + } + else if (!strcmp(cmd, "p")) { + key = parse_key(arg); + dht_value* val = dht_value_new_from_string(value); + dht_runner_put(runner, &key, val, dht_put_done_callback, runner, true); + dht_value_unref(val); + } + else { + printf("Unkown command: %s\n", cmd); + } } - free(addrs); - dht_runner_cancel_listen(runner, &h, token); - dht_op_token_delete(token); + // Graceful shutdown + printf("Stopping…\n"); + struct op_context ctx; + ctx.runner = runner; + atomic_init(&ctx.stop, false); + dht_runner_shutdown(runner, dht_shutdown_callback, &ctx); + // Wait until shutdown callback is called + while (!atomic_load(&ctx.stop)) { + usleep(10000); + } dht_runner_delete(runner); - return 0; + return EXIT_SUCCESS; } diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index 8b8adb7b7..3fde3d853 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Authors: Adrien Béraud * Simon Désaulniers @@ -146,6 +146,7 @@ void cmd_loop(std::shared_ptr& node, dht_params& params node->getNodeInfo([&](const std::shared_ptr& nodeInfo) { print_node_info(*nodeInfo); std::cout << nodeInfo->ongoing_ops << " ongoing operations" << std::endl; + std::cout << "Storage has " << nodeInfo->storage_values << " values, using " << (nodeInfo->storage_size/1024) << " KB" << std::endl; std::cout << "IPv4 stats:" << std::endl; std::cout << nodeInfo->ipv4.toString() << std::endl; std::cout << "IPv6 stats:" << std::endl; @@ -156,7 +157,7 @@ void cmd_loop(std::shared_ptr& node, dht_params& params if (auto stats = proxy.second->stats()) std::cout << " " << stats->toString() << std::endl; else - std::cout << " (stats not available yet)" << std::endl; + std::cout << " (stats not available yet)" << std::endl; } #endif }); @@ -327,15 +328,17 @@ void cmd_loop(std::shared_ptr& node, dht_params& params if (op == "g") { std::string rem; std::getline(iss, rem); - node->get(id, [start](const std::vector>& values) { + auto total = std::make_shared(); + node->get(id, [start, total](const std::vector>& values) { auto now = std::chrono::high_resolution_clock::now(); - std::cout << "Get: found " << values.size() << " value(s) after " << print_duration(now-start) << std::endl; + (*total) += values.size(); + std::cout << "Get: found " << values.size() << " value(s) after " << print_duration(now-start) << " (total " << *total << ')' << std::endl; for (const auto& value : values) std::cout << "\t" << *value << std::endl; return true; - }, [start](bool ok) { + }, [start, total](bool ok) { auto end = std::chrono::high_resolution_clock::now(); - std::cout << "Get: " << (ok ? "completed" : "failure") << ", took " << print_duration(end-start) << std::endl; + std::cout << "Get: " << (ok ? "completed" : "failure") << ", took " << print_duration(end-start) << " (total " << *total << ')' << std::endl; }, {}, dht::Where {rem}); } else if (op == "q") { @@ -356,8 +359,13 @@ void cmd_loop(std::shared_ptr& node, dht_params& params else if (op == "l") { std::string rem; std::getline(iss, rem); - auto token = node->listen(id, [](const std::vector>& values, bool expired) { - std::cout << "Listen: found " << values.size() << " values" << (expired ? " expired" : "") << std::endl; + auto total = std::make_shared(); + auto token = node->listen(id, [total](const std::vector>& values, bool expired) { + if (expired) + (*total) -= values.size(); + else + (*total) += values.size(); + std::cout << "Listen: found " << values.size() << " values" << (expired ? " expired" : "") << " (total " << *total << ')' << std::endl; for (const auto& value : values) std::cout << "\t" << *value << std::endl; return true; @@ -467,7 +475,7 @@ void cmd_loop(std::shared_ptr& node, dht_params& params << " hash: " << p.hash() << std::endl; std::cout << " entries:" << std::endl; for (const auto& v : vals) - std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl; + std::cout << " " << v->first.toString() << "[vid: " << std::hex << v->second << std::dec << "]" << std::endl; }, [start](bool ok) { auto end = std::chrono::high_resolution_clock::now(); diff --git a/tools/dhtscanner.cpp b/tools/dhtscanner.cpp index 66006398b..0f7750fdf 100644 --- a/tools/dhtscanner.cpp +++ b/tools/dhtscanner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/durl.cpp b/tools/durl.cpp index 368b0ef8f..7aaa740f6 100644 --- a/tools/durl.cpp +++ b/tools/durl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Authors: Adrien Béraud * diff --git a/tools/perftest.cpp b/tools/perftest.cpp index 59faf7ac3..4ef6a866f 100644 --- a/tools/perftest.cpp +++ b/tools/perftest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -102,7 +102,7 @@ benchPingPong(unsigned netSize, unsigned n_parallel) { auto start = clock::now(); - for (unsigned i=0; i # # This program is free software; you can redistribute it and/or modify diff --git a/tools/tools_common.h b/tools/tools_common.h index dfe6bd3ed..c12361720 100644 --- a/tools/tools_common.h +++ b/tools/tools_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 Savoir-faire Linux Inc. + * Copyright (C) 2014-2022 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Author: Sébastien Blin From 82689f6f8b428be9290a1cb3a9872db233663df7 Mon Sep 17 00:00:00 2001 From: Lucas Dias Date: Tue, 10 Dec 2024 20:34:23 -0300 Subject: [PATCH 2/2] Revert "network_engine::process could throw an exception in message type MessageType::ValueUpdate" This reverts commit b21e9228f565a66fbb1a7d6ffc614b6f48924f65. --- .devcontainer/devcontainer.json | 12 - .github/workflows/ccpp.yml | 50 +--- .github/workflows/clang-analyzer.yml | 35 --- .gitignore | 5 - .gitmodules | 4 + .travis.yml | 67 +++++ .vscode/launch.json | 54 ---- .vscode/tasks.json | 44 --- CMakeLists.txt | 121 +++++--- Makefile.am | 4 - README.md | 14 +- argon2 | 1 + autogen.sh | 1 + c/Makefile.am | 12 - c/opendht.cpp | 171 +++-------- c/opendht_c.h | 40 +-- cmake/CheckAtomic.cmake | 156 +++++----- cmake/DetermineGCCCompatible.cmake | 13 - cmake/FindMsgpack.cmake | 64 ++++ configure.ac | 47 ++- docker/Dockerfile | 16 +- docker/DockerfileBionic | 19 +- docker/DockerfileDeps | 13 +- docker/DockerfileDepsBionic | 10 +- docker/DockerfileDepsLlvm | 16 +- docker/DockerfileLlvm | 16 +- docker/DockerfileTravis | 9 + docker/DockerfileTravisLlvm | 7 + docker/DockerfileTravisProxy | 4 + include/opendht.h | 2 +- include/opendht/callbacks.h | 26 +- include/opendht/crypto.h | 62 +--- include/opendht/default_types.h | 14 +- include/opendht/dht.h | 31 +- include/opendht/dht_interface.h | 14 +- include/opendht/dht_proxy_client.h | 28 +- include/opendht/dht_proxy_server.h | 3 +- include/opendht/dhtrunner.h | 57 ++-- include/opendht/http.h | 14 +- include/opendht/indexation/pht.h | 4 +- include/opendht/infohash.h | 63 ++-- include/opendht/log.h | 2 +- include/opendht/log_enable.h | 2 +- include/opendht/network_engine.h | 25 +- include/opendht/network_utils.h | 4 +- include/opendht/node.h | 2 +- include/opendht/node_cache.h | 2 +- include/opendht/peer_discovery.h | 2 +- include/opendht/proxy.h | 2 +- include/opendht/rate_limiter.h | 2 +- include/opendht/rng.h | 2 +- include/opendht/routing_table.h | 2 +- include/opendht/scheduler.h | 31 +- include/opendht/securedht.h | 31 +- include/opendht/sockaddr.h | 14 +- include/opendht/thread_pool.h | 80 +---- include/opendht/utils.h | 6 +- include/opendht/value.h | 47 ++- m4/ax_cxx_compile_stdcxx.m4 | 64 +--- python/opendht.pyx | 32 +- python/opendht_cpp.pxd | 22 +- python/setup.py.in | 6 +- python/tools/benchmark.py | 2 +- python/tools/dht/network.py | 2 +- python/tools/dht/tests.py | 2 +- python/tools/dht/virtual_network_builder.py | 2 +- python/tools/dhtcluster.py | 2 +- python/tools/http_server.py | 2 +- python/tools/network_monitor.py | 2 +- python/tools/pingpong.py | 2 +- python/tools/scanner.py | 2 +- rust/examples/dhtnode.rs | 2 +- rust/src/blob.rs | 2 +- rust/src/crypto.rs | 2 +- rust/src/dhtrunner.rs | 2 +- rust/src/ffi.rs | 2 +- rust/src/infohash.rs | 2 +- rust/src/lib.rs | 2 +- rust/src/pkid.rs | 2 +- rust/src/value.rs | 2 +- src/Makefile.am | 29 +- src/base64.cpp | 2 +- src/base64.h | 2 +- src/callbacks.cpp | 18 +- src/compat/msvc/unistd.h | 2 +- src/compat/os_cert.cpp | 24 +- src/compat/os_cert.h | 2 +- src/crypto.cpp | 262 +++++----------- src/default_types.cpp | 2 +- src/dht.cpp | 309 ++++++++----------- src/dht_proxy_client.cpp | 49 ++- src/dht_proxy_server.cpp | 121 +++++--- src/dhtrunner.cpp | 314 +++++++------------- src/http.cpp | 69 +---- src/indexation/pht.cpp | 2 +- src/infohash.cpp | 8 +- src/listener.h | 2 +- src/log.cpp | 6 +- src/net.h | 2 +- src/network_engine.cpp | 93 +++--- src/network_utils.cpp | 2 +- src/node.cpp | 7 +- src/node_cache.cpp | 2 +- src/op_cache.cpp | 4 +- src/op_cache.h | 24 +- src/parsed_message.h | 93 +++--- src/peer_discovery.cpp | 11 +- src/request.h | 6 +- src/rng.cpp | 2 +- src/routing_table.cpp | 2 +- src/search.h | 125 +++----- src/securedht.cpp | 61 ++-- src/storage.h | 58 ++-- src/thread_pool.cpp | 37 ++- src/utils.cpp | 4 +- src/value.cpp | 24 +- src/value_cache.h | 31 +- tests/cryptotester.cpp | 16 +- tests/cryptotester.h | 7 +- tests/dhtproxytester.cpp | 47 +-- tests/dhtproxytester.h | 5 +- tests/dhtrunnertester.cpp | 188 ++---------- tests/dhtrunnertester.h | 12 +- tests/httptester.cpp | 2 +- tests/httptester.h | 2 +- tests/infohashtester.cpp | 2 +- tests/infohashtester.h | 2 +- tests/peerdiscoverytester.cpp | 2 +- tests/peerdiscoverytester.h | 2 +- tests/tests_runner.cpp | 2 +- tests/threadpooltester.cpp | 28 +- tests/threadpooltester.h | 4 +- tests/valuetester.cpp | 2 +- tests/valuetester.h | 2 +- tools/CMakeLists.txt | 10 +- tools/Makefile.am | 13 +- tools/dhtchat.cpp | 2 +- tools/dhtcnode.c | 272 ++++------------- tools/dhtnode.cpp | 26 +- tools/dhtscanner.cpp | 2 +- tools/durl.cpp | 2 +- tools/perftest.cpp | 4 +- tools/proxy_loadtester.py | 2 +- tools/tools_common.h | 2 +- 144 files changed, 1511 insertions(+), 2719 deletions(-) delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .github/workflows/clang-analyzer.yml create mode 100644 .gitmodules create mode 100644 .travis.yml delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json create mode 160000 argon2 delete mode 100644 c/Makefile.am delete mode 100644 cmake/DetermineGCCCompatible.cmake create mode 100644 cmake/FindMsgpack.cmake create mode 100644 docker/DockerfileTravis create mode 100644 docker/DockerfileTravisLlvm create mode 100644 docker/DockerfileTravisProxy diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 9157472bd..000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "C++", - "build": { - "dockerfile": "../docker/DockerfileDepsLlvm", - }, - "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], - "settings": {}, - "extensions": [ - "ms-vscode.cpptools" - ], - "forwardPorts": [4222], -} diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 10e1f0a90..8e0321e89 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1,20 +1,24 @@ name: C/C++ CI -on: [push, pull_request] +on: [push] jobs: - build-ubuntu: - name: Ubuntu/GCC build + build: + runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v1 - name: deps run: | sudo apt install libncurses5-dev libreadline-dev nettle-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 + autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev - name: autogen run: ./autogen.sh + - name: argon2 + run: | + cd argon2 && make && sudo make install && cd .. - name: asio run: | wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \ @@ -28,39 +32,3 @@ jobs: run: make - name: make check run: make check - - build-macos: - name: macOS/Clang build - runs-on: macos-11 - steps: - - uses: actions/checkout@v3 - - name: deps - run: | - brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl http-parser cppunit - - - name: restinio - run: | - mkdir restinio && cd restinio - wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz - ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz - cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev - cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \ - -DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \ - -DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . - make -j8 && sudo make install - cd ../../.. && rm -rf restinio - - - name: cmake - run: | - mkdir build && cd build - export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH" - export LDFLAGS="-L/usr/local/opt/openssl@3/lib" - export CPPFLAGS="-I/usr/local/opt/openssl@3/include" - export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig" - cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \ - -DOPENDHT_C=On -DOPENDHT_TESTS=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \ - -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On - - - name: make - run: cd build && make - diff --git a/.github/workflows/clang-analyzer.yml b/.github/workflows/clang-analyzer.yml deleted file mode 100644 index a86372284..000000000 --- a/.github/workflows/clang-analyzer.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Clang Static Analysis -on: - push -jobs: - clang-analyzer: - name: Clang Static Analysis - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: deps - run: | - sudo apt install libncurses5-dev libreadline-dev nettle-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: restinio - run: | - mkdir restinio && cd restinio \ - && wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \ - && 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: | - mkdir build && cd build && \ - cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DOPENDHT_C=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off -DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On - - name: scan-build - run: cd build && scan-build --status-bugs make diff --git a/.gitignore b/.gitignore index fd367eaaa..016541716 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,6 @@ *.exe *.out *.app -**/dhtnode -**/dhtchat -**/dhtscanner # Autotools /ac @@ -76,5 +73,3 @@ doc/Doxyfile # build dir build -build_dev -.DS_Store diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..ef38b69b0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "argon2"] + path = argon2 + url = https://github.com/P-H-C/phc-winner-argon2 + ignore = dirty diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..2c45aa22d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,67 @@ +dist: xenial +sudo: required + +services: + - docker + +language: cpp + +env: + matrix: + - OPENDHT_TEST_JOB="opendht.classic" + - OPENDHT_TEST_JOB="opendht.llvm" + - OPENDHT_TEST_JOB="opendht.proxyserver" + - OPENDHT_TEST_JOB="opendht.proxyclient" + - OPENDHT_TEST_JOB="opendht.push" + +before_install: + - | + if [[ "$OPENDHT_TEST_JOB" == *"opendht.classic"* ]]; then + docker pull aberaud/opendht-deps-bionic; + fi + if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then + docker pull aberaud/opendht-deps; + fi + if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then + docker pull aberaud/opendht-deps-llvm + fi + +script: + - | + # classic build + if [[ "$OPENDHT_TEST_JOB" == *"opendht.classic"* ]]; then + docker build -t opendht -f docker/DockerfileTravis .; + fi + + - | + # proxy builds + if [[ "$OPENDHT_TEST_JOB" != *"opendht.llvm"* ]] && [[ "$OPENDHT_TEST_JOB" != *"opendht.classic"* ]]; then + docker build -t opendht-proxy -f docker/DockerfileTravisProxy .; + options='-DOPENDHT_SANITIZE=On '; + if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyserver"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then + options+='-DOPENDHT_PROXY_SERVER=ON '; + else + options+='-DOPENDHT_PROXY_SERVER=OFF '; + fi + if [[ "$OPENDHT_TEST_JOB" == *"opendht.proxyclient"* ]] || [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then + options+='-DOPENDHT_PROXY_CLIENT=ON '; + else + options+='-DOPENDHT_PROXY_CLIENT=OFF '; + fi + if [[ "$OPENDHT_TEST_JOB" == *"opendht.push"* ]]; then + options+='-DOPENDHT_PUSH_NOTIFICATIONS=ON '; + else + options+='-DOPENDHT_PUSH_NOTIFICATIONS=OFF '; + fi + docker run opendht-proxy /bin/sh -c "cd /root/opendht && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=ON -DOPENDHT_LTO=ON -DOPENDHT_TESTS=ON $options .. && make -j8 && ./opendht_unit_tests && make install"; + fi + + - | + # llvm build + if [[ "$OPENDHT_TEST_JOB" == *"opendht.llvm"* ]]; then + docker build -f docker/DockerfileTravisLlvm . + fi + +notifications: + email: + - adrien.beraud@savoirfairelinux.com diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 24364e781..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "dhtnode", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build_dev/tools/dhtnode", - "args": ["-v", "-p", "4222"], - "cwd": "${workspaceFolder}/build_dev", - "environment": [], - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "build", - "linux": { - "MIMode": "gdb", - "externalConsole": false, - }, - "osx": { - "MIMode": "lldb", - "externalConsole": true, - }, - }, - { - "name": "tests", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build_dev/opendht_unit_tests", - "cwd": "${workspaceFolder}/build_dev", - "environment": [], - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "build", - "linux": { - "MIMode": "gdb", - "externalConsole": false, - }, - "osx": { - "MIMode": "lldb", - "externalConsole": true, - }, - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index f7cfc5f40..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceRoot}/build_dev" - }, - "command": "make", - "args": ["-j4"], - "dependsOn": "cmake" - }, - { - "label": "cmake", - "type": "shell", - "options": { - "cwd": "${workspaceRoot}/build_dev" - }, - "command": "cmake", - "args": [ - "${workspaceRoot}", - "-DCMAKE_BUILD_TYPE=Debug", - "-DOPENDHT_PROXY_CLIENT=On", - "-DOPENDHT_PROXY_SERVER=On", - "-DOPENDHT_TESTS=On", - "-DOPENDHT_C=On" - ], - "dependsOn": "builddir" - }, - { - "label": "builddir", - "type": "shell", - "options": { - "cwd": "${workspaceRoot}" - }, - "command": "mkdir", - "args": [ - "-p", - "${workspaceRoot}/build_dev" - ] - }, - ] -} diff --git a/CMakeLists.txt b/CMakeLists.txt index 69b957e9d..9fff55d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,4 @@ -cmake_minimum_required (VERSION 3.10) -if(POLICY CMP0065) - cmake_policy(SET CMP0065 NEW) -endif() -if(POLICY CMP0069) - cmake_policy(SET CMP0069 NEW) -endif() -if(POLICY CMP0073) - cmake_policy(SET CMP0073 NEW) -endif() -if(POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) -endif() +cmake_minimum_required (VERSION 3.1) project (opendht) include(CMakePackageConfigHelpers) @@ -19,7 +7,7 @@ include(FindPkgConfig) include(cmake/CheckAtomic.cmake) set (opendht_VERSION_MAJOR 2) -set (opendht_VERSION_MINOR 4.3) +set (opendht_VERSION_MINOR 1.9) set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR}) set (PACKAGE_VERSION ${opendht_VERSION}) set (VERSION "${opendht_VERSION}") @@ -32,12 +20,15 @@ option (OPENDHT_PYTHON "Build Python bindings" OFF) option (OPENDHT_TOOLS "Build DHT tools" ON) option (OPENDHT_SYSTEMD "Install systemd module" OFF) option (OPENDHT_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file") +option (OPENDHT_ARGON2 "Use included argon2 sources" OFF) +option (OPENDHT_LTO "Build with LTO" OFF) option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF) option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF) option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF) option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF) option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF) option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON) +option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF) CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON) option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON) option (OPENDHT_INDEX "Build DHT indexation feature" OFF) @@ -49,22 +40,28 @@ find_package(Doxygen) option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) # Dependencies -if (NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) - link_libraries (atomic) -endif () - list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if (NOT MSVC) set (THREADS_PREFER_PTHREAD_FLAG TRUE) find_package (Threads) find_package (PkgConfig REQUIRED) find_package (GnuTLS 3.3 REQUIRED) - pkg_search_module (Nettle REQUIRED nettle) - find_package (msgpack REQUIRED) + pkg_search_module (Nettle nettle) + find_package (Msgpack 1.2 REQUIRED) if (OPENDHT_TOOLS) find_package (Readline 6 REQUIRED) endif () - pkg_search_module(argon2 REQUIRED libargon2) + if (NOT OPENDHT_ARGON2) + pkg_search_module(argon2 libargon2) + if (argon2_FOUND) + message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")") + link_directories (${argon2_LIBRARY_DIRS}) + else () + message("Argon2 not found, using included version.") + set(OPENDHT_ARGON2 ON) + endif() + endif () + pkg_search_module(Jsoncpp jsoncpp) if (Jsoncpp_FOUND) add_definitions(-DOPENDHT_JSONCPP) @@ -74,11 +71,8 @@ if (NOT MSVC) ) endif() - if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY) - find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED) - endif () - if (OPENDHT_HTTP) + find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED) find_package(Restinio REQUIRED) find_library(FMT_LIBRARY fmt) add_library(fmt SHARED IMPORTED) @@ -98,6 +92,9 @@ if (NOT MSVC) message(SEND_ERROR "OpenSSL is required for DHT proxy as specified") endif() endif() + if (OPENDHT_PROXY_HTTP_PARSER_FORK) + add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK) + endif() else () set(OPENDHT_PROXY_OPENSSL OFF) endif () @@ -128,7 +125,7 @@ if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY) endif() # Build flags -set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD 14) set (CMAKE_CXX_STANDARD_REQUIRED on) if (NOT MSVC) @@ -146,7 +143,7 @@ else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_MSC_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") endif () -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT") if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -157,6 +154,15 @@ if (OPENDHT_LOG) else () add_definitions(-DOPENDHT_LOG=false) endif() +if (OPENDHT_LTO AND NOT MSVC) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") + if (CMAKE_COMPILER_IS_GNUCC) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-linker-plugin") + set (CMAKE_AR "gcc-ar") + set (CMAKE_NM "gcc-nm") + set (CMAKE_RANLIB "gcc-ranlib") + endif () +endif () if (MSGPACK_INCLUDE_DIRS) include_directories (SYSTEM "${MSGPACK_INCLUDE_DIRS}") @@ -178,7 +184,6 @@ if (Jsoncpp_INCLUDE_DIRS) endif () link_directories (${Nettle_LIBRARY_DIRS}) link_directories (${Jsoncpp_LIBRARY_DIRS}) -link_directories (${argon2_LIBRARY_DIRS}) include_directories ( ./ include/ @@ -306,6 +311,23 @@ if (OPENDHT_HTTP) ) endif () +if(OPENDHT_ARGON2) + # make sure argon2 submodule is up to date and initialized + message("Initializing Argon2 submodule") + execute_process(COMMAND git submodule update --init) + + # add local argon2 files to build + list (APPEND opendht_SOURCES + argon2/src/argon2.c + argon2/src/core.c + argon2/src/blake2/blake2b.c + argon2/src/thread.c + argon2/src/ref.c + argon2/src/encoding.c + ) + include_directories(argon2/include/) +endif() + if (MSVC) list (APPEND opendht_HEADERS src/compat/msvc/unistd.h) endif () @@ -318,7 +340,11 @@ if (OPENDHT_STATIC) ${opendht_HEADERS} ) set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht") - target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) + if (OPENDHT_ARGON2) + target_include_directories(opendht-static SYSTEM PRIVATE argon2) + else () + target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) + endif () target_link_libraries(opendht-static PRIVATE ${argon2_LIBRARIES} PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES} @@ -383,43 +409,40 @@ if (OPENDHT_SHARED) set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib") set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION}) target_compile_definitions(opendht PRIVATE OPENDHT_BUILD) - target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) + if (OPENDHT_ARGON2) + target_include_directories(opendht SYSTEM PRIVATE argon2) + else () + target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES}) + target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS}) + endif () if (APPLE) target_link_libraries(opendht PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Jsoncpp_LIBRARIES} - ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES} + ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} SYSTEM "-framework CoreFoundation" "-framework Security") else () target_link_libraries(opendht PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES} ${Jsoncpp_LIBRARIES} - ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES}) + ${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}) endif () install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht) endif () if (OPENDHT_C) + add_library (opendht-c SHARED + c/opendht.cpp + c/opendht_c.h + ) + target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD) if (OPENDHT_SHARED) - add_library (opendht-c SHARED - c/opendht.cpp - c/opendht_c.h - ) - target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD) - target_link_libraries(opendht-c PRIVATE opendht) - install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c) - endif () - - if (OPENDHT_STATIC) - add_library (opendht-c-static STATIC - c/opendht.cpp - c/opendht_c.h - ) - target_link_libraries(opendht-c-static PRIVATE opendht-static) - install (TARGETS opendht-c-static DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c-static) + target_link_libraries(opendht-c opendht) + else () + target_link_libraries(opendht-c opendht-static) endif () # PkgConfig module @@ -428,8 +451,8 @@ if (OPENDHT_C) opendht-c.pc @ONLY ) + install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht-c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install (FILES c/opendht_c.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/opendht) endif () if (OPENDHT_TOOLS) diff --git a/Makefile.am b/Makefile.am index 498329ba2..7ba6efbb2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,10 +4,6 @@ SUBDIRS = SUBDIRS += src -if ENABLE_C -SUBDIRS += c -endif - if ENABLE_TOOLS SUBDIRS += tools endif diff --git a/README.md b/README.md index ee5377daa..34fb21b85 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ OpenDHT -A lightweight C++17 Distributed Hash Table implementation. +A lightweight C++14 Distributed Hash Table implementation. OpenDHT provides an easy to use distributed in-memory data store. Every node in the network can read and write values to the store. @@ -14,7 +14,7 @@ Values are distributed over the network, with redundancy. * High resilience to network disruption * Public key cryptography layer providing optional data signature and encryption (using GnuTLS) * IPv4 and IPv6 support - * Clean and powerful **C++17** map API + * Clean and powerful **C++14** map API * Bindings for **C, Rust & Python 3** * REST API with optional HTTP client+server with push notification support @@ -27,7 +27,7 @@ Build instructions: - * - * 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 . - */ - #include "opendht_c.h" - -#include -#include +#include "opendht.h" using ValueSp = std::shared_ptr; using PrivkeySp = std::shared_ptr; @@ -30,13 +10,6 @@ using CertSp = std::shared_ptr; extern "C" { #endif -#include - -const char* dht_version() -{ - return dht::version(); -} - // dht::InfoHash inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) { @@ -76,11 +49,7 @@ bool dht_infohash_is_zero(const dht_infohash* h) { } void dht_infohash_from_hex(dht_infohash* h, const char* dat) { - *h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat, HASH_LEN*2))); -} - -void dht_infohash_from_hex_null(dht_infohash* h, const char* dat) { - *h = dht_infohash_to_c(dht::InfoHash(std::string_view(dat))); + *h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2))); } const char* dht_pkid_print(const dht_pkid* h) { @@ -128,20 +97,10 @@ const char* dht_value_get_user_type(const dht_value* data) { return vsp->user_type.c_str(); } -void dht_value_set_user_type(dht_value* data, const char* user_type) { - (*reinterpret_cast(data))->user_type = user_type; -} - dht_value* dht_value_new(const uint8_t* data, size_t size) { return reinterpret_cast(new ValueSp(std::make_shared(data, size))); } -dht_value* dht_value_new_from_string(const char* str) { - ValueSp value = std::make_shared((const uint8_t*)str, strlen(str)); - value->user_type = "text/plain"; - return reinterpret_cast(new ValueSp(std::move(value))); -} - dht_value* dht_value_ref(const dht_value* v) { return reinterpret_cast(new ValueSp(*reinterpret_cast(v))); } @@ -185,13 +144,9 @@ bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, si dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) { const auto& pkey = *reinterpret_cast(pk); - try { - auto rdata = std::make_unique(); - *rdata = pkey->encrypt((const uint8_t*)data, data_size); - return (dht_blob*)rdata.release(); - } catch (...) { - return nullptr; - } + auto rdata = new dht::Blob; + *rdata = pkey->encrypt((const uint8_t*)data, data_size); + return (dht_blob*)rdata; } // dht::crypto::PrivateKey @@ -218,18 +173,7 @@ int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) { const auto& key = *reinterpret_cast(k); - return reinterpret_cast(new PubkeySp(key->getSharedPublicKey())); -} - -dht_blob* dht_privatekey_decrypt(const dht_privatekey* k, const char* data, size_t data_size) { - const auto& key = *reinterpret_cast(k); - try { - auto rdata = std::make_unique(); - *rdata = key->decrypt((const uint8_t*)data, data_size); - return (dht_blob*)rdata.release(); - } catch (...) { - return nullptr; - } + return reinterpret_cast(new PubkeySp(std::make_shared(key->getPublicKey()))); } void dht_privatekey_delete(dht_privatekey* pk) { @@ -303,7 +247,7 @@ void dht_runner_config_default(dht_runner_config* config) { } // dht::DhtRunner -dht_runner* dht_runner_new(void) { +dht_runner* dht_runner_new() { return reinterpret_cast(new dht::DhtRunner); } @@ -311,60 +255,39 @@ void dht_runner_delete(dht_runner* runner) { delete reinterpret_cast(runner); } -int dht_runner_run(dht_runner* r, in_port_t port) { +void dht_runner_run(dht_runner* r, in_port_t port) { auto runner = reinterpret_cast(r); - try { - runner->run(port, {}, true); - } catch(...) { - return ENOTCONN; - } - return 0; + runner->run(port, {}, true); } -int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) { +void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) { auto runner = reinterpret_cast(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.maintain_storage = conf->dht_config.node_config.maintain_storage; - config.dht_config.node_config.node_id = *reinterpret_cast(&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(conf->dht_config.id.privatekey); - - if (conf->dht_config.id.certificate) - config.dht_config.id.second = *reinterpret_cast(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.peer_discovery = conf->peer_discovery; - config.peer_publish = conf->peer_publish; - - dht::DhtRunner::Context context; - if (conf->log) { - context.logger = dht::log::getStdLogger(); - } - runner->run(port, config, std::move(context)); - } catch(...) { - return ENOTCONN; - } - return 0; -} - -void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len, dht_done_cb done_cb, void* cb_user_data) { + dht::DhtRunner::Config config; + 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(&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(conf->dht_config.id.privatekey); + + if (conf->dht_config.id.certificate) + config.dht_config.id.second = *reinterpret_cast(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.peer_discovery = conf->peer_discovery; + config.peer_publish = conf->peer_publish; + runner->run(port, config); +} + +void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) { auto runner = reinterpret_cast(r); - if (done_cb) { - runner->bootstrap(dht::SockAddr(addr, addr_len), [done_cb, cb_user_data](bool ok){ - done_cb(ok, cb_user_data); - }); - } else { - runner->bootstrap(dht::SockAddr(addr, addr_len)); - } + runner->bootstrap(dht::SockAddr(addr, addr_len)); } void dht_runner_bootstrap(dht_runner* r, const char* host, const char* service) { @@ -403,11 +326,8 @@ dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_ auto runner = reinterpret_cast(r); auto hash = reinterpret_cast(h); auto fret = new std::future; - *fret = runner->listen(*hash, [ - cb, - cb_user_data, - guard = done_cb ? std::make_shared(done_cb, cb_user_data) : std::shared_ptr{} - ](const std::vector>& values, bool expired) { + auto guard = done_cb ? std::make_shared(done_cb, cb_user_data) : std::shared_ptr{}; + *fret = runner->listen(*hash, [cb,cb_user_data, guard](const std::vector>& values, bool expired) { for (const auto& value : values) { if (not cb(reinterpret_cast(&value), expired, cb_user_data)) return false; @@ -473,17 +393,6 @@ void dht_runner_shutdown(dht_runner* r, dht_shutdown_cb done_cb, void* cb_user_d }); } -bool dht_runner_is_running(const dht_runner* r) { - if (not r) return false; - auto runner = reinterpret_cast(r); - return runner->isRunning(); -} - -in_port_t dht_runner_get_bound_port(const dht_runner* r, sa_family_t af) { - auto runner = reinterpret_cast(r); - return runner->getBoundPort(af); -} - dht_infohash dht_runner_get_node_id(const dht_runner* r) { auto runner = reinterpret_cast(r); dht_infohash ret; @@ -505,9 +414,9 @@ struct sockaddr** dht_runner_get_public_address(const dht_runner* r) { return nullptr; auto ret = (struct sockaddr**)malloc(sizeof(struct sockaddr*) * (addrs.size() + 1)); for (size_t i=0; i - * - * 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 . - */ - #pragma once #ifdef __cplusplus extern "C" { #endif -#include +#include "def.h" #include #include #include @@ -36,8 +18,6 @@ struct OPENDHT_C_PUBLIC dht_data_view { }; typedef struct dht_data_view dht_data_view; -OPENDHT_C_PUBLIC const char* dht_version(); - // dht::Blob struct OPENDHT_C_PUBLIC dht_blob; typedef struct dht_blob dht_blob; @@ -50,7 +30,6 @@ typedef struct dht_infohash dht_infohash; OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h); OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h); OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat); -OPENDHT_C_PUBLIC void dht_infohash_from_hex_null(dht_infohash* h, const char* dat); OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size); OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str); OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h); @@ -79,7 +58,6 @@ OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bit OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password); OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password); OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*); -OPENDHT_C_PUBLIC dht_blob* dht_privatekey_decrypt(const dht_privatekey*, const char* data, size_t data_size); OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*); // dht::crypto::Certificate @@ -104,7 +82,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_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*); OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data); @@ -112,7 +89,6 @@ OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data); OPENDHT_C_PUBLIC dht_publickey* dht_value_get_owner(const dht_value* data); OPENDHT_C_PUBLIC dht_infohash dht_value_get_recipient(const dht_value* data); OPENDHT_C_PUBLIC const char* dht_value_get_user_type(const dht_value* data); -OPENDHT_C_PUBLIC void dht_value_set_user_type(dht_value* data, const char* user_type); // callbacks typedef bool (*dht_get_cb)(const dht_value* value, void* user_data); @@ -150,7 +126,6 @@ struct OPENDHT_PUBLIC dht_runner_config { bool peer_publish; dht_certificate* server_ca; dht_identity client_identity; - bool log; }; typedef struct dht_runner_config dht_runner_config; OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config); @@ -158,13 +133,11 @@ OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config); // dht::DhtRunner struct OPENDHT_C_PUBLIC dht_runner; typedef struct dht_runner dht_runner; -OPENDHT_C_PUBLIC dht_runner* dht_runner_new(void); +OPENDHT_C_PUBLIC dht_runner* dht_runner_new(); OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner); -/* Returns 0 on success, standard error code on failure */ -OPENDHT_C_PUBLIC int dht_runner_run(dht_runner* runner, in_port_t port); -/* Returns 0 on success, standard error code on failure */ -OPENDHT_C_PUBLIC int dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config); -OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len, dht_done_cb done_cb, void* cb_user_data); +OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port); +OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config); +OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len); OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host, const char* service); OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data); OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data); @@ -176,9 +149,6 @@ OPENDHT_C_PUBLIC void dht_runner_cancel_put(dht_runner* runner, const dht_infoha OPENDHT_C_PUBLIC void dht_runner_shutdown(dht_runner* runner, dht_shutdown_cb done_cb, void* cb_user_data); OPENDHT_C_PUBLIC dht_infohash dht_runner_get_node_id(const dht_runner* runner); OPENDHT_C_PUBLIC dht_infohash dht_runner_get_id(const dht_runner* runner); -OPENDHT_C_PUBLIC bool dht_runner_is_running(const dht_runner* runner); -OPENDHT_C_PUBLIC in_port_t dht_runner_get_bound_port(const dht_runner* runner, sa_family_t af); -/** Returns null-terminated array that must be freed after use as well as each element */ OPENDHT_C_PUBLIC struct sockaddr** dht_runner_get_public_address(const dht_runner* runner); #ifdef __cplusplus diff --git a/cmake/CheckAtomic.cmake b/cmake/CheckAtomic.cmake index b6be817d7..d4a671109 100644 --- a/cmake/CheckAtomic.cmake +++ b/cmake/CheckAtomic.cmake @@ -1,103 +1,95 @@ -# atomic builtins are required for threading support. +# University of Illinois/NCSA +# Open Source License +# +# Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign. +# All rights reserved. +# +# Developed by: +# +# LLVM Team +# +# University of Illinois at Urbana-Champaign +# +# http://llvm.org +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal with +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimers. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimers in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of the LLVM Team, University of Illinois at +# Urbana-Champaign, nor the names of its contributors may be used to +# endorse or promote products derived from this Software without specific +# prior written permission. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +# SOFTWARE. -INCLUDE(CheckCXXSourceCompiles) -INCLUDE(CheckLibraryExists) -INCLUDE("${CMAKE_CURRENT_LIST_DIR}/DetermineGCCCompatible.cmake") +include(CheckCXXSourceCompiles) +include(CheckLibraryExists) # Sometimes linking against libatomic is required for atomic ops, if # the platform doesn't support lock-free atomics. function(check_working_cxx_atomics varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") - CHECK_CXX_SOURCE_COMPILES(" -#include -std::atomic x; -std::atomic y; -std::atomic z; -int main() { - ++z; - ++y; - return ++x; -} -" ${varname}) - set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) -endfunction(check_working_cxx_atomics) - -function(check_working_cxx_atomics64 varname) - set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") + get_directory_property(compile_options COMPILE_OPTIONS) + set(CMAKE_REQUIRED_FLAGS ${compile_options}) CHECK_CXX_SOURCE_COMPILES(" #include #include -std::atomic x (0); -int main() { - uint64_t i = x.load(std::memory_order_relaxed); - (void)i; - return 0; -} -" ${varname}) +std::atomic v1; +std::atomic v2; +int main(int, char**) { + return v1 + v2; +}" ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) -endfunction(check_working_cxx_atomics64) +endfunction(check_working_cxx_atomics) -# Check for (non-64-bit) atomic operations. -if(MSVC) - set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) -elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") - # First check if atomics work without the library. - check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) - # If not, check if the library exists, and atomics work with it. - if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") - check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) - if (NOT HAVE_CXX_ATOMICS_WITH_LIB) - message(FATAL_ERROR "Host compiler must support std::atomic!") - endif() +if(NOT DEFINED PROXYGEN_COMPILER_IS_GCC_COMPATIBLE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) + elseif(MSVC) + set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE OFF) + elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) + elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") + set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON) endif() endif() -# Check for 64 bit atomic operations. -if(MSVC) - set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) -elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL") +# This isn't necessary on MSVC, so avoid command-line switch annoyance +# by only running on GCC-like hosts. +if(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE) # First check if atomics work without the library. - check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) # If not, check if the library exists, and atomics work with it. - if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") - check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) - if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) - message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") + if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) + check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) + if(HAVE_LIBATOMIC) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() + list(APPEND CMAKE_CXX_STANDARD_LIBRARIES -latomic) + else() + message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") endif() endif() endif() - -## TODO: This define is only used for the legacy atomic operations in -## llvm's Atomic.h, which should be replaced. Other code simply -## assumes C++11 works. -CHECK_CXX_SOURCE_COMPILES(" -#ifdef _MSC_VER -#include -#endif -int main() { -#ifdef _MSC_VER - volatile LONG val = 1; - MemoryBarrier(); - InterlockedCompareExchange(&val, 0, 1); - InterlockedIncrement(&val); - InterlockedDecrement(&val); -#else - volatile unsigned long val = 1; - __sync_synchronize(); - __sync_val_compare_and_swap(&val, 1, 0); - __sync_add_and_fetch(&val, 1); - __sync_sub_and_fetch(&val, 1); -#endif - return 0; - } -" LLVM_HAS_ATOMICS) - -if( NOT LLVM_HAS_ATOMICS ) - message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing") -endif() \ No newline at end of file diff --git a/cmake/DetermineGCCCompatible.cmake b/cmake/DetermineGCCCompatible.cmake deleted file mode 100644 index 1369ebe9d..000000000 --- a/cmake/DetermineGCCCompatible.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# Determine if the compiler has GCC-compatible command-line syntax. - -if(NOT DEFINED LLVM_COMPILER_IS_GCC_COMPATIBLE) - if(CMAKE_COMPILER_IS_GNUCXX) - set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) - elseif( MSVC ) - set(LLVM_COMPILER_IS_GCC_COMPATIBLE OFF) - elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) - set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) - elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" ) - set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) - endif() -endif() diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake new file mode 100644 index 000000000..7d9dd816d --- /dev/null +++ b/cmake/FindMsgpack.cmake @@ -0,0 +1,64 @@ +# - Try to find msgpack +# Once done this will define +# MSGPACK_FOUND - System has msgpack +# MSGPACK_INCLUDE_DIRS - The msgpack include directories +# MSGPACK_LIBRARIES - The libraries needed to use msgpack + +if(NOT MSGPACK_USE_BUNDLED) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_search_module(PC_MSGPACK QUIET + msgpackc>=${Msgpack_FIND_VERSION} + msgpack>=${Msgpack_FIND_VERSION}) + endif() +else() + set(PC_MSGPACK_INCLUDEDIR) + set(PC_MSGPACK_INCLUDE_DIRS) + set(PC_MSGPACK_LIBDIR) + set(PC_MSGPACK_LIBRARY_DIRS) + set(LIMIT_SEARCH NO_DEFAULT_PATH) +endif() + +set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER}) + +find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h + HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS} + ${LIMIT_SEARCH}) + +if(MSGPACK_INCLUDE_DIR) + file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h) + string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}") + string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}") + string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}") + set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}") +else() + set(MSGPACK_VERSION_STRING) +endif() + +# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name. +if(MSGPACK_USE_STATIC) + list(APPEND MSGPACK_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}" + "${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}") +endif() + +list(APPEND MSGPACK_NAMES msgpackc msgpack) + +find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES} + # Check each directory for all names to avoid using headers/libraries from + # different places. + NAMES_PER_DIR + HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS} + ${LIMIT_SEARCH}) + +mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) + +set(MSGPACK_LIBRARIES ${MSGPACK_LIBRARY}) +set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set MSGPACK_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(Msgpack + REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR + VERSION_VAR MSGPACK_VERSION_STRING) diff --git a/configure.ac b/configure.ac index 04119dd94..23a317b77 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl define macros m4_define([opendht_major_version], 2) -m4_define([opendht_minor_version], 4) -m4_define([opendht_patch_version], 3) +m4_define([opendht_minor_version], 1) +m4_define([opendht_patch_version], 9) m4_define([opendht_version], [opendht_major_version.opendht_minor_version.opendht_patch_version]) @@ -32,13 +32,6 @@ AS_IF([test "x$enable_logs" != "xno"], [ AC_DEFINE([OPENDHT_LOG], [false], [Define if DHT logs are enabled]) ]) -dnl Check for C binding -AC_ARG_ENABLE([c], [AS_HELP_STRING([--disable-c], [Disable DHT C binding])]) -AM_CONDITIONAL(ENABLE_C, test x$enable_c != "xno") -AM_COND_IF(ENABLE_C, [ - AC_DEFINE([OPENDHT_C], [], [Define if DHT C biding is enabled]) -]) - dnl Check for indexation AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])]) AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno") @@ -109,7 +102,7 @@ AS_IF([test "x$SYS" = "xandroid"], LT_INIT() LT_LANG(C++) -AX_CXX_COMPILE_STDCXX(17,[noext],[mandatory]) +AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory]) PKG_PROG_PKG_CONFIG() @@ -139,8 +132,6 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro PKG_CHECK_MODULES([Nettle], [nettle >= 2.4]) PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3]) PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2]) -PKG_CHECK_MODULES([Argon2], [libargon2]) -AC_SUBST(argon2_lib, [", libargon2"]) AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support])) AS_IF([test "x$with_jsoncpp" != "xno"], @@ -166,6 +157,14 @@ AS_IF([test "x$have_openssl" = "xyes"], [ AC_MSG_NOTICE([Not using OpenSSL]) ]) +AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API])) +AS_IF([test "x$with_http_parser_fork" = "xyes"],[ + AC_MSG_NOTICE([Using http_parser fork]) + AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork]) +], [ + AC_MSG_NOTICE([Not using http_parser fork]) +]) + AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files])) CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE" @@ -182,7 +181,28 @@ AM_COND_IF([PROXY_CLIENT_OR_SERVER], [ 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" +CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT" + +dnl Check for Argon2 +AC_ARG_WITH([argon2], AS_HELP_STRING([--without-argon2], [Use included Argon2])) +AS_IF([test "x$with_argon2" != "xno"], + [PKG_CHECK_MODULES([Argon2], [libargon2], [have_argon2=yes], [have_argon2=no])], + [have_argon2=no]) +AS_IF([test "x$have_argon2" = "xyes"], [ + AC_MSG_NOTICE([Using system Argon2]) + AC_SUBST(argon2_lib, [", libargon2"]) +], [ + AS_IF([test "x$with_argon2" = "xyes"], [ + AC_MSG_ERROR([Argon2 requested but not found]) + ],[ + AC_MSG_NOTICE([Using included Argon2]) + AC_SUBST(Argon2_CFLAGS, "-I\${top_srcdir}/argon2/src -I\${top_srcdir}/argon2/include") + AC_SUBST(Argon2_LIBS, "libargon2.la") + AC_SUBST(Argon2_LDFLAGS, "-L\${abs_top_srcdir}/argon2/src/.libs") + ]) +]) + +AM_CONDITIONAL([WITH_INCLUDED_ARGON2], [test "x$have_argon2" = "xno"]) AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes) AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes) @@ -205,7 +225,6 @@ AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs") AC_CONFIG_FILES([Makefile src/Makefile - c/Makefile tools/Makefile python/Makefile python/setup.py diff --git a/docker/Dockerfile b/docker/Dockerfile index 6e510d685..2b4a744f2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,16 +1,6 @@ -FROM ghcr.io/savoirfairelinux/opendht/opendht-deps:latest -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht - +FROM aberaud/opendht-deps +MAINTAINER Adrien Béraud RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ - && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ - -DOPENDHT_C=On \ - -DOPENDHT_PEER_DISCOVERY=On \ - -DOPENDHT_PYTHON=On \ - -DOPENDHT_TOOLS=On \ - -DOPENDHT_PROXY_SERVER=On \ - -DOPENDHT_PROXY_CLIENT=On \ - && make -j8 && make install \ + && cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileBionic b/docker/DockerfileBionic index 577291226..4e2c27245 100644 --- a/docker/DockerfileBionic +++ b/docker/DockerfileBionic @@ -1,16 +1,13 @@ -FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-bionic:latest -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht +FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.1.3 +MAINTAINER Adrien Béraud RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ - -DOPENDHT_C=On \ - -DOPENDHT_PEER_DISCOVERY=On \ - -DOPENDHT_PYTHON=On \ - -DOPENDHT_TOOLS=On \ - -DOPENDHT_PROXY_SERVER=On \ - -DOPENDHT_PROXY_CLIENT=On \ - && make -j8 && make install \ + -DOPENDHT_PROXY_CLIENT=On \ + -DOPENDHT_PROXY_SERVER=On \ + -DOPENDHT_C=On \ + -DOPENDHT_PYTHON=On \ + -DOPENDHT_LTO=On \ + && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileDeps b/docker/DockerfileDeps index a031091a3..57cb87b41 100644 --- a/docker/DockerfileDeps +++ b/docker/DockerfileDeps @@ -1,6 +1,5 @@ FROM ubuntu:20.04 -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht +MAINTAINER Adrien Béraud RUN apt-get update && apt-get install -y \ dialog apt-utils \ @@ -9,18 +8,18 @@ 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 \ + autotools-dev autoconf \ cython3 python3-dev python3-setuptools \ libncurses5-dev libreadline-dev nettle-dev libcppunit-dev \ libgnutls28-dev libuv1-dev libjsoncpp-dev libargon2-dev \ libssl-dev libfmt-dev libhttp-parser-dev libasio-dev libmsgpack-dev \ - && apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/* + && apt-get clean RUN echo "*** Downloading RESTinio ***" \ && mkdir restinio && cd restinio \ - && wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \ + && wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ + && ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ + && cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/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 . \ diff --git a/docker/DockerfileDepsBionic b/docker/DockerfileDepsBionic index 559264df0..ad854587b 100644 --- a/docker/DockerfileDepsBionic +++ b/docker/DockerfileDepsBionic @@ -1,16 +1,14 @@ FROM ubuntu:18.04 -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht +MAINTAINER Adrien Béraud 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 cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \ - libargon2-0-dev \ - autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev python3-pip \ - && apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/* + autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \ + && apt-get clean -RUN pip3 install --upgrade cmake +RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake # libasio-dev (1.10) is too old RUN echo "** Building a recent version of asio ***" \ diff --git a/docker/DockerfileDepsLlvm b/docker/DockerfileDepsLlvm index aaa02e5ea..a207d304c 100644 --- a/docker/DockerfileDepsLlvm +++ b/docker/DockerfileDepsLlvm @@ -1,30 +1,26 @@ FROM ubuntu:20.04 -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht - +MAINTAINER Adrien Béraud RUN apt-get update && apt-get install -y \ dialog apt-utils \ && apt-get clean \ && echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections RUN apt-get update \ - && apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \ - libtool git wget libncurses5-dev libreadline-dev \ + && apt-get install -y llvm llvm-dev clang make cmake pkg-config git wget libncurses5-dev libreadline-dev \ nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \ python3-setuptools libcppunit-dev python3-pip \ autotools-dev autoconf libssl-dev libargon2-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/* + && apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean ENV CC cc ENV CXX c++ RUN echo "*** Downloading RESTinio ***" \ && mkdir restinio && cd restinio \ - && wget https://github.com/aberaud/restinio/archive/e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && ls -l && tar -xzf e0a261dd8488246a3cb8bbb3ea781ea5139c3c94.tar.gz \ - && cd restinio-e0a261dd8488246a3cb8bbb3ea781ea5139c3c94/dev \ + && wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ + && ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \ + && cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/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 . \ diff --git a/docker/DockerfileLlvm b/docker/DockerfileLlvm index ad1917491..62a08cd4f 100644 --- a/docker/DockerfileLlvm +++ b/docker/DockerfileLlvm @@ -1,16 +1,6 @@ -FROM ghcr.io/savoirfairelinux/opendht/opendht-deps-llvm:latest -LABEL maintainer="Adrien Béraud " -LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht - +FROM aberaud/opendht-deps-llvm +MAINTAINER Adrien Béraud RUN git clone https://github.com/savoirfairelinux/opendht.git \ && cd opendht && mkdir build && cd build \ - && cmake .. -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On \ - -DOPENDHT_C=On \ - -DOPENDHT_PEER_DISCOVERY=On \ - -DOPENDHT_PYTHON=On \ - -DOPENDHT_TOOLS=On \ - -DOPENDHT_PROXY_SERVER=On \ - -DOPENDHT_PROXY_CLIENT=On \ - && make -j8 && make install \ + && cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On && make -j8 && make install \ && cd ../.. && rm -rf opendht diff --git a/docker/DockerfileTravis b/docker/DockerfileTravis new file mode 100644 index 000000000..625efb7ea --- /dev/null +++ b/docker/DockerfileTravis @@ -0,0 +1,9 @@ +FROM aberaud/opendht-deps-bionic +MAINTAINER Adrien Béraud + +RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake + +COPY . /root/opendht +RUN cd /root/opendht && mkdir build && cd build \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \ + && make -j8 && ./opendht_unit_tests && make install diff --git a/docker/DockerfileTravisLlvm b/docker/DockerfileTravisLlvm new file mode 100644 index 000000000..679e8828c --- /dev/null +++ b/docker/DockerfileTravisLlvm @@ -0,0 +1,7 @@ +FROM aberaud/opendht-deps-llvm +MAINTAINER Adrien Béraud + +COPY . /root/opendht +RUN cd /root/opendht && mkdir build && cd build \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \ + && make -j8 && ./opendht_unit_tests && make install diff --git a/docker/DockerfileTravisProxy b/docker/DockerfileTravisProxy new file mode 100644 index 000000000..a4a883589 --- /dev/null +++ b/docker/DockerfileTravisProxy @@ -0,0 +1,4 @@ +FROM aberaud/opendht-deps +MAINTAINER Adrien Béraud + +COPY . /root/opendht diff --git a/include/opendht.h b/include/opendht.h index 937a3acab..bfd6c00ad 100644 --- a/include/opendht.h +++ b/include/opendht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index 88eeff425..b45e3f927 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -82,8 +82,6 @@ struct OPENDHT_PUBLIC NodeInfo { NodeStats ipv4 {}; NodeStats ipv6 {}; size_t ongoing_ops {0}; - size_t storage_values {0}; - size_t storage_size {0}; in_port_t bound4 {0}; in_port_t bound6 {0}; @@ -134,10 +132,7 @@ struct OPENDHT_PUBLIC Config { /* If non-0, overrides the default maximum store size. -1 means no limit. */ ssize_t max_store_size {0}; - /* If non-0, overrides the default maximum store key count. -1 means no limit. */ - ssize_t max_store_keys {0}; - - /** + /** * Use appropriate bahavior for a public IP, stable node: * - No connectivity change triggered when a search fails * - Larger listen refresh time @@ -153,7 +148,7 @@ struct OPENDHT_PUBLIC SecureDhtConfig Config node_config {}; crypto::Identity id {}; - /** + /** * Cache all encountered public keys and certificates, * for use by the certificate store, putEncrypted and putSigned */ @@ -169,7 +164,6 @@ using GetCallback = std::function> using ValueCallback = std::function>& values, bool expired)>; using GetCallbackSimple = std::function value)>; using ShutdownCallback = std::function; -using IdentityAnnouncedCb = std::function; using CertificateStoreQuery = std::function>(const InfoHash& pk_id)>; @@ -184,13 +178,13 @@ typedef bool (*FilterRaw)(const Value&, void *user_data); using DoneCallbackSimple = std::function; -OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data); -OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb); -OPENDHT_PUBLIC ValueCallback bindValueCb(ValueCallbackRaw raw_cb, void* user_data); -OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data); +OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data); +OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb); +OPENDHT_PUBLIC ValueCallback bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data); +OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data); OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb); -OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data); -OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data); -OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data); +OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data); +OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data); +OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data); } diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index 4c67dbecc..e3e0a20a0 100644 --- a/include/opendht/crypto.h +++ b/include/opendht/crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * Vsevolod Ivanov * @@ -80,8 +80,6 @@ struct OPENDHT_PUBLIC PublicKey * Takes ownership of an existing gnutls_pubkey. */ PublicKey(gnutls_pubkey_t k) : pk(k) {} - - /** Import public key from serialized data */ PublicKey(const uint8_t* dat, size_t dat_size); PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {} PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; }; @@ -108,12 +106,12 @@ struct OPENDHT_PUBLIC PublicKey PkId getLongId() const; bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const; - inline bool checkSignature(const Blob& data, const Blob& signature) const { + bool checkSignature(const Blob& data, const Blob& signature) const { return checkSignature(data.data(), data.size(), signature.data(), signature.size()); } Blob encrypt(const uint8_t* data, size_t data_len) const; - inline Blob encrypt(const Blob& data) const { + Blob encrypt(const Blob& data) const { return encrypt(data.data(), data.size()); } @@ -164,9 +162,7 @@ struct OPENDHT_PUBLIC PrivateKey ~PrivateKey(); explicit operator bool() const { return key; } - const PublicKey& getPublicKey() const; - const std::shared_ptr& getSharedPublicKey() const; - + PublicKey getPublicKey() const; int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const; Blob serialize(const std::string& password = {}) const; @@ -174,16 +170,14 @@ struct OPENDHT_PUBLIC PrivateKey * Sign the provided binary object. * @returns the signature data. */ - Blob sign(const uint8_t* data, size_t data_len) const; - inline Blob sign(const Blob& dat) const { return sign(dat.data(), dat.size()); } + Blob sign(const Blob&) const; /** * Try to decrypt the provided cypher text. * In case of failure a CryptoException is thrown. * @returns the decrypted data. */ - Blob decrypt(const uint8_t* cypher, size_t cypher_len) const; - Blob decrypt(const Blob& cypher) const { return decrypt(cypher.data(), cypher.size()); } + Blob decrypt(const Blob& cypher) const; /** * Generate a new RSA key pair @@ -201,7 +195,7 @@ struct OPENDHT_PUBLIC PrivateKey PrivateKey& operator=(const PrivateKey&) = delete; Blob decryptBloc(const uint8_t* src, size_t src_size) const; - mutable std::shared_ptr publicKey_ {}; + //friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length); }; class OPENDHT_PUBLIC RevocationList @@ -316,24 +310,6 @@ class OPENDHT_PUBLIC CertificateRequest { gnutls_x509_crq_t request {nullptr}; }; -class OPENDHT_PUBLIC OcspRequest -{ -public: - OcspRequest(gnutls_ocsp_req_t r) : request(r) {}; - OcspRequest(const uint8_t* dat_ptr, size_t dat_size); - ~OcspRequest(); - - /* - * Get OCSP Request in readable format. - */ - std::string toString(const bool compact = true) const; - - Blob pack() const; - Blob getNonce() const; -private: - gnutls_ocsp_req_t request; -}; - class OPENDHT_PUBLIC OcspResponse { public: @@ -355,11 +331,11 @@ class OPENDHT_PUBLIC OcspResponse gnutls_ocsp_cert_status_t getCertificateStatus() const; /* - * Verify OCSP response and return OCSP status. - * Throws CryptoException in case of error in the response. + * Verify OCSP response. + * Return OCSP verify reason. * http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t */ - gnutls_ocsp_cert_status_t verifyDirect(const Certificate& crt, const Blob& nonce); + gnutls_ocsp_verify_reason_t verifyDirect(const Certificate& crt, const Blob& nonce); private: gnutls_ocsp_resp_t response; @@ -541,8 +517,8 @@ struct OPENDHT_PUBLIC Certificate { void addRevocationList(RevocationList&&); void addRevocationList(std::shared_ptr); - static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false, int64_t validity = 0); - static Certificate generate(const CertificateRequest& request, const Identity& ca, int64_t validity = 0); + static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false); + static Certificate generate(const CertificateRequest& request, const Identity& ca); gnutls_x509_crt_t getCopy() const { if (not cert) @@ -592,20 +568,12 @@ struct OPENDHT_PUBLIC Certificate { */ std::pair generateOcspRequest(gnutls_x509_crt_t& issuer); - /** - * Change certificate's expiration - */ - void setValidity(const Identity& ca, int64_t validity); - void setValidity(const PrivateKey& key, int64_t validity); - gnutls_x509_crt_t cert {nullptr}; std::shared_ptr issuer {}; std::shared_ptr ocspResponse; private: Certificate(const Certificate&) = delete; Certificate& operator=(const Certificate&) = delete; - mutable InfoHash cachedId_ {}; - mutable PkId cachedLongId_ {}; struct crlNumberCmp { bool operator() (const std::shared_ptr& lhs, const std::shared_ptr& rhs) const { @@ -781,10 +749,8 @@ 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 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); } +OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key); +OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password); } } diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h index 0c5ad1f08..ef3434cfb 100644 --- a/include/opendht/default_types.h +++ b/include/opendht/default_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -66,10 +66,8 @@ class OPENDHT_PUBLIC SignedValue : public Value::Serializable public: virtual void unpackValue(const Value& v) override { - if (v.owner) { - owner = v.owner; + if (v.owner) from = v.owner->getId(); - } BaseClass::unpackValue(v); } @@ -77,7 +75,6 @@ class OPENDHT_PUBLIC SignedValue : public Value::Serializable return [](const Value& v){ return v.isSigned(); }; } - Sp owner; dht::InfoHash from; }; @@ -147,18 +144,17 @@ class OPENDHT_PUBLIC TrustRequest : public EncryptedValue static const ValueType TYPE; TrustRequest() {} - TrustRequest(std::string s, std::string ci = {}) : service(s), conversationId(ci) {} - TrustRequest(std::string s, std::string ci, const Blob& d) : service(s), conversationId(ci), payload(d) {} + TrustRequest(std::string s) : service(s) {} + TrustRequest(std::string s, const Blob& d) : service(s), payload(d) {} static Value::Filter getFilter() { return EncryptedValue::getFilter(); } std::string service; - std::string conversationId; Blob payload; bool confirm {false}; - MSGPACK_DEFINE_MAP(service, conversationId, payload, confirm) + MSGPACK_DEFINE_MAP(service, payload, confirm) }; class OPENDHT_PUBLIC IceCandidates : public EncryptedValue diff --git a/include/opendht/dht.h b/include/opendht/dht.h index f940cc58d..061e22191 100644 --- a/include/opendht/dht.h +++ b/include/opendht/dht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -61,6 +61,9 @@ struct LocalListener; */ class OPENDHT_PUBLIC Dht final : public DhtInterface { public: + + Dht(); + /** * Initialise the Dht with two open sockets (for IPv4 and IP6) * and an ID for the node. @@ -95,7 +98,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { /** * Performs final operations before quitting. */ - void shutdown(ShutdownCallback cb, bool stop = false) override; + void shutdown(ShutdownCallback cb) override; /** * Returns true if the node is running (have access to an open socket). @@ -114,7 +117,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void addBootstrap(const std::string& host, const std::string& service) override { bootstrap_nodes.emplace_back(host, service); - startBootstrap(); + onDisconnected(); } void clearBootstrap() override { @@ -302,9 +305,6 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override { max_store_size = limit; } - size_t getStorageLimit() const override { - return max_store_size; - } /** * Returns the total memory usage of stored values and the number @@ -343,7 +343,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { static constexpr unsigned LISTEN_NODES {4}; /* The maximum number of hashes we're willing to track. */ - static constexpr unsigned MAX_HASHES {1024 * 1024 * 1024}; + static constexpr unsigned MAX_HASHES {1024 * 1024}; /* The maximum number of searches we keep data about. */ static constexpr unsigned MAX_SEARCHES {1024 * 1024}; @@ -359,8 +359,6 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)}; - static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10}; - static constexpr size_t TOKEN_SIZE {32}; // internal structures @@ -398,7 +396,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { Kad dht6 {}; std::vector> bootstrap_nodes {}; - std::chrono::steady_clock::duration bootstrap_period {BOOTSTRAP_PERIOD}; + std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)}; Sp bootstrapJob {}; std::map store; @@ -450,13 +448,13 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { // Storage void storageAddListener(const InfoHash& id, const Sp& node, size_t tid, Query&& = {}, int version = 0); bool storageStore(const InfoHash& id, const Sp& value, time_point created, const SockAddr& sa = {}, bool permanent = false); + bool storageErase(const InfoHash& id, Value::Id vid); bool storageRefresh(const InfoHash& id, Value::Id vid); void expireStore(); void expireStorage(InfoHash h); void expireStore(decltype(store)::iterator); - void storageRemoved(const InfoHash& id, Storage& st, const std::vector>& values, size_t totalSize); - void storageChanged(const InfoHash& id, Storage& st, const Sp&, bool newValue); + void storageChanged(const InfoHash& id, Storage& st, ValueStorage&, bool newValue); std::string printStorageLog(const decltype(store)::value_type&) const; /** @@ -485,9 +483,6 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void sendCachedPing(Bucket& b); bool bucketMaintenance(RoutingTable&); void dumpBucket(const Bucket& b, std::ostream& out) const; - void bootstrap(); - void startBootstrap(); - void stopBootstrap(); // Nodes void onNewNode(const Sp& node, int confirm); @@ -495,6 +490,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { bool trySearchInsert(const Sp& node); // Searches + inline SearchMap& searches(sa_family_t af) { return dht(af).searches; } inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; } @@ -519,8 +515,6 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { void confirmNodes(); void expire(); - - void onConnected(); void onDisconnected(); /** @@ -576,8 +570,7 @@ class OPENDHT_PUBLIC Dht final : public DhtInterface { * * @param sr The search to execute its operations. */ - void searchStep(std::weak_ptr ws); - + void searchStep(Sp); void searchSynchedNodeListen(const Sp&, SearchNode&); void dumpSearch(const Search& sr, std::ostream& out) const; diff --git a/include/opendht/dht_interface.h b/include/opendht/dht_interface.h index bb0362f07..7a9f2cda7 100644 --- a/include/opendht/dht_interface.h +++ b/include/opendht/dht_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify @@ -21,8 +21,6 @@ #include "infohash.h" #include "log_enable.h" -#include - namespace dht { namespace net { @@ -48,10 +46,6 @@ class OPENDHT_PUBLIC DhtInterface { virtual NodeStatus getStatus(sa_family_t af) const = 0; virtual NodeStatus getStatus() const = 0; - void addOnConnectedCallback(std::function cb) { - onConnectCallbacks_.emplace(std::move(cb)); - } - virtual net::DatagramSocket* getSocket() const { return {}; }; /** @@ -61,10 +55,8 @@ class OPENDHT_PUBLIC DhtInterface { /** * Performs final operations before quitting. - * stop: if true, cancel ongoing operations and call their 'done' - * callbacks synchronously. */ - virtual void shutdown(ShutdownCallback cb, bool stop = false) = 0; + virtual void shutdown(ShutdownCallback cb) = 0; /** * Returns true if the node is running (have access to an open socket). @@ -221,7 +213,6 @@ class OPENDHT_PUBLIC DhtInterface { * Set the in-memory storage limit in bytes */ virtual void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) = 0; - virtual size_t getStorageLimit() const = 0; /** * Returns the total memory usage of stored values and the number @@ -273,7 +264,6 @@ class OPENDHT_PUBLIC DhtInterface { protected: std::shared_ptr logger_ {}; - std::queue> onConnectCallbacks_ {}; }; } // namespace dht diff --git a/include/opendht/dht_proxy_client.h b/include/opendht/dht_proxy_client.h index 3c011b43d..848ea0af6 100644 --- a/include/opendht/dht_proxy_client.h +++ b/include/opendht/dht_proxy_client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -85,7 +85,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { /** * Performs final operations before quitting. */ - void shutdown(ShutdownCallback cb, bool) override; + void shutdown(ShutdownCallback cb) override; /** * Returns true if the node is running (have access to an open socket). @@ -107,13 +107,13 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { */ virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override; virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override { - get(key, cb, bindDoneCb(std::move(donecb)), std::forward(f), std::forward(w)); + get(key, cb, bindDoneCb(donecb), std::forward(f), std::forward(w)); } virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override { - get(key, bindGetCb(cb), std::move(donecb), std::forward(f), std::forward(w)); + get(key, bindGetCb(cb), donecb, std::forward(f), std::forward(w)); } virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override { - get(key, bindGetCb(cb), bindDoneCb(std::move(donecb)), std::forward(f), std::forward(w)); + get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward(f), std::forward(w)); } /** @@ -134,7 +134,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, v, bindDoneCb(std::move(cb)), created, permanent); + put(key, v, bindDoneCb(cb), created, permanent); } void put(const InfoHash& key, @@ -143,7 +143,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, std::make_shared(std::move(v)), std::move(cb), created, permanent); + put(key, std::make_shared(std::move(v)), cb, created, permanent); } void put(const InfoHash& key, Value&& v, @@ -151,7 +151,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { time_point created=time_point::max(), bool permanent = false) override { - put(key, std::forward(v), bindDoneCb(std::move(cb)), created, permanent); + put(key, std::forward(v), bindDoneCb(cb), created, permanent); } /** @@ -176,14 +176,14 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override; virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override { - return listen(key, [cb=std::move(cb)](const std::vector>& vals, bool expired){ + return listen(key, [cb](const std::vector>& vals, bool expired){ if (not expired) return cb(vals); return true; }, std::forward(f), std::forward(w)); } virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override { - return listen(key, bindGetCb(std::move(cb)), std::forward(f), std::forward(w)); + return listen(key, bindGetCb(cb), std::forward(f), std::forward(w)); } /* * This function relies on the cache implementation. @@ -214,7 +214,7 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { */ virtual void query(const InfoHash& /*key*/, QueryCallback /*cb*/, DoneCallback /*done_cb*/ = {}, Query&& /*q*/ = {}) override { } virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override { - query(key, cb, bindDoneCb(std::move(done_cb)), std::forward(q)); + query(key, cb, bindDoneCb(done_cb), std::forward(q)); } /** @@ -263,7 +263,6 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { void dumpTables() const override {} std::vector getNodeMessageStats(bool) override { return {}; } void setStorageLimit(size_t) override {} - virtual size_t getStorageLimit() const { return 0; } void connectivityChanged(sa_family_t) override { getProxyInfos(); } @@ -338,7 +337,6 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { NodeStats stats6_ {}; SockAddr publicAddressV4_; SockAddr publicAddressV6_; - std::atomic_bool launchConnectedCbs_ {false}; InfoHash myid {}; @@ -380,8 +378,8 @@ class OPENDHT_PUBLIC DhtProxyClient final : public DhtInterface { * Retrieve if we can connect to the proxy (update statusIpvX_) */ void handleProxyConfirm(const asio::error_code &ec); - std::unique_ptr nextProxyConfirmationTimer_; - std::unique_ptr listenerRestartTimer_; + Sp nextProxyConfirmationTimer_; + Sp listenerRestartTimer_; /** * Relaunch LISTEN requests if the client disconnect/reconnect. diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index e1facd70a..5dcc4193c 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -445,6 +445,7 @@ class OPENDHT_PUBLIC DhtProxyServer std::map> listeners; MSGPACK_DEFINE_ARRAY(listeners) }; + std::mutex lockPushListeners_; std::map pushListeners_; proxy::ListenToken tokenPushNotif_ {0}; #endif //OPENDHT_PUSH_NOTIFICATIONS diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index 11e3810e7..41fbd9802 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -65,7 +65,6 @@ class OPENDHT_PUBLIC DhtRunner { bool peer_publish {false}; std::shared_ptr server_ca; dht::crypto::Identity client_identity; - SockAddr bind4 {}, bind6 {}; }; struct Context { @@ -74,7 +73,6 @@ class OPENDHT_PUBLIC DhtRunner { std::shared_ptr peerDiscovery {}; StatusCallback statusChangedCallback {}; CertificateStoreQuery certificateStore {}; - IdentityAnnouncedCb identityAnnouncedCb {}; Context() {} }; @@ -99,7 +97,7 @@ class OPENDHT_PUBLIC DhtRunner { template void get(InfoHash hash, std::function&&)> cb, DoneCallbackSimple dcb={}) { - get(hash, [cb=std::move(cb)](const std::vector>& vals) { + get(hash, [=](const std::vector>& vals) { return cb(unpackVector(vals)); }, dcb, @@ -108,7 +106,7 @@ class OPENDHT_PUBLIC DhtRunner { template void get(InfoHash hash, std::function cb, DoneCallbackSimple dcb={}) { - get(hash, [cb=std::move(cb)](const std::vector>& vals) { + get(hash, [=](const std::vector>& vals) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v))) @@ -157,7 +155,7 @@ class OPENDHT_PUBLIC DhtRunner { std::future listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {}); std::future listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) { - return listen(key, [cb=std::move(cb)](const std::vector>& vals, bool expired){ + return listen(key, [cb](const std::vector>& vals, bool expired){ if (not expired) return cb(vals); return true; @@ -171,7 +169,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function&&)> cb) { - return listen(hash, [cb=std::move(cb)](const std::vector>& vals) { + return listen(hash, [=](const std::vector>& vals) { return cb(unpackVector(vals)); }, getFilterSet()); @@ -179,7 +177,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function&&, bool)> cb) { - return listen(hash, [cb=std::move(cb)](const std::vector>& vals, bool expired) { + return listen(hash, [=](const std::vector>& vals, bool expired) { return cb(unpackVector(vals), expired); }, getFilterSet()); @@ -188,7 +186,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function cb, Value::Filter f = {}, Where w = {}) { - return listen(hash, [cb=std::move(cb)](const std::vector>& vals) { + return listen(hash, [=](const std::vector>& vals) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v))) @@ -204,7 +202,7 @@ class OPENDHT_PUBLIC DhtRunner { template std::future listen(InfoHash hash, std::function cb, Value::Filter f = {}, Where w = {}) { - return listen(hash, [cb=std::move(cb)](const std::vector>& vals, bool expired) { + return listen(hash, [=](const std::vector>& vals, bool expired) { for (const auto& v : vals) { try { if (not cb(Value::unpack(*v), expired)) @@ -257,29 +255,18 @@ class OPENDHT_PUBLIC DhtRunner { } void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false); - void putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallback cb={}, bool permanent = false); - void putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallbackSimple cb, bool permanent = false) { - putEncrypted(hash, to, value, bindDoneCb(cb), permanent); - } - - void putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallback cb={}, bool permanent = false); - void putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallbackSimple cb, bool permanent = false) { - putEncrypted(hash, to, std::forward(value), bindDoneCb(cb), permanent); - } - - /** * Insert known nodes to the routing table, without necessarly ping them. * Usefull to restart a node and get things running fast without putting load on the network. */ - void bootstrap(std::vector nodes, DoneCallbackSimple cb={}); - void bootstrap(SockAddr addr, DoneCallbackSimple cb={}); + void bootstrap(std::vector nodes, DoneCallbackSimple&& cb={}); + void bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb={}); /** * Insert known nodes to the routing table, without necessarly ping them. * Usefull to restart a node and get things running fast without putting load on the network. */ - void bootstrap(std::vector nodes); + void bootstrap(const std::vector& nodes); /** * Add host:service to bootstrap nodes, and ping this node. @@ -314,7 +301,6 @@ class OPENDHT_PUBLIC DhtRunner { * Get the public key fingerprint if an identity is used with this node, 0 otherwise. */ InfoHash getId() const; - std::shared_ptr getPublicKey() const; /** * Get the ID of the DHT node. @@ -335,7 +321,6 @@ class OPENDHT_PUBLIC DhtRunner { std::pair getStoreSize() const; - void getStorageLimit() const; void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT); std::vector exportNodes() const; @@ -374,7 +359,6 @@ class OPENDHT_PUBLIC DhtRunner { std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const; std::vector getPublicAddress(sa_family_t af = AF_UNSPEC); std::vector getPublicAddressStr(sa_family_t af = AF_UNSPEC); - void getPublicAddress(std::function&&)>, sa_family_t af = AF_UNSPEC); // securedht methods @@ -395,12 +379,22 @@ class OPENDHT_PUBLIC DhtRunner { config.threaded = threaded; run(port, config); } - void run(in_port_t port, Config& config, Context&& context = {}); + void run(in_port_t port, const Config& config, Context&& context = {}); + + /** + * @param local4: Local IPv4 address and port to bind. Can be null. + * @param local6: Local IPv6 address and port to bind. Can be null. + * You should allways bind to a global IPv6 address. + * @param identity: RSA key pair to use for cryptographic operations. + * @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched. + * @param cb: Optional callback to receive general state information. + */ + void run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context = {}); /** * Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port). */ - void run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context = {}); + void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {}); void run(const Config& config, Context&& context); @@ -421,7 +415,7 @@ class OPENDHT_PUBLIC DhtRunner { /** * Gracefuly disconnect from network. */ - void shutdown(ShutdownCallback cb = {}, bool stop = false); + void shutdown(ShutdownCallback cb = {}); /** * Quit and wait for all threads to terminate. @@ -457,6 +451,8 @@ class OPENDHT_PUBLIC DhtRunner { void forwardAllMessages(bool forward); private: + static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10}; + enum class State { Idle, Running, @@ -485,7 +481,6 @@ class OPENDHT_PUBLIC DhtRunner { /** Current configuration */ Config config_; - IdentityAnnouncedCb identityAnnouncedCb_; /** * reset dht clients diff --git a/include/opendht/http.h b/include/opendht/http.h index baeeed2e9..76ba5f0e5 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Vsevolod Ivanov * * This program is free software; you can redistribute it and/or modify @@ -375,3 +375,15 @@ class OPENDHT_PUBLIC Request : public std::enable_shared_from_this } // namespace http } // namespace dht +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK +namespace restinio +{ +/* Custom HTTP-methods for RESTinio > 0.5.0. + * https://github.com/Stiffstream/restinio/issues/26 + */ +constexpr const restinio::http_method_id_t method_listen {HTTP_LISTEN, "LISTEN"}; +constexpr const restinio::http_method_id_t method_stats {HTTP_STATS, "STATS"}; +constexpr const restinio::http_method_id_t method_sign {HTTP_SIGN, "SIGN"}; +constexpr const restinio::http_method_id_t method_encrypt {HTTP_ENCRYPT, "ENCRYPT"}; +} // namespace restinio +#endif diff --git a/include/opendht/indexation/pht.h b/include/opendht/indexation/pht.h index ae5d2bb41..6113a1780 100644 --- a/include/opendht/indexation/pht.h +++ b/include/opendht/indexation/pht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * Nicolas Reynaud @@ -335,7 +335,7 @@ class OPENDHT_PUBLIC Pht { void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true); void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true) { - lookup(k, [cb=std::move(cb)](std::vector>& values, Prefix) { cb(values); }, done_cb, exact_match); + lookup(k, [=](std::vector>& values, Prefix) { cb(values); }, done_cb, exact_match); } /** diff --git a/include/opendht/infohash.h b/include/opendht/infohash.h index 414c528b8..cf774cd61 100644 --- a/include/opendht/infohash.h +++ b/include/opendht/infohash.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -40,12 +40,10 @@ typedef uint16_t in_port_t; #include #include #include -#include #include #include #include #include -#include namespace dht { @@ -56,9 +54,9 @@ namespace crypto { } /** - * Represents an Hash, - * a byte array of N bytes. - * Hashes identify nodes and values in the Dht. + * Represents an InfoHash. + * An InfoHash is a byte array of HASH_LEN bytes. + * InfoHashes identify nodes and values in the Dht. */ template class OPENDHT_PUBLIC Hash { @@ -67,10 +65,10 @@ class OPENDHT_PUBLIC Hash { typedef typename T::iterator iterator; typedef typename T::const_iterator const_iterator; - Hash() noexcept { + Hash () noexcept { data_.fill(0); } - Hash(const uint8_t* h, size_t data_len) { + Hash (const uint8_t* h, size_t data_len) { if (data_len < N) data_.fill(0); else @@ -81,12 +79,7 @@ class OPENDHT_PUBLIC Hash { * hex must be at least 2.HASH_LEN characters long. * If too long, only the first 2.HASH_LEN characters are read. */ - explicit Hash(std::string_view hex) { - if (hex.size() < 2*N) - data_.fill(0); - else - fromString(hex.data()); - } + explicit Hash(const std::string& hex); Hash(const msgpack::object& o) { msgpack_unpack(o); @@ -100,8 +93,6 @@ class OPENDHT_PUBLIC Hash { iterator end() { return data_.end(); } const_iterator cend() const { return data_.cend(); } - static constexpr inline Hash zero() noexcept { return Hash{}; } - bool operator==(const Hash& h) const { auto a = reinterpret_cast(data_.data()); auto b = reinterpret_cast(h.data_.data()); @@ -121,14 +112,6 @@ class OPENDHT_PUBLIC Hash { return false; } - Hash operator^(const Hash& o) const { - Hash result; - for(auto i = 0u; i < N; i++) { - result[i] = data_[i] ^ o.data_[i]; - } - return result; - } - explicit operator bool() const { auto a = reinterpret_cast(data_.data()); auto b = reinterpret_cast(data_.data() + N); @@ -159,6 +142,10 @@ class OPENDHT_PUBLIC Hash { return 8 * i + j; } + /** + * Forget about the ``XOR-metric''. An id is just a path from the + * root of the tree, so bits are numbered from the start. + */ static inline int cmp(const Hash& id1, const Hash& id2) { return std::memcmp(id1.data_.data(), id2.data_.data(), N); } @@ -192,12 +179,16 @@ class OPENDHT_PUBLIC Hash { int xorCmp(const Hash& id1, const Hash& id2) const { - for (unsigned i = 0; i < N; i++) { + for(unsigned i = 0; i < N; i++) { + uint8_t xor1, xor2; if(id1.data_[i] == id2.data_[i]) continue; - uint8_t xor1 = id1.data_[i] ^ data_[i]; - uint8_t xor2 = id2.data_[i] ^ data_[i]; - return (xor1 < xor2) ? -1 : 1; + xor1 = id1.data_[i] ^ data_[i]; + xor2 = id2.data_[i] ^ data_[i]; + if(xor1 < xor2) + return -1; + else + return 1; } return 0; } @@ -226,7 +217,7 @@ class OPENDHT_PUBLIC Hash { return v; } - static inline Hash get(std::string_view data) { + static inline Hash get(const std::string& data) { return get((const uint8_t*)data.data(), data.size()); } @@ -298,6 +289,14 @@ std::istream& operator>> (std::istream& s, Hash& h) return s; } +template +Hash::Hash(const std::string& hex) { + if (hex.size() < 2*N) + data_.fill(0); + else + fromString(hex.c_str()); +} + template void Hash::fromString(const char* in) { @@ -341,7 +340,7 @@ Hash::getRandom(Rd& rdev) return h; } -struct alignas(std::max_align_t) HexMap : public std::array, 256> { +struct HexMap : public std::array, 256> { HexMap() { for (size_t i=0; i const char* Hash::to_c_str() const { - alignas(std::max_align_t) thread_local std::array buf; + thread_local std::array buf; for (size_t i=0; i::toString() const return std::string(to_c_str(), N*2); } +const InfoHash zeroes {}; + struct OPENDHT_PUBLIC NodeExport { InfoHash id; sockaddr_storage ss; diff --git a/include/opendht/log.h b/include/opendht/log.h index 7369d6d52..f5af1bce9 100644 --- a/include/opendht/log.h +++ b/include/opendht/log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/include/opendht/log_enable.h b/include/opendht/log_enable.h index d60c947c5..3811e1410 100644 --- a/include/opendht/log_enable.h +++ b/include/opendht/log_enable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index 4204060b7..3523125f5 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -214,6 +214,7 @@ class NetworkEngine final using RequestErrorCb = std::function; using RequestExpiredCb = std::function; + NetworkEngine(const Sp& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr&& sock); NetworkEngine( InfoHash& myid, NetworkConfig config, @@ -252,12 +253,12 @@ class NetworkEngine final * @param values The values to send. * @param version If version = 1, a request will be used to answer to the listener */ - void tellListener(const Sp& n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, + void tellListener(Sp n, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, std::vector>&& nodes, std::vector>&& nodes6, std::vector>&& values, const Query& q, int version); - void tellListenerRefreshed(const Sp& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); - void tellListenerExpired(const Sp& n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); + void tellListenerRefreshed(Sp n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); + void tellListenerExpired(Sp n, Tid socket_id, const InfoHash& hash, const Blob& ntoken, const std::vector& values, int version); bool isRunning(sa_family_t af) const; inline want_t want () const { return dht_socket->hasIPv4() and dht_socket->hasIPv6() ? (WANT4 | WANT6) : -1; } @@ -278,7 +279,7 @@ class NetworkEngine final * @return the request with information concerning its success. */ Sp - sendPing(const Sp& n, RequestCb&& on_done, RequestExpiredCb&& on_expired); + sendPing(Sp n, RequestCb&& on_done, RequestExpiredCb&& on_expired); /** * Send a "ping" request to a given node. @@ -292,7 +293,7 @@ class NetworkEngine final */ Sp sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) { - return sendPing(std::make_shared(InfoHash::zero(), std::move(sa), rd), + return sendPing(std::make_shared(zeroes, std::move(sa), rd), std::forward(on_done), std::forward(on_expired)); } @@ -309,7 +310,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendFindNode(const Sp& n, + Sp sendFindNode(Sp n, const InfoHash& hash, want_t want = -1, RequestCb&& on_done = {}, @@ -328,7 +329,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendGetValues(const Sp& n, + Sp sendGetValues(Sp n, const InfoHash& hash, const Query& query, want_t want, @@ -357,7 +358,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendListen(const Sp& n, + Sp sendListen(Sp n, const InfoHash& hash, const Query& query, const Blob& token, @@ -377,7 +378,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendAnnounceValue(const Sp& n, + Sp sendAnnounceValue(Sp n, const InfoHash& hash, const Sp& v, time_point created, @@ -397,7 +398,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendRefreshValue(const Sp& n, + Sp sendRefreshValue(Sp n, const InfoHash& hash, const Value::Id& vid, const Blob& token, @@ -416,7 +417,7 @@ class NetworkEngine final * * @return the request with information concerning its success. */ - Sp sendUpdateValues(const Sp& n, + Sp sendUpdateValues(Sp n, const InfoHash& infohash, const std::vector>& values, time_point created, diff --git a/include/opendht/network_utils.h b/include/opendht/network_utils.h index 238b876f1..4559ea303 100644 --- a/include/opendht/network_utils.h +++ b/include/opendht/network_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -42,7 +42,7 @@ namespace dht { namespace net { static const constexpr in_port_t DHT_DEFAULT_PORT = 4222; -static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 64; +static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16; static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650); int bindSocket(const SockAddr& addr, SockAddr& bound); diff --git a/include/opendht/node.h b/include/opendht/node.h index 615089eb0..47c443b3c 100644 --- a/include/opendht/node.h +++ b/include/opendht/node.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * diff --git a/include/opendht/node_cache.h b/include/opendht/node_cache.h index 06897a362..19a8d3b1c 100644 --- a/include/opendht/node_cache.h +++ b/include/opendht/node_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/peer_discovery.h b/include/opendht/peer_discovery.h index 610e444f4..2eedbb273 100644 --- a/include/opendht/peer_discovery.h +++ b/include/opendht/peer_discovery.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Mingrui Zhang * Vsevolod Ivanov * diff --git a/include/opendht/proxy.h b/include/opendht/proxy.h index c8ad58cf6..2cc292a50 100644 --- a/include/opendht/proxy.h +++ b/include/opendht/proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/rate_limiter.h b/include/opendht/rate_limiter.h index 7ab315215..ec71d6439 100644 --- a/include/opendht/rate_limiter.h +++ b/include/opendht/rate_limiter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/rng.h b/include/opendht/rng.h index 579e44382..c1419b766 100644 --- a/include/opendht/rng.h +++ b/include/opendht/rng.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/include/opendht/routing_table.h b/include/opendht/routing_table.h index d488cb9c2..234488d56 100644 --- a/include/opendht/routing_table.h +++ b/include/opendht/routing_table.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * diff --git a/include/opendht/scheduler.h b/include/opendht/scheduler.h index 2b3b83350..01cee921a 100644 --- a/include/opendht/scheduler.h +++ b/include/opendht/scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -36,9 +36,8 @@ namespace dht { class Scheduler { public: struct Job { - Job(std::function&& f, time_point t) : do_(std::move(f)), t_(t) {} + Job(std::function&& f) : do_(std::move(f)) {} std::function do_; - const time_point t_; void cancel() { do_ = {}; } }; @@ -51,12 +50,17 @@ class Scheduler { * @return pointer to the newly scheduled job. */ Sp add(time_point t, std::function&& job_func) { - auto job = std::make_shared(std::move(job_func), t); + auto job = std::make_shared(std::move(job_func)); if (t != time_point::max()) timers.emplace(std::move(t), job); return job; } + void add(const Sp& job, time_point t) { + if (t != time_point::max()) + timers.emplace(std::move(t), job); + } + /** * Reschedules a job. * @@ -64,29 +68,16 @@ class Scheduler { * @param t The time at which the job shall be rescheduled. */ void edit(Sp& job, time_point t) { - if (not job) + if (not job) { return; + } // std::function move doesn't garantee to leave the object empty. // Force clearing old value. auto task = std::move(job->do_); - cancel(job); + job->do_ = {}; job = add(t, std::move(task)); } - bool cancel(Sp& job) { - if (job) { - job->cancel(); - for (auto r = timers.equal_range(job->t_); r.first != r.second; ++r.first) { - if (r.first->second == job) { - timers.erase(r.first); - job.reset(); - return true; - } - } - } - return false; - } - /** * Runs the jobs to do up to now. * diff --git a/include/opendht/securedht.h b/include/opendht/securedht.h index f73e5a1d1..9f6ff4a2d 100644 --- a/include/opendht/securedht.h +++ b/include/opendht/securedht.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -45,13 +45,15 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { return c; } + SecureDht() {} + /** * s, s6: bound socket descriptors for IPv4 and IPv6, respectively. * For the Dht to be initialised, at least one of them must be >= 0. * id: the identity to use for the crypto layer and to compute * our own hash on the Dht. */ - SecureDht(std::unique_ptr dht, Config config, IdentityAnnouncedCb iacb = {}, const std::shared_ptr& l = {}); + SecureDht(std::unique_ptr dht, Config config); virtual ~SecureDht(); @@ -61,9 +63,6 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { PkId getLongId() const { return key_ ? key_->getPublicKey().getLongId() : PkId(); } - Sp getPublicKey() const { - return key_ ? key_->getSharedPublicKey() : Sp{}; - } ValueType secureType(ValueType&& type); @@ -118,10 +117,6 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) { putEncrypted(hash, to, std::make_shared(std::move(v)), callback, permanent); } - void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Sp val, DoneCallback callback, bool permanent = false); - void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Value&& v, DoneCallback callback, bool permanent = false) { - putEncrypted(hash, to, std::make_shared(std::move(v)), callback, permanent); - } /** * Take ownership of the value and sign it using our private key. @@ -133,13 +128,13 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { Value decrypt(const Value& v); void findCertificate(const InfoHash& node, const std::function)>& cb); - void findPublicKey(const InfoHash& node, const std::function)>& cb); + void findPublicKey(const InfoHash& node, const std::function)>& cb); - Sp registerCertificate(const InfoHash& node, const Blob& cert); + const Sp registerCertificate(const InfoHash& node, const Blob& cert); void registerCertificate(Sp& cert); - Sp getCertificate(const InfoHash& node) const; - Sp getPublicKey(const InfoHash& node) const; + const Sp getCertificate(const InfoHash& node) const; + const Sp getPublicKey(const InfoHash& node) const; /** * Allows to set a custom callback called by the library to find a locally-stored certificate. @@ -153,8 +148,8 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { /** * SecureDht to Dht proxy */ - void shutdown(ShutdownCallback cb, bool stop = false) override { - dht_->shutdown(cb, stop); + void shutdown(ShutdownCallback cb) override { + dht_->shutdown(cb); } void dumpTables() const override { dht_->dumpTables(); @@ -173,10 +168,6 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override { dht_->setStorageLimit(limit); } - size_t getStorageLimit() const override { - return dht_->getStorageLimit(); - } - std::vector exportNodes() const override { return dht_->exportNodes(); } @@ -365,7 +356,7 @@ class OPENDHT_PUBLIC SecureDht final : public DhtInterface { // our certificate cache std::map> nodesCertificates_ {}; - std::map> nodesPubKeys_ {}; + std::map> nodesPubKeys_ {}; std::atomic_bool forward_all_ {false}; bool enableCache_ {false}; diff --git a/include/opendht/sockaddr.h b/include/opendht/sockaddr.h index 2e3229bcd..790204dec 100644 --- a/include/opendht/sockaddr.h +++ b/include/opendht/sockaddr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -68,7 +68,7 @@ class OPENDHT_PUBLIC SockAddr { * Build from existing address. */ SockAddr(const sockaddr* sa, socklen_t length) { - if (length > static_cast(sizeof(sockaddr_storage))) + if (length > sizeof(sockaddr_storage)) throw std::runtime_error("Socket address length is too large"); set(sa, length); } @@ -144,7 +144,7 @@ class OPENDHT_PUBLIC SockAddr { if (len) addr.reset((sockaddr*)::calloc(len, 1)); else addr.reset(); } - if (len) + if (len > sizeof(sa_family_t)) addr->sa_family = af; } @@ -223,16 +223,16 @@ class OPENDHT_PUBLIC SockAddr { */ sockaddr* get() { return addr.get(); } - inline const sockaddr_in& getIPv4() const { + const sockaddr_in& getIPv4() const { return *reinterpret_cast(get()); } - inline const sockaddr_in6& getIPv6() const { + const sockaddr_in6& getIPv6() const { return *reinterpret_cast(get()); } - inline sockaddr_in& getIPv4() { + sockaddr_in& getIPv4() { return *reinterpret_cast(get()); } - inline sockaddr_in6& getIPv6() { + sockaddr_in6& getIPv6() { return *reinterpret_cast(get()); } diff --git a/include/opendht/thread_pool.h b/include/opendht/thread_pool.h index 24ad91dd6..d7a2995c7 100644 --- a/include/opendht/thread_pool.h +++ b/include/opendht/thread_pool.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -27,8 +27,6 @@ #include #include -#include // fix windows compiler bug - namespace dht { class OPENDHT_PUBLIC ThreadPool { @@ -65,14 +63,15 @@ class OPENDHT_PUBLIC ThreadPool { void join(); private: - std::mutex lock_ {}; - std::condition_variable cv_ {}; + struct ThreadState; std::queue> tasks_ {}; - std::vector> threads_; + std::vector> threads_; unsigned readyThreads_ {0}; - bool running_ {true}; + std::mutex lock_ {}; + std::condition_variable cv_ {}; const unsigned maxThreads_; + bool running_ {true}; }; class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this { @@ -94,71 +93,4 @@ class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this { void schedule(); }; -class OPENDHT_PUBLIC ExecutionContext { -public: - ExecutionContext(ThreadPool& pool) - : threadPool_(pool), state_(std::make_shared()) - {} - - ~ExecutionContext() { - state_->destroy(); - } - - /** Wait for ongoing tasks to complete execution and drop other pending tasks */ - void stop() { - state_->destroy(false); - } - - void run(std::function&& task) { - std::lock_guard lock(state_->mtx); - if (state_->shutdown_) return; - state_->pendingTasks++; - threadPool_.get().run([task = std::move(task), state = state_] { - state->run(task); - }); - } - -private: - struct SharedState { - std::mutex mtx {}; - std::condition_variable cv {}; - unsigned pendingTasks {0}; - unsigned ongoingTasks {0}; - /** When true, prevents new tasks to be scheduled */ - bool shutdown_ {false}; - /** When true, prevents scheduled tasks to be executed */ - std::atomic_bool destroyed {false}; - - void destroy(bool wait = true) { - std::unique_lock lock(mtx); - if (destroyed) return; - if (wait) { - cv.wait(lock, [this] { return pendingTasks == 0 && ongoingTasks == 0; }); - } - shutdown_ = true; - if (not wait) { - cv.wait(lock, [this] { return ongoingTasks == 0; }); - } - destroyed = true; - } - - void run(const std::function& task) { - { - std::lock_guard lock(mtx); - pendingTasks--; - ongoingTasks++; - } - if (destroyed) return; - task(); - { - std::lock_guard lock(mtx); - ongoingTasks--; - cv.notify_all(); - } - } - }; - std::reference_wrapper threadPool_; - std::shared_ptr state_; -}; - } diff --git a/include/opendht/utils.h b/include/opendht/utils.h index 691e936e5..93b6e8d98 100644 --- a/include/opendht/utils.h +++ b/include/opendht/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -178,8 +178,8 @@ msgpack::object* findMapValue(const msgpack::object& map, const char* key, size_ inline msgpack::object* findMapValue(const msgpack::object& map, const char* key) { return findMapValue(map, key, strlen(key)); } -inline msgpack::object* findMapValue(const msgpack::object& map, std::string_view key) { - return findMapValue(map, key.data(), key.size()); +inline msgpack::object* findMapValue(const msgpack::object& map, const std::string& key) { + return findMapValue(map, key.c_str(), key.size()); } } // namespace dht diff --git a/include/opendht/value.h b/include/opendht/value.h index 2298a57f6..198d5f621 100644 --- a/include/opendht/value.h +++ b/include/opendht/value.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -43,9 +42,8 @@ #endif namespace dht { -using namespace std::literals; -static constexpr auto VALUE_KEY_ID("id"); +static const std::string VALUE_KEY_ID("id"); static const std::string VALUE_KEY_DAT("dat"); static const std::string VALUE_KEY_PRIO("p"); static const std::string VALUE_KEY_SIGNATURE("sig"); @@ -119,7 +117,7 @@ struct OPENDHT_PUBLIC ValueType { Id id {0}; std::string name {}; - duration expiration {std::chrono::minutes(10)}; + duration expiration {60 * 10}; StorePolicy storePolicy {DEFAULT_STORE_POLICY}; EditPolicy editPolicy {DEFAULT_EDIT_POLICY}; }; @@ -207,7 +205,7 @@ struct OPENDHT_PUBLIC Value } static Filter chainOr(Filter&& f1, Filter&& f2) { if (not f1 or not f2) return {}; - return [f1=std::move(f1),f2=std::move(f2)](const Value& v) { + return [f1,f2](const Value& v) { return f1(v) or f2(v); }; } @@ -233,7 +231,8 @@ struct OPENDHT_PUBLIC Value } static Filter TypeFilter(const ValueType& t) { - return [tid = t.id](const Value& v) { + const auto tid = t.id; + return [tid](const Value& v) { return v.type == tid; }; } @@ -271,8 +270,8 @@ struct OPENDHT_PUBLIC Value }; } - static Filter UserTypeFilter(std::string ut) { - return [ut = std::move(ut)](const Value& v) { + static Filter UserTypeFilter(const std::string& ut) { + return [ut](const Value& v) { return v.user_type == ut; }; } @@ -358,7 +357,7 @@ struct OPENDHT_PUBLIC Value void sign(const crypto::PrivateKey& key) { if (isEncrypted()) throw DhtException("Can't sign encrypted data."); - owner = key.getSharedPublicKey(); + owner = std::make_shared(key.getPublicKey()); signature = key.sign(getToSign()); } @@ -370,8 +369,8 @@ struct OPENDHT_PUBLIC Value return isSigned() and owner->checkSignature(getToSign(), signature); } - std::shared_ptr getOwner() const { - return std::static_pointer_cast(owner); + std::shared_ptr getOwner() const { + return std::static_pointer_cast(owner); } /** @@ -596,7 +595,7 @@ struct OPENDHT_PUBLIC Value /** * Public key of the signer. */ - std::shared_ptr owner {}; + std::shared_ptr owner {}; /** * Hash of the recipient (optional). @@ -661,7 +660,7 @@ struct OPENDHT_PUBLIC FieldValue FieldValue() {} FieldValue(Value::Field f, uint64_t int_value) : field(f), intValue(int_value) {} FieldValue(Value::Field f, InfoHash hash_value) : field(f), hashValue(hash_value) {} - FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(std::move(blob_value)) {} + FieldValue(Value::Field f, Blob blob_value) : field(f), blobValue(blob_value) {} bool operator==(const FieldValue& fd) const; @@ -674,9 +673,9 @@ struct OPENDHT_PUBLIC FieldValue template void msgpack_pack(Packer& p) const { p.pack_map(2); - p.pack("f"sv); p.pack(static_cast(field)); + p.pack(std::string("f")); p.pack(static_cast(field)); - p.pack("v"sv); + p.pack(std::string("v")); switch (field) { case Value::Field::Id: case Value::Field::ValueType: @@ -698,12 +697,12 @@ struct OPENDHT_PUBLIC FieldValue hashValue = {}; blobValue.clear(); - if (auto f = findMapValue(msg, "f"sv)) + if (auto f = findMapValue(msg, "f")) field = (Value::Field)f->as(); else throw msgpack::type_error(); - auto v = findMapValue(msg, "v"sv); + auto v = findMapValue(msg, "v"); if (not v) throw msgpack::type_error(); else @@ -743,7 +742,7 @@ struct OPENDHT_PUBLIC FieldValue struct OPENDHT_PUBLIC Select { Select() { } - Select(std::string_view q_str); + Select(const std::string& q_str); bool isSatisfiedBy(const Select& os) const; @@ -798,7 +797,7 @@ struct OPENDHT_PUBLIC Select struct OPENDHT_PUBLIC Where { Where() { } - Where(std::string_view q_str); + Where(const std::string& q_str); bool isSatisfiedBy(const Where& where) const; @@ -865,7 +864,7 @@ struct OPENDHT_PUBLIC Where * * @return the resulting Where instance. */ - Where& userType(std::string_view user_type) { + Where& userType(std::string user_type) { FieldValue fv {Value::Field::UserType, Blob {user_type.begin(), user_type.end()}}; if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end()) filters_.emplace_back(std::move(fv)); @@ -938,11 +937,11 @@ struct OPENDHT_PUBLIC Query * - $string$: a simple string WITHOUT SPACES. * - $integer$: a simple integer. */ - Query(std::string_view q_str) { + Query(std::string q_str) { auto pos_W = q_str.find("WHERE"); auto pos_w = q_str.find("where"); - auto pos = std::min(pos_W != std::string_view::npos ? pos_W : q_str.size(), - pos_w != std::string_view::npos ? pos_w : q_str.size()); + auto pos = std::min(pos_W != std::string::npos ? pos_W : q_str.size(), + pos_w != std::string::npos ? pos_w : q_str.size()); select = q_str.substr(0, pos); where = q_str.substr(pos, q_str.size()-pos); } diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 51a35054d..43087b2e6 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -10,13 +10,13 @@ # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for -# the respective C++ standard version. +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with -# preference for no added switch, and then for an extended mode. +# preference for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -35,15 +35,13 @@ # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper -# Copyright (c) 2020 Jason Merrill -# Copyright (c) 2021 Jörn Heusipp # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 14 +#serial 11 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -52,7 +50,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], - [$1], [20], [ax_cxx_compile_alternatives="20"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], @@ -65,16 +62,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl AC_LANG_PUSH([C++])dnl ac_success=no - m4_if([$2], [], [dnl - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi]) - m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do @@ -153,6 +140,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) + dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], @@ -160,24 +148,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) -dnl Test body for checking C++17 support - m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) -dnl Test body for checking C++20 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 -) - - dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ @@ -973,33 +949,3 @@ namespace cxx17 #endif // __cplusplus < 201703L ]]) - - -dnl Tests for new features in C++20 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 202002L - -#error "This is not a C++20 compiler" - -#else - -#include - -namespace cxx20 -{ - -// As C++20 supports feature test macros in the standard, there is no -// immediate need to actually test for feature availability on the -// Autoconf side. - -} // namespace cxx20 - -#endif // __cplusplus < 202002L - -]]) diff --git a/python/opendht.pyx b/python/opendht.pyx index 454deffe7..c888c0fc1 100644 --- a/python/opendht.pyx +++ b/python/opendht.pyx @@ -1,11 +1,11 @@ # distutils: language = c++ -# distutils: extra_compile_args = -std=c++17 +# distutils: extra_compile_args = -std=c++14 # distutils: include_dirs = ../../include # distutils: library_dirs = ../../src # distutils: libraries = opendht gnutls # cython: language_level=3 # -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author(s): Guillaume Roguez # Adrien Béraud # Simon Désaulniers @@ -36,7 +36,6 @@ from libcpp.memory cimport shared_ptr from cython.parallel import parallel, prange from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec from cpython cimport ref -from datetime import timedelta cimport opendht_cpp as cpp @@ -236,9 +235,8 @@ cdef class Where(object): cdef class Value(object): cdef shared_ptr[cpp.Value] _value - def __init__(self, bytes val=b'', cpp.uint16_t id=0): - self._value.reset(new cpp.Value(id, val, len(val))) - + def __init__(self, bytes val=b''): + self._value.reset(new cpp.Value(val, len(val))) def __str__(self): return self._value.get().toString().decode() property owner: @@ -272,14 +270,6 @@ cdef class Value(object): def __get__(self): return self._value.get().size() -cdef class ValueType(object): - cdef cpp.ValueType * _value - def __init__(self, cpp.uint16_t id, str name, expiration: timedelta): - if not isinstance(expiration, timedelta): - raise TypeError("expiration argument must be of type timedelta") - cdef cpp.seconds duration = cpp.seconds(int(expiration.total_seconds())) - self._value = new cpp.ValueType(id, name.encode(), duration) - cdef class NodeSetIter(object): cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter @@ -329,11 +319,11 @@ cdef class PrivateKey(_WithID): cdef shared_ptr[cpp.PrivateKey] _key def getId(self): h = InfoHash() - h._infohash = self._key.get().getSharedPublicKey().get().getId() + h._infohash = self._key.get().getPublicKey().getId() return h def getPublicKey(self): pk = PublicKey() - pk._key = self._key.get().getSharedPublicKey() + pk._key = self._key.get().getPublicKey() return pk def decrypt(self, bytes dat): cdef size_t d_len = len(dat) @@ -358,17 +348,17 @@ cdef class PrivateKey(_WithID): return k cdef class PublicKey(_WithID): - cdef cpp.shared_ptr[cpp.PublicKey] _key + cdef cpp.PublicKey _key def getId(self): h = InfoHash() - h._infohash = self._key.get().getId() + h._infohash = self._key.getId() return h def encrypt(self, bytes dat): cdef size_t d_len = len(dat) cdef cpp.uint8_t* d_ptr = dat cdef cpp.Blob indat indat.assign(d_ptr, (d_ptr + d_len)) - cdef cpp.Blob encrypted = self._key.get().encrypt(indat) + cdef cpp.Blob encrypted = self._key.encrypt(indat) cdef char* encrypted_c_str = encrypted.data() cdef Py_ssize_t length = encrypted.size() return encrypted_c_str[:length] @@ -440,7 +430,7 @@ cdef class Identity(object): property publickey: def __get__(self): k = PublicKey() - k._key = self._id.first.get().getSharedPublicKey() + k._key = self._id.first.get().getPublicKey() return k property certificate: def __get__(self): @@ -523,8 +513,6 @@ cdef class DhtRunner(_WithID): cb_obj = {'shutdown':shutdown_cb} ref.Py_INCREF(cb_obj) self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, cb_obj)) - def registerType(self, ValueType type): - self.thisptr.get().registerType(deref(type._value)) def enableLogging(self): cpp.enableLogging(self.thisptr.get()[0]) def disableLogging(self): diff --git a/python/opendht_cpp.pxd b/python/opendht_cpp.pxd index 98961e7c4..1bc866a0f 100644 --- a/python/opendht_cpp.pxd +++ b/python/opendht_cpp.pxd @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # @@ -26,14 +26,6 @@ from libc.string cimport const_char, const_uchar ctypedef uint16_t in_port_t ctypedef unsigned short int sa_family_t; -cdef extern from "" namespace "std::chrono" nogil: - cdef cppclass duration[ulong]: - duration() except + - - cdef cppclass seconds: - duration seconds(uint64_t) except + - duration seconds() - cdef extern from "" namespace "std" nogil: cdef cppclass shared_ptr[T]: shared_ptr() except + @@ -97,7 +89,7 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto": cdef cppclass PrivateKey: PrivateKey() - shared_ptr[PublicKey] getSharedPublicKey() const + PublicKey getPublicKey() const Blob decrypt(Blob data) const @staticmethod PrivateKey generate() @@ -139,6 +131,7 @@ cdef extern from "opendht/value.h" namespace "dht::Value": cdef extern from "opendht/value.h" namespace "dht::Value::Field": cdef Field None cdef Field Id + cdef Field ValueType cdef Field OwnerPk cdef Field SeqNum cdef Field UserType @@ -148,7 +141,7 @@ cdef extern from "opendht/value.h" namespace "dht": cdef cppclass Value: Value() except + Value(vector[uint8_t]) except + - Value(const uint16_t t, const uint8_t* dat_ptr, size_t dat_len) except + + Value(const uint8_t* dat_ptr, size_t dat_len) except + string toString() const size_t size() const uint64_t id @@ -157,12 +150,6 @@ cdef extern from "opendht/value.h" namespace "dht": vector[uint8_t] data string user_type - cdef cppclass ValueType: - ValueType(uint16_t id, string name, seconds expiration) except + - uint16_t id - string name - seconds expiration - cdef cppclass Query: Query() except + Query(Select s, Where w) except + @@ -247,7 +234,6 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht": void run(const_char*, const_char*, const_char*, Config config) void join() void shutdown(ShutdownCallback) - void registerType(ValueType& value); bool isRunning() SockAddr getBound(sa_family_t af) const string getStorageLog() const diff --git a/python/setup.py.in b/python/setup.py.in index 168b126ec..e72f80be8 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -1,4 +1,4 @@ -# Copyright (C) 2014-2022 Savoir-faire Linux Inc. +# Copyright (C) 2014-2020 Savoir-faire Linux Inc. # Author: Guillaume Roguez # Author: Adrien Béraud # @@ -50,8 +50,8 @@ setup(name="opendht", ["@CURRENT_SOURCE_DIR@/opendht.pyx"], include_dirs = ['@PROJECT_SOURCE_DIR@/include'], language="c++", - extra_compile_args=["-std=c++17"], - extra_link_args=["-std=c++17"], + extra_compile_args=["-std=c++14"], + extra_link_args=["-std=c++14"], libraries=["opendht"], library_dirs = ['@CURRENT_BINARY_DIR@', '@PROJECT_BINARY_DIR@'] )) diff --git a/python/tools/benchmark.py b/python/tools/benchmark.py index 5856a25a8..b90b4d23d 100755 --- a/python/tools/benchmark.py +++ b/python/tools/benchmark.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (C) 2014-2022 Savoir-faire Linux Inc. +# Copyright (C) 2014-2020 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # diff --git a/python/tools/dht/network.py b/python/tools/dht/network.py index a012c1999..6a84d839b 100755 --- a/python/tools/dht/network.py +++ b/python/tools/dht/network.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers # diff --git a/python/tools/dht/tests.py b/python/tools/dht/tests.py index 6c1e0cb0b..18daa0387 100644 --- a/python/tools/dht/tests.py +++ b/python/tools/dht/tests.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2015-2022 Savoir-Faire Linux Inc. +# Copyright (C) 2015-2019 Savoir-Faire Linux Inc. # Author(s): Adrien Béraud # Simon Désaulniers diff --git a/python/tools/dht/virtual_network_builder.py b/python/tools/dht/virtual_network_builder.py index 8484dcb5b..1757770d6 100755 --- a/python/tools/dht/virtual_network_builder.py +++ b/python/tools/dht/virtual_network_builder.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/dhtcluster.py b/python/tools/dhtcluster.py index bb0427654..cc3121a49 100755 --- a/python/tools/dhtcluster.py +++ b/python/tools/dhtcluster.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (C) 2014-2022 Savoir-faire Linux Inc. +# Copyright (C) 2014-2020 Savoir-faire Linux Inc. # Author(s): Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/http_server.py b/python/tools/http_server.py index db9d357e9..d2da4c0e9 100755 --- a/python/tools/http_server.py +++ b/python/tools/http_server.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2022 Savoir-faire Linux Inc. +# Copyright (c) 2016-2019 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/network_monitor.py b/python/tools/network_monitor.py index 185415d1b..074bee228 100755 --- a/python/tools/network_monitor.py +++ b/python/tools/network_monitor.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/pingpong.py b/python/tools/pingpong.py index ef0d54aa0..14c903296 100755 --- a/python/tools/pingpong.py +++ b/python/tools/pingpong.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/python/tools/scanner.py b/python/tools/scanner.py index 558a46372..17d9e7cc2 100755 --- a/python/tools/scanner.py +++ b/python/tools/scanner.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2022 Savoir-faire Linux Inc. +# Copyright (c) 2015-2019 Savoir-faire Linux Inc. # Author: Adrien Béraud # # This program is free software; you can redistribute it and/or modify diff --git a/rust/examples/dhtnode.rs b/rust/examples/dhtnode.rs index d9a96bcf3..c491b87f2 100644 --- a/rust/examples/dhtnode.rs +++ b/rust/examples/dhtnode.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/blob.rs b/rust/src/blob.rs index 491cbfa18..ff2743be9 100644 --- a/rust/src/blob.rs +++ b/rust/src/blob.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/crypto.rs b/rust/src/crypto.rs index 1d123cdd1..afb6751c6 100644 --- a/rust/src/crypto.rs +++ b/rust/src/crypto.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/dhtrunner.rs b/rust/src/dhtrunner.rs index 114614d1e..12d31fe6a 100644 --- a/rust/src/dhtrunner.rs +++ b/rust/src/dhtrunner.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index 7470cc26b..c2c36f2ec 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/infohash.rs b/rust/src/infohash.rs index e66c7fa03..059128f95 100644 --- a/rust/src/infohash.rs +++ b/rust/src/infohash.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 72d9ac5c5..b9040dee7 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/pkid.rs b/rust/src/pkid.rs index 0c8fe8a31..1ce604e21 100644 --- a/rust/src/pkid.rs +++ b/rust/src/pkid.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/rust/src/value.rs b/rust/src/value.rs index 016e5d252..9276a8ed8 100644 --- a/rust/src/value.rs +++ b/rust/src/value.rs @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/src/Makefile.am b/src/Makefile.am index 2820655ba..b41ec421b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@ libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@ -libopendht_la_LDFLAGS = @LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@ +libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@ libopendht_la_SOURCES = \ dht.cpp \ storage.h \ @@ -87,3 +87,30 @@ endif clean-local: rm -rf libargon2.la + +###################### +# ARGON2 submodule # +###################### + +if WITH_INCLUDED_ARGON2 +noinst_LTLIBRARIES = libargon2.la +libopendht_la_DEPENDENCIES = libargon2.la + +libargon2_la_CFLAGS = -std=c89 -fPIC -pthread -O3 -Wall -I@top_builddir@/argon2/include -I@top_builddir@/argon2/src +libargon2_la_SOURCES = \ + @top_builddir@/argon2/src/argon2.c \ + @top_builddir@/argon2/src/core.c \ + @top_builddir@/argon2/src/blake2/blake2b.c \ + @top_builddir@/argon2/src/thread.c \ + @top_builddir@/argon2/src/ref.c \ + @top_builddir@/argon2/src/encoding.c + +noinst_HEADERS = \ + @top_builddir@/argon2/include/argon2.h \ + @top_builddir@/argon2/src/blake2/blake2.h \ + @top_builddir@/argon2/src/blake2/blake2-impl.h \ + @top_builddir@/argon2/src/blake2/blamka-round-ref.h \ + @top_builddir@/argon2/src/core.h \ + @top_builddir@/argon2/src/encoding.h \ + @top_builddir@/argon2/src/thread.h +endif diff --git a/src/base64.cpp b/src/base64.cpp index faeea68df..d2406d7c6 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 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 diff --git a/src/base64.h b/src/base64.h index a01fa6b5c..ecd7fd380 100644 --- a/src/base64.h +++ b/src/base64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 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 diff --git a/src/callbacks.cpp b/src/callbacks.cpp index ecda4057a..c1e3e1459 100644 --- a/src/callbacks.cpp +++ b/src/callbacks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ namespace dht { GetCallbackSimple -bindGetCb(GetCallbackRaw raw_cb, void* user_data) +bindGetCb(const GetCallbackRaw& raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](const std::shared_ptr& value) { @@ -35,10 +35,10 @@ bindGetCb(GetCallbackRaw raw_cb, void* user_data) } GetCallback -bindGetCb(GetCallbackSimple cb) +bindGetCb(const GetCallbackSimple& cb) { if (not cb) return {}; - return [cb=std::move(cb)](const std::vector>& values) { + return [=](const std::vector>& values) { for (const auto& v : values) if (not cb(v)) return false; @@ -47,7 +47,7 @@ bindGetCb(GetCallbackSimple cb) } ValueCallback -bindValueCb(ValueCallbackRaw raw_cb, void* user_data) +bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](const std::vector>& values, bool expired) { @@ -59,7 +59,7 @@ bindValueCb(ValueCallbackRaw raw_cb, void* user_data) } ShutdownCallback -bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data) +bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data) { return [=]() { shutdown_cb_raw(user_data); }; } @@ -69,11 +69,11 @@ bindDoneCb(DoneCallbackSimple donecb) { if (not donecb) return {}; using namespace std::placeholders; - return std::bind(std::move(donecb), _1); + return std::bind(donecb, _1); } DoneCallback -bindDoneCb(DoneCallbackRaw raw_cb, void* user_data) +bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](bool success, const std::vector>& nodes) { @@ -82,7 +82,7 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data) } DoneCallbackSimple -bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) { +bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) { if (not raw_cb) return {}; return [=](bool success) { raw_cb(success, user_data); diff --git a/src/compat/msvc/unistd.h b/src/compat/msvc/unistd.h index 3146f42af..c164e762a 100644 --- a/src/compat/msvc/unistd.h +++ b/src/compat/msvc/unistd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Andreas Traczyk * diff --git a/src/compat/os_cert.cpp b/src/compat/os_cert.cpp index ea89f12a7..9dd9611c4 100644 --- a/src/compat/os_cert.cpp +++ b/src/compat/os_cert.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2020 Savoir-faire Linux Inc. * Author: Andreas Traczyk * * This program is free software; you can redistribute it and/or modify @@ -189,15 +189,19 @@ void PEMCache::fillX509Store(SSL_CTX* ctx) { if (logger) - logger->d("adding %d decoded certs to X509 store", pems_.size()); - if (X509_STORE* store = SSL_CTX_get_cert_store(ctx)) { - for (const auto& pem : pems_) { - if (X509_STORE_add_cert(store, pem.get()) != 1) - if (logger) - logger->w("couldn't add local certificate"); - } - } else if (logger) - logger->e("couldn't get the context cert store"); + logger->w("adding %d decoded certs to X509 store", pems_.size()); + X509_STORE* store = SSL_CTX_get_cert_store(ctx); + if (store == nullptr) { + if (logger) + logger->e("couldn't get the context cert store"); + return; + } + for (const auto& pem : pems_) { + if (X509_STORE_add_cert(store, pem.get()) == 1) + continue; + if (logger) + logger->d("couldn't add local certificate"); + } } } /*namespace http*/ diff --git a/src/compat/os_cert.h b/src/compat/os_cert.h index f20bd7292..b037037d8 100644 --- a/src/compat/os_cert.h +++ b/src/compat/os_cert.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2020 Savoir-faire Linux Inc. * Author: Andreas Traczyk * * This program is free software; you can redistribute it and/or modify diff --git a/src/crypto.cpp b/src/crypto.cpp index 9eb80f6e4..9c2800f75 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * Vsevolod Ivanov * @@ -54,7 +54,7 @@ static std::uniform_int_distribution rand_byte; #define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256 #endif -#define DHT_AES_LEGACY_ENCRYPT 0 +#define DHT_AES_LEGACY_ENCRYPT 1 #define DHT_AES_LEGACY_DECRYPT 1 namespace dht { @@ -69,7 +69,7 @@ constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) { GNUTLS_DIG_SHA1)); } -constexpr size_t gnutlsHashSize(gnutls_digest_algorithm_t algo) { +constexpr size_t gnutlsHashSize(int algo) { return (algo == GNUTLS_DIG_SHA512) ? 512/8 : ( (algo == GNUTLS_DIG_SHA256) ? 256/8 : ( (algo == GNUTLS_DIG_SHA1) ? 160/8 : 0 )); @@ -128,37 +128,37 @@ Blob aesEncrypt(const Blob& data, const std::string& password) return encrypted; } -Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key) +Blob aesDecrypt(const Blob& data, const Blob& key) { if (not aesKeySizeGood(key.size())) throw DecryptError("Wrong key size"); - if (data_length <= GCM_IV_SIZE + GCM_DIGEST_SIZE) + if (data.size() <= GCM_IV_SIZE + GCM_DIGEST_SIZE) throw DecryptError("Wrong data size"); std::array digest; struct gcm_aes_ctx aes; gcm_aes_set_key(&aes, key.size(), key.data()); - gcm_aes_set_iv(&aes, GCM_IV_SIZE, data); + gcm_aes_set_iv(&aes, GCM_IV_SIZE, data.data()); - size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE; + size_t data_sz = data.size() - GCM_IV_SIZE - GCM_DIGEST_SIZE; Blob ret(data_sz); - gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE); + gcm_aes_decrypt(&aes, data_sz, ret.data(), 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 (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE)) { #if DHT_AES_LEGACY_DECRYPT - //gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE); + //gcm_aes_decrypt(&aes, data_sz, ret.data(), 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_set_iv(&aes_d, GCM_IV_SIZE, data.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)) + if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE)) throw DecryptError("Can't decrypt data"); #else throw DecryptError("Can't decrypt data"); @@ -168,13 +168,14 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key) return ret; } -Blob aesDecrypt(const uint8_t* data, size_t data_len, const std::string& password) +Blob aesDecrypt(const Blob& data, const std::string& password) { - if (data_len <= PASSWORD_SALT_LENGTH) + if (data.size() <= PASSWORD_SALT_LENGTH) throw DecryptError("Wrong data size"); - Blob salt {data, data+PASSWORD_SALT_LENGTH}; + Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH}; Blob key = stretchKey(password, salt, 256/8); - return aesDecrypt(data+PASSWORD_SALT_LENGTH, data_len - PASSWORD_SALT_LENGTH, key); + Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()}; + return aesDecrypt(encrypted, key); } Blob stretchKey(const std::string& password, Blob& salt, size_t key_length) @@ -291,14 +292,14 @@ PrivateKey::operator=(PrivateKey&& o) noexcept } Blob -PrivateKey::sign(const uint8_t* data, size_t data_length) const +PrivateKey::sign(const Blob& data) const { if (!key) throw CryptoException("Can't sign data: no private key set !"); - if (std::numeric_limits::max() < data_length) + if (std::numeric_limits::max() < data.size()) throw CryptoException("Can't sign data: too large !"); gnutls_datum_t sig; - const gnutls_datum_t dat {(unsigned char*)data, (unsigned)data_length}; + const gnutls_datum_t dat {(unsigned char*)data.data(), (unsigned)data.size()}; if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS) throw CryptoException("Can't sign data !"); Blob ret(sig.data, sig.data+sig.size); @@ -320,7 +321,7 @@ PrivateKey::decryptBloc(const uint8_t* src, size_t src_size) const } Blob -PrivateKey::decrypt(const uint8_t* cypher, size_t cypher_len) const +PrivateKey::decrypt(const Blob& cipher) const { if (!key) throw CryptoException("Can't decrypt data without private key !"); @@ -333,12 +334,12 @@ PrivateKey::decrypt(const uint8_t* cypher, size_t cypher_len) const throw CryptoException("Must be an RSA key"); unsigned cypher_block_sz = key_len / 8; - if (cypher_len < cypher_block_sz) + if (cipher.size() < cypher_block_sz) throw DecryptError("Unexpected cipher length"); - else if (cypher_len == cypher_block_sz) - return decryptBloc(cypher, cypher_block_sz); + else if (cipher.size() == cypher_block_sz) + return decryptBloc(cipher.data(), cypher_block_sz); - return aesDecrypt(cypher + cypher_block_sz, cypher_len - cypher_block_sz, decryptBloc(cypher, cypher_block_sz)); + return aesDecrypt(Blob {cipher.begin() + cypher_block_sz, cipher.end()}, decryptBloc(cipher.data(), cypher_block_sz)); } Blob @@ -368,22 +369,13 @@ PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password : gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len); } -const PublicKey& +PublicKey PrivateKey::getPublicKey() const { - return *getSharedPublicKey(); -} - -const std::shared_ptr& -PrivateKey::getSharedPublicKey() const -{ - if (publicKey_) - return publicKey_; - auto pk = std::make_shared(); - if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0)) + PublicKey pk; + if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0)) throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err)); - publicKey_ = pk; - return publicKey_; + return pk; } PublicKey::PublicKey() @@ -549,7 +541,12 @@ PublicKey::getId() const return {}; InfoHash id; size_t sz = id.size(); - if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz)) +#if GNUTLS_VERSION_NUMBER < 0x030401 + const int flags = 0; +#else + const int flags = (id.size() == 32) ? GNUTLS_KEYID_USE_SHA256 : 0; +#endif + if (auto err = gnutls_pubkey_get_key_id(pk, flags, id.data(), &sz)) throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get public key ID: wrong output length."); @@ -714,13 +711,13 @@ CertificateRequest::sign(const PrivateKey& key, const std::string& password) } bool -CertificateRequest::verify() const +CertificateRequest::verify() const { return gnutls_x509_crq_verify(request, 0) >= 0; } -Blob -CertificateRequest::pack() const +Blob +CertificateRequest::pack() const { gnutls_datum_t dat {nullptr, 0}; if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat)) @@ -731,7 +728,7 @@ CertificateRequest::pack() const } std::string -CertificateRequest::toString() const +CertificateRequest::toString() const { gnutls_datum_t dat {nullptr, 0}; if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat)) @@ -853,15 +850,12 @@ Certificate::getId() const { if (not cert) return {}; - if (cachedId_) - return cachedId_; InfoHash id; size_t sz = id.size(); if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz)) throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get certificate public key ID: wrong output length."); - cachedId_ = id; return id; } @@ -870,8 +864,6 @@ Certificate::getLongId() const { if (not cert) return {}; - if (cachedLongId_) - return cachedLongId_; #if GNUTLS_VERSION_NUMBER < 0x030401 throw CryptoException("Can't get certificate 256 bits public key ID: GnuTLS 3.4.1 or higher required."); #else @@ -881,7 +873,6 @@ Certificate::getLongId() const throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err)); if (sz != id.size()) throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length."); - cachedLongId_ = id; return id; #endif } @@ -1057,8 +1048,6 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer) Blob noncebuf(32); gnutls_datum_t nonce = { noncebuf.data(), (unsigned)noncebuf.size() }; err = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size); - if (err < 0) - throw CryptoException(gnutls_strerror(err)); err = gnutls_ocsp_req_set_nonce(req.get(), 0, &nonce); if (err < 0) throw CryptoException(gnutls_strerror(err)); @@ -1159,20 +1148,20 @@ void setRandomSerial(gnutls_x509_crt_t cert) { random_device rdev; - std::uniform_int_distribution dist{1}; - int64_t cert_serial = dist(rdev); + std::uniform_int_distribution dist{}; + uint64_t cert_serial = dist(rdev); gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial)); } Certificate -Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca, int64_t validity) +Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca) { gnutls_x509_crt_t cert; if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) return {}; Certificate ret {cert}; - setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity); + setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60); if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) { throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err)); } @@ -1181,7 +1170,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden } // TODO: compute the subject key using the recommended RFC method - const auto& pk = key.getPublicKey(); + auto pk = key.getPublicKey(); auto pk_id = pk.getId(); const std::string uid_str = pk_id.toString(); @@ -1218,7 +1207,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden } Certificate -Certificate::generate(const CertificateRequest& request, const Identity& ca, int64_t validity) +Certificate::generate(const CertificateRequest& request, const Identity& ca) { gnutls_x509_crt_t cert; if (auto err = gnutls_x509_crt_init(&cert)) @@ -1231,7 +1220,7 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca, int throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err)); } - setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity); + setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60); setRandomSerial(cert); if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) { @@ -1242,32 +1231,6 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca, int return ret.getPacked(); } -void -Certificate::setValidity(const Identity& ca, int64_t validity) -{ - setValidityPeriod(cert, validity); - setRandomSerial(cert); - if (ca.first && ca.second) { - if (not ca.second->isCA()) { - throw CryptoException("Signing certificate must be CA"); - } - if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) { - throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err)); - } - } -} - -void -Certificate::setValidity(const PrivateKey& key, int64_t validity) -{ - setValidityPeriod(cert, validity); - setRandomSerial(cert); - const auto& pk = key.getPublicKey(); - 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)); - } -} - std::vector> Certificate::getRevocationLists() const { @@ -1278,70 +1241,6 @@ Certificate::getRevocationLists() const return ret; } -// OcspRequest - -OcspRequest::OcspRequest(const uint8_t* dat_ptr, size_t dat_size) -{ - int ret = gnutls_ocsp_req_init(&request); - if (ret < 0) - throw CryptoException(gnutls_strerror(ret)); - gnutls_datum_t dat = {(unsigned char*)dat_ptr,(unsigned int)dat_size}; - ret = gnutls_ocsp_req_import(request, &dat); - if (ret < 0){ - gnutls_ocsp_req_deinit(request); - throw CryptoException(gnutls_strerror(ret)); - } -} - -OcspRequest::~OcspRequest() -{ - if (request) { - gnutls_ocsp_req_deinit(request); - request = nullptr; - } -} - -std::string -OcspRequest::toString(const bool compact) const -{ - int ret; - gnutls_datum_t dat; - ret = gnutls_ocsp_req_print(request, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat); - - std::string str; - if (ret == 0) { - str = std::string((const char*)dat.data, (size_t)dat.size); - gnutls_free(dat.data); - } else - throw CryptoException(gnutls_strerror(ret)); - return str; -} - -Blob -OcspRequest::pack() const -{ - gnutls_datum_t dat; - int err = gnutls_ocsp_req_export(request, &dat); - if (err < 0) - throw CryptoException(gnutls_strerror(err)); - Blob ret {dat.data, dat.data + dat.size}; - gnutls_free(dat.data); - return ret; -} - -Blob -OcspRequest::getNonce() const -{ - gnutls_datum_t dat; - unsigned critical; - int err = gnutls_ocsp_req_get_nonce(request, &critical, &dat); - if (err < 0) - throw CryptoException(gnutls_strerror(err)); - Blob ret {dat.data, dat.data + dat.size}; - gnutls_free(dat.data); - return ret; -} - // OcspResponse OcspResponse::OcspResponse(const uint8_t* dat_ptr, size_t dat_size) @@ -1366,12 +1265,10 @@ Blob OcspResponse::pack() const { gnutls_datum_t dat; - int err = gnutls_ocsp_resp_export(response, &dat); - if (err < 0) - throw CryptoException(gnutls_strerror(err)); - Blob ret {dat.data, dat.data + dat.size}; - gnutls_free(dat.data); - return ret; + int ret = gnutls_ocsp_resp_export(response, &dat); + if (ret < 0) + throw CryptoException(gnutls_strerror(ret)); + return {dat.data, dat.data + dat.size}; } std::string @@ -1401,7 +1298,7 @@ OcspResponse::getCertificateStatus() const return (gnutls_ocsp_cert_status_t) status; } -gnutls_ocsp_cert_status_t +gnutls_ocsp_verify_reason_t OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce) { // Check OCSP response @@ -1412,52 +1309,39 @@ OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce) if (status != GNUTLS_OCSP_RESP_SUCCESSFUL) throw CryptoException("OCSP request unsuccessful: " + std::to_string(ret)); - if (not nonce.empty()) { - // Ensure no replay attack has been done - gnutls_datum_t rnonce; - ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce); - if (ret < 0) - throw CryptoException(gnutls_strerror(ret)); - if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){ - gnutls_free(rnonce.data); - throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); - } - gnutls_free(rnonce.data); - } + // Check whether the OCSP response is about the provided certificate. + if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0) + throw CryptoException(gnutls_strerror(ret)); // Verify signature of the Basic OCSP response against the public key in the issuer certificate. unsigned int verify = 0; ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert, &verify, 0); if (ret < 0) throw CryptoException(gnutls_strerror(ret)); - if (verify) { - if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) - throw CryptoException("Signer cert not found"); - if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) - throw CryptoException("Signer cert keyusage error"); - if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) - throw CryptoException("Signer cert is not trusted"); - if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) - throw CryptoException("Insecure algorithm"); - if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) - throw CryptoException("Signature failure"); - if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) - throw CryptoException("Signer cert not yet activated"); - if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) - throw CryptoException("Signer cert expired"); - throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); - } - - // Check whether the OCSP response is about the provided certificate. - if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0) - throw CryptoException(gnutls_strerror(ret)); // Check certificate revocation status unsigned status_ocsp; ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status_ocsp, NULL, NULL, NULL, NULL); if (ret < 0) throw CryptoException(gnutls_strerror(ret)); - return (gnutls_ocsp_cert_status_t)status_ocsp; + gnutls_ocsp_cert_status_t certStatus = (gnutls_ocsp_cert_status_t)ret; + if (certStatus == GNUTLS_OCSP_CERT_REVOKED) + throw CryptoException("Certificate was revoked"); + else if (certStatus != GNUTLS_OCSP_CERT_GOOD) + throw CryptoException("Certificate is unknown"); + + // Ensure no replay attack has been done + gnutls_datum_t rnonce; + ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce); + if (ret < 0) + throw CryptoException(gnutls_strerror(ret)); + if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){ + gnutls_free(rnonce.data); + throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR)); + } + gnutls_free(rnonce.data); + + return (gnutls_ocsp_verify_reason_t) verify; } // RevocationList @@ -1475,7 +1359,7 @@ RevocationList::RevocationList(const Blob& b) } catch (const std::exception& e) { gnutls_x509_crl_deinit(crl); crl = nullptr; - throw; + throw e; } } diff --git a/src/default_types.cpp b/src/default_types.cpp index f5c3ae2ca..73ec669de 100644 --- a/src/default_types.cpp +++ b/src/default_types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/dht.cpp b/src/dht.cpp index 946102c2a..ef1748060 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -30,20 +30,16 @@ #include #include -#include - namespace dht { using namespace std::placeholders; constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME; constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME; -constexpr std::chrono::seconds Dht::BOOTSTRAP_PERIOD; constexpr duration Dht::LISTEN_EXPIRE_TIME; constexpr duration Dht::LISTEN_EXPIRE_TIME_PUBLIC; constexpr duration Dht::REANNOUNCE_MARGIN; static constexpr size_t MAX_REQUESTS_PER_SEC {8 * 1024}; -static constexpr duration BOOTSTRAP_PERIOD_MAX {std::chrono::hours(24)}; NodeStatus Dht::updateStatus(sa_family_t af) @@ -53,10 +49,15 @@ Dht::updateStatus(sa_family_t af) d.status = d.getStatus(scheduler.time()); if (d.status != old) { auto& other = dht(af == AF_INET ? AF_INET6 : AF_INET); - if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) { + if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) onDisconnected(); - } else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) { - onConnected(); + else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) { + // On connected + if (bootstrapJob) { + bootstrapJob->cancel(); + bootstrapJob.reset(); + } + bootstrap_period = std::chrono::seconds(10); } } return d.status; @@ -81,27 +82,11 @@ Dht::Kad::getStatus(time_point now) const } void -Dht::shutdown(ShutdownCallback cb, bool stop) +Dht::shutdown(ShutdownCallback cb) { if (not persistPath.empty()) saveState(persistPath); - if (stop) { - for (auto dht : {&dht4, &dht6}) { - for (auto& sr : dht->searches) { - for (const auto& r : sr.second->callbacks) - r.second.done_cb(false, {}); - sr.second->callbacks.clear(); - for (const auto& a : sr.second->announce) { - if (a.callback) a.callback(false, {}); - } - sr.second->announce.clear(); - sr.second->listeners.clear(); - } - } - network_engine.clear(); - } - if (not maintain_storage) { if (cb) cb(); return; @@ -288,7 +273,7 @@ Dht::searchNodeGetDone(const net::Request& req, if (srn->syncJob) scheduler.edit(srn->syncJob, syncTime); else - srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, ws)); + srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, sr)); } onGetValuesDone(req.node, answer, sr, query); } @@ -490,27 +475,25 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { } catch (std::out_of_range&) { } auto next_refresh_time = now + getType(a.value->type).expiration; - auto& acked = sn->acked[a.value->id]; - scheduler.cancel(acked.refresh); /* 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: %d)", sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id); auto created = a.permanent ? time_point::max() : a.created; - acked = { + sn->acked[a.value->id] = { network_engine.sendAnnounceValue(sn->node, sr->id, a.value, created, sn->token, onDone, onExpired), next_refresh_time }; } 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: %d)", sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id); - acked = { + sn->acked[a.value->id] = { network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone, - [this, ws, node=sn->node, v=a.value, - onDone, - onExpired, + [this, ws, node=sn->node, v=a.value, + onDone, + onExpired, created = a.permanent ? time_point::max() : a.created, next_refresh_time ](const net::Request& /*req*/, net::DhtProtocolException&& e){ @@ -534,17 +517,21 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { }; } 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: %d). Aborting.", sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id); auto ack_req = std::make_shared(net::Request::State::COMPLETED); ack_req->reply_time = now; - acked = {std::move(ack_req), next_refresh_time}; + sn->acked[a.value->id] = std::make_pair(std::move(ack_req), next_refresh_time); /* step to clear announces */ scheduler.edit(sr->nextSearchStep, now); } if (a.permanent) { - acked.refresh = scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, std::bind(&Dht::searchStep, this, ws)); + scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, [this,ws] { + if (auto sr = ws.lock()) { + searchStep(sr); + } + }); } } }; @@ -569,7 +556,7 @@ void Dht::searchSendAnnounceValue(const Sp& sr) { 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: %d)", 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), @@ -604,7 +591,7 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) std::weak_ptr ws = sr; for (const auto& l : sr->listeners) { const auto& query = l.second.query; - + auto r = n.listenStatus.find(query); if (n.getListenTime(r, listenExp) > scheduler.time()) continue; @@ -642,8 +629,8 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) if (auto sr = ws.lock()) { scheduler.edit(sr->nextSearchStep, scheduler.time()); if (auto sn = sr->getNode(req.node)) { - auto job = scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, ws)); - sn->onListenSynced(query, true, std::move(job)); + scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, sr)); + sn->onListenSynced(query); } onListenDone(req.node, answer, sr); } @@ -669,9 +656,8 @@ Dht::searchSynchedNodeListen(const Sp& sr, SearchNode& n) /* When a search is in progress, we periodically call search_step to send further requests. */ void -Dht::searchStep(std::weak_ptr ws) +Dht::searchStep(Sp sr) { - auto sr = ws.lock(); if (not sr or sr->expired or sr->done) return; const auto& now = scheduler.time(); @@ -739,7 +725,7 @@ Dht::searchStep(std::weak_ptr ws) while (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES and searchSendGetValues(sr)); - + if (sr->getNumberOfConsecutiveBadNodes() >= std::min(sr->nodes.size(), SEARCH_MAX_BAD_NODES)) { if (logger_) @@ -824,7 +810,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q sr->expired = false; sr->nodes.clear(); sr->nodes.reserve(SEARCH_NODES+1); - sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr(sr))); + sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, sr)); if (logger_) logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6'); if (search_id == 0) @@ -876,11 +862,6 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte size_t Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where) { - if (not id) { - if (logger_) - logger_->w(id, "Listen called with invalid key"); - return 0; - } scheduler.syncTime(); auto token = ++listener_token; @@ -963,9 +944,7 @@ struct GetStatus : public OpStatus { void Dht::put(const InfoHash& id, Sp val, DoneCallback callback, time_point created, bool permanent) { - if (not id or not val) { - if (logger_) - logger_->w(id, "Put called with invalid key or value"); + if (not val) { if (callback) callback(false, {}); return; @@ -1035,13 +1014,6 @@ bool callbackWrapper(Cb get_cb, DoneCallback done_cb, const std::vector>& void Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filter&& filter, Where&& where) { - if (not id) { - if (logger_) - logger_->w(id, "Get called with invalid key"); - if (donecb) - donecb(false, {}); - return; - } scheduler.syncTime(); auto op = std::make_shared>>>(); @@ -1082,13 +1054,6 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Query&& q) { - if (not id) { - if (logger_) - logger_->w(id, "Query called with invalid key"); - if (done_cb) - done_cb(false, {}); - return; - } scheduler.syncTime(); auto op = std::make_shared>>>(); auto f = q.where.getFilter(); @@ -1194,20 +1159,15 @@ Dht::cancelPut(const InfoHash& id, const Value::Id& vid) }; canceled |= sr_cancel_put(dht4.searches); canceled |= sr_cancel_put(dht6.searches); - if (canceled) { - auto st = store.find(id); - if (st != store.end()) { - if (auto value = st->second.remove(id, vid)) - storageRemoved(id, st->second, {value}, value->size()); - } - } + if (canceled) + storageErase(id, vid); return canceled; } // Storage void -Dht::storageChanged(const InfoHash& id, Storage& st, const Sp& v, bool newValue) +Dht::storageChanged(const InfoHash& id, Storage& st, ValueStorage& v, bool newValue) { if (newValue) { if (not st.local_listeners.empty()) { @@ -1217,8 +1177,8 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp& v, bool ne cbs.reserve(st.local_listeners.size()); for (const auto& l : st.local_listeners) { std::vector> vals; - if (not l.second.filter or l.second.filter(*v)) - vals.push_back(v); + if (not l.second.filter or l.second.filter(*v.data)) + vals.push_back(v.data); if (not vals.empty()) { if (logger_) logger_->d(id, "[store %s] sending update local listener with token %lu", @@ -1239,14 +1199,14 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp& v, bool ne for (const auto& node_listeners : st.listeners) { for (const auto& l : node_listeners.second) { auto f = l.second.query.where.getFilter(); - if (f and not f(*v)) + if (f and not f(*v.data)) continue; if (logger_) logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update", id.toString().c_str(), node_listeners.first->toString().c_str()); std::vector> vals {}; - vals.push_back(v); + vals.push_back(v.data); Blob ntoken = makeToken(node_listeners.first->getAddr(), false); network_engine.tellListener(node_listeners.first, l.first, id, 0, ntoken, {}, {}, std::move(vals), l.second.query, l.second.version); @@ -1282,23 +1242,30 @@ Dht::storageStore(const InfoHash& id, const Sp& value, time_point created if (auto vs = store.first) { total_store_size += store.second.size_diff; total_values += store.second.values_diff; - scheduler.cancel(vs->expiration_job); if (not permanent) { - vs->expiration_job = scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); + scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); } if (total_store_size > max_store_size) { - auto value = vs->data; - auto value_diff = store.second.values_diff; expireStore(); - storageChanged(id, st->second, value, value_diff > 0); - } else { - storageChanged(id, st->second, vs->data, store.second.values_diff > 0); } + storageChanged(id, st->second, *vs, store.second.values_diff > 0); } return std::get<0>(store); } +bool +Dht::storageErase(const InfoHash& id, Value::Id vid) +{ + auto st = store.find(id); + if (st == store.end()) + return false; + auto ret = st->second.remove(id, vid); + total_store_size += ret.size_diff; + total_values += ret.values_diff; + return ret.values_diff; +} + void Dht::storageAddListener(const InfoHash& id, const Sp& node, size_t socket_id, Query&& query, int version) { @@ -1330,8 +1297,36 @@ Dht::expireStore(decltype(store)::iterator i) const auto& id = i->first; auto& st = i->second; auto stats = st.expire(id, scheduler.time()); + total_store_size += stats.first; + total_values -= stats.second.size(); if (not stats.second.empty()) { - storageRemoved(id, st, stats.second, -stats.first); + if (logger_) + logger_->d(id, "[store %s] discarded %ld expired values (%ld bytes)", + id.toString().c_str(), stats.second.size(), -stats.first); + + if (not st.listeners.empty()) { + if (logger_) + logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size()); + + std::vector ids; + ids.reserve(stats.second.size()); + for (const auto& v : stats.second) + ids.emplace_back(v->id); + + for (const auto& node_listeners : st.listeners) { + for (const auto& l : node_listeners.second) { + if (logger_) + logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired", + id.toString().c_str(), + node_listeners.first->toString().c_str()); + Blob ntoken = makeToken(node_listeners.first->getAddr(), false); + network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version); + } + } + } + for (const auto& local_listeners : st.local_listeners) { + local_listeners.second.get_cb(stats.second, true); + } } } @@ -1343,41 +1338,6 @@ Dht::expireStorage(InfoHash h) expireStore(i); } -void -Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector>& values, size_t totalSize) -{ - if (logger_) - logger_->d(id, "[store %s] discarded %ld values (%ld bytes)", - id.toString().c_str(), values.size(), totalSize); - - total_store_size -= totalSize; - total_values -= values.size(); - - if (not st.listeners.empty()) { - if (logger_) - logger_->d(id, "[store %s] %lu remote listeners", id.toString().c_str(), st.listeners.size()); - - std::vector ids; - ids.reserve(values.size()); - for (const auto& v : values) - ids.emplace_back(v->id); - - for (const auto& node_listeners : st.listeners) { - for (const auto& l : node_listeners.second) { - if (logger_) - logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired", - id.toString().c_str(), - node_listeners.first->toString().c_str()); - Blob ntoken = makeToken(node_listeners.first->getAddr(), false); - network_engine.tellListenerExpired(node_listeners.first, l.first, id, ntoken, ids, l.second.version); - } - } - } - for (const auto& local_listeners : st.local_listeners) { - local_listeners.second.get_cb(values, true); - } -} - void Dht::expireStore() { @@ -1403,23 +1363,23 @@ Dht::expireStore() break; } auto largest = store_quota.begin(); - for (auto it = std::next(largest); it != store_quota.end(); ++it) { + for (auto it = ++largest; it != store_quota.end(); ++it) { if (it->second.size() > largest->second.size()) largest = it; } - if (largest != store_quota.end()) { - while (true) { - auto exp_value = largest->second.getOldest(); - auto storage = store.find(exp_value.first); - if (storage != store.end()) { - if (logger_) - logger_->w("Storage quota full: discarding value from %s at %s %016" PRIx64, largest->first.toString().c_str(), exp_value.first.to_c_str(), exp_value.second); - - if (auto value = storage->second.remove(exp_value.first, exp_value.second)) { - storageRemoved(storage->first, storage->second, {value}, value->size()); - break; - } - } + if (logger_) + logger_->w("No space left: discarding value of largest consumer %s", largest->first.toString().c_str()); + while (true) { + auto exp_value = largest->second.getOldest(); + auto storage = store.find(exp_value.first); + if (storage != store.end()) { + auto ret = storage->second.remove(exp_value.first, exp_value.second); + total_store_size += ret.size_diff; + total_values += ret.values_diff; + if (logger_) + logger_->w("Discarded %ld bytes, still %ld used", largest->first.toString().c_str(), total_store_size); + if (ret.values_diff) + break; } } } @@ -1443,7 +1403,6 @@ Dht::connectivityChanged(sa_family_t 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 } void @@ -1625,10 +1584,10 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const 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) { + if (ack == n.acked.end() or not ack->second.first) { out << ' '; } else { - out << ack->second.req->getStateChar(); + out << ack->second.first->getStateChar(); } } out << "] "; @@ -1668,7 +1627,7 @@ Dht::dumpTables() const std::string Dht::getStorageLog() const { - std::ostringstream out; + std::stringstream out; for (const auto& s : store) out << printStorageLog(s); out << std::endl << std::endl; @@ -1788,13 +1747,14 @@ fromDhtConfig(const Config& config) return netConf; } +Dht::Dht() : store(), network_engine(logger_, rd, scheduler, {}) {} + Dht::Dht(std::unique_ptr&& sock, const Config& config, const Sp& l) : DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom(rd)), store(), store_quota(), - max_store_keys(config.max_store_keys ? (int)config.max_store_keys : MAX_HASHES), - max_store_size(config.max_store_size ? (int)config.max_store_size : DEFAULT_STORAGE_LIMIT), + max_store_keys(config.max_store_size ? (int)config.max_store_size : MAX_HASHES), max_searches(config.max_searches ? (int)config.max_searches : MAX_SEARCHES), network_engine(myid, fromDhtConfig(config), std::move(sock), logger_, rd, scheduler, std::bind(&Dht::onError, this, _1, _2), @@ -2023,26 +1983,8 @@ Dht::expire() scheduler.add(expire_stuff_time, std::bind(&Dht::expire, this)); } -void -Dht::onConnected() -{ - stopBootstrap(); - auto callbacks = std::move(onConnectCallbacks_); - while (not callbacks.empty()) { - callbacks.front()(); - callbacks.pop(); - } -} - void Dht::onDisconnected() -{ - if (not bootstrapJob) - bootstrap(); -} - -void -Dht::bootstrap() { if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected) return; @@ -2061,23 +2003,10 @@ Dht::bootstrap() logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what()); } } - scheduler.cancel(bootstrapJob); - bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::bootstrap, this)); - bootstrap_period = std::min(bootstrap_period * 2, BOOTSTRAP_PERIOD_MAX); -} - -void -Dht::startBootstrap() -{ - stopBootstrap(); - bootstrapJob = scheduler.add(scheduler.time(), std::bind(&Dht::bootstrap, this)); -} - -void -Dht::stopBootstrap() -{ - scheduler.cancel(bootstrapJob); - bootstrap_period = BOOTSTRAP_PERIOD; + if (bootstrapJob) + bootstrapJob->cancel(); + bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::onDisconnected, this)); + bootstrap_period *= 2; } void @@ -2194,25 +2123,25 @@ Dht::exportNodes() const if (b4 != dht4.buckets.end()) { for (auto& n : b4->nodes) if (n->isGood(now)) - nodes.emplace_back(n->exportNode()); + nodes.push_back(n->exportNode()); } const auto b6 = dht6.buckets.findBucket(myid); if (b6 != dht6.buckets.end()) { for (auto& n : b6->nodes) if (n->isGood(now)) - nodes.emplace_back(n->exportNode()); + nodes.push_back(n->exportNode()); } for (auto b = dht4.buckets.begin(); b != dht4.buckets.end(); ++b) { if (b == b4) continue; for (auto& n : b->nodes) if (n->isGood(now)) - nodes.emplace_back(n->exportNode()); + nodes.push_back(n->exportNode()); } for (auto b = dht6.buckets.begin(); b != dht6.buckets.end(); ++b) { if (b == b6) continue; for (auto& n : b->nodes) if (n->isGood(now)) - nodes.emplace_back(n->exportNode()); + nodes.push_back(n->exportNode()); } return nodes; } @@ -2485,7 +2414,7 @@ Dht::onAnnounce(Sp 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 %s", hash.toString().c_str(), node.toString().c_str(), std::to_string(v->id).c_str()); } else { const auto& type = getType(lv->type); if (type.editPolicy(hash, lv, vc, node.id, node.getAddr())) { @@ -2528,7 +2457,7 @@ Dht::onRefresh(Sp node, const InfoHash& hash, const Blob& token, const Val } 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 %s", hash.toString().c_str(), node->toString().c_str(), std::to_string(vid).c_str()); } else { if (logger_) logger_->d(hash, node->id, "[store %s] [node %s] got refresh for unknown value", @@ -2563,13 +2492,9 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid) } } - auto expiration = s->second.refresh(id, now, vid, types); - if (expiration.first) { - scheduler.cancel(expiration.first->expiration_job); - if (expiration.second != time_point::max()) { - expiration.first->expiration_job = scheduler.add(expiration.second, std::bind(&Dht::expireStorage, this, id)); - } - } + auto expiration = s->second.refresh(now, vid, types); + if (expiration != time_point::max()) + scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id)); return true; } return false; @@ -2603,7 +2528,7 @@ Dht::saveState(const std::string& path) const state.nodes = exportNodes(); state.values = exportValues(); std::ofstream file(path); - msgpack::pack(file, state); + msgpack::pack(file, state); } void diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp index 71d01aee3..e4fea2e8a 100644 --- a/src/dht_proxy_client.cpp +++ b/src/dht_proxy_client.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -41,15 +41,15 @@ struct DhtProxyClient::OperationState { struct DhtProxyClient::Listener { Listener(OpValueCache&& c): - cache(std::move(c)) {} + cache(std::move(c)) + {} + unsigned callbackId; OpValueCache cache; CacheValueCallback cb; Sp opstate; std::shared_ptr request; -#ifdef OPENDHT_PUSH_NOTIFICATIONS std::unique_ptr refreshSubscriberTimer; -#endif }; struct PermanentPut { @@ -155,10 +155,10 @@ DhtProxyClient::startProxy() if (logger_) logger_->d("[proxy:client] start proxy with %s", proxyUrl_.c_str()); - nextProxyConfirmationTimer_ = std::make_unique(httpContext_, std::chrono::steady_clock::now()); + nextProxyConfirmationTimer_ = std::make_shared(httpContext_, std::chrono::steady_clock::now()); nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1)); - listenerRestartTimer_ = std::make_unique(httpContext_); + listenerRestartTimer_ = std::make_shared(httpContext_); loopSignal_(); } @@ -242,7 +242,7 @@ DhtProxyClient::cancelAllListeners() } void -DhtProxyClient::shutdown(ShutdownCallback cb, bool) +DhtProxyClient::shutdown(ShutdownCallback cb) { stop(); if (cb) @@ -720,19 +720,9 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa } auto newStatus = std::max(statusIpv4_, statusIpv6_); if (newStatus == NodeStatus::Connected) { - if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting || launchConnectedCbs_) { - launchConnectedCbs_ = false; + if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting) { listenerRestartTimer_->expires_at(std::chrono::steady_clock::now()); listenerRestartTimer_->async_wait(std::bind(&DhtProxyClient::restartListeners, this, std::placeholders::_1)); - if (not onConnectCallbacks_.empty()) { - std::lock_guard lock(lockCallbacks_); - callbacks_.emplace_back([cbs = std::move(onConnectCallbacks_)]() mutable { - while (not cbs.empty()) { - cbs.front()(); - cbs.pop(); - } - }); - } } nextProxyConfirmationTimer_->expires_at(std::chrono::steady_clock::now() + std::chrono::minutes(15)); nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1)); @@ -814,7 +804,6 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt } return false; }; -#ifdef OPENDHT_PUSH_NOTIFICATIONS if (not deviceKey_.empty()) { /* * Relaunch push listeners even if a timeout is not received @@ -827,13 +816,17 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt l->second.refreshSubscriberTimer->async_wait(std::bind(&DhtProxyClient::handleResubscribe, this, std::placeholders::_1, key, token, opstate)); } -#endif ListenMethod method; restinio::http_request_header_t header; if (deviceKey_.empty()){ // listen method = ListenMethod::LISTEN; +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + header.method(restinio::method_listen); + header.request_target("/" + key.toString()); +#else header.method(restinio::http_method_get()); header.request_target("/key/" + key.toString() + "/listen"); +#endif } else { method = ListenMethod::SUBSCRIBE; @@ -1149,8 +1142,13 @@ DhtProxyClient::restartListeners(const asio::error_code &ec) auto cb = listener.cb; // define header restinio::http_request_header_t header; +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + header.method(restinio::method_listen); + header.request_target("/" + search.first.toString()); +#else header.method(restinio::http_method_get()); header.request_target("/key/" + search.first.toString() + "/listen"); +#endif sendListen(header, cb, opstate, listener, ListenMethod::LISTEN); } } @@ -1163,9 +1161,6 @@ DhtProxyClient::pushNotificationReceived(const std::map l(lockCurrentProxyInfos_); - auto oldStatus = std::max(statusIpv4_, statusIpv6_); - if (oldStatus != NodeStatus::Connected) - launchConnectedCbs_ = true; statusIpv4_ = NodeStatus::Connected; statusIpv6_ = NodeStatus::Connected; } @@ -1231,7 +1226,7 @@ DhtProxyClient::pushNotificationReceived(const std::map lockCb(lockCallbacks_); + std::lock_guard lock(lockCallbacks_); callbacks_.emplace_back([this, key, token, opstate, ids, sendTime]() { if (opstate->stop) return; @@ -1271,7 +1266,11 @@ DhtProxyClient::resubscribe(const InfoHash& key, const size_t token, Listener& l logger_->d("[proxy:client] [resubscribe] [search %s]", key.to_c_str()); auto opstate = listener.opstate; - listener.request.reset(); // This will update ok to false + opstate->stop = true; + if (listener.request){ + listener.request.reset(); + } + opstate->stop = false; opstate->ok = true; restinio::http_request_header_t header; diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 92c514856..d1f801cae 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * Adrien Béraud * Vsevolod Ivanov @@ -38,7 +38,26 @@ using namespace std::placeholders; using namespace std::chrono_literals; -using namespace std::literals; + +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK +namespace restinio { +struct custom_http_methods_t +{ + static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept { + if(m == method_listen.raw_id()) + return method_listen; + else if(m == method_stats.raw_id()) + return method_stats; + else if(m == method_sign.raw_id()) + return method_sign; + else if(m == method_encrypt.raw_id()) + return method_encrypt; + else + return restinio::default_http_methods_t::from_nodejs(m); + } +}; +} +#endif namespace dht { constexpr char RESP_MSG_JSON_INCORRECT[] = "{\"err:\":\"Incorrect JSON\"}"; @@ -100,7 +119,7 @@ class DhtProxyServer::ConnectionListener { public: ConnectionListener() {}; - explicit ConnectionListener(std::function onClosed) : onClosed_(std::move(onClosed)) {}; + ConnectionListener(std::function onClosed) : onClosed_(std::move(onClosed)) {}; ~ConnectionListener() {}; /** @@ -137,6 +156,9 @@ DhtProxyServer::onConnectionClosed(restinio::connection_id_t id) struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits_t { using timer_manager_t = restinio::asio_timer_manager_t; +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + using http_methods_mapper_t = restinio::custom_http_methods_t; +#endif using logger_t = opendht_logger_t; using request_handler_t = RestRouter; using connection_state_listener_t = ConnectionListener; @@ -144,6 +166,9 @@ struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t { using timer_manager_t = restinio::asio_timer_manager_t; +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + using http_methods_mapper_t = restinio::custom_http_methods_t; +#endif using logger_t = opendht_logger_t; using request_handler_t = RestRouter; using connection_state_listener_t = ConnectionListener; @@ -152,25 +177,25 @@ struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t void DhtProxyServer::PermanentPut::msgpack_unpack(const msgpack::object& o) { - if (auto cid = findMapValue(o, "cid"sv)) { + if (auto cid = findMapValue(o, "cid")) { clientId = cid->as(); } - if (auto exp = findMapValue(o, "exp"sv)) { + if (auto exp = findMapValue(o, "exp")) { expiration = from_time_t(exp->as()); } - if (auto token = findMapValue(o, "token"sv)) { + if (auto token = findMapValue(o, "token")) { pushToken = token->as(); } - if (auto sid = findMapValue(o, "sid"sv)) { + if (auto sid = findMapValue(o, "sid")) { if (not sessionCtx) sessionCtx = std::make_shared(sid->as()); else sessionCtx->sessionId = sid->as(); } - if (auto t = findMapValue(o, "t"sv)) { + if (auto t = findMapValue(o, "t")) { type = t->as(); } - if (auto val = findMapValue(o, "value"sv)) { + if (auto val = findMapValue(o, "value")) { value = std::make_shared(*val); } } @@ -179,19 +204,19 @@ DhtProxyServer::PermanentPut::msgpack_unpack(const msgpack::object& o) void DhtProxyServer::Listener::msgpack_unpack(const msgpack::object& o) { - if (auto cid = findMapValue(o, "cid"sv)) { + if (auto cid = findMapValue(o, "cid")) { clientId = cid->as(); } - if (auto exp = findMapValue(o, "exp"sv)) { + if (auto exp = findMapValue(o, "exp")) { expiration = from_time_t(exp->as()); } - if (auto sid = findMapValue(o, "sid"sv)) { + if (auto sid = findMapValue(o, "sid")) { if (not sessionCtx) sessionCtx = std::make_shared(sid->as()); else sessionCtx->sessionId = sid->as(); } - if (auto t = findMapValue(o, "t"sv)) { + if (auto t = findMapValue(o, "t")) { type = t->as(); } } @@ -346,7 +371,7 @@ DhtProxyServer::loadState(Is& is, size_t size) { while (pac.next(oh)) { if (oh.get().type != msgpack::type::MAP) continue; - if (auto puts = findMapValue(oh.get(), "puts"sv)) { + if (auto puts = findMapValue(oh.get(), "puts")) { std::lock_guard lock(lockSearchPuts_); puts_ = puts->as(); if (logger_) @@ -383,9 +408,9 @@ DhtProxyServer::loadState(Is& is, size_t size) { logger_->d("No persistent puts in state"); } #ifdef OPENDHT_PUSH_NOTIFICATIONS - if (auto pushListeners = findMapValue(oh.get(), "pushListeners"sv)) { + if (auto listeners = findMapValue(oh.get(), "pushListeners")) { std::lock_guard lock(lockListener_); - pushListeners_ = pushListeners->as(); + pushListeners_ = listeners->as(); if (logger_) logger_->d("Loading %zu push listeners", pushListeners_.size()); for (auto& pushListener : pushListeners_) { @@ -588,6 +613,11 @@ DhtProxyServer::createRestRouter() // **************************** LEGACY ROUTES **************************** // node.info router->http_get("/", std::bind(&DhtProxyServer::getNodeInfo, this, _1, _2)); +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + // node.stats + router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_stats.raw_id()), + "/", std::bind(&DhtProxyServer::getStats, this, _1, _2)); +#endif // key.options router->add_handler(restinio::http_method_options(), "/:hash", std::bind(&DhtProxyServer::options, this, _1, _2)); @@ -595,6 +625,11 @@ DhtProxyServer::createRestRouter() router->http_get("/:hash", std::bind(&DhtProxyServer::get, this, _1, _2)); // key.post router->http_post("/:hash", std::bind(&DhtProxyServer::put, this, _1, _2)); +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + // key.listen + router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_listen.raw_id()), + "/:hash", std::bind(&DhtProxyServer::listen, this, _1, _2)); +#endif #ifdef OPENDHT_PUSH_NOTIFICATIONS // key.subscribe router->add_handler(restinio::http_method_subscribe(), @@ -604,6 +639,14 @@ DhtProxyServer::createRestRouter() "/:hash", std::bind(&DhtProxyServer::unsubscribe, this, _1, _2)); #endif //OPENDHT_PUSH_NOTIFICATIONS #ifdef OPENDHT_PROXY_SERVER_IDENTITY +#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK + // key.sign + router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_sign.raw_id()), + "/:hash", std::bind(&DhtProxyServer::putSigned, this, _1, _2)); + // key.encrypt + router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_encrypt.raw_id()), + "/:hash", std::bind(&DhtProxyServer::putEncrypted, this, _1, _2)); +#endif #endif // OPENDHT_PROXY_SERVER_IDENTITY // **************************** NEW ROUTES **************************** @@ -684,9 +727,9 @@ DhtProxyServer::get(restinio::request_handle_t request, { requestNum_++; try { - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); auto response = std::make_shared( initHttpResponse(request->create_response())); response->flush(); @@ -715,9 +758,9 @@ DhtProxyServer::listen(restinio::request_handle_t request, requestNum_++; try { - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); auto response = std::make_shared( initHttpResponse(request->create_response())); response->flush(); @@ -751,9 +794,9 @@ DhtProxyServer::subscribe(restinio::request_handle_t request, { requestNum_++; try { - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); std::string err; Json::Value r; @@ -779,7 +822,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request, logger_->d("[proxy:server] [subscribe %s] [client %s] [session %s]", infoHash.toString().c_str(), clientId.c_str(), sessionId.c_str()); // Insert new or return existing push listeners of a token - std::lock_guard lock(lockListener_); + std::lock_guard lock(lockPushListeners_); auto& pushListener = pushListeners_[pushToken]; auto& pushListeners = pushListener.listeners[infoHash]; @@ -893,9 +936,9 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request, { requestNum_++; - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); if (logger_) logger_->d("[proxy:server] [unsubscribe %s]", infoHash.toString().c_str()); @@ -1005,13 +1048,7 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso notification["platform"] = type == PushType::Android ? 2 : 1; notification["data"] = std::move(json); notification["priority"] = highPriority ? "high" : "normal"; - if (type == PushType::Android) - notification["time_to_live"] = 3600 * 24; // 24 hours - else { - const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24); - uint32_t exp = std::chrono::duration_cast(expiration.time_since_epoch()).count(); - notification["expiration"] = exp; - } + notification["time_to_live"] = 600; Json::Value notifications(Json::arrayValue); notifications[0] = notification; @@ -1081,9 +1118,9 @@ DhtProxyServer::put(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1222,9 +1259,9 @@ DhtProxyServer::putSigned(restinio::request_handle_t request, restinio::router::route_params_t params) const { requestNum_++; - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1272,9 +1309,9 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - InfoHash infoHash(params["hash"]); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); if (request->body().empty()){ auto response = initHttpResponse(request->create_response(restinio::status_bad_request())); @@ -1344,10 +1381,10 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request, restinio::router::route_params_t params) { requestNum_++; - auto query = params["value"]; - InfoHash infoHash(params["hash"]); + auto value = params["value"].to_string(); + InfoHash infoHash(params["hash"].to_string()); if (!infoHash) - infoHash = InfoHash::get(params["hash"]); + infoHash = InfoHash::get(params["hash"].to_string()); try { auto response = std::make_shared( @@ -1362,7 +1399,7 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request, [response] (bool /*ok*/){ response->done(); }, - {}, query); + {}, value); return restinio::request_handling_status_t::accepted; } catch (const std::exception& e){ return serverError(*request); diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp index ded8baca9..2ece5e217 100644 --- a/src/dhtrunner.cpp +++ b/src/dhtrunner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -36,6 +36,7 @@ namespace dht { +constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD; static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht"; struct DhtRunner::Listener { @@ -75,17 +76,19 @@ DhtRunner::~DhtRunner() } void -DhtRunner::run(in_port_t port, Config& config, Context&& context) +DhtRunner::run(in_port_t port, const Config& config, Context&& context) { - config.bind4.setFamily(AF_INET); - config.bind4.setPort(port); - config.bind6.setFamily(AF_INET6); - config.bind6.setPort(port); - run(config, std::move(context)); + SockAddr sin4; + sin4.setFamily(AF_INET); + sin4.setPort(port); + SockAddr sin6; + sin6.setFamily(AF_INET6); + sin6.setPort(port); + run(sin4, sin6, config, std::move(context)); } void -DhtRunner::run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context) +DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context) { auto res4 = SockAddr::resolve(ip4, service); auto res6 = SockAddr::resolve(ip6, service); @@ -93,109 +96,84 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, Config& co res4.emplace_back(); if (res6.empty()) res6.emplace_back(); - config.bind4 = std::move(res4.front()); - config.bind6 = std::move(res6.front()); - run(config, std::move(context)); + run(res4.front(), res6.front(), config, std::move(context)); } void -DhtRunner::run(const Config& config, Context&& context) +DhtRunner::run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context) { - std::lock_guard lck(dht_mtx); - 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.", this); - return; - } - - try { - auto local4 = config.bind4; - 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", this); - local4.setFamily(AF_INET); - local6.setFamily(AF_INET6); - } + if (running == State::Idle) { auto state_path = config.dht_config.node_config.persist_path; - if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) { + if (not state_path.empty()) { state_path += "_port.txt"; std::ifstream inConfig(state_path); if (inConfig.is_open()) { in_port_t port; if (inConfig >> port) { - if (local4.getPort() == 0) { - if (context.logger) - context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port); + if (context.logger) + context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port); + if (local4.getPort() == 0) 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", this, port); + if (context.logger) + context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port); + if (local6.getPort() == 0) local6.setPort(port); - } } } } - if (context.logger) { - logger_ = context.logger; - } - - if (not context.sock) { + if (not context.sock) context.sock.reset(new net::UdpSocket(local4, local6, context.logger)); - } if (not state_path.empty()) { std::ofstream outConfig(state_path); outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl; outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl; } + run(config, std::move(context)); + } +} - if (context.logger) { - logger_->d("[runner %p] state changed to Running", this); - } +void +DhtRunner::run(const Config& config, Context&& context) +{ + std::lock_guard lck(dht_mtx); + auto expected = State::Idle; + if (not running.compare_exchange_strong(expected, State::Running)) + return; - context.sock->setOnReceive([&] (net::PacketList&& pkts) { - net::PacketList ret; - { - std::lock_guard lck(sock_mtx); - rcv.splice(rcv.end(), std::move(pkts)); - size_t dropped = 0; - while (rcv.size() > net::RX_QUEUE_MAX_SIZE) { - rcv.pop_front(); - dropped++; - } - if (dropped and logger_) { - logger_->w("[runner %p] dropped %zu packets: queue is full!", this, dropped); - } - ret = std::move(rcv_free); + if (context.logger) { + logger_ = context.logger; + logger_->d("[runner %p] state changed to Running", this); + } + + context.sock->setOnReceive([&] (net::PacketList&& pkts) { + net::PacketList ret; + { + std::lock_guard lck(sock_mtx); + auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size(); + while (rcv.size() > maxSize) { + if (logger_) + logger_->e("Dropping packet: queue is full!"); + rcv.pop_front(); } - cv.notify_all(); - return ret; - }); + + rcv.splice(rcv.end(), std::move(pkts)); + ret = std::move(rcv_free); + } + cv.notify_all(); + return ret; + }); + + auto dht = std::unique_ptr(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger)); + dht_ = std::unique_ptr(new SecureDht(std::move(dht), config.dht_config)); #ifdef OPENDHT_PROXY_CLIENT - config_ = config; - identityAnnouncedCb_ = context.identityAnnouncedCb; -#endif - auto dht = std::make_unique(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger); - dht_ = std::make_unique(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger); - enableProxy(not config.proxy_server.empty()); - } catch(const std::exception& e) { - config_ = {}; - identityAnnouncedCb_ = {}; - dht_.reset(); -#ifdef OPENDHT_PROXY_CLIENT - dht_via_proxy_.reset(); + config_ = config; #endif - running = State::Idle; - throw; - } - + enableProxy(not config.proxy_server.empty()); if (context.logger and dht_via_proxy_) { dht_via_proxy_->setLogger(context.logger); } @@ -283,39 +261,29 @@ DhtRunner::run(const Config& config, Context&& context) } void -DhtRunner::shutdown(ShutdownCallback cb, bool stop) { - std::unique_lock lck(storage_mtx); +DhtRunner::shutdown(ShutdownCallback cb) { auto expected = State::Running; if (not running.compare_exchange_strong(expected, State::Stopping)) { if (expected == State::Stopping and ongoing_ops) { + std::lock_guard lck(storage_mtx); shutdownCallbacks_.emplace_back(std::move(cb)); } - else if (cb) { - lck.unlock(); - cb(); - } + else if (cb) cb(); return; } if (logger_) logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load()); -#ifdef OPENDHT_PROXY_CLIENT - ongoing_ops += 2; -#else + std::lock_guard lck(storage_mtx); ongoing_ops++; -#endif shutdownCallbacks_.emplace_back(std::move(cb)); - pending_ops.emplace([=](SecureDht&) mutable { + pending_ops_prio.emplace([=](SecureDht&) mutable { auto onShutdown = [this]{ opEnded(); }; #ifdef OPENDHT_PROXY_CLIENT if (dht_via_proxy_) - dht_via_proxy_->shutdown(onShutdown, stop); - else - opEnded(); + dht_via_proxy_->shutdown(onShutdown); #endif if (dht_) - dht_->shutdown(onShutdown, stop); - else - opEnded(); + dht_->shutdown(onShutdown); }); cv.notify_all(); } @@ -344,11 +312,11 @@ DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) { bool DhtRunner::checkShutdown() { + if (running != State::Stopping or ongoing_ops) + return false; decltype(shutdownCallbacks_) cbs; { std::lock_guard lck(storage_mtx); - if (running != State::Stopping or ongoing_ops) - return false; cbs = std::move(shutdownCallbacks_); } for (auto& cb : cbs) @@ -380,13 +348,9 @@ DhtRunner::join() { std::lock_guard lck(storage_mtx); - if (ongoing_ops and logger_) { - 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)(); ongoing_ops = 0; - shutdownCallbacks_.clear(); } { std::lock_guard lck(dht_mtx); @@ -429,14 +393,6 @@ DhtRunner::getId() const return {}; } -std::shared_ptr -DhtRunner::getPublicKey() const -{ - if (auto dht = activeDht()) - return dht->getPublicKey(); - return {}; -} - InfoHash DhtRunner::getNodeId() const { @@ -572,7 +528,6 @@ DhtRunner::getNodeInfo(std::function)> cb) info.node_id = dht.getNodeId(); info.ipv4 = dht.getNodesStats(AF_INET); info.ipv6 = dht.getNodesStats(AF_INET6); - std::tie(info.storage_size, info.storage_values) = dht.getStoreSize(); if (auto sock = dht.getSocket()) { info.bound4 = sock->getBoundRef(AF_INET).getPort(); info.bound6 = sock->getBoundRef(AF_INET6).getPort(); @@ -638,18 +593,6 @@ DhtRunner::getPublicAddressStr(sa_family_t af) return ret; } -void -DhtRunner::getPublicAddress(std::function&&)> cb, sa_family_t af) -{ - std::lock_guard lck(storage_mtx); - ongoing_ops++; - pending_ops_prio.emplace([cb = std::move(cb), this, af](SecureDht& dht){ - cb(dht.getPublicAddress(af)); - opEnded(); - }); - cv.notify_all(); -} - void DhtRunner::registerCertificate(std::shared_ptr cert) { std::lock_guard lck(dht_mtx); @@ -729,8 +672,8 @@ DhtRunner::loop_() rcv_free.splice(rcv_free.end(), std::move(received_treated)); } - if (dropped && logger_) - logger_->e("[runner %p] Dropped %zu packets with high delay.", this, dropped); + if (dropped) + std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl; NodeStatus nstatus4 = dht->updateStatus(AF_INET); NodeStatus nstatus6 = dht->updateStatus(AF_INET6); @@ -747,12 +690,11 @@ DhtRunner::loop_() void DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (dcb) dcb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=](SecureDht& dht) mutable { dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w)); @@ -767,12 +709,11 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, } void DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (done_cb) done_cb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=](SecureDht& dht) mutable { dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q)); @@ -784,12 +725,11 @@ std::future DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w) { auto ret_token = std::make_shared>(); - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); ret_token->set_value(0); return ret_token->get_future(); } + std::lock_guard lck(storage_mtx); pending_ops.emplace([=](SecureDht& dht) mutable { #ifdef OPENDHT_PROXY_CLIENT auto tokenbGlobal = listener_token_++; @@ -827,28 +767,19 @@ void DhtRunner::cancelListen(InfoHash h, size_t token) { std::lock_guard lck(storage_mtx); - if (running != State::Running) - return; - ongoing_ops++; #ifdef OPENDHT_PROXY_CLIENT pending_ops.emplace([=](SecureDht&) { auto it = listeners_.find(token); - if (it != listeners_.end()) { - if (it->second.tokenClassicDht) - dht_->cancelListen(h, it->second.tokenClassicDht); - if (it->second.tokenProxyDht and dht_via_proxy_) - dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); - listeners_.erase(it); - } else { - if (logger_) - logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token); - } - opEnded(); + if (it == listeners_.end()) return; + if (it->second.tokenClassicDht) + dht_->cancelListen(h, it->second.tokenClassicDht); + if (it->second.tokenProxyDht and dht_via_proxy_) + dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); + listeners_.erase(it); }); #else pending_ops.emplace([=](SecureDht& dht) { dht.cancelListen(h, token); - opEnded(); }); #endif // OPENDHT_PROXY_CLIENT cv.notify_all(); @@ -858,29 +789,19 @@ void DhtRunner::cancelListen(InfoHash h, std::shared_future ftoken) { std::lock_guard lck(storage_mtx); - if (running != State::Running) - return; - ongoing_ops++; #ifdef OPENDHT_PROXY_CLIENT - pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht&) { - auto token = ftoken.get(); - auto it = listeners_.find(token); - if (it != listeners_.end()) { - if (it->second.tokenClassicDht) - dht_->cancelListen(h, it->second.tokenClassicDht); - if (it->second.tokenProxyDht and dht_via_proxy_) - dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); - listeners_.erase(it); - } else { - if (logger_) - logger_->w("[runner %p] cancelListen: unknown token %zu.", this, token); - } - opEnded(); + pending_ops.emplace([=](SecureDht&) { + auto it = listeners_.find(ftoken.get()); + if (it == listeners_.end()) return; + if (it->second.tokenClassicDht) + dht_->cancelListen(h, it->second.tokenClassicDht); + if (it->second.tokenProxyDht and dht_via_proxy_) + dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht); + listeners_.erase(it); }); #else - pending_ops.emplace([this, h, ftoken = std::move(ftoken)](SecureDht& dht) { + pending_ops.emplace([=](SecureDht& dht) { dht.cancelListen(h, ftoken.get()); - opEnded(); }); #endif // OPENDHT_PROXY_CLIENT cv.notify_all(); @@ -889,12 +810,11 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future ftoken) void DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (cb) cb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -908,14 +828,13 @@ DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created void DhtRunner::put(InfoHash hash, std::shared_ptr value, DoneCallback cb, time_point created, bool permanent) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (cb) cb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; - pending_ops.emplace([=, value = std::move(value), cb = std::move(cb)](SecureDht& dht) mutable { + pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable { dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent); }); cv.notify_all(); @@ -950,12 +869,11 @@ DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr& value) void DhtRunner::putSigned(InfoHash hash, std::shared_ptr value, DoneCallback cb, bool permanent) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (cb) cb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -981,12 +899,11 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c void DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr value, DoneCallback cb, bool permanent) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (cb) cb(false, {}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([=, cb = std::move(cb), @@ -1009,31 +926,6 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done putEncrypted(InfoHash::get(key), to, std::forward(value), std::move(cb), permanent); } -void -DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr& to, std::shared_ptr value, DoneCallback cb, bool permanent) -{ - std::unique_lock lck(storage_mtx); - if (running != State::Running) { - lck.unlock(); - if (cb) cb(false, {}); - return; - } - ongoing_ops++; - pending_ops.emplace([=, - cb = std::move(cb), - value = std::move(value) - ] (SecureDht& dht) mutable { - dht.putEncrypted(hash, *to, value, bindOpDoneCallback(std::move(cb)), permanent); - }); - cv.notify_all(); -} - -void -DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr& to, Value&& value, DoneCallback cb, bool permanent) -{ - putEncrypted(hash, to, std::make_shared(std::move(value)), std::move(cb), permanent); -} - void DhtRunner::bootstrap(const std::string& host, const std::string& service) { @@ -1065,7 +957,7 @@ DhtRunner::clearBootstrap() } void -DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple cb) +DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple&& cb) { if (running != State::Running) { cb(false); @@ -1095,16 +987,15 @@ DhtRunner::bootstrap(std::vector nodes, DoneCallbackSimple cb) } void -DhtRunner::bootstrap(SockAddr addr, DoneCallbackSimple cb) +DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); if (cb) cb(false); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; - pending_ops_prio.emplace([addr = std::move(addr), cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable { + pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable { dht.pingNode(std::move(addr), std::move(cb)); }); cv.notify_all(); @@ -1113,9 +1004,9 @@ DhtRunner::bootstrap(SockAddr addr, DoneCallbackSimple cb) void DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address) { - std::lock_guard lck(storage_mtx); if (running != State::Running) return; + std::unique_lock lck(storage_mtx); pending_ops_prio.emplace([id, address](SecureDht& dht) mutable { dht.insertNode(id, address); }); @@ -1123,12 +1014,12 @@ DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address) } void -DhtRunner::bootstrap(std::vector nodes) +DhtRunner::bootstrap(const std::vector& nodes) { - std::lock_guard lck(storage_mtx); if (running != State::Running) return; - pending_ops_prio.emplace([nodes = std::move(nodes)](SecureDht& dht) { + std::lock_guard lck(storage_mtx); + pending_ops_prio.emplace([=](SecureDht& dht) { for (auto& node : nodes) dht.insertNode(node); }); @@ -1151,12 +1042,11 @@ DhtRunner::connectivityChanged() void DhtRunner::findCertificate(InfoHash hash, std::function&)> cb) { - std::unique_lock lck(storage_mtx); if (running != State::Running) { - lck.unlock(); cb({}); return; } + std::lock_guard lck(storage_mtx); ongoing_ops++; pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) { dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp& crt){ @@ -1232,7 +1122,7 @@ DhtRunner::enableProxy(bool proxify) if (not config_.push_token.empty()) dht_via_proxy->setPushNotificationToken(config_.push_token); #endif - dht_via_proxy_ = std::unique_ptr(new SecureDht(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_)); + dht_via_proxy_ = std::unique_ptr(new SecureDht(std::move(dht_via_proxy), config_.dht_config)); // add current listeners for (auto& l: listeners_) l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w); diff --git a/src/http.cpp b/src/http.cpp index 203b526a8..983bcc4b2 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Vsevolod Ivanov * * This program is free software; you can redistribute it and/or modify @@ -561,63 +561,12 @@ void Connection::async_connect(std::vector&& endpoints, ConnectHandlerCb cb) { std::lock_guard lock(mutex_); - if (!ssl_socket_ && !socket_) { - cb(asio::error::operation_aborted, {}); - return; - } - auto& base = ssl_socket_? ssl_socket_->lowest_layer() : *socket_; - - ConnectHandlerCb wcb = [&base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) { - if (!ec) { - auto socket = base.native_handle(); - // 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() - 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); - }; if (ssl_socket_) - asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(wcb))); - else - asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(wcb))); + asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(cb))); + else if (socket_) + asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(cb))); + else if (cb) + cb(asio::error::operation_aborted, {}); } void @@ -1305,11 +1254,9 @@ Request::terminate(const asio::error_code& ec) return; response_.aborted = ec == asio::error::operation_aborted; - if (ec == asio::error::basic_errors::broken_pipe) - response_.status_code = 0U; // Avoid to give a successful answer (happen with a broken pipe, takes the last status) if (logger_) { - if (ec and ec != asio::error::eof and !response_.aborted) + if (ec and ec != asio::error::eof and ec != asio::error::operation_aborted) logger_->e("[http:request:%i] end with error: %s", id_, ec.message().c_str()); else logger_->d("[http:request:%i] done with status code %u", id_, response_.status_code); @@ -1468,7 +1415,7 @@ Request::await() std::unique_lock lock(mtx); std::condition_variable cv; bool ok {false}; - add_on_done_callback([&](const Response&){ + add_on_done_callback([&](const Response& resp){ std::lock_guard lk(mtx); ok = true; cv.notify_all(); diff --git a/src/indexation/pht.cpp b/src/indexation/pht.cpp index 0840c0e3f..2494365cc 100644 --- a/src/indexation/pht.cpp +++ b/src/indexation/pht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * Nicolas Reynaud diff --git a/src/infohash.cpp b/src/infohash.cpp index 84d04ae2e..69c79b8a9 100644 --- a/src/infohash.cpp +++ b/src/infohash.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -22,8 +22,6 @@ #include #include -using namespace std::literals; - namespace dht { const HexMap hex_map = {}; @@ -35,9 +33,9 @@ NodeExport::msgpack_unpack(msgpack::object o) throw msgpack::type_error(); if (o.via.map.size < 2) throw msgpack::type_error(); - if (o.via.map.ptr[0].key.as() != "id"sv) + if (o.via.map.ptr[0].key.as() != "id") throw msgpack::type_error(); - if (o.via.map.ptr[1].key.as() != "addr"sv) + if (o.via.map.ptr[1].key.as() != "addr") throw msgpack::type_error(); const auto& addr = o.via.map.ptr[1].val; if (addr.type != msgpack::type::BIN) diff --git a/src/listener.h b/src/listener.h index 0087952df..18663f0bb 100644 --- a/src/listener.h +++ b/src/listener.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/log.cpp b/src/log.cpp index 100f0f74b..b9a62204c 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -38,7 +38,7 @@ printLog(std::ostream& s, char const *m, va_list args) { // print log to buffer std::array buffer; int ret = vsnprintf(buffer.data(), buffer.size(), m, args); - if (ret <= 0) + if (ret < 0) return; // write timestamp @@ -89,7 +89,7 @@ std::shared_ptr getSyslogLogger(const char* name) { #ifndef _WIN32 struct Syslog { - explicit Syslog(const char* n) { + Syslog(const char* n) { openlog(n, LOG_NDELAY, LOG_USER); } ~Syslog() { diff --git a/src/net.h b/src/net.h index e7bdf3899..dd4b91473 100644 --- a/src/net.h +++ b/src/net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/network_engine.cpp b/src/network_engine.cpp index 4bfaeb59d..10991629c 100644 --- a/src/network_engine.cpp +++ b/src/network_engine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -82,6 +82,10 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg) nodes6(std::move(msg.nodes6)) {} +NetworkEngine::NetworkEngine(const Sp& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr&& sock) + : myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler) +{} + NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c, std::unique_ptr&& sock, const Sp& log, @@ -116,7 +120,7 @@ NetworkEngine::~NetworkEngine() { } void -NetworkEngine::tellListener(const Sp& node, Tid socket_id, const InfoHash& hash, want_t want, +NetworkEngine::tellListener(Sp node, Tid socket_id, const InfoHash& hash, want_t want, const Blob& ntoken, std::vector>&& nodes, std::vector>&& nodes6, std::vector>&& values, const Query& query, int version) @@ -135,7 +139,7 @@ NetworkEngine::tellListener(const Sp& node, Tid socket_id, const InfoHash& } void -NetworkEngine::tellListenerRefreshed(const Sp& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) +NetworkEngine::tellListenerRefreshed(Sp n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) { msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -186,7 +190,7 @@ NetworkEngine::tellListenerRefreshed(const Sp& n, Tid socket_id, const Inf } void -NetworkEngine::tellListenerExpired(const Sp& n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) +NetworkEngine::tellListenerExpired(Sp n, Tid socket_id, const InfoHash&, const Blob& token, const std::vector& values, int version) { msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -219,7 +223,7 @@ NetworkEngine::tellListenerExpired(const Sp& n, Tid socket_id, const InfoH Tid tid (n->getNewTid()); pk.pack(KEY_Q); pk.pack(QUERY_UPDATE); - pk.pack(KEY_TID); pk.pack(tid); + pk.pack(KEY_TID); pk.pack(tid); auto req = std::make_shared(MessageType::UpdateValue, tid, n, Blob(buffer.data(), buffer.data() + buffer.size()), @@ -376,7 +380,7 @@ NetworkEngine::isMartian(const SockAddr& addr) 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, zeroes.data(), 16) == 0 || memcmp(address, v4prefix, 12) == 0; } default: @@ -456,13 +460,9 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f) pmsg_it->second.last_part = now; // check data completion if (pmsg_it->second.msg->complete()) { - try { - // process the full message - process(std::move(pmsg_it->second.msg), from); - partial_messages.erase(pmsg_it); - } catch (...) { - return; - } + // process the full message + process(std::move(pmsg_it->second.msg), from); + partial_messages.erase(pmsg_it); } else scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, msg->tid)); } @@ -485,11 +485,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f) } if (msg->value_parts.empty()) { - try { - process(std::move(msg), from); - } catch(...) { - return; - } + process(std::move(msg), from); } else { // starting partial message session auto k = msg->tid; @@ -519,15 +515,8 @@ NetworkEngine::process(std::unique_ptr&& 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 (DhtProtocolException &ex) { - if (logIncoming_) - if (logger_) - logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); - return; - } + 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); @@ -590,26 +579,13 @@ NetworkEngine::process(std::unique_ptr&& msg, const SockAddr& fro r.node->authSuccess(); } r.reply_time = scheduler.time(); - try { - deserializeNodes(*msg, from); - r.setDone(std::move(*msg)); - } catch (DhtProtocolException &ex) { - if (logIncoming_) - if (logger_) - logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); - return; - } + + 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 (DhtProtocolException &ex) { - if (logIncoming_) - if (logger_) - logger_->ERR("Exception in deserializeNodes: %s, code: %u", ex.getMsg().c_str(), ex.getCode()); - return; - } + deserializeNodes(*msg, from); + rsocket->on_receive(node, std::move(*msg)); } break; default: @@ -719,7 +695,7 @@ NetworkEngine::send(const SockAddr& addr, const char *buf, size_t len, bool conf } Sp -NetworkEngine::sendPing(const Sp& node, RequestCb&& on_done, RequestExpiredCb&& on_expired) { +NetworkEngine::sendPing(Sp node, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (node->getNewTid()); msgpack::sbuffer buffer; msgpack::packer pk(&buffer); @@ -777,7 +753,7 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) { } Sp -NetworkEngine::sendFindNode(const Sp& n, const InfoHash& target, want_t want, +NetworkEngine::sendFindNode(Sp n, const InfoHash& target, want_t want, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (n->getNewTid()); msgpack::sbuffer buffer; @@ -822,7 +798,7 @@ NetworkEngine::sendFindNode(const Sp& n, const InfoHash& target, want_t wa Sp -NetworkEngine::sendGetValues(const Sp& n, const InfoHash& info_hash, const Query& query, want_t want, +NetworkEngine::sendGetValues(Sp n, const InfoHash& info_hash, const Query& query, want_t want, RequestCb&& on_done, RequestExpiredCb&& on_expired) { Tid tid (n->getNewTid()); msgpack::sbuffer buffer; @@ -975,8 +951,8 @@ NetworkEngine::sendValueParts(Tid tid, const std::vector& svals, const Soc pk.pack(KEY_TID); pk.pack(tid); pk.pack(KEY_V); pk.pack_map(1); pk.pack(i); pk.pack_map(2); - pk.pack("o"sv); pk.pack(start); - pk.pack("d"sv); pk.pack_bin(end-start); + pk.pack(std::string("o")); pk.pack(start); + pk.pack(std::string("d")); pk.pack_bin(end-start); pk.pack_bin_body((const char*)v.data()+start, end-start); send(addr, buffer.data(), buffer.size()); start = end; @@ -1018,8 +994,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes, auto fields = query.select.getSelection(); pk.pack(KEY_REQ_FIELDS); pk.pack_map(2); - pk.pack("f"sv); pk.pack(fields); - pk.pack("v"sv); pk.pack_array(st.size()*fields.size()); + pk.pack(std::string("f")); pk.pack(fields); + pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size()); for (const auto& v : st) v->msgpack_pack_fields(fields, pk); //DHT_LOG_DBG("sending closest nodes (%d+%d nodes.), %u value headers containing %u fields", @@ -1093,7 +1069,7 @@ NetworkEngine::bufferNodes(sa_family_t af, const InfoHash& id, want_t want, } Sp -NetworkEngine::sendListen(const Sp& n, +NetworkEngine::sendListen(Sp n, const InfoHash& hash, const Query& query, const Blob& token, @@ -1162,7 +1138,7 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) { } Sp -NetworkEngine::sendAnnounceValue(const Sp& n, +NetworkEngine::sendAnnounceValue(Sp n, const InfoHash& infohash, const Sp& value, time_point created, @@ -1175,12 +1151,11 @@ NetworkEngine::sendAnnounceValue(const Sp& n, msgpack::packer pk(&buffer); 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); + pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4)); pk.pack(KEY_REQ_ID); pk.pack(myid); pk.pack(KEY_REQ_H); pk.pack(infohash); auto v = packValueHeader(buffer, {value}); - if (add_created) { + if (created < scheduler.time()) { pk.pack(KEY_REQ_CREATION); pk.pack(to_time_t(created)); } @@ -1221,7 +1196,7 @@ NetworkEngine::sendAnnounceValue(const Sp& n, } Sp -NetworkEngine::sendUpdateValues(const Sp& n, +NetworkEngine::sendUpdateValues(Sp n, const InfoHash& infohash, const std::vector>& values, time_point created, @@ -1267,7 +1242,7 @@ NetworkEngine::sendUpdateValues(const Sp& n, } Sp -NetworkEngine::sendRefreshValue(const Sp& n, +NetworkEngine::sendRefreshValue(Sp n, const InfoHash& infohash, const Value::Id& vid, const Blob& token, diff --git a/src/network_utils.cpp b/src/network_utils.cpp index e9cd4ee5f..b7e3588ad 100644 --- a/src/network_utils.cpp +++ b/src/network_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/node.cpp b/src/node.cpp index c444bbe22..d207cb68f 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -137,7 +137,10 @@ Node::openSocket(SocketCb&& cb) if (++transaction_id == 0) transaction_id = 1; - sockets_[transaction_id] = std::make_shared(std::move(cb)); + auto sock = std::make_shared(std::move(cb)); + auto s = sockets_.emplace(transaction_id, std::move(sock)); + if (not s.second) + s.first->second = std::move(sock); return transaction_id; } diff --git a/src/node_cache.cpp b/src/node_cache.cpp index 34366c4e0..dc25b386e 100644 --- a/src/node_cache.cpp +++ b/src/node_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/op_cache.cpp b/src/op_cache.cpp index de2c4606d..6c6ebb7bc 100644 --- a/src/op_cache.cpp +++ b/src/op_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -175,7 +175,7 @@ SearchCache::listen(const ValueCallback& get_cb, const Sp& q, const Value auto op = getOp(q); if (op == ops.end()) { // New query - op = ops.emplace(q, std::make_unique()).first; + op = ops.emplace(q, std::unique_ptr(new OpCache)).first; auto& cache = *op->second; cache.searchToken = onListen(q, [&](const std::vector>& values, bool expired){ return cache.onValue(values, expired); diff --git a/src/op_cache.h b/src/op_cache.h index a32751fea..516681575 100644 --- a/src/op_cache.h +++ b/src/op_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -28,13 +28,13 @@ struct OpCacheValueStorage Sp data {}; unsigned refCount {1}; system_clock::time_point updated {system_clock::time_point::min()}; - explicit OpCacheValueStorage(Sp val) : data(std::move(val)) {} + OpCacheValueStorage(Sp val) : data(val) {} }; class OpValueCache { public: OpValueCache(ValueCallback&& cb) noexcept : callback(std::forward(cb)) {} - explicit OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) { + OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) { o.callback = {}; } @@ -51,8 +51,8 @@ class OpValueCache { } bool onValue(const std::vector>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) { - return expired - ? onValuesExpired(vals, t) + return expired + ? onValuesExpired(vals, t) : onValuesAdded(vals, t); } @@ -74,7 +74,6 @@ class OpValueCache { std::vector> get(const Value::Filter& filter) const; Sp get(Value::Id id) const; std::vector> getValues() const; - size_t size() const { return values.size(); } private: OpValueCache(const OpValueCache&) = delete; @@ -146,11 +145,7 @@ class OpCache { } time_point getExpiration() const; - size_t size() const { - return cache.size(); - } - - size_t searchToken {0}; + size_t searchToken; private: constexpr static const std::chrono::seconds EXPIRATION {60}; OpCache(const OpCache&) = delete; @@ -181,13 +176,6 @@ class SearchCache { std::vector> get(const Value::Filter& filter) const; Sp get(Value::Id id) const; - std::pair size() const { - size_t tot = 0; - for (const auto& c : ops) - tot += c.second->size(); - return {ops.size(), tot}; - } - private: SearchCache(const SearchCache&) = delete; SearchCache& operator=(const SearchCache&) = delete; diff --git a/src/parsed_message.h b/src/parsed_message.h index 6f5063c06..70de16d7d 100644 --- a/src/parsed_message.h +++ b/src/parsed_message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -22,50 +22,47 @@ #include "net.h" #include -#include - -using namespace std::literals; namespace dht { namespace net { -static constexpr auto KEY_Y = "y"sv; -static constexpr auto KEY_R = "r"sv; -static constexpr auto KEY_U = "u"sv; -static constexpr auto KEY_E = "e"sv; -static constexpr auto KEY_V = "p"sv; -static constexpr auto KEY_TID = "t"sv; -static constexpr auto KEY_UA = "v"sv; -static constexpr auto KEY_NETID = "n"sv; -static constexpr auto KEY_ISCLIENT = "s"sv; -static constexpr auto KEY_Q = "q"sv; -static constexpr auto KEY_A = "a"sv; +static const std::string KEY_Y {"y"}; +static const std::string KEY_R {"r"}; +static const std::string KEY_U {"u"}; +static const std::string KEY_E {"e"}; +static const std::string KEY_V {"p"}; +static const std::string KEY_TID {"t"}; +static const std::string KEY_UA {"v"}; +static const std::string KEY_NETID {"n"}; +static const std::string KEY_ISCLIENT {"s"}; +static const std::string KEY_Q {"q"}; +static const std::string KEY_A {"a"}; -static constexpr auto KEY_REQ_SID = "sid"sv; -static constexpr auto KEY_REQ_ID = "id"sv; -static constexpr auto KEY_REQ_H = "h"sv; -static constexpr auto KEY_REQ_TARGET = "target"sv; -static constexpr auto KEY_REQ_QUERY = "q"sv; -static constexpr auto KEY_REQ_TOKEN = "token"sv; -static constexpr auto KEY_REQ_VALUE_ID = "vid"sv; -static constexpr auto KEY_REQ_NODES4 = "n4"sv; -static constexpr auto KEY_REQ_NODES6 = "n6"sv; -static constexpr auto KEY_REQ_CREATION = "c"sv; -static constexpr auto KEY_REQ_ADDRESS = "sa"sv; -static constexpr auto KEY_REQ_VALUES = "values"sv; -static constexpr auto KEY_REQ_EXPIRED = "exp"sv; -static constexpr auto KEY_REQ_REFRESHED = "re"sv; -static constexpr auto KEY_REQ_FIELDS = "fileds"sv; -static constexpr auto KEY_REQ_WANT = "w"sv; -static constexpr auto KEY_VERSION = "ve"sv; +static const std::string KEY_REQ_SID {"sid"}; +static const std::string KEY_REQ_ID {"id"}; +static const std::string KEY_REQ_H {"h"}; +static const std::string KEY_REQ_TARGET {"target"}; +static const std::string KEY_REQ_QUERY {"q"}; +static const std::string KEY_REQ_TOKEN {"token"}; +static const std::string KEY_REQ_VALUE_ID {"vid"}; +static const std::string KEY_REQ_NODES4 {"n4"}; +static const std::string KEY_REQ_NODES6 {"n6"}; +static const std::string KEY_REQ_CREATION {"c"}; +static const std::string KEY_REQ_ADDRESS {"sa"}; +static const std::string KEY_REQ_VALUES {"values"}; +static const std::string KEY_REQ_EXPIRED {"exp"}; +static const std::string KEY_REQ_REFRESHED {"re"}; +static const std::string KEY_REQ_FIELDS {"fileds"}; +static const std::string KEY_REQ_WANT {"w"}; +static const std::string KEY_VERSION {"ve"}; -static constexpr auto QUERY_PING = "ping"sv; -static constexpr auto QUERY_FIND = "find"sv; -static constexpr auto QUERY_GET = "get"sv; -static constexpr auto QUERY_UPDATE = "update"sv; -static constexpr auto QUERY_PUT = "put"sv; -static constexpr auto QUERY_LISTEN = "listen"sv; -static constexpr auto QUERY_REFRESH = "refresh"sv; +static const std::string QUERY_PING {"ping"}; +static const std::string QUERY_FIND {"find"}; +static const std::string QUERY_GET {"get"}; +static const std::string QUERY_UPDATE {"update"}; +static const std::string QUERY_PUT {"put"}; +static const std::string QUERY_LISTEN {"listen"}; +static const std::string QUERY_REFRESH {"refresh"}; Tid unpackTid(const msgpack::object& o) { switch (o.type) { @@ -176,14 +173,14 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) msgpack::object* e; msgpack::object* v; msgpack::object* a; - std::string_view q; + std::string q; } parsed {}; for (unsigned i = 0; i < msg.via.map.size; i++) { auto& o = msg.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; - auto key = o.key.as(); + auto key = o.key.as(); if (key == KEY_Y) parsed.y = &o.val; else if (key == KEY_R) @@ -203,7 +200,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) else if (key == KEY_ISCLIENT) is_client = o.val.as(); else if (key == KEY_Q) - parsed.q = o.val.as(); + parsed.q = o.val.as(); else if (key == KEY_A) parsed.a = &o.val; } @@ -216,7 +213,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) type = MessageType::ValueData; else if (parsed.u) type = MessageType::ValueUpdate; - else if (parsed.y and parsed.y->as() != "q"sv) + else if (parsed.y and parsed.y->as() != "q") throw msgpack::type_error(); else if (parsed.q == QUERY_PING) type = MessageType::Ping; @@ -240,8 +237,8 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) throw msgpack::type_error(); for (size_t i = 0; i < parsed.v->via.map.size; ++i) { auto& vdat = parsed.v->via.map.ptr[i]; - auto o = findMapValue(vdat.val, "o"sv); - auto d = findMapValue(vdat.val, "d"sv); + auto o = findMapValue(vdat.val, "o"); + auto d = findMapValue(vdat.val, "d"); if (not o or not d) continue; value_parts.emplace(vdat.key.as(), std::pair(o->as(), unpackBlob(*d))); @@ -270,7 +267,7 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) auto& o = req.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; - auto key = o.key.as(); + auto key = o.key.as(); if (key == KEY_REQ_SID) socket_id = unpackTid(o.val); else if (key == KEY_REQ_ID) @@ -344,9 +341,9 @@ ParsedMessage::msgpack_unpack(const msgpack::object& msg) } } } else if (parsedReq.fields) { - if (auto rfields = findMapValue(*parsedReq.fields, "f"sv)) { + if (auto rfields = findMapValue(*parsedReq.fields, "f")) { auto vfields = rfields->as>(); - if (auto rvalues = findMapValue(*parsedReq.fields, "v"sv)) { + if (auto rvalues = findMapValue(*parsedReq.fields, "v")) { if (rvalues->type != msgpack::type::ARRAY) throw msgpack::type_error(); size_t val_num = rvalues->via.array.size / vfields.size(); diff --git a/src/peer_discovery.cpp b/src/peer_discovery.cpp index a25da780e..56ccad965 100644 --- a/src/peer_discovery.cpp +++ b/src/peer_discovery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Mingrui Zhang * Vsevolod Ivanov * Adrien Béraud @@ -24,8 +24,6 @@ #include -using namespace std::literals; - namespace dht { // Organization-local Scope multicast @@ -63,7 +61,7 @@ class PeerDiscovery::DomainPeerDiscovery msgpack::sbuffer sbuf_; std::map messages_; - std::map> callbackmap_; + std::map callbackmap_; bool lrunning_ {false}; bool drunning_ {false}; @@ -135,18 +133,19 @@ PeerDiscovery::DomainPeerDiscovery::loopListener() msgpack::object obj = rcv.get(); if (obj.type == msgpack::type::STR) { - if (lrunning_ and obj.as() == "q"sv) + if (lrunning_ and obj.as() == "q") publish(receiveFrom_); } else if (obj.type == msgpack::type::MAP) { for (unsigned i = 0; i < obj.via.map.size; i++) { auto& o = obj.via.map.ptr[i]; if (o.key.type != msgpack::type::STR) continue; + auto key = o.key.as(); ServiceDiscoveredCallback cb; { std::lock_guard lck(dmtx_); if (drunning_) { - auto callback = callbackmap_.find(o.key.as()); + auto callback = callbackmap_.find(key); if (callback != callbackmap_.end()) cb = callback->second; } else diff --git a/src/request.h b/src/request.h index 318d120a0..5c468c04c 100644 --- a/src/request.h +++ b/src/request.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -74,14 +74,14 @@ struct Request { Blob&& msg, std::function on_done, std::function on_expired) : - node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_expired(std::move(on_expired)), msg(std::move(msg)) { } + node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)) { } Request(MessageType type, Tid tid, Sp node, Blob&& msg, std::function on_done, std::function on_error, std::function on_expired) : - node(std::move(node)), tid(tid), type(type), on_done(std::move(on_done)), on_error(std::move(on_error)), on_expired(std::move(on_expired)), msg(std::move(msg)) { } + node(node), tid(tid), type(type), on_done(on_done), on_error(on_error), on_expired(on_expired), msg(std::move(msg)) { } Tid getTid() const { return tid; } MessageType getType() const { return type; } diff --git a/src/rng.cpp b/src/rng.cpp index da39372a6..3ea47db32 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/routing_table.cpp b/src/routing_table.cpp index 6f2846abf..e8b9ea6d3 100644 --- a/src/routing_table.cpp +++ b/src/routing_table.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify diff --git a/src/search.h b/src/search.h index 5ec9160cc..b7a5ffcb5 100644 --- a/src/search.h +++ b/src/search.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -49,21 +49,12 @@ struct Dht::Announce { }; struct Dht::SearchNode { - - struct AnnounceStatus { - Sp req {}; - Sp refresh {}; - time_point refresh_time; - AnnounceStatus(){}; - AnnounceStatus(Sp r, time_point t): req(std::move(r)), refresh_time(t) - {} - }; /** * Foreach value id, we keep track of a pair (net::Request, time_point) where the * request is the request returned by the network engine and the time_point * is the next time at which the value must be refreshed. */ - using AnnounceStatusMap = std::map; + using AnnounceStatus = std::map, time_point>>; /** * Foreach Query, we keep track of the request returned by the network * engine when we sent the "get". @@ -72,7 +63,6 @@ struct Dht::SearchNode { struct CachedListenStatus { ValueCache cache; - Sp refresh {}; Sp cacheExpirationJob {}; Sp req {}; Tid socketId {0}; @@ -97,7 +87,7 @@ struct Dht::SearchNode { SyncStatus getStatus {}; /* get/sync status */ NodeListenerStatus listenStatus {}; /* listen status */ - AnnounceStatusMap acked {}; /* announcement status for a given value id */ + AnnounceStatus acked {}; /* announcement status for a given value id */ Blob token {}; /* last token the node sent to us after a get request */ time_point last_get_reply {time_point::min()}; /* last time received valid token */ @@ -134,14 +124,6 @@ struct Dht::SearchNode { return last_get_reply + Node::NODE_EXPIRE_TIME; } - friend std::ostream& operator<< (std::ostream& s, const SearchNode& node) { - s << "getStatus:" << node.getStatus.size() - << " listenStatus:" << node.listenStatus.size() - << " acked:" << node.acked.size() - << " cache:" << (node.listenStatus.empty() ? 0 : node.listenStatus.begin()->second.cache.size()) << std::endl; - return s; - } - /** * Could a particular "get" request be sent to this node now ? * @@ -164,12 +146,12 @@ struct Dht::SearchNode { if (node->isExpired()) return false; - bool is_pending {false}, + bool pending {false}, completed_sq_status {false}, pending_sq_status {false}; for (const auto& s : getStatus) { if (s.second and s.second->pending()) - is_pending = true; + pending = true; if (s.first and q and q->isSatisfiedBy(*s.first) and s.second) { if (s.second->pending()) pending_sq_status = true; @@ -180,7 +162,7 @@ struct Dht::SearchNode { } } - return (not is_pending and now > last_get_reply + Node::NODE_EXPIRE_TIME) or + return (not pending and now > last_get_reply + Node::NODE_EXPIRE_TIME) or not (completed_sq_status or pending_sq_status or hasStartedPagination(q)); } @@ -249,12 +231,9 @@ struct Dht::SearchNode { } } - void onListenSynced(const Sp& q, bool synced = true, Sp refreshJob = {}) { + void onListenSynced(const Sp& q, bool synced = true) { auto l = listenStatus.find(q); if (l != listenStatus.end()) { - if (l->second.refresh) - l->second.refresh->cancel(); - l->second.refresh = std::move(refreshJob); l->second.cache.onSynced(synced); } } @@ -292,7 +271,7 @@ struct Dht::SearchNode { return std::find_if(status.cbegin(), status.cend(), [](const SyncStatus::value_type& r){ return r.second and r.second->pending(); - }) != status.cend(); + }) != status.end(); } static bool pending(const NodeListenerStatus& status) { return std::find_if(status.begin(), status.end(), @@ -305,18 +284,16 @@ struct Dht::SearchNode { bool isAnnounced(Value::Id vid) const { auto ack = acked.find(vid); - if (ack == acked.end() or not ack->second.req) + if (ack == acked.end() or not ack->second.first) return false; - return ack->second.req->completed(); + return ack->second.first->completed(); } void cancelAnnounce() { for (const auto& status : acked) { - const auto& req = status.second.req; + const auto& req = status.second.first; if (req and req->pending()) { node->cancelRequest(req); } - if (status.second.refresh) - status.second.refresh->cancel(); } acked.clear(); } @@ -343,21 +320,14 @@ struct Dht::SearchNode { return listen_status->second.req->reply_time + listen_expire > now; } void cancelListen() { - for (const auto& status : listenStatus) { + for (const auto& status : listenStatus) node->cancelRequest(status.second.req); - if (status.second.refresh) - status.second.refresh->cancel(); - if (status.second.cacheExpirationJob) - status.second.cacheExpirationJob->cancel(); - } - listenStatus.clear(); + listenStatus.clear(); } void cancelListen(const Sp& query) { auto it = listenStatus.find(query); if (it != listenStatus.end()) { node->cancelRequest(it->second.req); - if (it->second.refresh) - it->second.refresh->cancel(); listenStatus.erase(it); } } @@ -367,13 +337,13 @@ struct Dht::SearchNode { */ time_point getAnnounceTime(Value::Id vid) const { const auto& ack = acked.find(vid); - if (ack == acked.cend() or not ack->second.req) { + if (ack == acked.cend() or not ack->second.first) { return time_point::min(); } - if (ack->second.req->completed()) { - return ack->second.refresh_time - REANNOUNCE_MARGIN; + if (ack->second.first->completed()) { + return ack->second.second - REANNOUNCE_MARGIN; } - return ack->second.req->pending() ? time_point::max() : time_point::min(); + return ack->second.first->pending() ? time_point::max() : time_point::min(); } /** @@ -437,35 +407,23 @@ struct Dht::Search { ~Search() { if (opExpirationJob) opExpirationJob->cancel(); - for (auto& g : callbacks) { - g.second.done_cb(false, {}); - g.second.done_cb = {}; + for (auto& get : callbacks) { + get.second.done_cb(false, {}); + get.second.done_cb = {}; } - for (auto& a : announce) { - a.callback(false, {}); - a.callback = {}; + for (auto& put : announce) { + put.callback(false, {}); + put.callback = {}; } } - friend std::ostream& operator<< (std::ostream& s, const Search& sr) { - auto csize = sr.cache.size(); - s << "announce:" << sr.announce.size() - << " gets:" << sr.callbacks.size() - << " listeners:" << sr.listeners.size() - << " cache:" << csize.first << ',' << csize.second << std::endl; - s << "nodes:" << std::endl; - for (const auto& n : sr.nodes) - s << *n; - return s; - } - /** * @returns true if the node was not present and added to the search */ bool insertNode(const Sp& n, time_point now, const Blob& token={}); SearchNode* getNode(const Sp& n) { - auto srn = std::find_if(nodes.begin(), nodes.end(), [&](const std::unique_ptr& sn) { + auto srn = std::find_if(nodes.begin(), nodes.end(), [&](std::unique_ptr& sn) { return n == sn->node; }); return (srn == nodes.end()) ? nullptr : (*srn).get(); @@ -563,15 +521,17 @@ struct Dht::Search { if (not opExpirationJob) opExpirationJob = scheduler.add(time_point::max(), [this,&scheduler]{ auto nextExpire = cache.expire(scheduler.time(), [&](size_t t){ + Sp query; const auto& ll = listeners.find(t); if (ll != listeners.cend()) { - auto query = ll->second.query; + query = ll->second.query; listeners.erase(ll); - if (listeners.empty()) { - for (auto& sn : nodes) sn->cancelListen(); - } else if (query) { - for (auto& sn : nodes) sn->cancelListen(query); - } + } + for (auto& sn : nodes) { + if (listeners.empty()) + sn->cancelListen(); + else if (query) + sn->cancelListen(query); } }); scheduler.edit(opExpirationJob, nextExpire); @@ -608,10 +568,8 @@ struct Dht::Search { for (auto& n : nodes) { auto ackIt = n->acked.find(vid); if (ackIt != n->acked.end()) { - if (ackIt->second.req) - ackIt->second.req->cancel(); - if (ackIt->second.refresh) - ackIt->second.refresh->cancel(); + if (ackIt->second.first) + ackIt->second.first->cancel(); n->acked.erase(ackIt); } } @@ -628,7 +586,7 @@ struct Dht::Search { announce.emplace_back(Announce {permanent, value, created, callback}); for (auto& n : nodes) { n->probe_query.reset(); - n->acked[value->id].req.reset(); + n->acked[value->id].first.reset(); } } else { a_sr->permanent = permanent; @@ -636,7 +594,7 @@ struct Dht::Search { if (a_sr->value != value) { a_sr->value = value; for (auto& n : nodes) { - n->acked[value->id].req.reset(); + n->acked[value->id].first.reset(); n->probe_query.reset(); } } @@ -665,11 +623,12 @@ struct Dht::Search { } unsigned getNumberOfConsecutiveBadNodes() const { unsigned count = 0; - for (const auto& sn : nodes) { + std::find_if(nodes.begin(), nodes.end(), [&count](const std::unique_ptr& sn) { if (not sn->node->isExpired()) - break; + return true; ++count; - } + return false; + }); return count; } @@ -759,8 +718,8 @@ struct Dht::Search { for (auto& n : nodes) { auto ackIt = n->acked.find(it->value->id); if (ackIt != n->acked.end()) { - if (ackIt->second.req) - ackIt->second.req->cancel(); + if (ackIt->second.first) + ackIt->second.first->cancel(); n->acked.erase(ackIt); } } diff --git a/src/securedht.cpp b/src/securedht.cpp index daaa3fe0d..e4dfc2239 100644 --- a/src/securedht.cpp +++ b/src/securedht.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Authors: Adrien Béraud * Simon Désaulniers * Sébastien Blin @@ -36,8 +36,8 @@ extern "C" { namespace dht { -SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf, IdentityAnnouncedCb iacb, const std::shared_ptr& l) -: DhtInterface(l), dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all) +SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf) +: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all) { if (!dht_) return; for (const auto& type : DEFAULT_TYPES) @@ -52,17 +52,16 @@ SecureDht::SecureDht(std::unique_ptr dht, SecureDht::Config conf, auto certId = certificate_->getId(); if (key_ and certId != key_->getPublicKey().getId()) throw DhtException("SecureDht: provided certificate doesn't match private key."); - dht_->addOnConnectedCallback([this, certId, cb=std::move(iacb)]{ - dht_->put(certId, Value { - CERTIFICATE_TYPE, - *certificate_, - 1 - }, [this, certId, cb=std::move(cb)](bool ok) { - if (cb) cb(ok); + + dht_->put(certId, Value { + CERTIFICATE_TYPE, + *certificate_, + 1 + }, [this, certId](bool ok) { + if (ok) if (logger_) - logger_->d(certId, "SecureDht: certificate announcement %s", ok ? "succeeded" : "failed"); - }, {}, true); - }); + logger_->d(certId, "SecureDht: public key announced successfully"); + }, {}, true); } } @@ -118,7 +117,7 @@ SecureDht::secureType(ValueType&& type) return type; } -Sp +const Sp SecureDht::getCertificate(const InfoHash& node) const { if (node == getId()) @@ -130,7 +129,7 @@ SecureDht::getCertificate(const InfoHash& node) const return it->second; } -Sp +const Sp SecureDht::getPublicKey(const InfoHash& node) const { if (node == getId()) @@ -142,7 +141,7 @@ SecureDht::getPublicKey(const InfoHash& node) const return it->second; } -Sp +const Sp SecureDht::registerCertificate(const InfoHash& node, const Blob& data) { Sp crt; @@ -200,6 +199,8 @@ SecureDht::findCertificate(const InfoHash& node, const std::function(false); dht_->get(node, [cb,node,found,this](const std::vector>& vals) { + if (*found) + return false; for (const auto& v : vals) { if (auto cert = registerCertificate(node, v->data)) { *found = true; @@ -210,7 +211,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function)>& cb) +SecureDht::findPublicKey(const InfoHash& node, const std::function)>& cb) { auto pk = getPublicKey(node); if (pk && *pk) { @@ -228,7 +229,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function& crt) { + findCertificate(node, [=](const Sp crt) { if (crt && *crt) { auto pk = std::make_shared(crt->getPublicKey()); if (*pk) { @@ -403,7 +404,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp val, callback(false, {}); return; } - findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp& pk) { + findPublicKey(to, [=](const Sp& pk) { if(!pk || !*pk) { if (callback) callback(false, {}); @@ -422,26 +423,6 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp val, }); } -void -SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp val, DoneCallback callback, bool permanent) -{ - if (not key_) { - if (callback) - callback(false, {}); - return; - } - if (logger_) - logger_->w("Encrypting data for PK: %s", pk.getLongId().to_c_str()); - try { - dht_->put(hash, encrypt(*val, pk), callback, time_point::max(), permanent); - } catch (const std::exception& e) { - if (logger_) - logger_->e("Error putting encrypted data: %s", e.what()); - if (callback) - callback(false, {}); - } -} - void SecureDht::sign(Value& v) const { diff --git a/src/storage.h b/src/storage.h index bff04ab5c..c41740f1e 100644 --- a/src/storage.h +++ b/src/storage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -37,32 +37,19 @@ class StorageBucket { storedValues_.emplace(expiration, std::pair(id, value.id)); } void erase(const InfoHash& id, const Value& value, time_point expiration) { + auto size = value.size(); + totalSize_ -= size; auto range = storedValues_.equal_range(expiration); for (auto rit = range.first; rit != range.second;) { if (rit->second.first == id && rit->second.second == value.id) { - totalSize_ -= value.size(); storedValues_.erase(rit); - return; + break; } else ++rit; } - // printf("StorageBucket::erase can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id); - } - void refresh(const InfoHash& id, const Value& value, time_point old_expiration, time_point expiration) { - auto range = storedValues_.equal_range(old_expiration); - for (auto rit = range.first; rit != range.second;) { - if (rit->second.first == id && rit->second.second == value.id) { - storedValues_.erase(rit); - storedValues_.emplace(expiration, std::pair(id, value.id)); - return; - } else - ++rit; - } - // printf("StorageBucket::refresh can't find value %s %016" PRIx64 "\n", id.to_c_str(), value.id); - insert(id, value, expiration); } size_t size() const { return totalSize_; } - std::pair getOldest() const { return storedValues_.empty() ? std::pair{} : storedValues_.begin()->second; } + std::pair getOldest() const { return storedValues_.begin()->second; } private: std::multimap> storedValues_; size_t totalSize_ {0}; @@ -72,7 +59,6 @@ struct ValueStorage { Sp data {}; time_point created {}; time_point expiration {}; - Sp expiration_job {}; StorageBucket* store_bucket {nullptr}; ValueStorage() {} @@ -88,7 +74,7 @@ struct Storage { size_t listener_token {1}; /* The maximum number of values we store for a given hash. */ - static constexpr unsigned MAX_VALUES {64 * 1024}; + static constexpr unsigned MAX_VALUES {1024}; /** * Changes caused by an operation on the storage. @@ -157,18 +143,14 @@ struct Storage { * @param vid The value id * @return time of the next expiration, time_point::max() if no expiration */ - std::pair - refresh(const InfoHash& id, const time_point& now, const Value::Id& vid, const TypeStore& types) { + time_point refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) { for (auto& vs : values) if (vs.data->id == vid) { vs.created = now; - auto oldExp = vs.expiration; - vs.expiration = std::max(oldExp, now + types.getType(vs.data->type).expiration); - if (vs.store_bucket) - vs.store_bucket->refresh(id, *vs.data, oldExp, vs.expiration); - return {&vs, vs.expiration}; + vs.expiration = std::max(vs.expiration, now + types.getType(vs.data->type).expiration); + return vs.expiration; } - return {nullptr, time_point::max()}; + return time_point::max(); } size_t listen(ValueCallback& cb, Value::Filter& f, const Sp& q); @@ -177,7 +159,7 @@ struct Storage { local_listeners.erase(token); } - Sp remove(const InfoHash& id, Value::Id); + StoreDiff remove(const InfoHash& id, Value::Id); std::pair>> expire(const InfoHash& id, time_point now); @@ -216,9 +198,9 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t if (it != values.end()) { /* Already there, only need to refresh */ it->created = created; + size_t size_old = it->data->size(); + ssize_t size_diff = size_new - (ssize_t)size_old; if (it->data != value) { - size_t size_old = it->data->size(); - ssize_t size_diff = size_new - (ssize_t)size_old; //DHT_LOG.DEBUG("Updating %s -> %s", id.toString().c_str(), value->toString().c_str()); // clear quota for previous value if (it->store_bucket) @@ -232,6 +214,7 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t total_size += size_diff; return std::make_pair(&(*it), StoreDiff{size_diff, 0, 0}); } + return std::make_pair(nullptr, StoreDiff{}); } else { //DHT_LOG.DEBUG("Storing %s -> %s", id.toString().c_str(), value->toString().c_str()); if (values.size() < MAX_VALUES) { @@ -242,11 +225,11 @@ Storage::store(const InfoHash& id, const Sp& value, time_point created, t sb->insert(id, *value, expiration); return std::make_pair(&values.back(), StoreDiff{size_new, 1, 0}); } + return std::make_pair(nullptr, StoreDiff{}); } - return std::make_pair(nullptr, StoreDiff{}); } -Sp +Storage::StoreDiff Storage::remove(const InfoHash& id, Value::Id vid) { auto it = std::find_if (values.begin(), values.end(), [&](const ValueStorage& vr) { @@ -257,12 +240,9 @@ Storage::remove(const InfoHash& id, Value::Id vid) ssize_t size = it->data->size(); if (it->store_bucket) it->store_bucket->erase(id, *it->data, it->expiration); - if (it->expiration_job) - it->expiration_job->cancel(); total_size -= size; - auto value = it->data; values.erase(it); - return value; + return {-size, -1, 0}; } Storage::StoreDiff @@ -303,13 +283,11 @@ Storage::expire(const InfoHash& id, time_point now) }); std::vector> ret; ret.reserve(std::distance(r, values.end())); - ssize_t size_diff {0}; + ssize_t size_diff {}; std::for_each(r, values.end(), [&](const ValueStorage& v) { size_diff -= v.data->size(); if (v.store_bucket) v.store_bucket->erase(id, *v.data, v.expiration); - if (v.expiration_job) - v.expiration_job->cancel(); ret.emplace_back(std::move(v.data)); }); total_size += size_diff; diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 1ebb1abd7..fb56365b2 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -28,6 +28,12 @@ namespace dht { constexpr const size_t IO_THREADS_MAX {64}; +struct ThreadPool::ThreadState +{ + std::thread thread {}; + std::atomic_bool run {true}; +}; + ThreadPool& ThreadPool::computation() { @@ -61,12 +67,14 @@ void ThreadPool::run(std::function&& cb) { std::unique_lock l(lock_); - if (not cb or not running_) return; + if (not running_) return; // launch new thread if necessary if (not readyThreads_ && threads_.size() < maxThreads_) { - threads_.emplace_back(std::make_unique([this]() { - while (true) { + threads_.emplace_back(new ThreadState()); + auto& t = *threads_.back(); + t.thread = std::thread([&]() { + while (t.run) { std::function task; // pick task from queue @@ -74,10 +82,10 @@ ThreadPool::run(std::function&& cb) std::unique_lock l(lock_); readyThreads_++; cv_.wait(l, [&](){ - return not running_ or not tasks_.empty(); + return not t.run or not tasks_.empty(); }); readyThreads_--; - if (not running_) + if (not t.run) break; task = std::move(tasks_.front()); tasks_.pop(); @@ -85,13 +93,14 @@ ThreadPool::run(std::function&& cb) // run task try { - task(); + if (task) + task(); } catch (const std::exception& e) { // LOG_ERR("Exception running task: %s", e.what()); std::cerr << "Exception running task: " << e.what() << std::endl; } } - })); + }); } // push task to queue @@ -104,8 +113,12 @@ ThreadPool::run(std::function&& cb) void ThreadPool::stop() { - std::lock_guard l(lock_); - running_ = false; + { + std::lock_guard l(lock_); + running_ = false; + } + for (auto& t : threads_) + t->run = false; cv_.notify_all(); } @@ -114,7 +127,7 @@ ThreadPool::join() { stop(); for (auto& t : threads_) - t->join(); + t->thread.join(); threads_.clear(); } @@ -134,7 +147,7 @@ Executor::run_(std::function&& task) { current_++; std::weak_ptr w = shared_from_this(); - threadPool_.get().run([w,task = std::move(task)] { + threadPool_.get().run([w,task] { try { task(); } catch (const std::exception& e) { diff --git a/src/utils.cpp b/src/utils.cpp index f29a9dd43..be69eac0d 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -106,7 +106,7 @@ print_addr(const sockaddr* sa, socklen_t slen) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; - std::ostringstream out; + std::stringstream out; if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { if (sa->sa_family == AF_INET6) out << "[" << hbuf << "]"; diff --git a/src/value.cpp b/src/value.cpp index 8252b56fe..6d50412c7 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * Simon Désaulniers * @@ -163,7 +163,7 @@ Value::msgpack_unpack_body(const msgpack::object& o) throw msgpack::type_error(); crypto::PublicKey new_owner; new_owner.msgpack_unpack(*rowner); - owner = std::make_shared(std::move(new_owner)); + owner = std::make_shared(std::move(new_owner)); if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) { recipient = rrecipient->as(); } @@ -193,7 +193,7 @@ Value::Value(const Json::Value& json) if (jowner.isString()) { auto ownerStr = jowner.asString(); auto ownerBlob = std::vector(ownerStr.begin(), ownerStr.end()); - owner = std::make_shared(ownerBlob); + owner = std::make_shared(ownerBlob); } const auto& jto = json[VALUE_KEY_TO]; if (jto.isString()) @@ -406,8 +406,8 @@ void trim_str(std::string& str) { str = str.substr(first, last - first + 1); } -Select::Select(std::string_view q_str) { - std::istringstream q_iss {std::string(q_str)}; +Select::Select(const std::string& q_str) { + std::istringstream q_iss {q_str}; std::string token {}; q_iss >> token; @@ -431,8 +431,8 @@ Select::Select(std::string_view q_str) { } } -Where::Where(std::string_view q_str) { - std::istringstream q_iss {std::string(q_str)}; +Where::Where(const std::string& q_str) { + std::istringstream q_iss {q_str}; std::string token {}; q_iss >> token; if (token == "WHERE" or token == "where") { @@ -482,13 +482,13 @@ Query::msgpack_unpack(const msgpack::object& o) if (o.type != msgpack::type::MAP) throw msgpack::type_error(); - auto rfilters = findMapValue(o, "w"sv); /* unpacking filters */ + auto rfilters = findMapValue(o, "w"); /* unpacking filters */ if (rfilters) where.msgpack_unpack(*rfilters); else throw msgpack::type_error(); - auto rfield_selector = findMapValue(o, "s"sv); /* unpacking field selectors */ + auto rfield_selector = findMapValue(o, "s"); /* unpacking field selectors */ if (rfield_selector) select.msgpack_unpack(*rfield_selector); else @@ -496,10 +496,10 @@ Query::msgpack_unpack(const msgpack::object& o) } template -bool subset(const std::vector& fds, const std::vector& qfds) +bool subset(std::vector fds, std::vector qfds) { - for (const auto& fd : fds) { - if (std::find_if(qfds.begin(), qfds.end(), [&fd](const T& _vfd) { return fd == _vfd; }) == qfds.end()) + for (auto& fd : fds) { + if (std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; }) == qfds.end()) return false; } return true; diff --git a/src/value_cache.h b/src/value_cache.h index 93265eed1..b168ee6ea 100644 --- a/src/value_cache.h +++ b/src/value_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author(s) : Adrien Béraud * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ using CallbackQueue = std::list>; class ValueCache { public: - explicit ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {}) + ValueCache(ValueStateCallback&& cb, SyncCallback&& scb = {}) : callback(std::forward(cb)), syncCallback(std::move(scb)) { if (syncCallback) @@ -53,12 +53,13 @@ class ValueCache { CallbackQueue clear() { std::vector> expired_values; expired_values.reserve(values.size()); - for (auto& v : values) + for (const auto& v : values) expired_values.emplace_back(std::move(v.second.data)); values.clear(); CallbackQueue ret; if (not expired_values.empty() and callback) { - ret.emplace_back([expired_values = std::move(expired_values), cb = callback]{ + auto cb = callback; + ret.emplace_back([expired_values, cb]{ cb(expired_values, true); }); } @@ -102,23 +103,24 @@ class ValueCache { } CallbackQueue ret; if (not expired_values.empty() and callback) { - ret.emplace_back([cb = callback, expired_values = std::move(expired_values)]{ - cb(expired_values, true); + auto cb = callback; + ret.emplace_back([cb, expired_values]{ + if (cb) cb(expired_values, true); }); } return ret; } time_point onValues - (const std::vector>& new_values, + (const std::vector>& values, const std::vector& refreshed_values, const std::vector& expired_values, const TypeStore& types, const time_point& now) { CallbackQueue cbs; time_point ret = time_point::max(); - if (not new_values.empty()) - cbs.splice(cbs.end(), addValues(new_values, types, now)); + if (not values.empty()) + cbs.splice(cbs.end(), addValues(values, types, now)); for (const auto& vid : refreshed_values) refreshValue(vid, types, now); for (const auto& vid : expired_values) @@ -140,10 +142,6 @@ class ValueCache { } } - size_t size() const { - return values.size(); - } - private: // prevent copy ValueCache(const ValueCache&) = delete; @@ -182,10 +180,11 @@ class ValueCache { v->second.expiration = now + types.getType(v->second.data->type).expiration; } } + auto cb = callback; CallbackQueue ret; - if (callback and not nvals.empty()) - ret.emplace_back([cb = callback, nvals = std::move(nvals)]{ - cb(nvals, false); + if (not nvals.empty()) + ret.emplace_back([cb, nvals]{ + if (cb) cb(nvals, false); }); return ret; } diff --git a/tests/cryptotester.cpp b/tests/cryptotester.cpp index a04f206e8..bf092c85e 100644 --- a/tests/cryptotester.cpp +++ b/tests/cryptotester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Vsevolod Ivanov @@ -33,7 +33,7 @@ CryptoTester::setUp() { void CryptoTester::testSignatureEncryption() { auto key = dht::crypto::PrivateKey::generate(); - const auto& public_key = key.getPublicKey(); + auto public_key = key.getPublicKey(); std::vector data1 {5, 10}; std::vector data2(64 * 1024, 10); @@ -44,10 +44,6 @@ CryptoTester::testSignatureEncryption() { // check signature CPPUNIT_ASSERT(public_key.checkSignature(data1, signature1)); CPPUNIT_ASSERT(public_key.checkSignature(data2, signature2)); - signature1[7]++; - signature2[8]--; - CPPUNIT_ASSERT(!public_key.checkSignature(data1, signature1)); - CPPUNIT_ASSERT(!public_key.checkSignature(data2, signature2)); // encrypt data { @@ -165,14 +161,6 @@ void CryptoTester::testCertificateSerialNumber() CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end())); } -void CryptoTester::testOcsp() { - auto ca = dht::crypto::generateIdentity("Test CA"); - auto device = dht::crypto::generateIdentity("Test Device", ca); - auto ocspRequest = device.second->generateOcspRequest(ca.second->cert); - auto req = dht::crypto::OcspRequest((const uint8_t*)ocspRequest.first.data(), ocspRequest.first.size()); - CPPUNIT_ASSERT(ocspRequest.second == req.getNonce()); -} - void CryptoTester::tearDown() { diff --git a/tests/cryptotester.h b/tests/cryptotester.h index 06cf290d4..04ce97ce9 100644 --- a/tests/cryptotester.h +++ b/tests/cryptotester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Vsevolod Ivanov @@ -32,7 +32,6 @@ class CryptoTester : public CppUnit::TestFixture { CPPUNIT_TEST(testCertificateRevocation); CPPUNIT_TEST(testCertificateRequest); CPPUNIT_TEST(testCertificateSerialNumber); - CPPUNIT_TEST(testOcsp); CPPUNIT_TEST_SUITE_END(); public: @@ -60,10 +59,6 @@ class CryptoTester : public CppUnit::TestFixture { * Test certificate serial number extraction */ void testCertificateSerialNumber(); - /** - * Test OCSP - */ - void testOcsp(); }; } // namespace test diff --git a/tests/dhtproxytester.cpp b/tests/dhtproxytester.cpp index 4e6820c53..5036c1287 100644 --- a/tests/dhtproxytester.cpp +++ b/tests/dhtproxytester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Sébastien Blin * Vsevolod Ivanov @@ -71,7 +71,7 @@ DhtProxyTester::tearDown() { cv.notify_all(); }); std::unique_lock lk(cv_m); - CPPUNIT_ASSERT(cv.wait_for(lk, 15s, [&]{ return done; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done; })); serverProxy.reset(); nodeProxy.reset(); } @@ -289,47 +289,4 @@ DhtProxyTester::testFuzzy() CPPUNIT_ASSERT(value->data == mtu); } -void -DhtProxyTester::testShutdownStop() -{ - constexpr size_t N = 40000; - constexpr unsigned C = 100; - - // Arrange - auto key = dht::InfoHash::get("testShutdownStop"); - std::vector> values; - std::vector mtu; - mtu.reserve(N); - for (size_t i = 0; i < N; i++) - mtu.emplace_back((i % 2) ? 'T' : 'M'); - - std::atomic_uint callback_count {0}; - - // Act - for (size_t i = 0; i < C; i++) { - auto nodeTest = std::make_shared(); - nodeTest->run(0, clientConfig); - nodeTest->put(key, dht::Value(mtu), [&](bool ok) { - callback_count++; - }); - nodeTest->get(key, [&](const std::vector>& vals){ - values.insert(values.end(), vals.begin(), vals.end()); - return true; - },[&](bool ok){ - callback_count++; - }); - bool done = false; - std::condition_variable cv; - std::mutex cv_m; - nodeTest->shutdown([&]{ - std::lock_guard lk(cv_m); - done = true; - cv.notify_all(); - }, true); - std::unique_lock lk(cv_m); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; })); - } - CPPUNIT_ASSERT_EQUAL(2*C, callback_count.load()); -} - } // namespace test diff --git a/tests/dhtproxytester.h b/tests/dhtproxytester.h index c0fa7b34f..6937c3e9d 100644 --- a/tests/dhtproxytester.h +++ b/tests/dhtproxytester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Sébastien Blin * @@ -36,7 +36,6 @@ class DhtProxyTester : public CppUnit::TestFixture { CPPUNIT_TEST(testResubscribeGetValues); CPPUNIT_TEST(testPutGet40KChars); CPPUNIT_TEST(testFuzzy); - CPPUNIT_TEST(testShutdownStop); CPPUNIT_TEST_SUITE_END(); public: @@ -69,8 +68,6 @@ class DhtProxyTester : public CppUnit::TestFixture { void testFuzzy(); - void testShutdownStop(); - private: dht::DhtRunner::Config clientConfig {}; dht::DhtRunner nodePeer; diff --git a/tests/dhtrunnertester.cpp b/tests/dhtrunnertester.cpp index 78df451ab..9f3d63ccb 100644 --- a/tests/dhtrunnertester.cpp +++ b/tests/dhtrunnertester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -19,13 +19,10 @@ #include "dhtrunnertester.h" -#include - #include #include #include using namespace std::chrono_literals; -using namespace std::literals; namespace test { CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester); @@ -35,11 +32,9 @@ DhtRunnerTester::setUp() { dht::DhtRunner::Config config; config.dht_config.node_config.max_peer_req_per_sec = -1; config.dht_config.node_config.max_req_per_sec = -1; - config.dht_config.node_config.max_store_size = -1; - config.dht_config.node_config.max_store_keys = -1; - node1.run(0, config); - node2.run(0, config); + node1.run(42222, config); + node2.run(42232, config); node2.bootstrap(node1.getBound()); } @@ -56,23 +51,15 @@ DhtRunnerTester::tearDown() { node1.shutdown(shutdown); node2.shutdown(shutdown); std::unique_lock lk(cv_m); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return done == 2u; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done == 2; })); node1.join(); node2.join(); } void DhtRunnerTester::testConstructors() { - CPPUNIT_ASSERT(node1.getBoundPort()); - CPPUNIT_ASSERT_EQUAL(node1.getBoundPort(), node1.getBound().getPort()); - CPPUNIT_ASSERT(node2.getBoundPort()); - CPPUNIT_ASSERT_EQUAL(node2.getBoundPort(), node2.getBound().getPort()); - - dht::DhtRunner::Config config {}; - dht::DhtRunner::Context context {}; - dht::DhtRunner testNode; - testNode.run(config, std::move(context)); - CPPUNIT_ASSERT(testNode.getBoundPort()); + CPPUNIT_ASSERT(node1.getBoundPort() == 42222); + CPPUNIT_ASSERT(node2.getBoundPort() == 42232); } void @@ -96,46 +83,32 @@ DhtRunnerTester::testListen() { std::condition_variable cv; std::atomic_uint valueCount(0); unsigned putCount(0); - unsigned putOkCount1(0); - unsigned putOkCount2(0); - unsigned putOkCount3(0); + unsigned putOkCount(0); auto a = dht::InfoHash::get("234"); auto b = dht::InfoHash::get("2345"); auto c = dht::InfoHash::get("23456"); auto d = dht::InfoHash::get("234567"); - constexpr unsigned N = 2048; + constexpr unsigned N = 256; constexpr unsigned SZ = 56 * 1024; - auto ftokena = node1.listen(a, [&](const std::vector>& values, bool expired) { - if (expired) - valueCount -= values.size(); - else - valueCount += values.size(); + auto ftokena = node1.listen(a, [&](const std::shared_ptr&) { + valueCount++; return true; }); - auto ftokenb = node1.listen(b, [&](const std::vector>& values, bool expired) { - if (expired) - valueCount -= values.size(); - else - valueCount += values.size(); + auto ftokenb = node1.listen(b, [&](const std::shared_ptr&) { + valueCount++; return false; }); - auto ftokenc = node1.listen(c, [&](const std::vector>& values, bool expired) { - if (expired) - valueCount -= values.size(); - else - valueCount += values.size(); + auto ftokenc = node1.listen(c, [&](const std::shared_ptr&) { + valueCount++; return true; }); - auto ftokend = node1.listen(d, [&](const std::vector>& values, bool expired) { - if (expired) - valueCount -= values.size(); - else - valueCount += values.size(); + auto ftokend = node1.listen(d, [&](const std::shared_ptr&) { + valueCount++; return true; }); @@ -148,21 +121,21 @@ DhtRunnerTester::testListen() { node2.put(a, dht::Value("v1"), [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount1++; + if (ok) putOkCount++; cv.notify_all(); }); node2.put(b, dht::Value("v2"), [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount2++; + if (ok) putOkCount++; cv.notify_all(); }); auto bigVal = std::make_shared(); bigVal->data = mtu; - node2.put(c, std::move(bigVal), [&](bool ok) { + node2.put(c, bigVal, [&](bool ok) { std::lock_guard lock(mutex); putCount++; - if (ok) putOkCount3++; + if (ok) putOkCount++; cv.notify_all(); }); } @@ -170,9 +143,7 @@ DhtRunnerTester::testListen() { { std::unique_lock lk(mutex); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 3u; })); - CPPUNIT_ASSERT_EQUAL(N, putOkCount1); - CPPUNIT_ASSERT_EQUAL(N, putOkCount2); - CPPUNIT_ASSERT_EQUAL(N, putOkCount3); + CPPUNIT_ASSERT_EQUAL(N * 3u, putOkCount); } CPPUNIT_ASSERT(ftokena.valid()); @@ -196,88 +167,6 @@ DhtRunnerTester::testListen() { node1.cancelListen(d, tokend); } -void -DhtRunnerTester::testIdOps() { - std::mutex mutex; - std::condition_variable cv; - unsigned valueCount(0); - - dht::DhtRunner::Config config2; - config2.dht_config.node_config.max_peer_req_per_sec = -1; - config2.dht_config.node_config.max_req_per_sec = -1; - config2.dht_config.id = dht::crypto::generateIdentity(); - - dht::DhtRunner::Context context2; - context2.identityAnnouncedCb = [&](bool ok) { - CPPUNIT_ASSERT(ok); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - }; - - node2.join(); - node2.run(42232, config2, std::move(context2)); - node2.bootstrap(node1.getBound()); - - { - std::unique_lock lk(mutex); - CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 1; })); - } - - node1.findCertificate(node2.getId(), [&](const std::shared_ptr& crt){ - CPPUNIT_ASSERT(crt); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - }); - - { - std::unique_lock lk(mutex); - CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 2; })); - } - - dht::DhtRunner::Context context1; - context1.identityAnnouncedCb = [&](bool ok) { - CPPUNIT_ASSERT(ok); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - }; - - config2.dht_config.id = dht::crypto::generateIdentity(); - node1.join(); - node1.run(42222, config2, std::move(context1)); - node1.bootstrap(node2.getBound()); - - auto key = dht::InfoHash::get("key"); - node1.putEncrypted(key, node2.getId(), dht::Value("yo"), [&](bool ok){ - CPPUNIT_ASSERT(ok); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - }); - - node1.putEncrypted(key, node2.getPublicKey(), dht::Value("yo"), [&](bool ok){ - CPPUNIT_ASSERT(ok); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - }); - - node2.listen(key, [&](std::string&& value){ - CPPUNIT_ASSERT_EQUAL("yo"s, value); - std::lock_guard lk(mutex); - valueCount++; - cv.notify_all(); - return true; - }); - - { - std::unique_lock lk(mutex); - CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; })); - } -} - void DhtRunnerTester::testListenLotOfBytes() { std::mutex mutex; @@ -325,39 +214,4 @@ DhtRunnerTester::testListenLotOfBytes() { node3.cancelListen(foo, ftokenfoo.get()); } - -void -DhtRunnerTester::testMultithread() { - std::mutex mutex; - std::condition_variable cv; - unsigned putCount(0); - unsigned putOkCount(0); - - constexpr unsigned N = 2048; - - for (unsigned i=0; i lock(mutex); - putCount++; - if (ok) putOkCount++; - cv.notify_all(); - }); - node2.get(dht::InfoHash::get("123" + std::to_string(N-i-1)), [](const std::shared_ptr&){ - return true; - }, [&](bool ok) { - std::lock_guard lock(mutex); - putCount++; - if (ok) putOkCount++; - cv.notify_all(); - }); - }); - } - std::unique_lock lk(mutex); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == 2*N; })); - CPPUNIT_ASSERT_EQUAL(2*N, putOkCount); - -} - - } // namespace test diff --git a/tests/dhtrunnertester.h b/tests/dhtrunnertester.h index ea0b93b0d..1d2338205 100644 --- a/tests/dhtrunnertester.h +++ b/tests/dhtrunnertester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -33,7 +33,6 @@ class DhtRunnerTester : public CppUnit::TestFixture { CPPUNIT_TEST(testGetPut); CPPUNIT_TEST(testListen); CPPUNIT_TEST(testListenLotOfBytes); - CPPUNIT_TEST(testIdOps); CPPUNIT_TEST_SUITE_END(); dht::DhtRunner node1 {}; @@ -59,19 +58,10 @@ class DhtRunnerTester : public CppUnit::TestFixture { * Test listen method */ void testListen(); - /** - * Test methods requiring a node identity - */ - void testIdOps(); /** * Test listen method with lot of datas */ void testListenLotOfBytes(); - /** - * Test multithread - */ - void testMultithread(); - }; } // namespace test diff --git a/tests/httptester.cpp b/tests/httptester.cpp index 342b2b95d..2f2dc41ca 100644 --- a/tests/httptester.cpp +++ b/tests/httptester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Vsevolod Ivanov * diff --git a/tests/httptester.h b/tests/httptester.h index c31905759..1f50af990 100644 --- a/tests/httptester.h +++ b/tests/httptester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Vsevolod Ivanov * diff --git a/tests/infohashtester.cpp b/tests/infohashtester.cpp index ba9650268..6245c93e2 100644 --- a/tests/infohashtester.cpp +++ b/tests/infohashtester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Sébastien Blin * diff --git a/tests/infohashtester.h b/tests/infohashtester.h index 52c07acf4..75d9f402b 100644 --- a/tests/infohashtester.h +++ b/tests/infohashtester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Sébastien Blin * diff --git a/tests/peerdiscoverytester.cpp b/tests/peerdiscoverytester.cpp index a1dac8d01..3f36e44ee 100644 --- a/tests/peerdiscoverytester.cpp +++ b/tests/peerdiscoverytester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Mingrui Zhang * diff --git a/tests/peerdiscoverytester.h b/tests/peerdiscoverytester.h index b27fe4fca..f5bef8595 100644 --- a/tests/peerdiscoverytester.h +++ b/tests/peerdiscoverytester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Mingrui Zhang * diff --git a/tests/tests_runner.cpp b/tests/tests_runner.cpp index c54b01595..dc06c70ab 100644 --- a/tests/tests_runner.cpp +++ b/tests/tests_runner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * Author: Sébastien Blin * * This program is free software; you can redistribute it and/or modify diff --git a/tests/threadpooltester.cpp b/tests/threadpooltester.cpp index b5ddbf6ab..4295b87bb 100644 --- a/tests/threadpooltester.cpp +++ b/tests/threadpooltester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -21,7 +21,6 @@ #include "opendht/thread_pool.h" #include -#include namespace test { CPPUNIT_TEST_SUITE_REGISTRATION(ThreadPoolTester); @@ -48,7 +47,7 @@ ThreadPoolTester::testThreadPool() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); pool.join(); - CPPUNIT_ASSERT_EQUAL(N, count.load()); + CPPUNIT_ASSERT(count.load() == N); } void @@ -60,7 +59,7 @@ ThreadPoolTester::testExecutor() auto executor8 = std::make_shared(pool, 8); constexpr unsigned N = 64 * 1024; - unsigned count1 {0}; + std::atomic_uint count1 {0}; std::atomic_uint count4 {0}; std::atomic_uint count8 {0}; for (unsigned i=0; i * @@ -29,7 +29,6 @@ class ThreadPoolTester : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ThreadPoolTester); CPPUNIT_TEST(testThreadPool); CPPUNIT_TEST(testExecutor); - CPPUNIT_TEST(testContext); CPPUNIT_TEST_SUITE_END(); public: @@ -44,7 +43,6 @@ class ThreadPoolTester : public CppUnit::TestFixture { void testThreadPool(); void testExecutor(); - void testContext(); }; } // namespace test diff --git a/tests/valuetester.cpp b/tests/valuetester.cpp index 90d4995f7..784bda4ab 100644 --- a/tests/valuetester.cpp +++ b/tests/valuetester.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tests/valuetester.h b/tests/valuetester.h index e71fa4439..f14449dae 100644 --- a/tests/valuetester.h +++ b/tests/valuetester.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b56507d0a..2e70c3b4a 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,9 +1,7 @@ if (OPENDHT_SHARED) set (OPENDHT_LIBS opendht) - set (OPENDHT_C_LIBS opendht-c) else () set (OPENDHT_LIBS opendht-static) - set (OPENDHT_C_LIBS opendht-c-static) if (MSVC) set (MSC_COMPAT_SOURCES ${MSC_COMPAT_DIR}/wingetopt.c) endif () @@ -11,8 +9,8 @@ endif () function (configure_tool name extra_files) add_executable (${name} ${name}.cpp ${extra_files}) - add_dependencies(${name} ${OPENDHT_LIBS}) - target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS} ${READLINE_LIBRARIES}) + target_link_libraries (${name} LINK_PUBLIC ${READLINE_LIBRARIES}) + target_link_libraries (${name} LINK_PUBLIC ${OPENDHT_LIBS}) if (MSVC) target_sources(${name} PRIVATE ${MSC_COMPAT_SOURCES}) target_include_directories (${name} PRIVATE ${MSC_COMPAT_DIR}) @@ -31,9 +29,7 @@ endif () if (OPENDHT_C) add_executable (dhtcnode dhtcnode.c) - add_dependencies(dhtcnode ${OPENDHT_C_LIBS}) - target_link_libraries (dhtcnode LINK_PUBLIC ${OPENDHT_C_LIBS} ${READLINE_LIBRARIES}) - target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c) + target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES}) endif () if (NOT DEFINED CMAKE_INSTALL_BINDIR) diff --git a/tools/Makefile.am b/tools/Makefile.am index c7a175f25..a9c4b1835 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,17 +4,10 @@ noinst_HEADERS = tools_common.h AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ dhtnode_SOURCES = dhtnode.cpp -dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ +dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ dhtchat_SOURCES = dhtchat.cpp -dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ +dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ dhtscanner_SOURCES = dhtscanner.cpp -dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@ - -if ENABLE_C -bin_PROGRAMS += dhtcnode -dhtcnode_CFLAGS = -std=c11 -isystem @top_srcdir@/c -isystem @top_srcdir@/include -dhtcnode_SOURCES = dhtcnode.c -dhtcnode_LDFLAGS = -lopendht-c -lreadline -L@top_builddir@/c/.libs -endif +dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@ diff --git a/tools/dhtchat.cpp b/tools/dhtchat.cpp index a1b2c0618..66d455ce6 100644 --- a/tools/dhtchat.cpp +++ b/tools/dhtchat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/dhtcnode.c b/tools/dhtcnode.c index bb693f341..ab3a4b825 100644 --- a/tools/dhtcnode.c +++ b/tools/dhtcnode.c @@ -1,53 +1,20 @@ -/* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. - * Author : Adrien Béraud - * - * 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 . - */ - -#include +#include #include #include #include #include -#include - -#include -#include -#include #include struct op_context { dht_runner* runner; - atomic_bool stop; -}; -struct listen_context { - dht_runner* runner; - dht_op_token* token; - size_t count; + int d; }; bool dht_value_callback(const dht_value* value, bool expired, void* user_data) { - struct listen_context* ctx = (struct listen_context*) user_data; - if (expired) - ctx->count--; - else - ctx->count++; dht_data_view data = dht_value_get_data(value); - printf("Listen: %s value: %.*s (total %zu).\n", expired ? "expired" : "new", (int)data.size, data.data, ctx->count); + printf("Value callback %s: %.*s.\n", expired ? "expired" : "new", (int)data.size, data.data); return true; } @@ -59,30 +26,16 @@ bool dht_get_callback(const dht_value* value, void* user_data) return true; } -void dht_get_done_callback(bool ok, void* user_data) -{ - dht_runner* runner = (dht_runner*)user_data; - printf("Get completed: %s\n", ok ? "success !" : "failure :-("); -} - -void dht_put_done_callback(bool ok, void* user_data) +void dht_done_callback(bool ok, void* user_data) { dht_runner* runner = (dht_runner*)user_data; - printf("Put completed: %s\n", ok ? "success !" : "failure :-("); + printf("Done callback. %s\n", ok ? "Success !" : "Failure :-("); } -void dht_shutdown_callback(void* user_data) +void op_context_free(void* user_data) { - printf("Stopped.\n"); struct op_context* ctx = (struct op_context*)user_data; - atomic_store(&ctx->stop, true); -} - -void listen_context_free(void* user_data) -{ - printf("listen_context_free.\n"); - struct listen_context* ctx = (struct listen_context*)user_data; - dht_op_token_delete(ctx->token); + printf("op_context_free %d.\n", ctx->d); free(ctx); } @@ -107,181 +60,66 @@ char* print_addr(const struct sockaddr* addr) { return s; } -struct dht_params { - bool help; - bool version; - bool generate_identity; - bool service; - bool peer_discovery; - bool log; - const char* bootstrap; - unsigned network; - in_port_t port; -}; +int main() +{ + dht_identity id = dht_identity_generate("testNode", NULL); + dht_infohash cert_id = dht_certificate_get_id(id.certificate); + printf("Cert ID: %s\n", dht_infohash_print(&cert_id)); -static const struct option long_options[] = { - {"help", no_argument , NULL, 'h'}, - {"port", required_argument, NULL, 'p'}, - {"net", required_argument, NULL, 'n'}, - {"bootstrap", required_argument, NULL, 'b'}, - {"identity", no_argument , NULL, 'i'}, - {"verbose", no_argument , NULL, 'v'}, - {"service", no_argument , NULL, 's'}, - {"peer-discovery", no_argument , NULL, 'D'}, - {"no-rate-limit", no_argument , NULL, 'U'}, - {"persist", required_argument, NULL, 'f'}, - {"logfile", required_argument, NULL, 'l'}, - {"syslog", no_argument , NULL, 'L'}, - {"version", no_argument , NULL, 'V'}, - {NULL, 0 , NULL, 0} -}; + dht_publickey* pk = dht_certificate_get_publickey(id.certificate); + dht_infohash pk_id = dht_publickey_get_id(pk); + printf("PK ID: %s\n", dht_infohash_print(&pk_id)); + dht_publickey_delete(pk); -struct dht_params -parse_args(int argc, char **argv) { - struct dht_params params; - memset(¶ms, 0, sizeof params); - int opt; - while ((opt = getopt_long(argc, argv, "hisvDp:n:b:f:l:", long_options, NULL)) != -1) { - switch (opt) { - case 'p': { - int port_arg = atoi(optarg); - if (port_arg >= 0 && port_arg < 0x10000) - params.port = port_arg; - } - break; - case 'D': - params.peer_discovery = true; - break; - case 'n': - params.network = strtoul(optarg, NULL, 0); - break; - case 'b': - params.bootstrap = (optarg[0] == '=') ? optarg+1 : optarg; - break; - case 'h': - params.help = true; - break; - case 'v': - params.log = true; - break; - case 'i': - params.generate_identity = true; - break; - case 's': - params.service = true; - break; - case 'V': - params.version = true; - break; - default: - break; - } - } - return params; -} + pk = dht_privatekey_get_publickey(id.privatekey); + pk_id = dht_publickey_get_id(pk); + printf("Key ID: %s\n", dht_infohash_print(&pk_id)); + dht_publickey_delete(pk); -dht_infohash parse_key(const char* key_str) { - dht_infohash key; - dht_infohash_from_hex_null(&key, key_str); - if (dht_infohash_is_zero(&key)) { - dht_infohash_get_from_string(&key, key_str); - printf("Using h(%s) = %s\n", key_str, dht_infohash_print(&key)); - } - return key; -} + dht_identity_delete(&id); -int main(int argc, char **argv) -{ - struct dht_params params = parse_args(argc, argv); + dht_runner* runner = dht_runner_new(); + dht_runner_run(runner, 4040); - if (params.version) { - printf("OpenDHT version %s\n", dht_version()); - return EXIT_SUCCESS; - } + dht_infohash h; + dht_infohash_random(&h); - dht_runner* runner = dht_runner_new(); - dht_runner_config dht_config; - dht_runner_config_default(&dht_config); - dht_config.peer_discovery = params.peer_discovery; // Look for other peers on the network - dht_config.peer_publish = params.peer_discovery; // Publish our own peer info - dht_config.dht_config.node_config.network = params.network; - dht_config.log = params.log; - dht_runner_run_config(runner, params.port, &dht_config); + printf("random hash: %s\n", dht_infohash_print(&h)); - if (params.bootstrap) { - printf("Bootstrap using %s\n", params.bootstrap); - dht_runner_bootstrap(runner, params.bootstrap, NULL); - } + // Put data + const char* data_str = "yo, this is some data"; + dht_value* val = dht_value_new(data_str, strlen(data_str)); + dht_runner_put(runner, &h, val, dht_done_callback, runner, false); + dht_value_unref(val); - char cmd[64]; - char arg[64]; - char value[256]; - dht_infohash key; - while (true) { - const char* line_read = readline("> "); - if (!line_read) - break; - if (!*line_read) - continue; - add_history(line_read); + // Get data + dht_runner_get(runner, &h, dht_get_callback, dht_done_callback, runner); - memset(cmd, 0, sizeof cmd); - memset(arg, 0, sizeof arg); - memset(value, 0, sizeof value); - sscanf(line_read, "%64s %64s %256s", cmd, arg, value); + // Listen for data + struct op_context* ctx = malloc(sizeof(struct op_context)); + ctx->runner = runner; + ctx->d = 42; + dht_op_token* token = dht_runner_listen(runner, &h, dht_value_callback, op_context_free, ctx); - if (!strcmp(cmd, "la")) { - struct sockaddr** addrs = dht_runner_get_public_address(runner); - if (addrs) { - for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) { - struct sockaddr* addr = *addrIt; - char* addr_str = print_addr(addr); - free(addr); - printf("Found public address: %s\n", addr_str); - free(addr_str); - } - free(addrs); - } - continue; - } - else if (!strcmp(cmd, "ll")) { - dht_infohash key = dht_runner_get_node_id(runner); - printf("DHT node %s running on port %u\n", dht_infohash_print(&key), dht_runner_get_bound_port(runner, AF_INET)); - continue; - } - else if (!strcmp(cmd, "g")) { - key = parse_key(arg); - dht_runner_get(runner, &key, dht_get_callback, dht_get_done_callback, runner); - } - else if (!strcmp(cmd, "l")) { - key = parse_key(arg); - struct listen_context* ctx = malloc(sizeof(struct listen_context)); - ctx->runner = runner; - ctx->count = 0; - ctx->token = dht_runner_listen(runner, &key, dht_value_callback, listen_context_free, ctx); - } - else if (!strcmp(cmd, "p")) { - key = parse_key(arg); - dht_value* val = dht_value_new_from_string(value); - dht_runner_put(runner, &key, val, dht_put_done_callback, runner, true); - dht_value_unref(val); - } - else { - printf("Unkown command: %s\n", cmd); - } - } + sleep(1); - // Graceful shutdown - printf("Stopping…\n"); - struct op_context ctx; - ctx.runner = runner; - atomic_init(&ctx.stop, false); - dht_runner_shutdown(runner, dht_shutdown_callback, &ctx); + dht_runner_bootstrap(runner, "bootstrap.jami.net", NULL); - // Wait until shutdown callback is called - while (!atomic_load(&ctx.stop)) { - usleep(10000); + sleep(2); + + struct sockaddr** addrs = dht_runner_get_public_address(runner); + for (struct sockaddr** addrIt = addrs; *addrIt; addrIt++) { + struct sockaddr* addr = *addrIt; + char* addr_str = print_addr(addr); + free(addr); + printf("Found public address: %s\n", addr_str); + free(addr_str); } + free(addrs); + + dht_runner_cancel_listen(runner, &h, token); + dht_op_token_delete(token); + dht_runner_delete(runner); - return EXIT_SUCCESS; + return 0; } diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index 3fde3d853..8b8adb7b7 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Authors: Adrien Béraud * Simon Désaulniers @@ -146,7 +146,6 @@ void cmd_loop(std::shared_ptr& node, dht_params& params node->getNodeInfo([&](const std::shared_ptr& nodeInfo) { print_node_info(*nodeInfo); std::cout << nodeInfo->ongoing_ops << " ongoing operations" << std::endl; - std::cout << "Storage has " << nodeInfo->storage_values << " values, using " << (nodeInfo->storage_size/1024) << " KB" << std::endl; std::cout << "IPv4 stats:" << std::endl; std::cout << nodeInfo->ipv4.toString() << std::endl; std::cout << "IPv6 stats:" << std::endl; @@ -157,7 +156,7 @@ void cmd_loop(std::shared_ptr& node, dht_params& params if (auto stats = proxy.second->stats()) std::cout << " " << stats->toString() << std::endl; else - std::cout << " (stats not available yet)" << std::endl; + std::cout << " (stats not available yet)" << std::endl; } #endif }); @@ -328,17 +327,15 @@ void cmd_loop(std::shared_ptr& node, dht_params& params if (op == "g") { std::string rem; std::getline(iss, rem); - auto total = std::make_shared(); - node->get(id, [start, total](const std::vector>& values) { + node->get(id, [start](const std::vector>& values) { auto now = std::chrono::high_resolution_clock::now(); - (*total) += values.size(); - std::cout << "Get: found " << values.size() << " value(s) after " << print_duration(now-start) << " (total " << *total << ')' << std::endl; + std::cout << "Get: found " << values.size() << " value(s) after " << print_duration(now-start) << std::endl; for (const auto& value : values) std::cout << "\t" << *value << std::endl; return true; - }, [start, total](bool ok) { + }, [start](bool ok) { auto end = std::chrono::high_resolution_clock::now(); - std::cout << "Get: " << (ok ? "completed" : "failure") << ", took " << print_duration(end-start) << " (total " << *total << ')' << std::endl; + std::cout << "Get: " << (ok ? "completed" : "failure") << ", took " << print_duration(end-start) << std::endl; }, {}, dht::Where {rem}); } else if (op == "q") { @@ -359,13 +356,8 @@ void cmd_loop(std::shared_ptr& node, dht_params& params else if (op == "l") { std::string rem; std::getline(iss, rem); - auto total = std::make_shared(); - auto token = node->listen(id, [total](const std::vector>& values, bool expired) { - if (expired) - (*total) -= values.size(); - else - (*total) += values.size(); - std::cout << "Listen: found " << values.size() << " values" << (expired ? " expired" : "") << " (total " << *total << ')' << std::endl; + auto token = node->listen(id, [](const std::vector>& values, bool expired) { + std::cout << "Listen: found " << values.size() << " values" << (expired ? " expired" : "") << std::endl; for (const auto& value : values) std::cout << "\t" << *value << std::endl; return true; @@ -475,7 +467,7 @@ void cmd_loop(std::shared_ptr& node, dht_params& params << " hash: " << p.hash() << std::endl; std::cout << " entries:" << std::endl; for (const auto& v : vals) - std::cout << " " << v->first.toString() << "[vid: " << std::hex << v->second << std::dec << "]" << std::endl; + std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl; }, [start](bool ok) { auto end = std::chrono::high_resolution_clock::now(); diff --git a/tools/dhtscanner.cpp b/tools/dhtscanner.cpp index 0f7750fdf..66006398b 100644 --- a/tools/dhtscanner.cpp +++ b/tools/dhtscanner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * diff --git a/tools/durl.cpp b/tools/durl.cpp index 7aaa740f6..368b0ef8f 100644 --- a/tools/durl.cpp +++ b/tools/durl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Authors: Adrien Béraud * diff --git a/tools/perftest.cpp b/tools/perftest.cpp index 4ef6a866f..59faf7ac3 100644 --- a/tools/perftest.cpp +++ b/tools/perftest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * @@ -102,7 +102,7 @@ benchPingPong(unsigned netSize, unsigned n_parallel) { auto start = clock::now(); - for (unsigned i=0; i # # This program is free software; you can redistribute it and/or modify diff --git a/tools/tools_common.h b/tools/tools_common.h index c12361720..dfe6bd3ed 100644 --- a/tools/tools_common.h +++ b/tools/tools_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2022 Savoir-faire Linux Inc. + * Copyright (C) 2014-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud * Author: Sébastien Blin