Compare commits

...
37 Commits
Author SHA1 Message Date
Adrien Béraud c3669cfd36 ci/github: update restinio tag name 2025-04-22 22:37:39 -04:00
Adrien Béraud 45f04a7b6f ci/github: update restinio 2025-04-22 22:33:59 -04:00
Adrien Béraud 33f9570ecb adapt for Asio 1.34 2025-04-22 20:02:37 -04:00
François-Simon Fauteux-Chapleau c2d8b19380 http: fix service name resolution failure 2025-04-14 22:12:56 -04:00
Adrien Béraud 9bd957da48 build/cmake: update CheckAtomic.cmake 2025-04-05 10:29:06 -04:00
Adrien Béraud 352e36500c utils: make HexMap constexpr 2025-04-05 09:49:58 -04:00
Adrien Béraud 7397bd615f infohash: always write end of string terminator 2025-03-24 23:37:07 -04:00
Adrien Béraud 6a264d6f73 infohash: constexpr HexMap constructor 2025-03-24 23:29:32 -04:00
François-Simon Fauteux-Chapleau b0fa19d6f8 Merge pull request #747 from savoirfairelinux/proxy_push_result
proxy client: provide result for pushNotificationReceived
2025-02-20 15:29:58 -05:00
Adrien Beraud b2860e1731 proxy client: provide result for pushNotificationReceived 2025-02-20 14:13:16 -05:00
Adrien Beraud ad65ce872b docker: update llvm image to Ubuntu 24.04 2025-02-14 12:03:55 -05:00
Adrien Beraud 0cdc828953 docker: update restinio 2025-02-14 11:50:46 -05:00
Adrien Beraud 65e13fff4e ci/github: update llhttp 2025-02-14 11:48:42 -05:00
Adrien Beraud 748247d660 ci/github: update actions 2025-02-14 11:46:05 -05:00
Adrien Beraud 456f266be3 update restinio 2025-02-14 11:41:16 -05:00
Adrien Beraud 2c26030108 build/cmake: accept both llhttp and libllhttp 2025-02-14 11:28:50 -05:00
Adrien Beraud efc26245ae update version to 3.3.0 2025-02-11 16:01:27 -05:00
Adrien Beraud b9e00c7a0f tools/cnode: show value ID when put completes 2025-02-11 15:48:59 -05:00
Simon Désaulniers 5bf19c875c c: dht_value_with_id_new for setting an ID
Necessary for cancelling put values. Otherwise, the user doesn't have
the value ID for asking to cancel the permanent put.
2025-02-04 13:24:54 -05:00
Simon Désaulniers 5c18c980aa c/opendht: check for server_ca null 2025-01-25 09:32:15 -05:00
Simon Désaulniers b8d6fdc8eb c/opendht: dht_runner_run_config, consider client_identity 2025-01-25 09:32:15 -05:00
Simon Désaulniers 27bfd547c5 c/opendht: dht_runner_run_config, consider server_ca 2025-01-25 09:32:15 -05:00
ovari 5237f0a3b3 Update dht.cpp 2025-01-05 10:01:40 -05:00
ovari 23af860532 Update pht.h 2024-12-19 15:29:21 -05:00
ovari 4c98f7c8f4 pht.h: cleanup 2024-12-19 15:29:21 -05:00
Adrien Beraud 2a4b357420 ci: update libargon2 on Ubuntu 2024-12-19 15:22:58 -05:00
Adrien Beraud a26ac441ba proxy: cleanup 2024-12-17 16:04:22 -05:00
Adrien Beraud 80cfed38a1 build/cmake: make using io_uring optional 2024-12-17 16:04:22 -05:00
Lucas Dias 83ae498008 Catch exception of DeserializeNodes
Fix calls to DeserializeNodes. They must
catch possible exceptions

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

No files matched your search

+127 -99
View File
@@ -1,5 +1,13 @@
name: C/C++ CI
env:
LLHTTP_VERSION: "v9.2.1"
RESTINIO_VERSION: "0.7.6"
EXPECTED_LITE_URL: "https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp"
UBUNTU_FULL_DEPS: "libncurses5-dev libreadline-dev nettle-dev libasio-dev libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev"
UBUNTU_MESON_DEPS: "ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev libgnutls28-dev libuv1-dev python3-dev python3-setuptools python3-pip libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-dev"
UBUNTU_MINIMAL_DEPS: "libncurses5-dev libreadline-dev nettle-dev libfmt-dev libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-dev"
on: [push, pull_request]
jobs:
@@ -7,122 +15,142 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Cython
run: sudo pip3 install Cython
- name: llhttp
run: |
mkdir llhttp
wget https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.0.tar.gz -O llhttp.tar.gz
tar -xzf llhttp.tar.gz -C llhttp --strip-components=1
cd llhttp && cmake -DCMAKE_INSTALL_PREFIX=/usr . && make -j2 && sudo make install
cd ../ && rm -rf llhttp*
- name: expected-lite
run: |
sudo mkdir /usr/local/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/local/include/nonstd/expected.hpp
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
- uses: actions/checkout@v4
- name: Install Dependencies
run: |
echo "Installing Ubuntu full dependencies:"
sudo apt-get update
sudo apt-get install -y $UBUNTU_FULL_DEPS
- name: Install Cython
run: sudo pip3 install Cython
- name: Build llhttp dependency
run: |
mkdir llhttp
wget "https://github.com/nodejs/llhttp/archive/refs/tags/release/${LLHTTP_VERSION}.tar.gz" -O llhttp.tar.gz
tar -xzf llhttp.tar.gz -C llhttp --strip-components=1
cd llhttp && cmake -DCMAKE_INSTALL_PREFIX=/usr . && make -j2 && sudo make install
cd ../ && rm -rf llhttp*
- name: Install expected-lite header
run: |
sudo mkdir -p /usr/local/include/nonstd
sudo wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Build restinio dependency
run: |
mkdir restinio && cd restinio
wget "https://github.com/Stiffstream/restinio/releases/download/v${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}.tar.bz2"
tar -xjf restinio-${RESTINIO_VERSION}.tar.bz2
cd restinio-${RESTINIO_VERSION}/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local \
-DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off \
-DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
sudo make install
cd ../../ && rm -rf restinio*
- name: Configure
run: |
./autogen.sh
./configure --enable-proxy-client
- name: Build
run: make
sudo make install
cd ../../ && rm -rf restinio*
- name: Configure project
run: |
./autogen.sh
./configure --enable-proxy-client
- name: Build
run: make
build-ubuntu-meson:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools python3-pip \
libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Python dependencies
run: sudo pip3 install meson Cython
- name: Configure
run: meson setup build .
- name: Build
run: cd build && ninja
- uses: actions/checkout@v4
- name: Install Dependencies
run: |
echo "Installing Ubuntu meson dependencies:"
sudo apt update
sudo apt install -y $UBUNTU_MESON_DEPS
- name: Install Python dependencies
run: sudo pip3 install meson Cython
- name: Configure with Meson
run: meson setup build .
- name: Build with Ninja
run: cd build && ninja
build-ubuntu-minimal:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libfmt-dev \
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
- name: Configure
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DBUILD_TESTING=On -DOPENDHT_PEER_DISCOVERY=Off -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=Off -DOPENDHT_PROXY_CLIENT=Off
- name: Build
run: cd build && make
- name: Unit tests
run: cd build && ./opendht_unit_tests
- uses: actions/checkout@v4
- name: Install Minimal Dependencies
run: |
echo "Installing Ubuntu minimal dependencies:"
sudo apt-get update
sudo apt-get install -y $UBUNTU_MINIMAL_DEPS
- name: Configure project with CMake
run: |
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=Off -DBUILD_TESTING=On \
-DOPENDHT_PEER_DISCOVERY=Off -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=Off -DOPENDHT_PROXY_CLIENT=Off
- name: Build
run: cd build && make
- name: Run Unit tests
run: cd build && ./opendht_unit_tests
build-macos:
name: macOS/Clang build
runs-on: macOS-15
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Dependencies
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- uses: actions/checkout@v4
- name: expected-lite
run: |
sudo mkdir -p /usr/local/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/local/include/nonstd/expected.hpp
- name: Install Homebrew Dependencies
run: brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
- name: Install expected-lite header
run: |
sudo mkdir -p /usr/local/include/nonstd
sudo wget "${EXPECTED_LITE_URL}" -O /usr/local/include/nonstd/expected.hpp
- name: Build restinio dependency
run: |
mkdir restinio && cd restinio
wget "https://github.com/Stiffstream/restinio/releases/download/v${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}.tar.bz2"
tar -xjf restinio-${RESTINIO_VERSION}.tar.bz2
cd restinio-${RESTINIO_VERSION}/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr/local \
-DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off \
-DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
make -j2 && sudo make install
cd ../../ && rm -rf restinio*
- name: Configure
run: |
mkdir build && cd build
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On -DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On -DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
- name: Build
run: cd build && make
- name: Configure project with CMake
run: |
mkdir build && cd build
# Set Homebrew OpenSSL paths
export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Debug \
-DOPENDHT_C=On -DBUILD_TESTING=On \
-DOPENDHT_PEER_DISCOVERY=On -DOPENDHT_PYTHON=Off \
-DOPENDHT_TOOLS=On -DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_PROXY_CLIENT=On -DOPENDHT_PUSH_NOTIFICATIONS=On
- name: Build
run: cd build && make
+4 -4
View File
@@ -12,7 +12,7 @@ jobs:
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev libasio-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev libasio-dev \
llvm llvm-dev clang clang-tools && \
sudo apt remove gcc g++
@@ -25,9 +25,9 @@ jobs:
- name: restinio
run: |
mkdir restinio && cd restinio
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2
ls -l && tar -xjf restinio-0.7.2.tar.bz2
cd restinio-0.7.2/dev
wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2
ls -l && tar -xjf restinio-0.7.3.tar.bz2
cd restinio-0.7.3/dev
cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system .
+10 -9
View File
@@ -13,7 +13,7 @@ include(CTest)
include(FetchContent)
set (opendht_VERSION_MAJOR 3)
set (opendht_VERSION_MINOR 2.0)
set (opendht_VERSION_MINOR 3.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -33,6 +33,7 @@ option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp"
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_IO_URING "Use io_uring if available on the system (Linux only)" OFF)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS_NETWORK "Enable unit tests that require network access" ON)
option (OPENDHT_C "Build C bindings" OFF)
@@ -107,7 +108,7 @@ if (NOT MSVC)
)
set(llhttp_target llhttp_static)
else()
FetchContent_Declare(llhttp-local URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.0.tar.gz")
FetchContent_Declare(llhttp-local URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.1.tar.gz")
if (BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "")
else()
@@ -122,7 +123,7 @@ if (NOT MSVC)
endif()
endif()
set(http_lib "-lllhttp")
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
@@ -156,14 +157,14 @@ else ()
${WIN32_DEP_DIR}/openssl/include
${WIN32_DEP_DIR}/restinio/dev
${WIN32_DEP_DIR}/fmt/include
${WIN32_DEP_DIR}/http_parser
${WIN32_DEP_DIR}/llhttp/include
)
endif ()
endif ()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
if (UNIX AND NOT APPLE)
if (OPENDHT_IO_URING AND UNIX AND NOT APPLE)
pkg_search_module(liburing IMPORTED_TARGET liburing)
endif ()
endif()
@@ -343,12 +344,12 @@ if (MSVC)
)
if (OPENDHT_HTTP)
add_obj_lib (win32_fmt ${WIN32_DEP_DIR}/fmt/msvc/Release/fmt.lib)
add_obj_lib (win32_http_parser ${WIN32_DEP_DIR}/http_parser/x64/Release/http-parser.lib)
add_obj_lib (win32_llhttp ${WIN32_DEP_DIR}/llhttp/build/Release/llhttp.lib)
add_obj_lib (win32_ssl ${WIN32_DEP_DIR}/openssl/libssl_static.lib)
add_obj_lib (win32_crypto ${WIN32_DEP_DIR}/openssl/libcrypto_static.lib)
list (APPEND obj_libs
$<TARGET_OBJECTS:win32_fmt>
$<TARGET_OBJECTS:win32_http_parser>
$<TARGET_OBJECTS:win32_llhttp>
$<TARGET_OBJECTS:win32_ssl>
$<TARGET_OBJECTS:win32_crypto>
)
@@ -361,7 +362,7 @@ if (MSVC)
)
list (APPEND win32_Libs
${PROJECT_SOURCE_DIR}/../fmt/msvc/Release/fmt.lib
${PROJECT_SOURCE_DIR}/../http_parser/x64/Release/http-parser.lib
${PROJECT_SOURCE_DIR}/../llhttp/build/Release/llhttp.lib
${PROJECT_SOURCE_DIR}/../openssl/libssl.lib
${PROJECT_SOURCE_DIR}/../openssl/libcrypto.lib
)
@@ -407,7 +408,7 @@ else()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (liburing_FOUND)
if (OPENDHT_IO_URING AND liburing_FOUND)
set(iouring_lib ", liburing")
target_link_libraries(opendht PUBLIC PkgConfig::liburing)
target_compile_definitions(opendht PUBLIC ASIO_HAS_IO_URING ASIO_DISABLE_EPOLL)
+22 -14
View File
@@ -132,8 +132,12 @@ void dht_value_set_user_type(dht_value* data, const char* user_type) {
(*reinterpret_cast<ValueSp*>(data))->user_type = user_type;
}
dht_value* dht_value_with_id_new(const uint8_t* data, size_t size, uint64_t value_id) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(dht::ValueType::USER_DATA.id, data, size, value_id)));
}
dht_value* dht_value_new(const uint8_t* data, size_t size) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
return dht_value_with_id_new(data, size, 0);
}
dht_value* dht_value_new_from_string(const char* str) {
@@ -325,12 +329,13 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
try {
dht::DhtRunner::Config config;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
config.dht_config.node_config.maintain_storage = conf->dht_config.node_config.maintain_storage;
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path) : std::string{};
config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
config.dht_config.node_config.network = conf->dht_config.node_config.network;
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path)
: std::string{};
if (conf->dht_config.id.privatekey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privatekey);
@@ -338,15 +343,18 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
if (conf->dht_config.id.certificate)
config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
config.threaded = conf->threaded;
config.proxy_server = conf->proxy_server ? std::string(conf->proxy_server) : std::string{};
config.push_node_id = conf->push_node_id ? std::string(conf->push_node_id) : std::string{};
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.push_topic = conf->push_topic ? std::string(conf->push_topic) : std::string{};
config.push_platform = conf->push_platform ? std::string(conf->push_platform) : std::string{};
config.threaded = conf->threaded;
config.proxy_server = conf->proxy_server ? std::string(conf->proxy_server) : std::string{};
config.push_node_id = conf->push_node_id ? std::string(conf->push_node_id) : std::string{};
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.push_topic = conf->push_topic ? std::string(conf->push_topic) : std::string{};
config.push_platform = conf->push_platform ? std::string(conf->push_platform) : std::string{};
config.proxy_user_agent = conf->proxy_user_agent ? std::string(conf->proxy_user_agent) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
if (conf->server_ca)
config.server_ca = *reinterpret_cast<const CertSp*>(conf->server_ca);
config.client_identity = dht_identity_from_c(&conf->client_identity);
dht::DhtRunner::Context context;
if (conf->log) {
+1
View File
@@ -104,6 +104,7 @@ struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_with_id_new(const uint8_t* data, size_t size, uint64_t value_id);
OPENDHT_C_PUBLIC dht_value* dht_value_new_from_string(const char* str);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
+31 -8
View File
@@ -49,10 +49,15 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
if(HAVE_LIBATOMIC)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
endif()
@@ -65,14 +70,32 @@ elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
if(HAVE_CXX_LIBATOMICS64)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
endif()
else()
#message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
endif()
endif()
endif()
# Set variable LLVM_ATOMIC_LIB specifying flags for linking against libatomic.
if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB)
# Use options --push-state, --as-needed and --pop-state if linker is known to support them.
# Use single option -Wl of compiler driver to avoid incorrect re-ordering of options by CMake.
if(LLVM_LINKER_IS_GNULD OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD OR LLVM_LINKER_IS_MOLD)
set(LLVM_ATOMIC_LIB "-Wl,--push-state,--as-needed,-latomic,--pop-state")
else()
set(LLVM_ATOMIC_LIB "-latomic")
endif()
else()
set(LLVM_ATOMIC_LIB)
endif()
## TODO: This define is only used for the legacy atomic operations in
## llvm's Atomic.h, which should be replaced. Other code simply
## assumes C++11 <atomic> works.
+1 -1
View File
@@ -1,6 +1,6 @@
dnl define macros
m4_define([opendht_major_version], 3)
m4_define([opendht_minor_version], 2)
m4_define([opendht_minor_version], 3)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
+3 -3
View File
@@ -24,9 +24,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
+3 -3
View File
@@ -17,9 +17,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
+3 -3
View File
@@ -26,9 +26,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
+3 -3
View File
@@ -24,9 +24,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
+6 -6
View File
@@ -1,4 +1,4 @@
FROM ubuntu:22.04
FROM ubuntu:24.04
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
LABEL org.opencontainers.image.source https://github.com/savoirfairelinux/opendht
@@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake pkg-config \
&& apt-get install -y llvm llvm-dev lldb clang gdb make cmake meson pkg-config \
libtool git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev python3-dev \
python3-setuptools libcppunit-dev python3-pip python3-build python3-virtualenv \
@@ -17,7 +17,7 @@ RUN apt-get update \
&& apt-get remove -y gcc g++ && apt-get autoremove -y \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
RUN pip3 install meson Cython
RUN pip3 install Cython --break-system-packages
ENV CC cc
ENV CXX c++
@@ -28,9 +28,9 @@ RUN mkdir /usr/include/nonstd \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.2/restinio-0.7.2.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.2.tar.bz2 \
&& cd restinio-0.7.2/dev \
&& wget https://github.com/Stiffstream/restinio/releases/download/v.0.7.3/restinio-0.7.3.tar.bz2 \
&& ls -l && tar -xjf restinio-0.7.3.tar.bz2 \
&& cd restinio-0.7.3/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=Off -DRESTINIO_SAMPLE=Off -DRESTINIO_BENCHMARK=Off \
-DRESTINIO_WITH_SOBJECTIZER=Off -DRESTINIO_DEP_STANDALONE_ASIO=system -DRESTINIO_DEP_LLHTTP=system \
-DRESTINIO_DEP_FMT=system -DRESTINIO_DEP_EXPECTED_LITE=system . \
+14
View File
@@ -163,6 +163,20 @@ struct OPENDHT_PUBLIC SecureDhtConfig
bool cert_cache_all {false};
};
enum class OPENDHT_PUBLIC PushNotificationResult: uint8_t {
/* success codes */
PutRefresh,
ListenRefresh,
Values,
ValuesExpired,
/* ignored/error codes */
IgnoredWrongSession = 0x80,
IgnoredNoOp,
IgnoredStopped,
IgnoredDisabled,
Error
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
using ValuesExport = std::pair<InfoHash, Blob>;
+3 -1
View File
@@ -315,7 +315,9 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override;
void pushNotificationReceived(const std::map<std::string, std::string>&) override {}
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>&) override {
return PushNotificationResult::IgnoredDisabled;
}
void resubscribe(unsigned) {}
private:
+1 -1
View File
@@ -262,7 +262,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
virtual PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
std::shared_ptr<Logger> logger_ {};
+1 -1
View File
@@ -216,7 +216,7 @@ public:
* Call linked callback with a push notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
+10 -10
View File
@@ -150,22 +150,22 @@ public:
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Push requests in the last " << print_duration(lastUpdated - serverStartTime) << ": "
<< "[Android: " << androidPush.toString() << "], "
<< "[iOS: " << iosPush.toString() << "], "
<< "[Unified: " << unifiedPush.toString() << "]" << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
auto ret = fmt::format("Listens: {}, Puts: {}, PushListeners: {}\n"
"Push requests in the last {}: [Android: {}], [iOS: {}], [Unified: {}]\n"
"Requests: {} per second.",
listenCount, putCount, pushListenersCount,
print_duration(lastUpdated - serverStartTime),
androidPush.toString(), iosPush.toString(), unifiedPush.toString(),
requestRate);
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
}
return ss.str();
return ret;
}
/**
+1 -1
View File
@@ -466,7 +466,7 @@ public:
/**
* Insert a push notification to process for OpenDHT
*/
void pushNotificationReceived(const std::map<std::string, std::string>& data);
std::future<PushNotificationResult> pushNotificationReceived(const std::map<std::string, std::string>& data);
/* Proxy server mothods */
void forwardAllMessages(bool forward);
+1 -1
View File
@@ -72,7 +72,7 @@ class OPENDHT_PUBLIC Url
{
public:
Url() = default;
Url(const std::string& url);
Url(std::string_view url);
std::string url;
std::string protocol {"http"};
std::string host;
+1 -1
View File
@@ -409,7 +409,7 @@ private:
/**
* This mutlimap contains all prefix insert in the tree in time order
* We could then delete the last one if there is too much node
* We could then delete the last one if there are too many nodes
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
+7 -6
View File
@@ -110,7 +110,7 @@ public:
bool operator!=(const Hash& h) const { return !(*this == h); }
bool operator<(const Hash& o) const {
for(unsigned i = 0; i < N; i++) {
for (unsigned i = 0; i < N; i++) {
if(data_[i] != o.data_[i])
return data_[i] < o.data_[i];
}
@@ -119,7 +119,7 @@ public:
Hash operator^(const Hash& o) const {
Hash result;
for(auto i = 0u; i < N; i++) {
for (auto i = 0u; i < N; i++) {
result[i] = data_[i] ^ o.data_[i];
}
return result;
@@ -345,8 +345,8 @@ Hash<N>::getRandom(Rd& rdev)
}
struct alignas(std::max_align_t) HexMap : public std::array<std::array<char, 2>, 256> {
HexMap() {
for (size_t i=0; i<size(); i++) {
constexpr HexMap() : std::array<std::array<char, 2>, 256>() {
for (size_t i = 0; i < size(); i++) {
auto& e = (*this)[i];
e[0] = hex_digits[(i >> 4) & 0x0F];
e[1] = hex_digits[i & 0x0F];
@@ -356,7 +356,7 @@ private:
static constexpr const char* hex_digits = "0123456789abcdef";
};
OPENDHT_PUBLIC extern const HexMap hex_map;
OPENDHT_PUBLIC constexpr HexMap hex_map = {};
inline std::string
toHex(const uint8_t* data, size_t size) {
@@ -380,10 +380,11 @@ Hash<N>::to_c_str() const
{
alignas(std::max_align_t) thread_local std::array<char, N*2+1> buf;
for (size_t i=0; i<N; i++) {
auto b = buf.data()+i*2;
auto b = buf.data() + i*2;
const auto& m = hex_map[data_[i]];
*((uint16_t*)b) = *((uint16_t*)&m);
}
buf[N*2] = '\0';
return buf.data();
}
+1 -1
View File
@@ -24,7 +24,7 @@ namespace proxy {
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
}
+2 -2
View File
@@ -328,8 +328,8 @@ public:
* Call linked callback with push_notification
* @param notification to process
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
dht_->pushNotificationReceived(notification);
PushNotificationResult pushNotificationReceived(const std::map<std::string, std::string>& notification) override {
return dht_->pushNotificationReceived(notification);
}
void setLogger(const Logger& logger) override {
+9 -22
View File
@@ -21,6 +21,7 @@
#include "def.h"
#include <msgpack.hpp>
#include <fmt/format.h>
#include <chrono>
#include <random>
@@ -60,7 +61,7 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
* Split "[host]:port" or "host:port" to pair<"host", "port">.
*/
OPENDHT_PUBLIC std::pair<std::string, std::string>
splitPort(const std::string& s);
splitPort(std::string_view s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
@@ -84,37 +85,23 @@ using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
template <class DT>
static double
print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
template <class DT>
static std::string
print_duration(DT d) {
if (d < std::chrono::seconds(0)) {
return "-" + print_duration(-d);
} else if (d < std::chrono::milliseconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
return fmt::format("{:.3g} us", std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
} else if (d < std::chrono::seconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
return fmt::format("{:.3g} ms", std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
} else if (d < std::chrono::minutes(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
return fmt::format("{:.3g} s", std::chrono::duration_cast<std::chrono::duration<double>>(d).count());
} else if (d < std::chrono::hours(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
return fmt::format("{:.3g} min", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count());
} else if (d < std::chrono::hours(72)) {
return fmt::format("{:.3g} h", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count());
} else {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
return fmt::format("{:.3g} days", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
project('opendht', 'c', 'cpp', 'cython',
version: '3.2.0',
version: '3.3.0',
default_options: [
'cpp_std=c++17',
'warning_level=3'
+68 -68
View File
@@ -93,7 +93,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
r.second.done_cb(false, {});
sr.second->callbacks.clear();
for (const auto& a : sr.second->announce) {
if (a.callback) a.callback(false, {});
for (auto& cb : a.callbacks) cb(false, {});
}
sr.second->announce.clear();
sr.second->listeners.clear();
@@ -113,7 +113,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
auto str_donecb = [=](bool, const std::vector<Sp<Node>>&) {
--*remaining;
if (logger_)
logger_->w("shuting down node: %u ops remaining", *remaining);
logger_->w("Shutting down node: %u ops remaining", *remaining);
if (!*remaining && cb) { cb(); }
};
@@ -121,7 +121,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
*remaining += maintainStorage(str, true, str_donecb);
if (logger_)
logger_->w("shuting down node: after storage, %u ops", *remaining);
logger_->w("Shutting down node: after storage, %u ops", *remaining);
if (!*remaining) {
if (cb) cb();
@@ -147,7 +147,7 @@ Dht::sendCachedPing(Bucket& b)
{
if (b.cached)
if (logger_)
logger_->d(b.cached->id, "[node %s] sending ping to cached node", b.cached->toString().c_str());
logger_->d(b.cached->id, "[node %s] Sending ping to cached node", b.cached->toString().c_str());
b.sendCachedPing(network_engine);
}
@@ -280,7 +280,7 @@ Dht::expireSearches()
auto b = sr.callbacks.empty() && sr.announce.empty() && sr.listeners.empty() && sr.step_time < t;
if (b) {
if (logger_)
logger_->d(srp.first, "[search %s] removing search", srp.first.toString().c_str());
logger_->d(srp.first, "[search %s] Removing search", srp.first.toString().c_str());
sr.clear();
return b;
} else { return false; }
@@ -360,7 +360,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
auto query_for_vid = std::make_shared<Query>(Select {}, Where {}.id(vid));
sn->pagination_queries[query].push_back(query_for_vid);
if (logger_)
logger_->d(id, sn->node->id, "[search %s] [node %s] sending %s",
logger_->d(id, sn->node->id, "[search %s] [node %s] Sending %s",
id.toString().c_str(), sn->node->toString().c_str(), query_for_vid->toString().c_str());
sn->getStatus[query_for_vid] = network_engine.sendGetValues(status.node,
id,
@@ -371,8 +371,8 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
);
} catch (const std::out_of_range&) {
if (logger_)
logger_->e(id, sn->node->id, "[search %s] [node %s] received non-id field in response to "\
"'SELECT id' request...",
logger_->e(id, sn->node->id, "[search %s] [node %s] Received non-id field in response to "\
"'SELECT id' request…",
id.toString().c_str(), sn->node->toString().c_str());
}
}
@@ -381,7 +381,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
n->pagination_queries[query].push_back(select_q);
if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending %s",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending %s",
sr->id.toString().c_str(), n->node->toString().c_str(), select_q->toString().c_str());
n->getStatus[select_q] = network_engine.sendGetValues(n->node,
sr->id,
@@ -426,7 +426,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
return nullptr;
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'find_node'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'find_node'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendFindNode(n->node,
sr->id,
@@ -439,9 +439,9 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
continue;
if (query and not query->select.empty()) {
/* The request contains a select. No need to paginate... */
/* The request contains a select. No need to paginate… */
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'get'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'get'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendGetValues(n->node,
sr->id,
@@ -453,7 +453,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
paginate(ws, query, n);
}
/* We only try to send one request. return. */
/* We only attempt to send one request. Return. */
return n;
} while (++cb != sr->callbacks.end());
@@ -519,7 +519,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
/* only put the value if the node doesn't already have it */
if (not hasValue or seq_no < a.value->seq) {
if (logger_)
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto created = a.permanent ? time_point::max() : a.created;
acked = {
@@ -528,7 +528,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else if (hasValue and a.permanent) {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %016" PRIx64 ")",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Sending 'refresh' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
acked = {
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
@@ -540,7 +540,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
](const net::Request& /*req*/, net::DhtProtocolException&& e){
if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
if (auto sr = ws.lock()) {
if (auto sn = sr->getNode(node)) {
sn->acked[v->id] = {
@@ -558,7 +558,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %016" PRIx64 "). Aborting.",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Already has value (vid: %016" PRIx64 "). Aborting.",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto ack_req = std::make_shared<net::Request>(net::Request::State::COMPLETED);
ack_req->reply_time = now;
@@ -594,7 +594,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
sendQuery = true;
} else {
if (logger_)
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
logger_->w(sr->id, n.node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), n.node->toString().c_str(), a.value->id);
n.acked[a.value->id] = {
network_engine.sendAnnounceValue(n.node, sr->id, a.value, a.created, n.token, onDone, onExpired),
@@ -607,7 +607,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
if (sendQuery) {
n.probe_query = PROBE_QUERY;
if (logger_)
logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending %s",
logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending %s",
sr->id.toString().c_str(), n.node->toString().c_str(), n.probe_query->toString().c_str());
auto req = network_engine.sendGetValues(n.node,
sr->id,
@@ -634,7 +634,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
if (n.getListenTime(r, listenExp) > scheduler.time())
continue;
// if (logger_)
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending 'listen'",
// sr->id.toString().c_str(), n.node->toString().c_str());
if (r == n.listenStatus.end()) {
@@ -706,7 +706,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
auto syncLevel = preSynced ? level - MARGIN : 0;
/*if (auto req_count = sr->currentlySolicitedNodeCount())
if (logger_)
logger_->d(sr->id, "[search %s IPv%c] step (%d requests)",
logger_->d(sr->id, "[search %s IPv%c] Step (%d requests)",
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', req_count);*/
sr->step_time = now;
@@ -787,7 +787,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
if (sr->getNumberOfConsecutiveBadNodes() >= std::min<size_t>(sr->nodes.size(), SEARCH_MAX_BAD_NODES))
{
if (logger_)
logger_->w(sr->id, "[search %s IPv%c] expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
logger_->w(sr->id, "[search %s IPv%c] Expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
sr->expire();
if (not public_stable)
connectivityChanged(sr->af);
@@ -804,7 +804,7 @@ unsigned Dht::refill(Dht::Search& sr) {
if (cached_nodes.empty()) {
if (logger_)
logger_->e(sr.id, "[search %s IPv%c] no nodes from cache while refilling search",
logger_->e(sr.id, "[search %s IPv%c] No nodes from cache while refilling search",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6');
return 0;
}
@@ -816,7 +816,7 @@ unsigned Dht::refill(Dht::Search& sr) {
++inserted;
}
if (logger_)
logger_->d(sr.id, "[search %s IPv%c] refilled search with %u nodes from node cache",
logger_->d(sr.id, "[search %s IPv%c] Refilled search with %u nodes from node cache",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6', inserted);
return inserted;
}
@@ -828,7 +828,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
{
if (!isRunning(af)) {
if (logger_)
logger_->e(id, "[search %s IPv%c] unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] Unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (dcb)
dcb(false, {});
return {};
@@ -856,7 +856,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
}
if (not sr) {
if (logger_)
logger_->e(id, "[search %s IPv%c] maximum number of searches reached !", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] Maximum number of searches reached!", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
return {};
}
}
@@ -870,7 +870,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
sr->nodes.reserve(SEARCH_NODES+1);
sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr<Search>(sr)));
if (logger_)
logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] New search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (search_id == 0)
search_id++;
}
@@ -904,16 +904,16 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
{
if (!isRunning(af))
return 0;
// logger__ERR("[search %s IPv%c] search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_dt(tm-clock::now()));
// logger__ERR("[search %s IPv%c] Search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_duration(tm-clock::now()));
//logger__WARN("listenTo %s", id.toString().c_str());
auto& srs = searches(af);
auto srp = srs.find(id);
Sp<Search> sr = (srp == srs.end()) ? search(id, af) : srp->second;
if (!sr)
throw DhtException("Can't create search");
throw DhtException("Unable to create search");
if (logger_)
logger_->w(id, "[search %s IPv%c] listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] Listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
return sr->listen(cb, std::move(f), q, scheduler);
}
@@ -1022,7 +1022,7 @@ Dht::put(const InfoHash& id, Sp<Value> val, DoneCallback callback, time_point cr
storageStore(id, val, created, {}, permanent);
if (logger_)
logger_->d(id, "put: adding %s -> %s", id.toString().c_str(), val->toString().c_str());
logger_->d(id, "put: adding %s → %s", id.toString().c_str(), val->toString().c_str());
auto op = std::make_shared<OpStatus>();
auto donecb = [callback](const std::vector<Sp<Node>>& nodes, OpStatus& op) {
@@ -1265,7 +1265,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
vals.push_back(v);
if (not vals.empty()) {
if (logger_)
logger_->d(id, "[store %s] sending update local listener with token %lu",
logger_->d(id, "[store %s] Sending update local listener with token %lu",
id.toString().c_str(),
l.first);
cbs.emplace_back(l.second.get_cb, std::move(vals));
@@ -1286,7 +1286,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
if (f and not f(*v))
continue;
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
@@ -1392,7 +1392,7 @@ void
Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>>& values, size_t totalSize)
{
if (logger_)
logger_->d(id, "[store %s] discarded %ld values (%ld bytes)",
logger_->d(id, "[store %s] Discarded %ld values (%ld bytes)",
id.toString().c_str(), values.size(), totalSize);
total_store_size -= totalSize;
@@ -1410,7 +1410,7 @@ Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending expired",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -1432,7 +1432,7 @@ Dht::expireStore()
if (i->second.empty() && i->second.listeners.empty() && i->second.local_listeners.empty()) {
if (logger_)
logger_->d(i->first, "[store %s] discarding empty storage", i->first.toString().c_str());
logger_->d(i->first, "[store %s] Discarding empty storage", i->first.toString().c_str());
i = store.erase(i);
}
else
@@ -1900,7 +1900,7 @@ Dht::neighbourhoodMaintenance(RoutingTable& list)
auto n = q->randomNode(rd);
if (n) {
if (logger_)
logger_->d(id, n->id, "[node %s] sending [find %s] for neighborhood maintenance",
logger_->d(id, n->id, "[node %s] Sending [find %s] for neighborhood maintenance",
n->toString().c_str(), id.toString().c_str());
/* Since our node-id is the same in both DHTs, it's probably
profitable to query both families. */
@@ -1954,14 +1954,14 @@ Dht::bucketMaintenance(RoutingTable& list)
}
if (logger_)
logger_->d(id, n->id, "[node %s] sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
logger_->d(id, n->id, "[node %s] Sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
//auto start = scheduler.time();
network_engine.sendFindNode(n, id, want, nullptr, [this,n](const net::Request&, bool over) {
if (over) {
const auto& end = scheduler.time();
// using namespace std::chrono;
// if (logger_)
// logger_->d(n->id, "[node %s] bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
// logger_->d(n->id, "[node %s] Bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
scheduler.edit(nextNodesConfirmation, end + Node::MAX_RESPONSE_TIME);
}
});
@@ -1979,7 +1979,7 @@ Dht::dataPersistence(InfoHash id)
auto str = store.find(id);
if (str != store.end() and now > str->second.maintenance_time) {
if (logger_)
logger_->d(id, "[storage %s] maintenance (%u values, %u bytes)",
logger_->d(id, "[storage %s] Maintenance (%u values, %u bytes)",
id.toString().c_str(), str->second.valueCount(), str->second.totalSize());
maintainStorage(*str);
str->second.maintenance_time = now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
@@ -2033,7 +2033,7 @@ Dht::periodic(const uint8_t *buf, size_t buflen, SockAddr from, const time_point
network_engine.processMessage(buf, buflen, std::move(from));
} catch (const std::exception& e) {
if (logger_)
logger_->w("Can't process message: %s", e.what());
logger_->w("Unable to process message: %s", e.what());
}
}
return scheduler.run();
@@ -2087,7 +2087,7 @@ Dht::bootstrap()
}
} catch (const std::exception& e) {
if (logger_)
logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
logger_->e(myid, "Unable to resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
}
}
scheduler.cancel(bootstrapJob);
@@ -2118,12 +2118,12 @@ Dht::confirmNodes()
if (dht4.searches.empty() and dht4.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] initial IPv4 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] Initial IPv4 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET);
}
if (dht6.searches.empty() and dht6.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] initial IPv6 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] Initial IPv6 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET6);
}
@@ -2281,7 +2281,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
const auto& node = req->node;
if (e.getCode() == net::DhtProtocolException::UNAUTHORIZED) {
if (logger_)
logger_->e(node->id, "[node %s] token flush", node->toString().c_str());
logger_->e(node->id, "[node %s] Token flush", node->toString().c_str());
node->authError();
for (auto& srp : searches(node->getFamily())) {
auto& sr = srp.second;
@@ -2296,7 +2296,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
}
} else if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
node->cancelRequest(req);
}
}
@@ -2347,7 +2347,7 @@ Dht::onGetValues(Sp<Node> node, const InfoHash& hash, want_t, const Query& query
if (st != store.end() && not st->second.empty()) {
answer.values = st->second.get(query.where.getFilter());
if (logger_)
logger_->d(hash, "[node %s] sending %u values", node->toString().c_str(), answer.values.size());
logger_->d(hash, "[node %s] Sending %u values", node->toString().c_str(), answer.values.size());
}
return answer;
}
@@ -2359,18 +2359,18 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
{
if (not sr) {
if (logger_)
logger_->w("[search unknown] got reply to 'get'. Ignoring.");
logger_->w("[search unknown] Got reply to 'get'. Ignoring.");
return;
}
/* if (logger_)
logger_->d(sr->id, "[search %s] [node %s] got reply to 'get' with %u nodes",
logger_->d(sr->id, "[search %s] [node %s] Got reply to 'get' with %u nodes",
sr->id.toString().c_str(), node->toString().c_str(), a.nodes4.size()+a.nodes6.size());*/
if (not a.ntoken.empty()) {
if (not a.values.empty() or not a.fields.empty()) {
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] found %u values",
logger_->d(sr->id, node->id, "[search %s] [node %s] Found %u values",
sr->id.toString().c_str(), node->toString().c_str(), a.values.size());
for (auto& getp : sr->callbacks) { /* call all callbacks for this search */
auto& get = getp.second;
@@ -2419,7 +2419,7 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
}
} else {
if (logger_)
logger_->w(sr->id, "[node %s] no token provided. Ignoring response content.", node->toString().c_str());
logger_->w(sr->id, "[node %s] No token provided. Ignoring response content.", node->toString().c_str());
network_engine.blacklistNode(node);
}
@@ -2436,7 +2436,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
{
if (not hash) {
if (logger_)
logger_->w(node->id, "[node %s] listen with no info_hash", node->toString().c_str());
logger_->w(node->id, "[node %s] Listen with no info_hash", node->toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::LISTEN_NO_INFOHASH
@@ -2444,7 +2444,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
}
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::LISTEN_WRONG_TOKEN};
}
Query q = query;
@@ -2456,7 +2456,7 @@ void
Dht::onListenDone(const Sp<Node>& /* node */, net::RequestAnswer& /* answer */, Sp<Search>& sr)
{
// if (logger_)
// logger_->d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
// logger_->d(sr->id, node->id, "[search %s] [node %s] Got listen confirmation",
// sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
if (not sr->done) {
@@ -2476,7 +2476,7 @@ Dht::onAnnounce(Sp<Node> n,
auto& node = *n;
if (not hash) {
if (logger_)
logger_->w(node.id, "put with no info_hash");
logger_->w(node.id, "Put with no info_hash");
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_NO_INFOHASH
@@ -2484,7 +2484,7 @@ Dht::onAnnounce(Sp<Node> n,
}
if (!tokenMatch(token, node.getAddr())) {
if (logger_)
logger_->w(hash, node.id, "[node %s] incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
logger_->w(hash, node.id, "[node %s] Incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::PUT_WRONG_TOKEN};
}
{
@@ -2493,7 +2493,7 @@ Dht::onAnnounce(Sp<Node> n,
auto closest_nodes = buckets(node.getFamily()).findClosestNodes(hash, scheduler.time(), SEARCH_NODES);
if (closest_nodes.size() >= TARGET_NODES and hash.xorCmp(closest_nodes.back()->id, myid) < 0) {
if (logger_)
logger_->w(hash, node.id, "[node %s] announce too far from the target. Dropping value.", node.toString().c_str());
logger_->w(hash, node.id, "[node %s] Announce too far from the target. Dropping value.", node.toString().c_str());
return {};
}
}
@@ -2502,7 +2502,7 @@ Dht::onAnnounce(Sp<Node> n,
for (const auto& v : values) {
if (v->id == Value::INVALID_ID) {
if (logger_)
logger_->w(hash, node.id, "[value %s] incorrect value id", hash.toString().c_str());
logger_->w(hash, node.id, "[value %s] Incorrect value id", hash.toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_INVALID_ID
@@ -2514,17 +2514,17 @@ Dht::onAnnounce(Sp<Node> n,
if (*lv == *vc) {
storageRefresh(hash, v->id);
if (logger_)
logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
logger_->d(hash, node.id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
} else {
const auto& type = getType(lv->type);
if (type.editPolicy(hash, lv, vc, node.id, node.getAddr())) {
if (logger_)
logger_->d(hash, node.id, "[store %s] editing %s",
logger_->d(hash, node.id, "[store %s] Editing %s",
hash.toString().c_str(), vc->toString().c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] rejecting edition of %s because of storage policy",
logger_->d(hash, node.id, "[store %s] Rejecting edition of %s because of storage policy",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2533,11 +2533,11 @@ Dht::onAnnounce(Sp<Node> n,
const auto& type = getType(vc->type);
if (type.storePolicy(hash, vc, node.id, node.getAddr())) {
// if (logger_)
// logger_->d(hash, node.id, "[store %s] storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
// logger_->d(hash, node.id, "[store %s] Storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] rejecting storage of %s",
logger_->d(hash, node.id, "[store %s] Rejecting storage of %s",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2552,15 +2552,15 @@ Dht::onRefresh(Sp<Node> node, const InfoHash& hash, const Blob& token, const Val
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
throw DhtProtocolException {DhtProtocolException::UNAUTHORIZED, DhtProtocolException::PUT_WRONG_TOKEN};
}
if (storageRefresh(hash, vid)) {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
logger_->d(hash, node->id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
} else {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] got refresh for unknown value",
logger_->d(hash, node->id, "[store %s] [node %s] Got refresh for unknown value",
hash.toString().c_str(), node->toString().c_str());
throw DhtProtocolException {DhtProtocolException::NOT_FOUND, DhtProtocolException::STORAGE_NOT_FOUND};
}
@@ -2583,7 +2583,7 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending refresh",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending refresh",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -2608,7 +2608,7 @@ void
Dht::onAnnounceDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>& sr)
{
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] got reply to put!",
logger_->d(sr->id, node->id, "[search %s] [node %s] Got reply to put!",
sr->id.toString().c_str(), node->toString().c_str());
searchSendGetValues(sr);
sr->checkAnnounced(answer.vid);
+14 -5
View File
@@ -813,8 +813,8 @@ SockAddr
DhtProxyClient::parsePublicAddress(const Json::Value& val)
{
auto public_ip = val.asString();
auto hostAndService = splitPort(public_ip);
auto sa = SockAddr::resolve(hostAndService.first);
auto [host, service] = splitPort(public_ip);
auto sa = SockAddr::resolve(host);
if (sa.empty()) return {};
return sa.front().getMappedIPv4();
}
@@ -1233,9 +1233,10 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
}
}
void
PushNotificationResult
DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& notification)
{
auto ret = PushNotificationResult::IgnoredNoOp;
#ifdef OPENDHT_PUSH_NOTIFICATIONS
{
// If a push notification is received, the proxy is up and running
@@ -1252,7 +1253,7 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
if (sessionId != notification.end() and sessionId->second != pushSessionId_) {
if (logger_)
logger_->d("[proxy:client] [push] ignoring push for other session");
return;
return PushNotificationResult::IgnoredWrongSession;
}
std::lock_guard<std::mutex> lock(searchLock_);
auto timeout = notification.find("timeout");
@@ -1269,10 +1270,12 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
else
put.refreshPutTimer->expires_at(std::chrono::steady_clock::now());
put.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, vid));
ret = PushNotificationResult::PutRefresh;
} else {
// Refresh listen
for (auto& list : search.listeners)
resubscribe(key, list.first, list.second);
ret = search.listeners.empty() ? PushNotificationResult::IgnoredNoOp : PushNotificationResult::ListenRefresh;
}
} else {
auto key = InfoHash(notification.at("key"));
@@ -1281,12 +1284,12 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
sendTime = system_clock::time_point(std::chrono::milliseconds(std::stoull(notification.at("t"))));
} catch (...) {}
auto& search = searches_.at(key);
auto expired = notification.find("exp");
for (auto& list : search.listeners) {
if (list.second.opstate->stop)
continue;
if (logger_)
logger_->d("[proxy:client] [push] [search %s] received", key.to_c_str());
auto expired = notification.find("exp");
auto token = list.first;
auto opstate = list.second.opstate;
if (expired == notification.end()) {
@@ -1299,6 +1302,7 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
// present in the new list
cb(oldValues, true, sendTime);
});
ret = PushNotificationResult::Values;
} else {
std::stringstream ss(expired->second);
std::vector<Value::Id> ids;
@@ -1324,16 +1328,21 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map<std::st
});
}
launchLoop = true;
ret = PushNotificationResult::ValuesExpired;
}
}
}
} catch (const std::out_of_range& e) {
ret = PushNotificationResult::IgnoredNoOp;
} catch (const std::exception& e) {
if (logger_)
logger_->e("[proxy:client] [push] receive error: %s", e.what());
ret = PushNotificationResult::Error;
}
if (launchLoop)
loopSignal_();
#endif
return ret;
}
void
+2
View File
@@ -631,6 +631,8 @@ DhtProxyServer::createRestRouter()
router->http_get("/key/:hash", std::bind(&DhtProxyServer::get, this, _1, _2));
// key.post
router->http_post("/key/:hash", std::bind(&DhtProxyServer::put, this, _1, _2));
router->add_handler(restinio::http_method_options(),
"/key/:hash/listen", std::bind(&DhtProxyServer::options, this, _1, _2));
// key.listen
router->http_get("/key/:hash/listen", std::bind(&DhtProxyServer::listen, this, _1, _2));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
+12 -5
View File
@@ -1186,18 +1186,25 @@ DhtRunner::setPushNotificationPlatform(const std::string& platform) {
#endif
}
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
std::future<PushNotificationResult>
DhtRunner::pushNotificationReceived([[maybe_unused]] const std::map<std::string, std::string>& data)
{
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
auto ret_token = std::make_shared<std::promise<PushNotificationResult>>();
auto future = ret_token->get_future();
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) {
pending_ops_prio.emplace([ret_token, this, data](SecureDht&) {
if (dht_)
dht_->pushNotificationReceived(data);
ret_token->set_value(dht_->pushNotificationReceived(data));
else
ret_token->set_value(PushNotificationResult::IgnoredStopped);
});
cv.notify_all();
return future;
#else
(void) data;
std::promise<PushNotificationResult> p {};
p.set_value(PushNotificationResult::IgnoredDisabled);
return p.get_future();
#endif
}
+28 -18
View File
@@ -54,7 +54,7 @@ constexpr const char HTTPS_PROTOCOL[] = "https://";
constexpr const char ORIGIN_PROTOCOL[] = "//";
constexpr unsigned MAX_REDIRECTS {5};
Url::Url(const std::string& url): url(url)
Url::Url(std::string_view url): url(url)
{
size_t addr_begin = 0;
// protocol
@@ -69,10 +69,9 @@ Url::Url(const std::string& url): url(url)
size_t addr_size = url.substr(addr_begin).find("/");
if (addr_size == std::string::npos)
addr_size = url.size() - addr_begin;
auto host_service = splitPort(url.substr(addr_begin, addr_size));
host = host_service.first;
if (!host_service.second.empty())
service = host_service.second;
auto [h, s] = splitPort(url.substr(addr_begin, addr_size));
host = std::move(h);
service = std::move(s);
// target, query and fragment
size_t query_begin = url.find("?");
auto addr_end = addr_begin + addr_size;
@@ -457,7 +456,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
}
// starts from CA and goes down the presented chain
auto verifier = asio::ssl::rfc2818_verification(hostname);
auto verifier = asio::ssl::host_name_verification(hostname);
bool verified = verifier(preverified, ctx);
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
@@ -592,12 +591,12 @@ Connection::async_write(BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_write(*ssl_socket_, write_buf_, wrapCallback(std::move(cb)));
else if (socket_) asio::async_write(*socket_, write_buf_, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -605,12 +604,12 @@ Connection::async_read_until(const char* delim, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -618,12 +617,12 @@ Connection::async_read_until(char delim, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -631,12 +630,12 @@ Connection::async_read(size_t bytes, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
if (ssl_socket_) asio::async_read(*ssl_socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallback(std::move(cb)));
else if (socket_) asio::async_read(*socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallback(std::move(cb)));
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
else if (cb) asio::post(ctx_, [cb](){ cb(asio::error::operation_aborted, 0); });
}
void
@@ -644,7 +643,7 @@ Connection::async_read_some(size_t bytes, BytesHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (!is_open()) {
if (cb) ctx_.post([cb](){ cb(asio::error::broken_pipe, 0); });
if (cb) asio::post(ctx_, [cb](){ cb(asio::error::broken_pipe, 0); });
return;
}
auto buf = read_buf_.prepare(bytes);
@@ -819,10 +818,21 @@ Resolver::add_callback(ResolverCb cb, sa_family_t family)
}
void
Resolver::resolve(const std::string& host, const std::string& service)
Resolver::resolve(const std::string& host, const std::string& serviceName)
{
asio::ip::tcp::resolver::query query_(host, service);
resolver_.async_resolve(query_, [this, host, service, destroyed = destroyed_]
auto service = serviceName;
// The async_resolve function used below typically relies on the contents of the
// /etc/services (Linux/POSIX) or c:\windows\system32\drivers\etc\services (Windows)
// file in order to resolve a descriptive service name into a port number. A
// resolution attempt that would otherwise succeed can therefore fail if the file
// is inaccessible or corrupted (which is rare but can happen in practice). We
// hardcode the port numbers for http and https to prevent this failure mode.
if (service == "http") {
service = "80";
} else if (service == "https") {
service = "443";
}
resolver_.async_resolve(host, service, [this, host, service, destroyed = destroyed_]
(const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints)
{
if (ec == asio::error::operation_aborted or *destroyed)
+21 -7
View File
@@ -526,8 +526,13 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find socket", msg->id};
node->received(now, {});
onNewNode(node, 2);
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
}
else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) {
auto rsocket = node->getSocket(msg->tid);
@@ -590,13 +595,22 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
r.node->authSuccess();
}
r.reply_time = scheduler.time();
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
try {
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
break;
} else { /* request socket data */
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
}
break;
default:
+4 -4
View File
@@ -97,7 +97,7 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
, ioContext_(ioContext)
, peerDiscoveryTimer(*ioContext_)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
, sockAddrSend_(asio::ip::make_address(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
{
try {
@@ -139,7 +139,7 @@ PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, Serv
callbackmap_[type] = callback;
if (not drunning_) {
drunning_ = true;
ioContext_->post([this] () {
asio::post(*ioContext_, [this] () {
loopListener();
query(sockAddrSend_);
});
@@ -245,7 +245,7 @@ PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const
messages_[type] = std::move(pack_buf_c);
reloadMessages();
lrunning_ = true;
ioContext_->post([this] () { publish(sockAddrSend_); });
asio::post(*ioContext_, [this] () { publish(sockAddrSend_); });
}
bool
@@ -327,7 +327,7 @@ PeerDiscovery::DomainPeerDiscovery::reDiscover()
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
ioContext_->post([this] () {
asio::post(*ioContext_, [this] () {
reDiscover();
publish(sockAddrSend_);
});
+26 -19
View File
@@ -45,7 +45,7 @@ struct Dht::Announce {
bool permanent;
Sp<Value> value;
time_point created;
DoneCallback callback;
std::vector<DoneCallback> callbacks;
};
struct Dht::SearchNode {
@@ -442,8 +442,9 @@ struct Dht::Search {
g.second.done_cb = {};
}
for (auto& a : announce) {
a.callback(false, {});
a.callback = {};
for (auto& cb : a.callbacks)
cb(false, {});
a.callbacks.clear();
}
}
@@ -627,7 +628,9 @@ struct Dht::Search {
return a.value->id == value->id;
});
if (a_sr == announce.end()) {
announce.emplace_back(Announce {permanent, value, created, callback});
auto& a = announce.emplace_back(Announce {permanent, value, created, {}} );
if (callback)
a.callbacks.emplace_back(std::move(callback));
for (auto& n : nodes) {
n->probe_query.reset();
n->acked[value->id].req.reset();
@@ -635,24 +638,26 @@ struct Dht::Search {
} else {
a_sr->permanent = permanent;
a_sr->created = created;
if (a_sr->value != value) {
if (a_sr->value != value && *a_sr->value != *value) {
// Value is updated, previous ops are failed
a_sr->value = value;
for (auto& n : nodes) {
n->acked[value->id].req.reset();
n->probe_query.reset();
}
}
if (isAnnounced(value->id)) {
if (a_sr->callback)
a_sr->callback(true, {});
a_sr->callback = {};
for (auto& cb: a_sr->callbacks)
cb(false, {});
a_sr->callbacks.clear();
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
} else if (isAnnounced(value->id)) {
// Same value, already announced
if (callback)
callback(true, {});
return;
} else {
if (a_sr->callback)
a_sr->callback(false, {});
a_sr->callback = callback;
// Same value, not announced yet
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
}
}
}
@@ -722,8 +727,8 @@ struct Dht::Search {
std::vector<DoneCallback> a_cbs;
a_cbs.reserve(announce.size());
for (auto ait = announce.begin() ; ait != announce.end(); ) {
if (ait->callback)
a_cbs.emplace_back(std::move(ait->callback));
a_cbs.insert(a_cbs.end(), std::make_move_iterator(ait->callbacks.begin()), std::make_move_iterator(ait->callbacks.end()));
ait->callbacks.clear();
if (not ait->permanent)
ait = announce.erase(ait);
else
@@ -747,9 +752,11 @@ struct Dht::Search {
if (vid != Value::INVALID_ID and (!a.value || a.value->id != vid))
return true;
if (isAnnounced(a.value->id)) {
if (a.callback) {
a.callback(true, getNodes());
a.callback = nullptr;
if (!a.callbacks.empty()) {
const auto& nodes = getNodes();
for (auto& cb : a.callbacks)
cb(true, nodes);
a.callbacks.clear();
}
if (not a.permanent)
return false;
+9 -11
View File
@@ -39,28 +39,26 @@ const char* version() {
return PACKAGE_VERSION;
}
const HexMap hex_map = {};
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
std::pair<std::string, std::string>
splitPort(const std::string& s) {
splitPort(std::string_view s) {
if (s.empty())
return {};
if (s[0] == '[') {
std::size_t closure = s.find_first_of(']');
std::size_t found = s.find_last_of(':');
if (closure == std::string::npos)
return {s, ""};
if (found == std::string::npos or found < closure)
return {s.substr(1,closure-1), ""};
return {s.substr(1,closure-1), s.substr(found+1)};
if (closure == std::string_view::npos)
return {std::string(s), ""};
if (found == std::string_view::npos or found < closure)
return {std::string(s.substr(1,closure-1)), ""};
return {std::string(s.substr(1,closure-1)), std::string(s.substr(found+1))};
}
std::size_t found = s.find_last_of(':');
std::size_t first = s.find_first_of(':');
if (found == std::string::npos or found != first)
return {s, ""};
return {s.substr(0,found), s.substr(found+1)};
if (found == std::string_view::npos or found != first)
return {std::string(s), ""};
return {std::string(s.substr(0,found)), std::string(s.substr(found+1))};
}
std::vector<SockAddr>
+53
View File
@@ -90,6 +90,59 @@ DhtRunnerTester::testGetPut() {
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutDuplicate() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("hey");
val->id = 42;
auto val_data = val->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutOverride() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("meh");
val->id = 42;
auto val2 = std::make_shared<dht::Value>("hey");
val2->id = 42;
CPPUNIT_ASSERT_EQUAL(val->id, val2->id);
auto val_data = val2->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val2, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(!p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testListen() {
std::mutex mutex;
+10
View File
@@ -31,6 +31,8 @@ class DhtRunnerTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DhtRunnerTester);
CPPUNIT_TEST(testConstructors);
CPPUNIT_TEST(testGetPut);
CPPUNIT_TEST(testPutDuplicate);
CPPUNIT_TEST(testPutOverride);
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testListenLotOfBytes);
CPPUNIT_TEST(testIdOps);
@@ -55,6 +57,14 @@ class DhtRunnerTester : public CppUnit::TestFixture {
* Test get and put methods
*/
void testGetPut();
/**
* Test get and multiple put
*/
void testPutDuplicate();
/**
* Test get and multiple put with changing value
*/
void testPutOverride();
/**
* Test listen method
*/
+2 -2
View File
@@ -107,8 +107,8 @@ main(int argc, char **argv)
token = dht.listen<dht::ImMessage>(room, [&](dht::ImMessage&& msg) {
if (msg.from != myid)
std::cout << msg.from.toString() << " at " << printTime(msg.date)
<< " (took " << print_dt(std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t(msg.date))
<< "s) " << (msg.to == myid ? "ENCRYPTED ":"") << ": " << msg.id << " - " << msg.msg << std::endl;
<< " (took " << print_duration(std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t(msg.date))
<< ") " << (msg.to == myid ? "ENCRYPTED ":"") << ": " << msg.id << " - " << msg.msg << std::endl;
return true;
});
connected = true;
+14 -5
View File
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <inttypes.h>
#include <getopt.h>
#include <readline/readline.h>
@@ -38,6 +39,10 @@ struct listen_context {
dht_op_token* token;
size_t count;
};
struct put_context {
dht_runner* runner;
dht_value* value;
};
bool dht_value_callback(const dht_value* value, bool expired, void* user_data)
{
@@ -67,8 +72,10 @@ void dht_get_done_callback(bool ok, void* user_data)
void dht_put_done_callback(bool ok, void* user_data)
{
dht_runner* runner = (dht_runner*)user_data;
printf("Put completed: %s\n", ok ? "success !" : "failure :-(");
struct put_context* ctx = (struct put_context*)user_data;
printf("Put completed (id: %" PRIx64 "): %s\n", dht_value_get_id(ctx->value), ok ? "success !" : "failure :-(");
dht_value_unref(ctx->value);
free(ctx);
}
void dht_shutdown_callback(void* user_data)
@@ -261,11 +268,13 @@ int main(int argc, char **argv)
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);
struct put_context* ctx = malloc(sizeof(struct put_context));
ctx->runner = runner;
ctx->value = val;
dht_runner_put(runner, &key, val, dht_put_done_callback, ctx, true);
}
else {
printf("Unkown command: %s\n", cmd);
printf("Unknown command: %s\n", cmd);
}
}
+236 -168
View File
@@ -1,190 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>OpenDHT tester</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">"use strict";
let onGet;
let onPut;
let setServer;
const valueGetElement = function(o) {
const d = window.atob(o.data);
return d;
};
$(function() {
let request = undefined;
let server;
const getTools = $("#getTools");
const getBtn = $("#getBtn");
const getDropdown = $("#getDropdown");
const listenBtn = $("#listenBtn").click(function(){onGet('LISTEN');});
const setGetRequest = function() {
getBtn.button('loading');
getStopBtn.appendTo(getTools);
getDropdown.hide();
}
const clearGetRequest = function() {
if (request === undefined)
return;
request.abort();
request = undefined;
getStopBtn.detach();
getDropdown.show();
getBtn.button('reset');
}
const getStopBtn = $("#getStopBtn").detach().click(clearGetRequest);
const putBtn = $("#putBtn");
const result = $("#dhtResult");
const group = $('<ul class="list-group"/>').appendTo(result);
onGet = function (method) {
if (request !== undefined)
return false;
const input = $("#getKey").val();
group.empty();
let lastAppended = 0;
let start = new Date().getTime();
request = new XMLHttpRequest();
request.onreadystatechange = function(event) {
if (this.readyState >= XMLHttpRequest.LOADING) {
if (this.readyState == XMLHttpRequest.DONE) {
clearGetRequest();
}
if (this.status === 200) {
const elements = this.responseText.split("\n");
const elementsLength = elements.length;
const now = new Date().getTime();
for (let i = lastAppended; i < elementsLength; i++) {
const element = elements[i];
if (!element || element.length == 0)
return;
const o = JSON.parse(element);
if (o.expired) {
$('#value'+o.id).slideUp(100, (e) => $(e.target).remove());
} else {
const d = window.atob(o.data);
const delay = Math.max(0, start-now);
$('<li class="list-group-item" id="value'+o.id+'"/>').append(valueGetElement(o)).appendTo(group).hide().delay(delay).slideDown(100);
lastAppended = i+1;
start = Math.max(start, now)+25;
}
}
} else if (this.status !== 0) {
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text("Error loading content: " + this.statusText));
}
}
};
request.onerror = function(event) {
clearGetRequest();
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text("Error loading content."));
};
request.open(method, server + input, true);
request.send(null);
setGetRequest();
return false;
};
onPut = function( ) {
const key = $("#getKey").val();
const value = $("#putValue").val();
$.ajax({
url: server + key,
type: 'POST',
data: JSON.stringify({
data:window.btoa(value)
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function( result ) {
putBtn.button('reset');
//$('<li class="list-group-item list-group-item-success"/>').append(valueGetElement(result)).appendTo(group.empty());
},
error: function(result) {
putBtn.button('reset');
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text(result.statusText));
}
});
putBtn.button('loading');
return false;
};
const serverValue = $("#serverValue");
const serverStatus = $("#serverStatus");
const serverBtn = $("#serverBtn");
setServer = function(event) {
server = serverValue.val() + '/';
serverStatus.empty();
serverBtn.button('loading');
$.getJSON(server, function(data){
$('<span><b>Node</b> '+data.node_id+'</span>').appendTo(serverStatus).hide().fadeIn();
}).fail(function(error) {
var message = " Cant' access node."
if (serverValue.val().indexOf("https") != -1){
message += "</br></br>Self-signed certificate must be allowed in browser."
}
serverStatus.html("<div class='alert alert-danger' style='margin-bottom: 0px;'>" +
"<span class='glyphicon glyphicon-remove' aria-hidden='true'></span>" +
message + "</div>");
}).always(function(error) {
serverBtn.button('reset');
});
return false;
};
setServer();
});
</script>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>OpenDHT web node</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap.min.css" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<body>
<div class="container" style="max-width: 730px;">
<header class="page-header">
<div class="container" style="max-width: 880px;">
<header class="m-3 p-3">
<div class="row">
<div class="col-sm-5">
<h1>OpenDHT tester</h1>
<div class="col-sm-5 d-flex align-items-center">
<h2>OpenDHT web node</h2>
</div>
<div class="col-sm-7">
<div class="well well-sm" style="margin-top:10px; margin-bottom:0px;">
<form id="serverForm" class="form-inline" onsubmit="return setServer();" style="margin-bottom:4px;">
<div class="card card-body bg-light" style="margin-top:10px; margin-bottom:0px;">
<form id="serverForm" class="form-inline" onsubmit="return setServer();"
style="margin-bottom:4px;">
<div class="input-group">
<input type="text" class="form-control" id="serverValue" placeholder="Proxy server" value="http://127.0.0.1:8080"/>
<span class="input-group-btn">
<button id="serverBtn" type="submit" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i>"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
</span>
<input type="text" class="form-control" id="serverValue" placeholder="Proxy server" value="http://127.0.0.1:8080" />
<button id="serverBtn" type="submit" class="btn btn-outline-secondary">
<div class='spinner-border spinner-border-sm' role='status'
style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-icon"><i class="bi bi-arrow-clockwise"></i></span>
</button>
</div>
</form>
<div id="serverStatus"><i class='fa fa-circle-o-notch fa-spin'></i></div>
<div id="serverStatus">
<div class='spinner-border spinner-border-sm' role='status'><span
class='visually-hidden'>Loading...</span></div>
</div>
</div>
</div>
</div>
</header>
<div class="panel panel-default" id="dhtResult">
<div class="panel-heading">
<div class="row">
<div class="col-xs-6">
<form class="form-inline" onsubmit="return onGet('GET');">
<div class="input-group">
<div class="list-group" id="dhtResult">
<div class="list-group-item list-group-item-light">
<div class="row">
<div class="col-sm-6">
<form class="form-inline" onsubmit="return onGet('');">
<div class="input-group" id="getTools">
<input type="text" class="form-control" id="getKey" placeholder="Key" aria-label="Key" />
<span class="input-group-btn" id="getTools">
<button id="getBtn" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i>" type="submit">Get</button>
<button id="getDropdown"type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button>
<ul class="dropdown-menu">
<li><a id="listenBtn" href="#">Listen</a></li>
</ul>
<button id="getStopBtn" class="btn btn-default" type="submit"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
</span>
<button id="getBtn" class="btn btn-outline-secondary" type="submit">
<div class='spinner-border spinner-border-sm' role='status' style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-text">Get</span>
</button>
<button id="menuBtn" type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" id="listenBtn" href="#">Listen</a></li>
</ul>
<button id="getStopBtn" class="btn btn-outline-secondary">Stop</button>
</div>
</form>
</div>
<div class="col-xs-6">
<div class="col-sm-6">
<form class="form-inline" onsubmit="return onPut();">
<div class="input-group">
<input type="text" class="form-control input-group-input" id="putValue" placeholder="Value" />
<span class="input-group-btn">
<button id="putBtn" type="submit" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i> Loading">Put</button>
</span>
<input type="text" class="form-control input-group-input" id="putValue"
placeholder="Value" />
<button id="putBtn" type="submit" class="btn btn-outline-secondary">
<div class='spinner-border spinner-border-sm' role='status' style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-text">Put</span>
</button>
</div>
</form>
</div>
@@ -192,5 +80,185 @@ $(function() {
</div>
</div>
</div>
<script type="text/javascript">"use strict";
const valueGetElement = (o) => window.atob(o.data);
const getTools = document.getElementById("getTools");
const getBtn = document.getElementById("getBtn");
const menuBtn = document.getElementById("menuBtn");
const getStopBtn = document.getElementById("getStopBtn");
const listenBtn = document.getElementById("listenBtn");
const putBtn = document.getElementById("putBtn");
const group = document.getElementById("dhtResult");
const serverValue = document.getElementById("serverValue");
const serverStatus = document.getElementById("serverStatus");
const serverBtn = document.getElementById("serverBtn");
var request = undefined;
const setGetRequest = () => {
getBtn.disabled = true;
getBtn.querySelector('.spinner-border').style.display = 'inline-block';
getBtn.querySelector('.btn-text').style.display = 'none';
menuBtn.style.display = 'none';
getTools.appendChild(getStopBtn);
};
const clearGetRequest = () => {
if (request === undefined)
return;
request.abort();
request = undefined;
if (getStopBtn.parentNode) {
getStopBtn.parentNode.removeChild(getStopBtn);
}
menuBtn.style.display = '';
getBtn.disabled = false;
getBtn.querySelector('.spinner-border').style.display = 'none';
getBtn.querySelector('.btn-text').style.display = 'inline';
};
const clearResults = () => {
while (group.children.length > 1) {
group.removeChild(group.lastChild);
}
};
var server;
const setServer = (event) => {
server = serverValue.value + '/';
serverStatus.innerHTML = '';
serverBtn.disabled = true;
serverBtn.querySelector('.spinner-border').style.display = 'inline-block';
serverBtn.querySelector('.btn-icon').style.display = 'none';
var xhr = new XMLHttpRequest();
xhr.open('GET', server, true);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
serverBtn.disabled = false;
serverBtn.querySelector('.spinner-border').style.display = 'none';
serverBtn.querySelector('.btn-icon').style.display = 'inline';
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
const span = document.createElement('span');
span.innerHTML = '<b>Node</b> ' + data.node_id;
serverStatus.appendChild(span);
} else {
const message = " Can't access node.";
if (serverValue.value.indexOf("https") != -1) {
message += "</br></br>Self-signed certificate must be allowed in browser.";
}
serverStatus.innerHTML = "<div class='alert alert-danger' style='margin-bottom: 0px;'>" +
"<span class='glyphicon glyphicon-remove' aria-hidden='true'></span>" +
message + "</div>";
}
}
};
xhr.send();
return false;
};
setServer();
const onGet = (path) => {
if (request !== undefined)
return false;
const input = document.getElementById("getKey").value;
clearResults()
let lastAppended = 0;
let start = new Date().getTime();
request = new XMLHttpRequest();
request.onreadystatechange = (event) => {
if (request.readyState >= 2) { // LOADING
if (request.status === 200) {
const elements = request.responseText.split("\n");
const elementsLength = elements.length;
const now = new Date().getTime();
for (let i = lastAppended; i < elementsLength; i++) {
const element = elements[i];
if (!element || element.length == 0)
break;
const o = JSON.parse(element);
if (o.expired) {
const expiredElement = document.getElementById('value' + o.id);
if (expiredElement) {
expiredElement.style.display = 'none';
if (expiredElement.parentNode) {
expiredElement.parentNode.removeChild(expiredElement);
}
}
} else {
const d = window.atob(o.data);
const delay = Math.max(0, start - now);
const li = document.createElement('li');
li.className = 'list-group-item';
li.id = 'value' + o.id;
li.innerHTML = valueGetElement(o);
li.style.opacity = 0;
li.style.transition = 'opacity 0.1s ease-in';
group.appendChild(li);
setTimeout(() => {
li.style.opacity = 1;
}, delay);
lastAppended = i + 1;
start = Math.max(start, now) + 25;
}
}
} else if (request.status !== 0) {
clearResults()
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = "Error loading content: " + request.statusText;
group.appendChild(li);
}
}
if (request.readyState == 4) { // DONE
clearGetRequest();
}
};
request.onerror = (event) => {
clearGetRequest();
clearResults()
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = "Error loading content.";
group.appendChild(li);
};
request.open('GET', server + 'key/' + input + path, true);
request.send(null);
setGetRequest();
return false;
};
const onPut = () => {
const key = document.getElementById("getKey").value;
const value = document.getElementById("putValue").value;
putBtn.disabled = true;
putBtn.querySelector('.spinner-border').style.display = 'inline-block';
putBtn.querySelector('.btn-text').style.display = 'none';
fetch(server + key, {
method: 'POST',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: JSON.stringify({ data: window.btoa(value) })
})
.then(response => {
if (!response.ok)
throw new Error(response.statusText);
})
.catch(error => {
group.innerHTML = '';
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = error.message;
group.appendChild(li);
})
.finally(() => {
putBtn.disabled = false;
putBtn.querySelector('.spinner-border').style.display = 'none';
putBtn.querySelector('.btn-text').style.display = 'inline';
});
return false;
};
listenBtn.addEventListener('click', () => { onGet('/listen'); });
getStopBtn.parentNode.removeChild(getStopBtn);
getStopBtn.addEventListener('click', clearGetRequest);
</script>
</body>
</html>
</html>