mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 12:28:42 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c29848ba1 |
No files matched your search
+103
-75
@@ -1,7 +1,4 @@
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
project (opendht)
|
||||
set (opendht_VERSION_MAJOR 2)
|
||||
set (opendht_VERSION_MINOR 0.0)
|
||||
@@ -10,90 +7,106 @@ set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
# Options
|
||||
option (OPENDHT_LIGHT "Build minimal version of the library" OFF)
|
||||
|
||||
option (OPENDHT_STATIC "Build static library" ON)
|
||||
|
||||
option (OPENDHT_SHARED "Build shared library" ON)
|
||||
option (OPENDHT_LOG "Build with logs" ON)
|
||||
option (OPENDHT_PYTHON "Build Python bindings" OFF)
|
||||
option (OPENDHT_TOOLS "Build DHT tools" ON)
|
||||
option (OPENDHT_SYSTEMD "Install systemd module" OFF)
|
||||
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
|
||||
option (OPENDHT_LTO "Build with LTO" OFF)
|
||||
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
|
||||
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
|
||||
option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
|
||||
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
|
||||
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
|
||||
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
|
||||
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
|
||||
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
|
||||
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
|
||||
option (OPENDHT_TESTS "Add unit tests executable" OFF)
|
||||
option (OPENDHT_C "Build C bindings" OFF)
|
||||
option (OPENDHT_TESTS "Add unit tests executable" OFF)
|
||||
|
||||
if (OPENDHT_LIGHT)
|
||||
set(OPENDHT_SHARED OFF)
|
||||
set(OPENDHT_TOOLS OFF)
|
||||
set(OPENDHT_PROXY_SERVER OFF)
|
||||
set(OPENDHT_PROXY_CLIENT OFF)
|
||||
set(OPENDHT_PEER_DISCOVERY OFF)
|
||||
set(OPENDHT_INDEX OFF)
|
||||
set(OPENDHT_PYTHON OFF)
|
||||
add_definitions(-DOPENDHT_LIGHT)
|
||||
endif()
|
||||
|
||||
option (OPENDHT_LOG "Build with logs" ON)
|
||||
option (OPENDHT_LTO "Build with LTO" OFF)
|
||||
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
|
||||
|
||||
find_package(Doxygen)
|
||||
option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
|
||||
|
||||
# Dependencies
|
||||
list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
find_package (Threads)
|
||||
find_package (PkgConfig)
|
||||
find_package (GnuTLS 3.3 REQUIRED)
|
||||
pkg_search_module (Nettle nettle)
|
||||
find_package (Msgpack 1.2 REQUIRED)
|
||||
if (OPENDHT_TOOLS)
|
||||
find_package (Readline 6 REQUIRED)
|
||||
endif ()
|
||||
if (NOT OPENDHT_ARGON2)
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(argon2 libargon2)
|
||||
if (argon2_FOUND)
|
||||
message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")")
|
||||
link_directories (${argon2_LIBRARY_DIRS})
|
||||
else ()
|
||||
message("Argon2 not found, using included version.")
|
||||
set(OPENDHT_ARGON2 ON)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
pkg_search_module(Jsoncpp jsoncpp)
|
||||
if (Jsoncpp_FOUND)
|
||||
add_definitions(-DOPENDHT_JSONCPP)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/base64.h
|
||||
src/base64.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (OPENDHT_HTTP)
|
||||
find_package(Restinio REQUIRED)
|
||||
if (Restinio_FOUND)
|
||||
find_library(FMT_LIBRARY fmt)
|
||||
add_library(fmt SHARED IMPORTED)
|
||||
find_library(HTTP_PARSER_LIBRARY http_parser)
|
||||
add_library(http_parser SHARED IMPORTED)
|
||||
endif()
|
||||
if (NOT Jsoncpp_FOUND)
|
||||
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
|
||||
endif()
|
||||
if (OPENDHT_PROXY_OPENSSL)
|
||||
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
|
||||
pkg_search_module(OPENSSL REQUIRED openssl)
|
||||
if (OPENSSL_FOUND)
|
||||
message(STATUS "Found OpenSSL ${OPENSSL_VERSION}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||
if (NOT OPENDHT_LIGHT)
|
||||
find_package (Threads)
|
||||
find_package (GnuTLS 3.3 REQUIRED)
|
||||
pkg_search_module (Nettle nettle)
|
||||
if (OPENDHT_TOOLS)
|
||||
find_package (Readline 6 REQUIRED)
|
||||
endif ()
|
||||
if (NOT OPENDHT_ARGON2)
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(argon2 libargon2)
|
||||
if (argon2_FOUND)
|
||||
message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")")
|
||||
link_directories (${argon2_LIBRARY_DIRS})
|
||||
else ()
|
||||
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
|
||||
message("Argon2 not found, using included version.")
|
||||
set(OPENDHT_ARGON2 ON)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
pkg_search_module(Jsoncpp jsoncpp)
|
||||
if (Jsoncpp_FOUND)
|
||||
add_definitions(-DOPENDHT_JSONCPP)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/base64.h
|
||||
src/base64.cpp
|
||||
)
|
||||
endif()
|
||||
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
|
||||
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
|
||||
|
||||
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
|
||||
find_package(Restinio REQUIRED)
|
||||
if (Restinio_FOUND)
|
||||
find_library(FMT_LIBRARY fmt)
|
||||
add_library(fmt SHARED IMPORTED)
|
||||
find_library(HTTP_PARSER_LIBRARY http_parser)
|
||||
add_library(http_parser SHARED IMPORTED)
|
||||
endif()
|
||||
if (NOT Jsoncpp_FOUND)
|
||||
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
|
||||
endif()
|
||||
if (OPENDHT_PROXY_OPENSSL)
|
||||
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
|
||||
pkg_search_module(OPENSSL REQUIRED openssl)
|
||||
if (OPENSSL_FOUND)
|
||||
message(STATUS "Found OpenSSL ${OPENSSL_VERSION}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||
else ()
|
||||
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
|
||||
endif()
|
||||
endif()
|
||||
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
|
||||
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
|
||||
endif()
|
||||
else()
|
||||
set(OPENDHT_PROXY_OPENSSL OFF)
|
||||
endif()
|
||||
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT OR OPENDHT_PEER_DISCOVERY)
|
||||
add_definitions(-DASIO_STANDALONE)
|
||||
endif()
|
||||
else()
|
||||
set(OPENDHT_PROXY_OPENSSL OFF)
|
||||
endif()
|
||||
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
|
||||
add_definitions(-DASIO_STANDALONE)
|
||||
endif()
|
||||
|
||||
# Build flags
|
||||
@@ -165,7 +178,6 @@ set (top_srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
list (APPEND opendht_SOURCES
|
||||
src/utils.cpp
|
||||
src/infohash.cpp
|
||||
src/crypto.cpp
|
||||
src/default_types.cpp
|
||||
src/node.cpp
|
||||
src/value.cpp
|
||||
@@ -183,11 +195,7 @@ list (APPEND opendht_SOURCES
|
||||
src/routing_table.cpp
|
||||
src/node_cache.cpp
|
||||
src/network_engine.cpp
|
||||
src/securedht.cpp
|
||||
src/dhtrunner.cpp
|
||||
src/log.cpp
|
||||
src/network_utils.cpp
|
||||
src/thread_pool.cpp
|
||||
)
|
||||
|
||||
list (APPEND opendht_HEADERS
|
||||
@@ -195,7 +203,6 @@ list (APPEND opendht_HEADERS
|
||||
include/opendht/utils.h
|
||||
include/opendht/sockaddr.h
|
||||
include/opendht/rng.h
|
||||
include/opendht/crypto.h
|
||||
include/opendht/infohash.h
|
||||
include/opendht/default_types.h
|
||||
include/opendht/node.h
|
||||
@@ -211,11 +218,27 @@ list (APPEND opendht_HEADERS
|
||||
include/opendht/securedht.h
|
||||
include/opendht/log.h
|
||||
include/opendht/log_enable.h
|
||||
include/opendht/thread_pool.h
|
||||
include/opendht/network_utils.h
|
||||
include/opendht.h
|
||||
)
|
||||
|
||||
if (NOT OPENDHT_LIGHT)
|
||||
list (APPEND opendht_SOURCES
|
||||
src/crypto.cpp
|
||||
src/securedht.cpp
|
||||
src/dhtrunner.cpp
|
||||
src/network_utils.cpp
|
||||
src/thread_pool.cpp
|
||||
)
|
||||
|
||||
list (APPEND opendht_HEADERS
|
||||
include/opendht/crypto.h
|
||||
include/opendht/securedht.h
|
||||
include/opendht/dhtrunner.h
|
||||
include/opendht/thread_pool.h
|
||||
include/opendht/network_utils.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (OPENDHT_PEER_DISCOVERY)
|
||||
list (APPEND opendht_SOURCES src/peer_discovery.cpp)
|
||||
list (APPEND opendht_HEADERS include/opendht/peer_discovery.h)
|
||||
@@ -255,7 +278,7 @@ if (OPENDHT_PROXY_CLIENT)
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (OPENDHT_HTTP)
|
||||
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
|
||||
if (OPENDHT_PUSH_NOTIFICATIONS)
|
||||
message("Using push notification")
|
||||
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
|
||||
@@ -361,6 +384,7 @@ if (OPENDHT_PYTHON)
|
||||
endif ()
|
||||
|
||||
# CMake module
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
|
||||
VERSION ${opendht_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
@@ -387,13 +411,17 @@ if (OPENDHT_TESTS)
|
||||
tests/infohashtester.cpp
|
||||
tests/valuetester.h
|
||||
tests/valuetester.cpp
|
||||
tests/cryptotester.h
|
||||
tests/cryptotester.cpp
|
||||
tests/dhtrunnertester.h
|
||||
tests/dhtrunnertester.cpp
|
||||
tests/threadpooltester.h
|
||||
tests/threadpooltester.cpp
|
||||
)
|
||||
if (NOT OPENDHT_LIGHT)
|
||||
list (APPEND test_FILES
|
||||
tests/cryptotester.h
|
||||
tests/cryptotester.cpp
|
||||
tests/dhtrunnertester.h
|
||||
tests/dhtrunnertester.cpp
|
||||
tests/threadpooltester.h
|
||||
tests/threadpooltester.cpp
|
||||
)
|
||||
endif()
|
||||
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
|
||||
list (APPEND test_FILES
|
||||
tests/httptester.h
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -14,9 +14,9 @@ Values are distributed over the network, with redundancy.
|
||||
* High resilience to network disruption
|
||||
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
|
||||
* IPv4 and IPv6 support
|
||||
* Clean and powerful **C++14** map API
|
||||
* Bindings for **C, Rust & Python 3**
|
||||
* REST API with optional HTTP client+server with push notification support
|
||||
* Clean and powerful C++14 map API
|
||||
* Python 3 bindings
|
||||
* REST API
|
||||
|
||||
## Documentation
|
||||
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
|
||||
@@ -27,7 +27,7 @@ Build instructions: <https://github.com/savoirfairelinux/opendht/wiki/Build-the-
|
||||
|
||||
#### How-to build a simple client app
|
||||
```bash
|
||||
g++ main.cpp -std=c++14 -lopendht
|
||||
g++ main.cpp -std=c++14 -lopendht -lgnutls
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -51,7 +51,7 @@ int main()
|
||||
|
||||
// Join the network through any running node,
|
||||
// here using a known bootstrap node.
|
||||
node.bootstrap("bootstrap.jami.net", "4222");
|
||||
node.bootstrap("bootstrap.ring.cx", "4222");
|
||||
|
||||
// put some data on the dht
|
||||
std::vector<uint8_t> some_data(5, 10);
|
||||
@@ -82,7 +82,7 @@ node.run()
|
||||
|
||||
# Join the network through any running node,
|
||||
# here using a known bootstrap node.
|
||||
node.bootstrap("bootstrap.jami.net", "4222")
|
||||
node.bootstrap("bootstrap.ring.cx", "4222")
|
||||
|
||||
# blocking call (provide callback arguments to make the call non-blocking)
|
||||
node.put(dht.InfoHash.get("unique_key"), dht.Value(b'some binary data'))
|
||||
@@ -106,7 +106,7 @@ for r in results:
|
||||
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
|
||||
|
||||
## License
|
||||
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
|
||||
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ void dht_publickey_delete(dht_publickey* pk) {
|
||||
|
||||
int dht_publickey_export(const dht_publickey* pk, char* out, size_t* outlen) {
|
||||
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
|
||||
return pkey->pack((uint8_t*)out, outlen);
|
||||
return gnutls_pubkey_export(pkey->pk, GNUTLS_X509_FMT_DER, out, outlen);
|
||||
}
|
||||
|
||||
dht_infohash dht_publickey_get_id(const dht_publickey* pk) {
|
||||
|
||||
@@ -140,7 +140,6 @@ AS_IF([test "x$with_jsoncpp" != "xno"],
|
||||
AS_IF([test "x$have_jsoncpp" = "xyes"], [
|
||||
AC_MSG_NOTICE([Using JsonCpp])
|
||||
CPPFLAGS+=" -DOPENDHT_JSONCPP"
|
||||
AC_SUBST(jsoncpp_lib, [", jsoncpp"])
|
||||
], [
|
||||
AC_MSG_NOTICE([Not using JsonCpp])
|
||||
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
|
||||
@@ -152,7 +151,6 @@ AS_IF([test "x$with_openssl" != "xno"],
|
||||
[have_openssl=no])
|
||||
AS_IF([test "x$have_openssl" = "xyes"], [
|
||||
AC_MSG_NOTICE([Using OpenSSL])
|
||||
AC_SUBST(openssl_lib, [", openssl"])
|
||||
], [
|
||||
AC_MSG_NOTICE([Not using OpenSSL])
|
||||
])
|
||||
@@ -177,7 +175,6 @@ AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
|
||||
# http_parser has no pkgconfig, instead we check with:
|
||||
AC_CHECK_LIB(http_parser, exit,, AC_MSG_ERROR([Missing HttpParser library files]))
|
||||
AC_CHECK_HEADERS([http_parser.h], [http_parser_headers=yes; break;])
|
||||
AC_SUBST(http_parser_lib, ["-lhttp_parser"])
|
||||
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
|
||||
])
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ RUN echo "*** Building nodejs/http_parser dependency ***" \
|
||||
|
||||
# libasio-dev (1.10.6-3) is too old
|
||||
RUN echo "** Building a recent version of asio ***" \
|
||||
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
|
||||
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
|
||||
&& wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
|
||||
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
|
||||
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
|
||||
&& make install \
|
||||
&& cd ../../ && rm -rf asio*
|
||||
|
||||
@@ -5,13 +5,13 @@ RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apt-transport-https build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
|
||||
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
|
||||
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \
|
||||
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev \
|
||||
&& apt-get clean
|
||||
|
||||
# libasio-dev (1.10) is too old
|
||||
RUN echo "** Building a recent version of asio ***" \
|
||||
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
|
||||
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
|
||||
&& wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
|
||||
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
|
||||
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
|
||||
&& make install \
|
||||
&& cd ../../ && rm -rf asio*
|
||||
|
||||
@@ -26,8 +26,8 @@ RUN echo "*** Building nodejs/http_parser dependency ***" \
|
||||
|
||||
# libasio-dev (1.10.6-3) is too old
|
||||
RUN echo "** Building a recent version of asio ***" \
|
||||
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
|
||||
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
|
||||
&& wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
|
||||
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
|
||||
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
|
||||
&& make install \
|
||||
&& cd ../../ && rm -rf asio*
|
||||
|
||||
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
|
||||
COPY . /root/opendht
|
||||
RUN cd /root/opendht && mkdir build && cd build \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
|
||||
&& make -j8 && ./opendht_unit_tests && make install
|
||||
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
|
||||
COPY . /root/opendht
|
||||
RUN cd /root/opendht && mkdir build && cd build \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \
|
||||
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_TESTS=ON .. \
|
||||
&& make -j8 && ./opendht_unit_tests && make install
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
#include <json/json.h>
|
||||
@@ -58,8 +57,6 @@ struct OPENDHT_PUBLIC NodeStats {
|
||||
cached_nodes {0},
|
||||
incoming_nodes {0};
|
||||
unsigned table_depth {0};
|
||||
unsigned searches {0};
|
||||
unsigned node_cache_size {0};
|
||||
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
|
||||
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
|
||||
std::string toString() const;
|
||||
@@ -73,7 +70,7 @@ struct OPENDHT_PUBLIC NodeStats {
|
||||
explicit NodeStats(const Json::Value& v);
|
||||
#endif
|
||||
|
||||
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth, searches, node_cache_size)
|
||||
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth)
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC NodeInfo {
|
||||
@@ -118,26 +115,14 @@ struct OPENDHT_PUBLIC Config {
|
||||
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
|
||||
std::string persist_path {};
|
||||
|
||||
/** If non-0, overrides the default global rate-limit. -1 means no limit. */
|
||||
/** If non-0, overrides the default global rate-limit.-1 means no limit. */
|
||||
ssize_t max_req_per_sec {0};
|
||||
|
||||
/** If non-0, overrides the default per-IP address rate-limit. -1 means no limit. */
|
||||
ssize_t max_peer_req_per_sec {0};
|
||||
|
||||
/* If non-0, overrides the default maximum number of searches. -1 means no limit. */
|
||||
ssize_t max_searches {0};
|
||||
|
||||
/* If non-0, overrides the default maximum store size. -1 means no limit. */
|
||||
ssize_t max_store_size {0};
|
||||
|
||||
/**
|
||||
* Use appropriate bahavior for a public IP, stable node:
|
||||
* - No connectivity change triggered when a search fails
|
||||
* - Larger listen refresh time
|
||||
*/
|
||||
bool public_stable {false};
|
||||
};
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
/**
|
||||
* SecureDht configuration.
|
||||
*/
|
||||
@@ -145,13 +130,8 @@ struct OPENDHT_PUBLIC SecureDhtConfig
|
||||
{
|
||||
Config node_config {};
|
||||
crypto::Identity id {};
|
||||
|
||||
/**
|
||||
* Cache all encountered public keys and certificates,
|
||||
* for use by the certificate store, putEncrypted and putSigned
|
||||
*/
|
||||
bool cert_cache_all {false};
|
||||
};
|
||||
#endif
|
||||
|
||||
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -114,7 +114,6 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
}
|
||||
|
||||
void pack(Blob& b) const;
|
||||
int pack(uint8_t* out, size_t* out_len) const;
|
||||
void unpack(const uint8_t* dat, size_t dat_size);
|
||||
|
||||
std::string toString() const;
|
||||
@@ -128,7 +127,7 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
gnutls_digest_algorithm_t getPreferredDigest() const;
|
||||
|
||||
@@ -226,7 +225,7 @@ public:
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
void revoke(const Certificate& crt, time_point t = time_point::min());
|
||||
|
||||
@@ -424,7 +423,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
|
||||
explicit operator bool() const { return cert; }
|
||||
PublicKey getPublicKey() const;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
MSGPACK_DEFINE(service, data)
|
||||
};
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
template <typename T>
|
||||
class OPENDHT_PUBLIC SignedValue : public Value::Serializable<T>
|
||||
{
|
||||
@@ -102,7 +103,6 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage>
|
||||
{
|
||||
private:
|
||||
@@ -177,19 +177,11 @@ public:
|
||||
{
|
||||
pk.pack_array(2);
|
||||
pk.pack(id);
|
||||
#if 1
|
||||
pk.pack_bin(ice_data.size());
|
||||
pk.pack_bin_body((const char*)ice_data.data(), ice_data.size());
|
||||
#else
|
||||
// hack for backward compatibility with old opendht compiled with msgpack 1.0
|
||||
// remove when enough people have moved to new versions
|
||||
pk.pack_array(ice_data.size());
|
||||
for (uint8_t b : ice_data)
|
||||
pk.pack(b);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void msgpack_unpack(const msgpack::object& o)
|
||||
virtual void msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
|
||||
if (o.via.array.size < 2) throw msgpack::type_error();
|
||||
@@ -200,6 +192,7 @@ public:
|
||||
Value::Id id {0};
|
||||
Blob ice_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* "Peer" announcement
|
||||
*/
|
||||
@@ -229,7 +222,7 @@ public:
|
||||
pk.pack_bin_body((const char*)addr.get(), addr.getLength());
|
||||
}
|
||||
|
||||
virtual void msgpack_unpack(const msgpack::object& o)
|
||||
virtual void msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type == msgpack::type::BIN)
|
||||
addr = {(sockaddr*)o.via.bin.ptr, (socklen_t)o.via.bin.size};
|
||||
@@ -261,8 +254,11 @@ private:
|
||||
SockAddr addr;
|
||||
};
|
||||
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES;
|
||||
#else
|
||||
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_TYPES;
|
||||
#endif
|
||||
|
||||
OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES;
|
||||
|
||||
|
||||
+26
-62
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -68,11 +68,7 @@ public:
|
||||
* Initialise the Dht with two open sockets (for IPv4 and IP6)
|
||||
* and an ID for the node.
|
||||
*/
|
||||
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {});
|
||||
|
||||
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {})
|
||||
: Dht(std::move(sock), config, std::make_shared<Logger>(l)) {}
|
||||
|
||||
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {});
|
||||
virtual ~Dht();
|
||||
|
||||
/**
|
||||
@@ -80,14 +76,10 @@ public:
|
||||
*/
|
||||
inline const InfoHash& getNodeId() const override { return myid; }
|
||||
|
||||
NodeStatus updateStatus(sa_family_t af) override;
|
||||
|
||||
/**
|
||||
* Get the current status of the node for the given family.
|
||||
*/
|
||||
NodeStatus getStatus(sa_family_t af) const override {
|
||||
return dht(af).status;
|
||||
}
|
||||
NodeStatus getStatus(sa_family_t af) const override;
|
||||
|
||||
NodeStatus getStatus() const override {
|
||||
return std::max(getStatus(AF_INET), getStatus(AF_INET6));
|
||||
@@ -115,15 +107,6 @@ public:
|
||||
return types.getType(type_id);
|
||||
}
|
||||
|
||||
void addBootstrap(const std::string& host, const std::string& service) override {
|
||||
bootstrap_nodes.emplace_back(host, service);
|
||||
onDisconnected();
|
||||
}
|
||||
|
||||
void clearBootstrap() override {
|
||||
bootstrap_nodes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a node in the main routing table.
|
||||
* The node is not pinged, so this should be
|
||||
@@ -136,9 +119,9 @@ public:
|
||||
|
||||
void pingNode(SockAddr, DoneCallbackSimple&& cb={}) override;
|
||||
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, 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 {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen), now);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) override;
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,10 +326,10 @@ private:
|
||||
static constexpr unsigned LISTEN_NODES {4};
|
||||
|
||||
/* The maximum number of hashes we're willing to track. */
|
||||
static constexpr unsigned MAX_HASHES {1024 * 1024};
|
||||
static constexpr unsigned MAX_HASHES {64 * 1024};
|
||||
|
||||
/* The maximum number of searches we keep data about. */
|
||||
static constexpr unsigned MAX_SEARCHES {1024 * 1024};
|
||||
static constexpr unsigned MAX_SEARCHES {64 * 1024};
|
||||
|
||||
static constexpr std::chrono::minutes MAX_STORAGE_MAINTENANCE_EXPIRE_TIME {10};
|
||||
|
||||
@@ -354,10 +337,9 @@ private:
|
||||
static constexpr std::chrono::minutes SEARCH_EXPIRE_TIME {62};
|
||||
|
||||
/* Timeout for listen */
|
||||
static constexpr duration LISTEN_EXPIRE_TIME {std::chrono::seconds(30)};
|
||||
static constexpr duration LISTEN_EXPIRE_TIME_PUBLIC {std::chrono::minutes(5)};
|
||||
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
|
||||
|
||||
static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
|
||||
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
|
||||
|
||||
static constexpr size_t TOKEN_SIZE {32};
|
||||
|
||||
@@ -379,50 +361,40 @@ private:
|
||||
// registred types
|
||||
TypeStore types;
|
||||
|
||||
using SearchMap = std::map<InfoHash, Sp<Search>>;
|
||||
struct Kad {
|
||||
RoutingTable buckets {};
|
||||
SearchMap searches {};
|
||||
unsigned pending_pings {0};
|
||||
NodeStatus status;
|
||||
|
||||
NodeStatus getStatus(time_point now) const;
|
||||
NodeStats getNodesStats(time_point now, const InfoHash& myid) const;
|
||||
};
|
||||
|
||||
Kad dht4 {};
|
||||
Kad dht6 {};
|
||||
|
||||
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
|
||||
std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)};
|
||||
Sp<Scheduler::Job> bootstrapJob {};
|
||||
// the stuff
|
||||
RoutingTable buckets4 {};
|
||||
RoutingTable buckets6 {};
|
||||
|
||||
std::map<InfoHash, Storage> store;
|
||||
std::map<SockAddr, StorageBucket, SockAddr::ipCmp> store_quota;
|
||||
size_t total_values {0};
|
||||
size_t total_store_size {0};
|
||||
size_t max_store_keys {MAX_HASHES};
|
||||
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
|
||||
|
||||
size_t max_searches {MAX_SEARCHES};
|
||||
size_t search_id {0};
|
||||
using SearchMap = std::map<InfoHash, Sp<Search>>;
|
||||
SearchMap searches4 {};
|
||||
SearchMap searches6 {};
|
||||
uint16_t search_id {0};
|
||||
|
||||
// map a global listen token to IPv4, IPv6 specific listen tokens.
|
||||
// 0 is the invalid token.
|
||||
std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
|
||||
size_t listener_token {1};
|
||||
|
||||
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
|
||||
|
||||
// timing
|
||||
Scheduler scheduler;
|
||||
Sp<Scheduler::Job> nextNodesConfirmation {};
|
||||
Sp<Scheduler::Job> nextStorageMaintenance {};
|
||||
|
||||
net::NetworkEngine network_engine;
|
||||
unsigned pending_pings4 {0};
|
||||
unsigned pending_pings6 {0};
|
||||
|
||||
using ReportedAddr = std::pair<unsigned, SockAddr>;
|
||||
std::vector<ReportedAddr> reported_addr;
|
||||
|
||||
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
|
||||
|
||||
std::string persistPath;
|
||||
|
||||
// are we a bootstrap node ?
|
||||
@@ -431,11 +403,6 @@ private:
|
||||
// be put in bootstrap mode.
|
||||
const bool is_bootstrap {false};
|
||||
const bool maintain_storage {false};
|
||||
const bool public_stable {false};
|
||||
|
||||
inline const duration& getListenExpiration() const {
|
||||
return public_stable ? LISTEN_EXPIRE_TIME_PUBLIC : LISTEN_EXPIRE_TIME;
|
||||
}
|
||||
|
||||
void rotateSecrets();
|
||||
|
||||
@@ -465,10 +432,8 @@ private:
|
||||
size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
|
||||
|
||||
// Buckets
|
||||
Kad& dht(sa_family_t af) { return af == AF_INET ? dht4 : dht6; }
|
||||
const Kad& dht(sa_family_t af) const { return af == AF_INET ? dht4 : dht6; }
|
||||
RoutingTable& buckets(sa_family_t af) { return dht(af).buckets; }
|
||||
const RoutingTable& buckets(sa_family_t af) const { return dht(af).buckets; }
|
||||
RoutingTable& buckets(sa_family_t af) { return af == AF_INET ? buckets4 : buckets6; }
|
||||
const RoutingTable& buckets(sa_family_t af) const { return af == AF_INET ? buckets4 : buckets6; }
|
||||
Bucket* findBucket(const InfoHash& id, sa_family_t af) {
|
||||
auto& b = buckets(af);
|
||||
auto it = b.findBucket(id);
|
||||
@@ -490,8 +455,8 @@ private:
|
||||
|
||||
// Searches
|
||||
|
||||
inline SearchMap& searches(sa_family_t af) { return dht(af).searches; }
|
||||
inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; }
|
||||
inline SearchMap& searches(sa_family_t af) { return af == AF_INET ? searches4 : searches6; }
|
||||
inline const SearchMap& searches(sa_family_t af) const { return af == AF_INET ? searches4 : searches6; }
|
||||
|
||||
/**
|
||||
* Low-level method that will perform a search on the DHT for the specified
|
||||
@@ -514,7 +479,6 @@ private:
|
||||
|
||||
void confirmNodes();
|
||||
void expire();
|
||||
void onDisconnected();
|
||||
|
||||
/**
|
||||
* Generic function to execute when a 'get' request has completed.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,8 +30,7 @@ namespace net {
|
||||
class OPENDHT_PUBLIC DhtInterface {
|
||||
public:
|
||||
DhtInterface() = default;
|
||||
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {};
|
||||
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {};
|
||||
DhtInterface(const Logger& l) : DHT_LOG(l) {};
|
||||
virtual ~DhtInterface() = default;
|
||||
|
||||
// [[deprecated]]
|
||||
@@ -42,7 +41,6 @@ public:
|
||||
/**
|
||||
* Get the current status of the node for the given family.
|
||||
*/
|
||||
virtual NodeStatus updateStatus(sa_family_t af) { return getStatus(af); };
|
||||
virtual NodeStatus getStatus(sa_family_t af) const = 0;
|
||||
virtual NodeStatus getStatus() const = 0;
|
||||
|
||||
@@ -70,9 +68,6 @@ public:
|
||||
|
||||
virtual const ValueType& getType(ValueType::Id type_id) const = 0;
|
||||
|
||||
virtual void addBootstrap(const std::string& /*host*/, const std::string& /*service*/) {};
|
||||
virtual void clearBootstrap() {};
|
||||
|
||||
/**
|
||||
* Insert a node in the main routing table.
|
||||
* The node is not pinged, so this should be
|
||||
@@ -83,8 +78,8 @@ public:
|
||||
|
||||
virtual void pingNode(SockAddr, DoneCallbackSimple&& cb={}) = 0;
|
||||
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) = 0;
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) = 0;
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) = 0;
|
||||
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) = 0;
|
||||
|
||||
/**
|
||||
* Get a value by searching on all available protocols (IPv4, IPv6),
|
||||
@@ -226,23 +221,15 @@ public:
|
||||
* Enable or disable logging of DHT internal messages
|
||||
*/
|
||||
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
|
||||
if (logger_) {
|
||||
logger_->DBG = std::move(debug);
|
||||
logger_->WARN = std::move(warn);
|
||||
logger_->ERR = std::move(error);
|
||||
} else
|
||||
logger_= std::make_shared<Logger>(std::move(error), std::move(warn), std::move(debug));
|
||||
DHT_LOG.DBG = debug;
|
||||
DHT_LOG.WARN = warn;
|
||||
DHT_LOG.ERR = error;
|
||||
}
|
||||
|
||||
virtual void setLogger(const Logger& l) {
|
||||
if (logger_)
|
||||
*logger_ = l;
|
||||
else
|
||||
logger_= std::make_shared<Logger>(l);
|
||||
}
|
||||
|
||||
virtual void setLogger(const std::shared_ptr<Logger>& l) {
|
||||
logger_ = l;
|
||||
DHT_LOG.DBG = l.DBG;
|
||||
DHT_LOG.WARN = l.WARN;
|
||||
DHT_LOG.ERR = l.ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,8 +237,7 @@ public:
|
||||
*/
|
||||
virtual void setLogFilter(const InfoHash& f)
|
||||
{
|
||||
if (logger_)
|
||||
logger_->setFilter(f);
|
||||
DHT_LOG.setFilter(f);
|
||||
}
|
||||
|
||||
virtual void setPushNotificationToken(const std::string&) {};
|
||||
@@ -263,7 +249,7 @@ public:
|
||||
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Logger> logger_ {};
|
||||
Logger DHT_LOG;
|
||||
};
|
||||
|
||||
} // namespace dht
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
@@ -197,9 +197,9 @@ public:
|
||||
*/
|
||||
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
|
||||
|
||||
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
|
||||
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen), now);
|
||||
time_point periodic(const uint8_t*, size_t, SockAddr) override;
|
||||
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
|
||||
return periodic(buf, buflen, SockAddr(from, fromlen));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +285,7 @@ private:
|
||||
*/
|
||||
struct InfoState;
|
||||
void getProxyInfos();
|
||||
void queryProxyInfo(const std::shared_ptr<InfoState>& infoState, const std::shared_ptr<http::Resolver>& resolver, sa_family_t family);
|
||||
void queryProxyInfo(std::shared_ptr<InfoState> infoState, sa_family_t family, std::shared_ptr<http::Resolver> resolver);
|
||||
void onProxyInfos(const Json::Value& val, const sa_family_t family);
|
||||
SockAddr parsePublicAddress(const Json::Value& val);
|
||||
|
||||
@@ -300,12 +300,10 @@ private:
|
||||
SUBSCRIBE,
|
||||
RESUBSCRIBE,
|
||||
};
|
||||
using CacheValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired, system_clock::time_point)>;
|
||||
|
||||
/**
|
||||
* Send Listen with httpClient_
|
||||
*/
|
||||
void sendListen(const restinio::http_request_header_t& header, const CacheValueCallback& cb,
|
||||
void sendListen(const restinio::http_request_header_t header, const ValueCallback& cb,
|
||||
const Sp<OperationState>& opstate, Listener& listener, ListenMethod method = ListenMethod::LISTEN);
|
||||
void handleResubscribe(const asio::error_code& ec, const InfoHash& key,
|
||||
const size_t token, std::shared_ptr<OperationState> opstate);
|
||||
@@ -329,7 +327,6 @@ private:
|
||||
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
|
||||
//std::pair<std::string, std::string> serverHostService_;
|
||||
std::string pushClientId_;
|
||||
std::string pushSessionId_;
|
||||
|
||||
mutable std::mutex lockCurrentProxyInfos_;
|
||||
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
|
||||
@@ -408,6 +405,7 @@ private:
|
||||
|
||||
Json::StreamWriterBuilder jsonBuilder_;
|
||||
std::unique_ptr<Json::CharReader> jsonReader_;
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
|
||||
std::shared_ptr<http::Request> buildRequest(const std::string& target = {});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
@@ -90,19 +90,20 @@ public:
|
||||
/** Average requests per second */
|
||||
double requestRate {0};
|
||||
/** Node Info **/
|
||||
std::shared_ptr<NodeInfo> nodeInfo {};
|
||||
NodeInfo nodeInfo {};
|
||||
|
||||
std::string toString() const {
|
||||
std::ostringstream ss;
|
||||
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
|
||||
ss << "Requests: " << requestRate << " per second." << std::endl;
|
||||
if (nodeInfo) {
|
||||
auto& ipv4 = nodeInfo->ipv4;
|
||||
if (ipv4.table_depth > 1)
|
||||
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
|
||||
auto& ipv6 = nodeInfo->ipv6;
|
||||
if (ipv6.table_depth > 1)
|
||||
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
|
||||
auto& ni = nodeInfo;
|
||||
auto& ipv4 = ni.ipv4;
|
||||
if (ipv4.table_depth > 1) {
|
||||
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
|
||||
}
|
||||
auto& ipv6 = ni.ipv6;
|
||||
if (ipv6.table_depth > 1) {
|
||||
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -116,15 +117,14 @@ public:
|
||||
result["putCount"] = static_cast<Json::UInt64>(putCount);
|
||||
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
|
||||
result["requestRate"] = requestRate;
|
||||
if (nodeInfo)
|
||||
result["nodeInfo"] = nodeInfo->toJson();
|
||||
result["nodeInfo"] = nodeInfo.toJson();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<ServerStats> stats() const { return stats_; }
|
||||
ServerStats stats() const { return stats_; }
|
||||
|
||||
std::shared_ptr<ServerStats> updateStats(std::shared_ptr<NodeInfo> info) const;
|
||||
void updateStats() const;
|
||||
|
||||
std::shared_ptr<DhtRunner> getNode() const { return dht_; }
|
||||
|
||||
@@ -134,8 +134,7 @@ private:
|
||||
struct RestRouterTraits;
|
||||
|
||||
template <typename HttpResponse>
|
||||
static HttpResponse initHttpResponse(HttpResponse response);
|
||||
static restinio::request_handling_status_t serverError(restinio::request_t& request);
|
||||
HttpResponse initHttpResponse(HttpResponse response) const;
|
||||
|
||||
template< typename ServerSettings >
|
||||
void addServerSettings(ServerSettings& serverSettings,
|
||||
@@ -282,7 +281,7 @@ private:
|
||||
* @param key of the device
|
||||
* @param json, the content to send
|
||||
*/
|
||||
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid, bool highPriority);
|
||||
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid);
|
||||
|
||||
/**
|
||||
* Send push notification with an expire timeout.
|
||||
@@ -292,7 +291,7 @@ private:
|
||||
* @param isAndroid
|
||||
*/
|
||||
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
|
||||
std::function<Json::Value()> json, const bool isAndroid);
|
||||
Json::Value json, const bool isAndroid);
|
||||
|
||||
/**
|
||||
* Remove a push listener between a client and a hash
|
||||
@@ -307,12 +306,10 @@ private:
|
||||
#endif //OPENDHT_PUSH_NOTIFICATIONS
|
||||
|
||||
void handlePrintStats(const asio::error_code &ec);
|
||||
void updateStats();
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point = clock::time_point;
|
||||
|
||||
std::shared_ptr<asio::io_context> ioContext_;
|
||||
std::shared_ptr<DhtRunner> dht_;
|
||||
Json::StreamWriterBuilder jsonBuilder_;
|
||||
Json::CharReaderBuilder jsonReaderBuilder_;
|
||||
@@ -324,14 +321,15 @@ private:
|
||||
|
||||
// http client
|
||||
std::pair<std::string, std::string> pushHostPort_;
|
||||
|
||||
|
||||
mutable std::mutex requestLock_;
|
||||
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
|
||||
std::shared_ptr<ServerStats> stats_;
|
||||
std::shared_ptr<NodeInfo> nodeInfo_ {};
|
||||
mutable std::mutex statsMutex_;
|
||||
mutable ServerStats stats_;
|
||||
mutable NodeInfo nodeInfo_ {};
|
||||
std::unique_ptr<asio::steady_timer> printStatsTimer_;
|
||||
|
||||
// Thread-safe access to listeners map.
|
||||
@@ -341,18 +339,12 @@ private:
|
||||
// Connection Listener observing conn state changes.
|
||||
std::shared_ptr<ConnectionListener> connListener_;
|
||||
|
||||
struct PushSessionContext {
|
||||
std::mutex lock;
|
||||
std::string sessionId;
|
||||
};
|
||||
struct PermanentPut {
|
||||
time_point expiration;
|
||||
std::string pushToken;
|
||||
std::string clientId;
|
||||
std::shared_ptr<PushSessionContext> sessionCtx;
|
||||
std::unique_ptr<asio::steady_timer> expireTimer;
|
||||
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
|
||||
Sp<Value> value;
|
||||
};
|
||||
struct SearchPuts {
|
||||
std::map<dht::Value::Id, PermanentPut> puts;
|
||||
@@ -368,7 +360,6 @@ private:
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
struct Listener {
|
||||
std::string clientId;
|
||||
std::shared_ptr<PushSessionContext> sessionCtx;
|
||||
std::future<size_t> internalToken;
|
||||
std::unique_ptr<asio::steady_timer> expireTimer;
|
||||
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -327,10 +327,7 @@ public:
|
||||
|
||||
std::vector<ValuesExport> exportValues() const;
|
||||
|
||||
void setLogger(const Sp<Logger>& logger = {});
|
||||
void setLogger(const Logger& logger) {
|
||||
setLogger(std::make_shared<Logger>(logger));
|
||||
}
|
||||
void setLogger(const Logger& logger = {});
|
||||
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
|
||||
|
||||
/**
|
||||
@@ -349,7 +346,6 @@ public:
|
||||
NodeStats getNodesStats(sa_family_t af) const;
|
||||
unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
|
||||
NodeInfo getNodeInfo() const;
|
||||
void getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)>);
|
||||
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
|
||||
std::string getStorageLog() const;
|
||||
@@ -459,6 +455,14 @@ private:
|
||||
Stopping
|
||||
};
|
||||
|
||||
/**
|
||||
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
|
||||
* thread and then queue ping requests. This list should contain reliable
|
||||
* nodes so that the DHT node can recover quickly from losing connection
|
||||
* with the network.
|
||||
*/
|
||||
void tryBootstrapContinuously();
|
||||
|
||||
time_point loop_();
|
||||
|
||||
NodeStatus getStatus() const {
|
||||
@@ -502,8 +506,16 @@ private:
|
||||
std::thread dht_thread {};
|
||||
std::condition_variable cv {};
|
||||
std::mutex sock_mtx {};
|
||||
net::PacketList rcv {};
|
||||
decltype(rcv) rcv_free {};
|
||||
std::queue<std::unique_ptr<net::ReceivedPacket>> rcv {};
|
||||
|
||||
/** true if currently actively boostraping */
|
||||
std::atomic_bool bootstraping {false};
|
||||
/* bootstrap nodes given as (host, service) pairs */
|
||||
std::vector<std::pair<std::string,std::string>> bootstrap_nodes_all {};
|
||||
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
|
||||
std::thread bootstrap_thread {};
|
||||
std::mutex bootstrap_mtx {};
|
||||
std::condition_variable bootstrap_cv {};
|
||||
|
||||
std::queue<std::function<void(SecureDht&)>> pending_ops_prio {};
|
||||
std::queue<std::function<void(SecureDht&)>> pending_ops {};
|
||||
|
||||
+6
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
@@ -119,12 +118,10 @@ private:
|
||||
template<typename T>
|
||||
T wrapCallabck(T cb) const {
|
||||
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
|
||||
cb(params...);
|
||||
return cb(params...);
|
||||
};
|
||||
}
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
unsigned int id_;
|
||||
static std::atomic_uint ids_;
|
||||
|
||||
@@ -188,7 +185,7 @@ public:
|
||||
private:
|
||||
void resolve(const std::string& host, const std::string& service);
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
std::mutex mutex_;
|
||||
|
||||
Url url_;
|
||||
asio::error_code ec_;
|
||||
@@ -202,15 +199,12 @@ private:
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
class Request;
|
||||
|
||||
struct Response
|
||||
{
|
||||
unsigned status_code {0};
|
||||
unsigned int status_code {0};
|
||||
std::map<std::string, std::string> headers;
|
||||
std::string body;
|
||||
bool aborted {false};
|
||||
std::weak_ptr<Request> request;
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
|
||||
@@ -223,10 +217,10 @@ public:
|
||||
RECEIVING,
|
||||
DONE
|
||||
};
|
||||
using OnStatusCb = std::function<void(unsigned status_code)>;
|
||||
using OnStatusCb = std::function<void(unsigned int status_code)>;
|
||||
using OnDataCb = std::function<void(const char* at, size_t length)>;
|
||||
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
|
||||
using OnJsonCb = std::function<void(Json::Value value, unsigned status_code)>;
|
||||
using OnJsonCb = std::function<void(Json::Value value, unsigned int status_code)>;
|
||||
using OnDoneCb = std::function<void(const Response& response)>;
|
||||
|
||||
// resolves implicitly
|
||||
@@ -253,12 +247,6 @@ public:
|
||||
inline const Url& get_url() const {
|
||||
return resolver_->get_url();
|
||||
};
|
||||
|
||||
/** The previous request in case of redirect following */
|
||||
std::shared_ptr<Request> getPrevious() const {
|
||||
return prev_.lock();
|
||||
}
|
||||
|
||||
inline std::string& to_string() {
|
||||
return request_;
|
||||
}
|
||||
@@ -324,8 +312,6 @@ private:
|
||||
void onBody(const char* at, size_t length);
|
||||
void onComplete();
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
|
||||
restinio::http_request_header_t header_;
|
||||
@@ -353,12 +339,6 @@ private:
|
||||
std::atomic<bool> finishing_ {false};
|
||||
std::unique_ptr<http_parser> parser_;
|
||||
std::unique_ptr<http_parser_settings> parser_s_;
|
||||
|
||||
// Next request in case of redirect following
|
||||
std::shared_ptr<Request> next_;
|
||||
std::weak_ptr<Request> prev_;
|
||||
unsigned num_redirect {0};
|
||||
bool follow_redirect {true};
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -50,7 +50,7 @@ namespace dht {
|
||||
using byte = uint8_t;
|
||||
|
||||
namespace crypto {
|
||||
OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
|
||||
OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -64,7 +64,7 @@ struct LogMethod {
|
||||
func(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
inline void log(char const* format, va_list args) const {
|
||||
void log(char const* format, va_list args) const {
|
||||
func(format, args);
|
||||
}
|
||||
explicit operator bool() const {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -212,13 +212,12 @@ public:
|
||||
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
|
||||
using RequestExpiredCb = std::function<void(const Request&, bool)>;
|
||||
|
||||
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
|
||||
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
|
||||
NetworkEngine(
|
||||
InfoHash& myid,
|
||||
NetworkConfig config,
|
||||
std::unique_ptr<DatagramSocket>&& sock,
|
||||
const Sp<Logger>& log,
|
||||
std::mt19937_64& rd,
|
||||
Logger& log,
|
||||
Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError)&& onError,
|
||||
decltype(NetworkEngine::onNewNode)&& onNewNode,
|
||||
@@ -275,8 +274,7 @@ public:
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request>
|
||||
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
|
||||
|
||||
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
|
||||
/**
|
||||
* Send a "ping" request to a given node.
|
||||
*
|
||||
@@ -288,12 +286,11 @@ public:
|
||||
* @return the request with information concerning its success.
|
||||
*/
|
||||
Sp<Request>
|
||||
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
|
||||
return sendPing(std::make_shared<Node>(zeroes, std::move(sa), rd),
|
||||
std::forward<RequestCb>(on_done),
|
||||
std::forward<RequestExpiredCb>(on_expired));
|
||||
}
|
||||
|
||||
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
|
||||
return sendPing(std::make_shared<Node>(zeroes, std::move(sa)),
|
||||
std::forward<RequestCb>(on_done),
|
||||
std::forward<RequestExpiredCb>(on_expired));
|
||||
}
|
||||
/**
|
||||
* Send a "find node" request to a given node.
|
||||
*
|
||||
@@ -432,21 +429,6 @@ public:
|
||||
return cache.getCachedNodes(id, sa_f, count);
|
||||
}
|
||||
|
||||
size_t getNodeCacheSize() const {
|
||||
return cache.size();
|
||||
}
|
||||
size_t getNodeCacheSize(sa_family_t af) const {
|
||||
return cache.size(af);
|
||||
}
|
||||
|
||||
size_t getRateLimiterSize() const {
|
||||
return address_rate_limiter.size();
|
||||
}
|
||||
|
||||
size_t getPartialCount() const {
|
||||
return partial_messages.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct PartialMessage;
|
||||
@@ -543,10 +525,9 @@ private:
|
||||
const InfoHash& myid;
|
||||
const NetworkConfig config {};
|
||||
const std::unique_ptr<DatagramSocket> dht_socket;
|
||||
Sp<Logger> logger_;
|
||||
std::mt19937_64& rd;
|
||||
const Logger& DHT_LOG;
|
||||
|
||||
NodeCache cache;
|
||||
NodeCache cache {};
|
||||
|
||||
// global limiting should be triggered by at least 8 different IPs
|
||||
using IpLimiter = RateLimiter;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -36,14 +36,11 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
|
||||
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
|
||||
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
|
||||
static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650);
|
||||
|
||||
int bindSocket(const SockAddr& addr, SockAddr& bound);
|
||||
|
||||
@@ -57,14 +54,10 @@ struct ReceivedPacket {
|
||||
SockAddr from;
|
||||
time_point received;
|
||||
};
|
||||
using PacketList = std::list<ReceivedPacket>;
|
||||
|
||||
class OPENDHT_PUBLIC DatagramSocket {
|
||||
public:
|
||||
/** A function that takes a list of new received packets and
|
||||
* optionally returns consumed packets for recycling.
|
||||
**/
|
||||
using OnReceive = std::function<PacketList(PacketList&& packets)>;
|
||||
using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>;
|
||||
virtual ~DatagramSocket() {};
|
||||
|
||||
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
|
||||
@@ -88,45 +81,24 @@ public:
|
||||
|
||||
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
|
||||
|
||||
/** Virtual resolver mothod allows to implement custom resolver */
|
||||
virtual std::vector<SockAddr> resolve(const std::string& host, const std::string& service = {}) {
|
||||
return SockAddr::resolve(host, service);
|
||||
}
|
||||
|
||||
virtual void stop() = 0;
|
||||
protected:
|
||||
|
||||
PacketList getNewPacket() {
|
||||
PacketList pkts;
|
||||
if (toRecycle_.empty()) {
|
||||
pkts.emplace_back();
|
||||
} else {
|
||||
auto begIt = toRecycle_.begin();
|
||||
auto begItNext = std::next(begIt);
|
||||
pkts.splice(pkts.end(), toRecycle_, begIt, begItNext);
|
||||
}
|
||||
return pkts;
|
||||
}
|
||||
|
||||
inline void onReceived(PacketList&& packets) {
|
||||
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
if (rx_callback) {
|
||||
auto r = rx_callback(std::move(packets));
|
||||
if (not r.empty() and toRecycle_.size() < RX_QUEUE_MAX_SIZE)
|
||||
toRecycle_.splice(toRecycle_.end(), std::move(r));
|
||||
}
|
||||
if (rx_callback)
|
||||
rx_callback(std::move(packet));
|
||||
}
|
||||
protected:
|
||||
mutable std::mutex lock;
|
||||
private:
|
||||
OnReceive rx_callback;
|
||||
PacketList toRecycle_;
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
|
||||
public:
|
||||
UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l = {});
|
||||
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l = {});
|
||||
UdpSocket(in_port_t port, const Logger& l = {});
|
||||
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l = {});
|
||||
~UdpSocket();
|
||||
|
||||
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
|
||||
@@ -146,7 +118,7 @@ public:
|
||||
|
||||
void stop() override;
|
||||
private:
|
||||
std::shared_ptr<Logger> logger;
|
||||
Logger logger;
|
||||
int s4 {-1};
|
||||
int s6 {-1};
|
||||
int stopfd {-1};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -47,10 +47,10 @@ struct Socket {
|
||||
struct Node {
|
||||
const InfoHash id;
|
||||
|
||||
Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client=false);
|
||||
Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client=false);
|
||||
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
|
||||
: Node(id, SockAddr(sa, salen), rd) {}
|
||||
Node(const InfoHash& id, const SockAddr& addr, bool client=false);
|
||||
Node(const InfoHash& id, SockAddr&& addr, bool client=false);
|
||||
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
|
||||
: Node(id, SockAddr(sa, salen)) {}
|
||||
|
||||
InfoHash getId() const {
|
||||
return id;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,13 +26,6 @@
|
||||
namespace dht {
|
||||
|
||||
struct NodeCache {
|
||||
size_t size(sa_family_t family) const {
|
||||
return cache(family).count();
|
||||
}
|
||||
size_t size() const {
|
||||
return size(AF_INET) + size(AF_INET6);
|
||||
}
|
||||
|
||||
Sp<Node> getNode(const InfoHash& id, sa_family_t family);
|
||||
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client=false);
|
||||
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const;
|
||||
@@ -44,19 +37,17 @@ struct NodeCache {
|
||||
*/
|
||||
void clearBadNodes(sa_family_t family = 0);
|
||||
|
||||
NodeCache(std::mt19937_64& r) : rd(r) {};
|
||||
~NodeCache();
|
||||
|
||||
private:
|
||||
class NodeMap : private std::map<InfoHash, std::weak_ptr<Node>> {
|
||||
public:
|
||||
Sp<Node> getNode(const InfoHash& id);
|
||||
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client, std::mt19937_64& rd);
|
||||
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client);
|
||||
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, size_t count) const;
|
||||
void clearBadNodes();
|
||||
void setExpired();
|
||||
void cleanup();
|
||||
size_t count() const { return size(); }
|
||||
private:
|
||||
size_t cleanup_counter {0};
|
||||
};
|
||||
@@ -65,7 +56,6 @@ private:
|
||||
NodeMap& cache(sa_family_t af) { return af == AF_INET ? cache_4 : cache_6; }
|
||||
NodeMap cache_4;
|
||||
NodeMap cache_6;
|
||||
std::mt19937_64& rd;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
@@ -82,8 +82,6 @@ public:
|
||||
bool stopPublish(const std::string &type);
|
||||
bool stopPublish(sa_family_t domain, const std::string &type);
|
||||
|
||||
void connectivityChanged();
|
||||
|
||||
private:
|
||||
class DomainPeerDiscovery;
|
||||
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,8 +22,8 @@
|
||||
namespace dht {
|
||||
namespace proxy {
|
||||
|
||||
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
|
||||
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
|
||||
constexpr const std::chrono::seconds OP_TIMEOUT {1 * 60 * 60}; // one hour
|
||||
constexpr const std::chrono::seconds OP_MARGIN {5 * 60}; // 5 minutes
|
||||
constexpr const char* const HTTP_PROTO {"http://"};
|
||||
using ListenToken = uint64_t;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -39,7 +39,7 @@ struct Bucket {
|
||||
Sp<Node> cached; /* the address of a likely candidate */
|
||||
|
||||
/** Return a random node in a bucket. */
|
||||
Sp<Node> randomNode(std::mt19937_64& rd);
|
||||
Sp<Node> randomNode();
|
||||
|
||||
void sendCachedPing(net::NetworkEngine& ne);
|
||||
void connectivityChanged() {
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
/**
|
||||
* Return a random id in the bucket's range.
|
||||
*/
|
||||
InfoHash randomId(const RoutingTable::const_iterator& bucket, std::mt19937_64& rd) const;
|
||||
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
unsigned depth(const RoutingTable::const_iterator& bucket) const;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
* @return The time for the next job to run.
|
||||
*/
|
||||
time_point run() {
|
||||
syncTime();
|
||||
while (not timers.empty()) {
|
||||
auto timer = timers.begin();
|
||||
/*
|
||||
@@ -113,7 +114,6 @@ public:
|
||||
*/
|
||||
inline const time_point& time() const { return now; }
|
||||
inline time_point syncTime() { return (now = clock::now()); }
|
||||
inline void syncTime(const time_point& n) { now = n; }
|
||||
|
||||
private:
|
||||
time_point now {clock::now()};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -195,14 +195,11 @@ public:
|
||||
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
|
||||
return dht_->getPublicAddress(family);
|
||||
}
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa, const time_point& now) override {
|
||||
return dht_->periodic(buf, buflen, std::move(sa), now);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa) override {
|
||||
return dht_->periodic(buf, buflen, std::move(sa));
|
||||
}
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
|
||||
return dht_->periodic(buf, buflen, from, fromlen, now);
|
||||
}
|
||||
NodeStatus updateStatus(sa_family_t af) override {
|
||||
return dht_->updateStatus(af);
|
||||
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
|
||||
return dht_->periodic(buf, buflen, from, fromlen);
|
||||
}
|
||||
NodeStatus getStatus(sa_family_t af) const override {
|
||||
return dht_->getStatus(af);
|
||||
@@ -219,12 +216,6 @@ public:
|
||||
const ValueType& getType(ValueType::Id type_id) const override {
|
||||
return dht_->getType(type_id);
|
||||
}
|
||||
void addBootstrap(const std::string& host, const std::string& service) override {
|
||||
dht_->addBootstrap(host, service);
|
||||
}
|
||||
void clearBootstrap() override {
|
||||
dht_->clearBootstrap();
|
||||
}
|
||||
void insertNode(const InfoHash& id, const SockAddr& sa) override {
|
||||
dht_->insertNode(id, sa);
|
||||
}
|
||||
@@ -325,16 +316,11 @@ public:
|
||||
dht_->setLogger(logger);
|
||||
}
|
||||
|
||||
void setLogger(const std::shared_ptr<Logger>& logger) override {
|
||||
DhtInterface::setLogger(logger);
|
||||
dht_->setLogger(logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
|
||||
*/
|
||||
void setLogFilter(const InfoHash& f) override {
|
||||
DhtInterface::setLogFilter(f);
|
||||
DHT_LOG.setFilter(f);
|
||||
dht_->setLogFilter(f);
|
||||
}
|
||||
|
||||
@@ -359,7 +345,6 @@ private:
|
||||
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
|
||||
|
||||
std::atomic_bool forward_all_ {false};
|
||||
bool enableCache_ {false};
|
||||
};
|
||||
|
||||
const ValueType CERTIFICATE_TYPE = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
+10
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -77,20 +77,12 @@ public:
|
||||
// Time related definitions and utility functions
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
using system_clock = std::chrono::system_clock;
|
||||
using time_point = clock::time_point;
|
||||
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.
|
||||
*/
|
||||
@@ -105,26 +97,14 @@ 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";
|
||||
} else if (d < std::chrono::seconds(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
|
||||
} else if (d < std::chrono::minutes(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
|
||||
} else if (d < std::chrono::hours(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
|
||||
} else {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
|
||||
}
|
||||
}
|
||||
|
||||
template <class TimePoint>
|
||||
static std::string
|
||||
print_time_relative(TimePoint now, TimePoint d) {
|
||||
if (d == TimePoint::min()) return "never";
|
||||
if (d == now) return "now";
|
||||
return (d > now) ? std::string("in ") + print_duration(d - now)
|
||||
: print_duration(now - d) + std::string(" ago");
|
||||
if (d < std::chrono::milliseconds(1)) {
|
||||
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
|
||||
} else if (d < std::chrono::seconds(1)) {
|
||||
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
|
||||
} else {
|
||||
return std::to_string(print_dt(d)) + " s";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Duration = duration>
|
||||
@@ -153,7 +133,7 @@ using Blob = std::vector<uint8_t>;
|
||||
/**
|
||||
* Provides backward compatibility with msgpack 1.0
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object& o);
|
||||
OPENDHT_PUBLIC Blob unpackBlob(msgpack::object& o);
|
||||
|
||||
template <typename Type>
|
||||
Blob
|
||||
@@ -173,7 +153,6 @@ unpackMsg(Blob b) {
|
||||
|
||||
msgpack::unpacked unpackMsg(Blob b);
|
||||
|
||||
msgpack::object* findMapValue(const msgpack::object& map, const char* key);
|
||||
msgpack::object* findMapValue(const msgpack::object& map, const std::string& key);
|
||||
msgpack::object* findMapValue(msgpack::object& map, const std::string& key);
|
||||
|
||||
} // namespace dht
|
||||
+44
-86
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -20,7 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "infohash.h"
|
||||
#include "crypto.h"
|
||||
//#include "crypto.h"
|
||||
#include "utils.h"
|
||||
#include "sockaddr.h"
|
||||
|
||||
@@ -43,22 +43,15 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
static const std::string VALUE_KEY_ID("id");
|
||||
static const std::string VALUE_KEY_DAT("dat");
|
||||
static const std::string VALUE_KEY_PRIO("p");
|
||||
static const std::string VALUE_KEY_SIGNATURE("sig");
|
||||
|
||||
static const std::string VALUE_KEY_SEQ("seq");
|
||||
static const std::string VALUE_KEY_DATA("data");
|
||||
static const std::string VALUE_KEY_OWNER("owner");
|
||||
static const std::string VALUE_KEY_TYPE("type");
|
||||
static const std::string VALUE_KEY_TO("to");
|
||||
static const std::string VALUE_KEY_BODY("body");
|
||||
static const std::string VALUE_KEY_USERTYPE("utype");
|
||||
|
||||
struct Value;
|
||||
struct Query;
|
||||
|
||||
namespace crypto {
|
||||
class PublicKey;
|
||||
class PrivateKey;
|
||||
class Certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* A storage policy is applied once to every incoming value storage requests.
|
||||
* If the policy returns false, the value is dropped.
|
||||
@@ -254,15 +247,9 @@ struct OPENDHT_PUBLIC Value
|
||||
};
|
||||
}
|
||||
|
||||
static Filter OwnerFilter(const crypto::PublicKey& pk) {
|
||||
return OwnerFilter(pk.getId());
|
||||
}
|
||||
static Filter OwnerFilter(const crypto::PublicKey& pk);
|
||||
|
||||
static Filter OwnerFilter(const InfoHash& pkh) {
|
||||
return [pkh](const Value& v) {
|
||||
return v.owner and v.owner->getId() == pkh;
|
||||
};
|
||||
}
|
||||
static Filter OwnerFilter(const InfoHash& pkh);
|
||||
|
||||
static Filter SeqNumFilter(uint16_t seq_no) {
|
||||
return [seq_no](const Value& v) {
|
||||
@@ -354,20 +341,13 @@ struct OPENDHT_PUBLIC Value
|
||||
* Afterward, checkSignature() will return true and owner will
|
||||
* be set to the corresponding public key.
|
||||
*/
|
||||
void sign(const crypto::PrivateKey& key) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Can't sign encrypted data.");
|
||||
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
|
||||
signature = key.sign(getToSign());
|
||||
}
|
||||
void sign(const crypto::PrivateKey& key);
|
||||
|
||||
/**
|
||||
* Check that the value is signed and that the signature matches.
|
||||
* If true, the owner field will contain the signer public key.
|
||||
*/
|
||||
bool checkSignature() const {
|
||||
return isSigned() and owner->checkSignature(getToSign(), signature);
|
||||
}
|
||||
bool checkSignature() const;
|
||||
|
||||
std::shared_ptr<const crypto::PublicKey> getOwner() const {
|
||||
return std::static_pointer_cast<const crypto::PublicKey>(owner);
|
||||
@@ -376,15 +356,7 @@ struct OPENDHT_PUBLIC Value
|
||||
/**
|
||||
* Sign the value with from and returns the encrypted version for to.
|
||||
*/
|
||||
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Data is already encrypted.");
|
||||
setRecipient(to.getId());
|
||||
sign(from);
|
||||
Value nv {id};
|
||||
nv.setCypher(to.encrypt(getToEncrypt()));
|
||||
return nv;
|
||||
}
|
||||
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to);
|
||||
|
||||
Value() {}
|
||||
|
||||
@@ -403,7 +375,7 @@ struct OPENDHT_PUBLIC Value
|
||||
* Build a value from a json object
|
||||
* @param json
|
||||
*/
|
||||
Value(const Json::Value& json);
|
||||
Value(Json::Value& json);
|
||||
#endif
|
||||
|
||||
template <typename Type>
|
||||
@@ -421,9 +393,7 @@ struct OPENDHT_PUBLIC Value
|
||||
|
||||
Value(Value&& o) noexcept
|
||||
: id(o.id), owner(std::move(o.owner)), recipient(o.recipient),
|
||||
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq)
|
||||
, signature(std::move(o.signature)), cypher(std::move(o.cypher))
|
||||
, priority(o.priority) {}
|
||||
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq), signature(std::move(o.signature)), cypher(std::move(o.cypher)) {}
|
||||
|
||||
template <typename Type>
|
||||
Value(const Type& vs)
|
||||
@@ -436,20 +406,14 @@ struct OPENDHT_PUBLIC Value
|
||||
msgpack_unpack(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if value contents are equals (not considering the value ID)
|
||||
*/
|
||||
inline bool contentEquals(const Value& o) {
|
||||
return isEncrypted() ? cypher == o.cypher :
|
||||
((owner == o.owner || (owner and o.owner and *owner == *o.owner))
|
||||
&& type == o.type
|
||||
&& data == o.data
|
||||
&& user_type == o.user_type
|
||||
&& signature == o.signature);
|
||||
}
|
||||
|
||||
inline bool operator== (const Value& o) {
|
||||
return id == o.id and contentEquals(o);
|
||||
return id == o.id &&
|
||||
(isEncrypted() ? cypher == o.cypher :
|
||||
(
|
||||
#ifndef OPENDHT_LIGHT
|
||||
(owner == o.owner || *owner == *o.owner) &&
|
||||
#endif
|
||||
type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
|
||||
}
|
||||
|
||||
void setRecipient(const InfoHash& r) {
|
||||
@@ -507,20 +471,24 @@ struct OPENDHT_PUBLIC Value
|
||||
template <typename Packer>
|
||||
void msgpack_pack_to_sign(Packer& pk) const
|
||||
{
|
||||
bool has_owner = owner && *owner;
|
||||
#ifndef OPENDHT_LIGHT
|
||||
bool has_owner = owner && *owner
|
||||
pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient ? 5 : 4):2));
|
||||
if (has_owner) { // isSigned
|
||||
pk.pack(VALUE_KEY_SEQ); pk.pack(seq);
|
||||
pk.pack(VALUE_KEY_OWNER); owner->msgpack_pack(pk);
|
||||
pk.pack(std::string("seq")); pk.pack(seq);
|
||||
pk.pack(std::string("owner")); owner->msgpack_pack(pk);
|
||||
if (recipient) {
|
||||
pk.pack(VALUE_KEY_TO); pk.pack(recipient);
|
||||
pk.pack(std::string("to")); pk.pack(recipient);
|
||||
}
|
||||
}
|
||||
pk.pack(VALUE_KEY_TYPE); pk.pack(type);
|
||||
pk.pack(VALUE_KEY_DATA); pk.pack_bin(data.size());
|
||||
pk.pack_bin_body((const char*)data.data(), data.size());
|
||||
#else
|
||||
pk.pack_map((user_type.empty()?0:1) + 2);
|
||||
#endif
|
||||
pk.pack(std::string("type")); pk.pack(type);
|
||||
pk.pack(std::string("data")); pk.pack_bin(data.size());
|
||||
pk.pack_bin_body((const char*)data.data(), data.size());
|
||||
if (not user_type.empty()) {
|
||||
pk.pack(VALUE_KEY_USERTYPE); pk.pack(user_type);
|
||||
pk.pack(std::string("utype")); pk.pack(user_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,10 +500,10 @@ struct OPENDHT_PUBLIC Value
|
||||
pk.pack_bin_body((const char*)cypher.data(), cypher.size());
|
||||
} else {
|
||||
pk.pack_map(isSigned() ? 2 : 1);
|
||||
pk.pack(VALUE_KEY_BODY); msgpack_pack_to_sign(pk);
|
||||
pk.pack(std::string("body")); msgpack_pack_to_sign(pk);
|
||||
if (isSigned()) {
|
||||
pk.pack(VALUE_KEY_SIGNATURE); pk.pack_bin(signature.size());
|
||||
pk.pack_bin_body((const char*)signature.data(), signature.size());
|
||||
pk.pack(std::string("sig")); pk.pack_bin(signature.size());
|
||||
pk.pack_bin_body((const char*)signature.data(), signature.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -543,12 +511,9 @@ struct OPENDHT_PUBLIC Value
|
||||
template <typename Packer>
|
||||
void msgpack_pack(Packer& pk) const
|
||||
{
|
||||
pk.pack_map(2 + (priority?1:0));
|
||||
pk.pack(VALUE_KEY_ID); pk.pack(id);
|
||||
pk.pack(VALUE_KEY_DAT); msgpack_pack_to_encrypt(pk);
|
||||
if (priority) {
|
||||
pk.pack(VALUE_KEY_PRIO); pk.pack(priority);
|
||||
}
|
||||
pk.pack_map(2);
|
||||
pk.pack(std::string("id")); pk.pack(id);
|
||||
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
@@ -563,9 +528,11 @@ struct OPENDHT_PUBLIC Value
|
||||
pk.pack(static_cast<uint64_t>(type));
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
#ifndef OPENDHT_LIGHT
|
||||
if (owner)
|
||||
owner->msgpack_pack(pk);
|
||||
else
|
||||
#endif
|
||||
InfoHash().msgpack_pack(pk);
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
@@ -579,7 +546,7 @@ struct OPENDHT_PUBLIC Value
|
||||
}
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
void msgpack_unpack(msgpack::object o);
|
||||
void msgpack_unpack_body(const msgpack::object& o);
|
||||
Blob getPacked() const {
|
||||
msgpack::sbuffer buffer;
|
||||
@@ -630,13 +597,6 @@ struct OPENDHT_PUBLIC Value
|
||||
*/
|
||||
Blob cypher {};
|
||||
|
||||
/**
|
||||
* Priority of this value (used for push notifications)
|
||||
* 0 = high priority
|
||||
* 1 = normal priority
|
||||
*/
|
||||
unsigned priority {0};
|
||||
|
||||
private:
|
||||
friend class SecureDht;
|
||||
/* Cache for crypto ops */
|
||||
@@ -693,7 +653,7 @@ struct OPENDHT_PUBLIC FieldValue
|
||||
}
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& msg) {
|
||||
void msgpack_unpack(msgpack::object msg) {
|
||||
hashValue = {};
|
||||
blobValue.clear();
|
||||
|
||||
@@ -780,8 +740,6 @@ struct OPENDHT_PUBLIC Select
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool empty() const { return fieldSelection_.empty(); }
|
||||
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
|
||||
private:
|
||||
std::vector<Value::Field> fieldSelection_ {};
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
Name: OpenDHT
|
||||
Description: C++14 Distributed Hash Table library
|
||||
Description: C++ Distributed Hash Table library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lopendht
|
||||
Libs.private: @http_parser_lib@ -pthread
|
||||
Requires.private: gnutls >= 3.3, nettle >= 2.4@argon2_lib@@jsoncpp_lib@@openssl_lib@
|
||||
Libs.private: -lpthread
|
||||
Requires.private: gnutls >= 3.1@argon2_lib@
|
||||
Cflags: -I${includedir}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
# Simon Désaulniers <sim.desaulniers@gmail.com>
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
|
||||
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -35,21 +35,13 @@ pong_node.ping(ping_node.getBound())
|
||||
loc_ping = dht.InfoHash.get("toto99")
|
||||
loc_pong = dht.InfoHash.get(str(loc_ping))
|
||||
|
||||
net = []
|
||||
for i in range(1,10):
|
||||
node = dht.DhtRunner()
|
||||
node.run(config=config)
|
||||
node.ping(ping_node.getBound())
|
||||
net.append(node)
|
||||
|
||||
i = 0
|
||||
MAX = 2048
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
def done(h, ok):
|
||||
pass
|
||||
#print(h, "over", ok)
|
||||
print(h, "over", ok)
|
||||
|
||||
def ping(node, h):
|
||||
global i
|
||||
@@ -60,20 +52,13 @@ def ping(node, h):
|
||||
loop.stop()
|
||||
|
||||
def pong(node, h):
|
||||
#print(node.getNodeId().decode(), "got ping", h, i)
|
||||
print(node.getNodeId().decode(), "got ping", h, i)
|
||||
loop.call_soon_threadsafe(ping, node, h)
|
||||
return True
|
||||
|
||||
t1 = time.time()
|
||||
|
||||
ping_node.listen(loc_ping, lambda v, e: pong(pong_node, loc_pong) if not e else True)
|
||||
pong_node.listen(loc_pong, lambda v, e: pong(ping_node, loc_ping) if not e else True)
|
||||
|
||||
ping(pong_node, loc_ping)
|
||||
|
||||
loop.run_forever()
|
||||
|
||||
t2 = time.time()
|
||||
|
||||
print(MAX, "ping-pong done, took", t2 - t1, "s")
|
||||
print(1000 * (t2 - t1)/MAX, "ms per rt", MAX/(t2 - t1), "rt per s")
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -131,7 +131,7 @@ base64_encode(const std::vector<unsigned char>& str)
|
||||
return base64_encode(str.cbegin(), str.cend());
|
||||
}
|
||||
|
||||
std::vector<unsigned char>
|
||||
std::string
|
||||
base64_decode(const std::string& str)
|
||||
{
|
||||
size_t output_length = str.length() / 4 * 3 + 2;
|
||||
@@ -139,5 +139,5 @@ base64_decode(const std::string& str)
|
||||
output.resize(output_length);
|
||||
base64_decode(str.data(), str.size(), output.data(), &output_length);
|
||||
output.resize(output_length);
|
||||
return output;
|
||||
return std::string(output.begin(), output.end());
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -33,4 +33,4 @@ std::string base64_encode(const std::vector<unsigned char>& str);
|
||||
* @param str the input buffer
|
||||
* @return a base64-decoded buffer
|
||||
*/
|
||||
std::vector<unsigned char> base64_decode(const std::string& str);
|
||||
std::string base64_decode(const std::string& str);
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -94,7 +94,6 @@ NodeStats::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Known nodes: " << good_nodes << " good, " << dubious_nodes << " dubious, " << incoming_nodes << " incoming." << std::endl;
|
||||
ss << searches << " searches, " << node_cache_size << " total cached nodes" << std::endl;
|
||||
if (table_depth > 1) {
|
||||
ss << "Routing table depth: " << table_depth << std::endl;
|
||||
ss << "Network size estimation: " << getNetworkSizeEstimation() << " nodes" << std::endl;
|
||||
|
||||
+5
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -412,18 +412,12 @@ PublicKey::pack(Blob& b) const
|
||||
throw CryptoException(std::string("Could not export public key: null key"));
|
||||
std::vector<uint8_t> tmp(2048);
|
||||
size_t sz = tmp.size();
|
||||
if (int err = pack(tmp.data(), &sz))
|
||||
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
|
||||
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
|
||||
tmp.resize(sz);
|
||||
b.insert(b.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
int
|
||||
PublicKey::pack(uint8_t* out, size_t* out_len) const
|
||||
{
|
||||
return gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, out, out_len);
|
||||
}
|
||||
|
||||
void
|
||||
PublicKey::unpack(const uint8_t* data, size_t data_size)
|
||||
{
|
||||
@@ -453,7 +447,7 @@ PublicKey::toString() const
|
||||
}
|
||||
|
||||
void
|
||||
PublicKey::msgpack_unpack(const msgpack::object& o)
|
||||
PublicKey::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type == msgpack::type::BIN)
|
||||
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
|
||||
@@ -798,7 +792,7 @@ Certificate::unpack(const uint8_t* dat, size_t dat_size)
|
||||
}
|
||||
|
||||
void
|
||||
Certificate::msgpack_unpack(const msgpack::object& o)
|
||||
Certificate::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type == msgpack::type::BIN)
|
||||
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
|
||||
@@ -1258,7 +1252,7 @@ RevocationList::unpack(const uint8_t* dat, size_t dat_size)
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::msgpack_unpack(const msgpack::object& o)
|
||||
RevocationList::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
try {
|
||||
if (o.type == msgpack::type::BIN)
|
||||
|
||||
+13
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -15,6 +15,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "default_types.h"
|
||||
|
||||
@@ -83,6 +86,8 @@ IpServiceAnnouncement::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const
|
||||
|
||||
const ValueType DhtMessage::TYPE(1, "DHT message", std::chrono::minutes(5), DhtMessage::storePolicy);
|
||||
const ValueType IpServiceAnnouncement::TYPE(2, "Internet Service Announcement", std::chrono::minutes(15), IpServiceAnnouncement::storePolicy);
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
const ValueType ImMessage::TYPE = {3, "IM message", std::chrono::minutes(5)};
|
||||
const ValueType TrustRequest::TYPE = {4, "Certificate trust request", std::chrono::hours(24*7)};
|
||||
const ValueType IceCandidates::TYPE = {5, "ICE candidates", std::chrono::minutes(1)};
|
||||
@@ -96,6 +101,13 @@ DEFAULT_TYPES
|
||||
IceCandidates::TYPE,
|
||||
TrustRequest::TYPE
|
||||
}};
|
||||
#else
|
||||
const std::array<std::reference_wrapper<const ValueType>, 1>
|
||||
DEFAULT_TYPES
|
||||
{{
|
||||
ValueType::USER_DATA
|
||||
}};
|
||||
#endif
|
||||
|
||||
const std::array<std::reference_wrapper<const ValueType>, 1>
|
||||
DEFAULT_INSECURE_TYPES
|
||||
|
||||
+291
-384
File diff suppressed because it is too large.
Load diff
+67
-114
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
@@ -46,7 +46,7 @@ struct DhtProxyClient::Listener
|
||||
|
||||
unsigned callbackId;
|
||||
OpValueCache cache;
|
||||
CacheValueCallback cb;
|
||||
ValueCallback cb;
|
||||
Sp<OperationState> opstate;
|
||||
std::shared_ptr<http::Request> request;
|
||||
std::unique_ptr<asio::steady_timer> refreshSubscriberTimer;
|
||||
@@ -68,7 +68,6 @@ struct DhtProxyClient::ProxySearch {
|
||||
std::unique_ptr<asio::steady_timer> opExpirationTimer;
|
||||
std::map<size_t, Listener> listeners {};
|
||||
std::map<Value::Id, PermanentPut> puts {};
|
||||
std::set<Sp<Value>> pendingPuts {};
|
||||
};
|
||||
|
||||
struct LineSplit {
|
||||
@@ -78,12 +77,13 @@ struct LineSplit {
|
||||
bool getLine(char c) {
|
||||
auto it = buf_.begin();
|
||||
while (it != buf_.end()) {
|
||||
if (*(it++) == c) {
|
||||
if (*it == c) {
|
||||
line_.clear();
|
||||
line_.insert(line_.end(), buf_.begin(), it);
|
||||
line_.insert(line_.end(), buf_.begin(), ++it);
|
||||
buf_.erase(buf_.begin(), it);
|
||||
return true;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -93,28 +93,17 @@ private:
|
||||
std::string line_ {};
|
||||
};
|
||||
|
||||
std::string
|
||||
getRandomSessionId(size_t length = 8) {
|
||||
static constexpr const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~";
|
||||
std::string str(length, 0);
|
||||
crypto::random_device rdev;
|
||||
std::uniform_int_distribution<> dist(0, (sizeof(chars)/sizeof(char)) - 1);
|
||||
std::generate_n( str.begin(), length, [&]{ return chars[dist(rdev)]; } );
|
||||
return str;
|
||||
}
|
||||
|
||||
DhtProxyClient::DhtProxyClient() {}
|
||||
|
||||
DhtProxyClient::DhtProxyClient(
|
||||
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
|
||||
std::function<void()> signal, const std::string& serverHost,
|
||||
const std::string& pushClientId, std::shared_ptr<dht::Logger> logger)
|
||||
: DhtInterface(logger)
|
||||
, proxyUrl_(serverHost)
|
||||
: proxyUrl_(serverHost)
|
||||
, clientIdentity_(clientIdentity), serverCertificate_(serverCA)
|
||||
, pushClientId_(pushClientId), pushSessionId_(getRandomSessionId())
|
||||
, loopSignal_(signal)
|
||||
, pushClientId_(pushClientId), loopSignal_(signal)
|
||||
, jsonReader_(Json::CharReaderBuilder{}.newCharReader())
|
||||
, logger_(logger)
|
||||
{
|
||||
jsonBuilder_["commentStyle"] = "None";
|
||||
jsonBuilder_["indentation"] = "";
|
||||
@@ -280,7 +269,7 @@ DhtProxyClient::isRunning(sa_family_t af) const
|
||||
}
|
||||
|
||||
time_point
|
||||
DhtProxyClient::periodic(const uint8_t*, size_t, SockAddr, const time_point& /*now*/)
|
||||
DhtProxyClient::periodic(const uint8_t*, size_t, SockAddr)
|
||||
{
|
||||
// Exec all currently stored callbacks
|
||||
decltype(callbacks_) callbacks;
|
||||
@@ -326,8 +315,7 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va
|
||||
auto& b = *rxBuf;
|
||||
b.append(at, length);
|
||||
// one value per body line
|
||||
std::vector<Sp<Value>> values;
|
||||
while (b.getLine('\n') and !opstate->stop) {
|
||||
while (b.getLine('\n') and !opstate->stop){
|
||||
std::string err;
|
||||
Json::Value json;
|
||||
const auto& line = b.line();
|
||||
@@ -336,19 +324,17 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va
|
||||
return;
|
||||
}
|
||||
auto value = std::make_shared<Value>(json);
|
||||
if ((not filter or filter(*value)) and cb)
|
||||
values.emplace_back(std::move(value));
|
||||
}
|
||||
if (not values.empty() and cb) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lockCallbacks_);
|
||||
callbacks_.emplace_back([opstate, cb, values = std::move(values)](){
|
||||
if (not opstate->stop.load() and not cb(values)){
|
||||
opstate->stop.store(true);
|
||||
}
|
||||
});
|
||||
if ((not filter or filter(*value)) and cb){
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lockCallbacks_);
|
||||
callbacks_.emplace_back([opstate, cb, value](){
|
||||
if (not opstate->stop.load() and not cb({value})){
|
||||
opstate->stop.store(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
loopSignal_();
|
||||
}
|
||||
loopSignal_();
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
if (logger_)
|
||||
@@ -401,22 +387,23 @@ DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_po
|
||||
if (logger_)
|
||||
logger_->d("[proxy:client] [put] [search %s]", key.to_c_str());
|
||||
|
||||
if (val->id == Value::INVALID_ID) {
|
||||
crypto::random_device rdev;
|
||||
val->id = std::uniform_int_distribution<Value::Id>{1}(rdev);
|
||||
}
|
||||
std::shared_ptr<std::atomic_bool> ok;
|
||||
if (permanent) {
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
ok = std::make_shared<std::atomic_bool>(true);
|
||||
auto id = val->id;
|
||||
auto& search = searches_[key];
|
||||
if (val->id) {
|
||||
auto id = val->id;
|
||||
auto refreshPutTimer = std::make_unique<asio::steady_timer>(httpContext_, proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, id));
|
||||
search.puts.erase(id);
|
||||
search.puts.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(id),
|
||||
std::forward_as_tuple(val, std::move(refreshPutTimer), ok));
|
||||
} else {
|
||||
search.pendingPuts.emplace(val);
|
||||
}
|
||||
auto refreshPutTimer = std::make_unique<asio::steady_timer>(httpContext_, std::chrono::steady_clock::now() +
|
||||
proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, id));
|
||||
search.puts.erase(id);
|
||||
ok = std::make_shared<std::atomic_bool>(true);
|
||||
search.puts.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(id),
|
||||
std::forward_as_tuple(val, std::move(refreshPutTimer), ok));
|
||||
}
|
||||
doPut(key, val, [this, cb, ok](bool result){
|
||||
if (ok)
|
||||
@@ -451,7 +438,7 @@ DhtProxyClient::handleRefreshPut(const asio::error_code &ec, InfoHash key, Value
|
||||
doPut(key, p->second.value, [ok = p->second.ok](bool result){
|
||||
*ok = result;
|
||||
}, time_point::max(), true);
|
||||
p->second.refreshPutTimer->expires_after(proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
p->second.refreshPutTimer->expires_at(std::chrono::steady_clock::now() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
p->second.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, id));
|
||||
}
|
||||
}
|
||||
@@ -463,7 +450,7 @@ DhtProxyClient::buildRequest(const std::string& target)
|
||||
auto resolver = resolver_;
|
||||
if (not resolver)
|
||||
resolver = std::make_shared<http::Resolver>(httpContext_, proxyUrl_, logger_);
|
||||
auto request = target.empty()
|
||||
auto request = target.empty()
|
||||
? std::make_shared<http::Request>(httpContext_, resolver)
|
||||
: std::make_shared<http::Request>(httpContext_, resolver, target);
|
||||
if (serverCertificate_)
|
||||
@@ -501,35 +488,9 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
|
||||
}
|
||||
}
|
||||
request->set_body(Json::writeString(jsonBuilder_, json));
|
||||
request->add_on_done_callback([this, reqid, cb, val, key, permanent] (const http::Response& response){
|
||||
request->add_on_done_callback([this, reqid, cb] (const http::Response& response){
|
||||
bool ok = response.status_code == 200;
|
||||
if (ok) {
|
||||
if (val->id == Value::INVALID_ID) {
|
||||
std::string err;
|
||||
Json::Value parsedValue;
|
||||
if (jsonReader_->parse(response.body.data(), response.body.data() + response.body.size(), &parsedValue, &err)){
|
||||
auto id = dht::Value(parsedValue).id;
|
||||
val->id = id;
|
||||
if (permanent) {
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
auto& search = searches_[key];
|
||||
auto it = search.pendingPuts.find(val);
|
||||
if (it != search.pendingPuts.end()) {
|
||||
auto sok = std::make_shared<std::atomic_bool>(ok);
|
||||
auto refreshPutTimer = std::make_unique<asio::steady_timer>(httpContext_, proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this, std::placeholders::_1, key, id));
|
||||
search.puts.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(id),
|
||||
std::forward_as_tuple(val, std::move(refreshPutTimer), sok));
|
||||
search.pendingPuts.erase(it);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (logger_)
|
||||
logger_->e("[proxy:client] [status] failed to parse value from server", response.status_code);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (not ok) {
|
||||
if (logger_)
|
||||
logger_->e("[proxy:client] [status] failed with code=%i", response.status_code);
|
||||
if (not response.aborted and response.status_code == 0)
|
||||
@@ -624,20 +585,20 @@ DhtProxyClient::getProxyInfos()
|
||||
logger_->d("[proxy:client] [status] sending request");
|
||||
|
||||
auto resolver = std::make_shared<http::Resolver>(httpContext_, proxyUrl_, logger_);
|
||||
queryProxyInfo(infoState, resolver, AF_INET);
|
||||
queryProxyInfo(infoState, resolver, AF_INET6);
|
||||
queryProxyInfo(infoState, AF_INET, resolver);
|
||||
queryProxyInfo(infoState, AF_INET6, resolver);
|
||||
resolver_ = resolver;
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyClient::queryProxyInfo(const Sp<InfoState>& infoState, const Sp<http::Resolver>& resolver, sa_family_t family)
|
||||
DhtProxyClient::queryProxyInfo(std::shared_ptr<InfoState> infoState, sa_family_t family, std::shared_ptr<http::Resolver> resolver)
|
||||
{
|
||||
if (logger_)
|
||||
logger_->d("[proxy:client] [status] query ipv%i info", family == AF_INET ? 4 : 6);
|
||||
try {
|
||||
auto request = std::make_shared<http::Request>(httpContext_, resolver, family);
|
||||
auto reqid = request->id();
|
||||
request->set_method(restinio::http_method_get());
|
||||
request->set_method(restinio::http_method_get());
|
||||
setHeaderFields(*request);
|
||||
request->add_on_done_callback([this, reqid, family, infoState] (const http::Response& response){
|
||||
if (infoState->cancel.load())
|
||||
@@ -654,9 +615,10 @@ DhtProxyClient::queryProxyInfo(const Sp<InfoState>& infoState, const Sp<http::Re
|
||||
Json::Value proxyInfos;
|
||||
if (!jsonReader_->parse(response.body.data(), response.body.data() + response.body.size(), &proxyInfos, &err)){
|
||||
onProxyInfos(Json::Value{}, family);
|
||||
} else if (not infoState->cancel) {
|
||||
onProxyInfos(proxyInfos, family);
|
||||
return;
|
||||
}
|
||||
if (not infoState->cancel)
|
||||
onProxyInfos(proxyInfos, family);
|
||||
}
|
||||
if (not isDestroying_) {
|
||||
std::lock_guard<std::mutex> l(requestLock_);
|
||||
@@ -788,7 +750,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
|
||||
// Add cache callback
|
||||
auto opstate = std::make_shared<OperationState>();
|
||||
l->second.opstate = opstate;
|
||||
l->second.cb = [this,key,token,opstate](const std::vector<Sp<Value>>& values, bool expired, system_clock::time_point t){
|
||||
l->second.cb = [this,key,token,opstate](const std::vector<Sp<Value>>& values, bool expired){
|
||||
if (opstate->stop)
|
||||
return false;
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
@@ -796,7 +758,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
|
||||
if (s != searches_.end()) {
|
||||
auto l = s->second.listeners.find(token);
|
||||
if (l != s->second.listeners.end()) {
|
||||
return l->second.cache.onValue(values, expired, t);
|
||||
return l->second.cache.onValue(values, expired);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -967,8 +929,8 @@ DhtProxyClient::handleExpireListener(const asio::error_code &ec, const InfoHash&
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyClient::sendListen(const restinio::http_request_header_t& header,
|
||||
const CacheValueCallback& cb,
|
||||
DhtProxyClient::sendListen(const restinio::http_request_header_t header,
|
||||
const ValueCallback& cb,
|
||||
const Sp<OperationState>& opstate,
|
||||
Listener& listener, ListenMethod method)
|
||||
{
|
||||
@@ -995,7 +957,7 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t& header,
|
||||
b.append(at, length);
|
||||
|
||||
// one value per body line
|
||||
while (b.getLine('\n') and !opstate->stop) {
|
||||
while (b.getLine('\n') and !opstate->stop){
|
||||
std::string err;
|
||||
Json::Value json;
|
||||
const auto& line = b.line();
|
||||
@@ -1013,7 +975,7 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t& header,
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lockCallbacks_);
|
||||
callbacks_.emplace_back([cb, value, opstate, expired]() {
|
||||
if (not opstate->stop.load() and not cb({value}, expired, system_clock::time_point::min()))
|
||||
if (not opstate->stop.load() and not cb({value}, expired))
|
||||
opstate->stop.store(true);
|
||||
});
|
||||
}
|
||||
@@ -1089,15 +1051,17 @@ DhtProxyClient::restartListeners()
|
||||
for (auto& search : searches_) {
|
||||
auto key = search.first;
|
||||
for (auto& put : search.second.puts) {
|
||||
doPut(key, put.second.value, [ok = put.second.ok](bool result){
|
||||
*ok = result;
|
||||
}, time_point::max(), true);
|
||||
if (!put.second.refreshPutTimer) {
|
||||
put.second.refreshPutTimer = std::make_unique<asio::steady_timer>(httpContext_);
|
||||
if (!*put.second.ok) {
|
||||
doPut(key, put.second.value, [ok = put.second.ok](bool result){
|
||||
*ok = result;
|
||||
}, time_point::max(), true);
|
||||
if (!put.second.refreshPutTimer){
|
||||
put.second.refreshPutTimer = std::make_unique<asio::steady_timer>(httpContext_);
|
||||
}
|
||||
put.second.refreshPutTimer->expires_at(std::chrono::steady_clock::now() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
put.second.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this,
|
||||
std::placeholders::_1, key, put.first));
|
||||
}
|
||||
put.second.refreshPutTimer->expires_at(std::chrono::steady_clock::now() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
|
||||
put.second.refreshPutTimer->async_wait(std::bind(&DhtProxyClient::handleRefreshPut, this,
|
||||
std::placeholders::_1, key, put.first));
|
||||
}
|
||||
}
|
||||
if (not deviceKey_.empty()) {
|
||||
@@ -1154,12 +1118,6 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
|
||||
statusIpv6_ = NodeStatus::Connected;
|
||||
}
|
||||
try {
|
||||
auto sessionId = notification.find("s");
|
||||
if (sessionId != notification.end() and sessionId->second != pushSessionId_) {
|
||||
if (logger_)
|
||||
logger_->d("[proxy:client] [push] ignoring push for other session");
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
auto timeout = notification.find("timeout");
|
||||
if (timeout != notification.cend()) {
|
||||
@@ -1182,10 +1140,6 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
|
||||
}
|
||||
} else {
|
||||
auto key = InfoHash(notification.at("key"));
|
||||
system_clock::time_point sendTime = system_clock::time_point::min();
|
||||
try {
|
||||
sendTime = system_clock::time_point(std::chrono::milliseconds(std::stoull(notification.at("t"))));
|
||||
} catch (...) {}
|
||||
auto& search = searches_.at(key);
|
||||
for (auto& list : search.listeners) {
|
||||
if (list.second.opstate->stop)
|
||||
@@ -1198,24 +1152,24 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
|
||||
if (expired == notification.end()) {
|
||||
auto cb = list.second.cb;
|
||||
auto oldValues = list.second.cache.getValues();
|
||||
get(key, [cb, sendTime](const std::vector<Sp<Value>>& vals) {
|
||||
return cb(vals, false, sendTime);
|
||||
}, [cb, oldValues, sendTime](bool /*ok*/) {
|
||||
get(key, [cb](const std::vector<Sp<Value>>& vals) {
|
||||
return cb(vals, false);
|
||||
}, [cb, oldValues](bool /*ok*/) {
|
||||
// Decrement old values refcount to expire values not
|
||||
// present in the new list
|
||||
cb(oldValues, true, sendTime);
|
||||
cb(oldValues, true);
|
||||
});
|
||||
} else {
|
||||
std::stringstream ss(expired->second);
|
||||
std::vector<Value::Id> ids;
|
||||
while(ss.good()) {
|
||||
while(ss.good()){
|
||||
std::string substr;
|
||||
getline(ss, substr, ',');
|
||||
ids.emplace_back(std::stoull(substr));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lockCallbacks_);
|
||||
callbacks_.emplace_back([this, key, token, opstate, ids, sendTime]() {
|
||||
callbacks_.emplace_back([this, key, token, opstate, ids]() {
|
||||
if (opstate->stop)
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(searchLock_);
|
||||
@@ -1225,7 +1179,7 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
|
||||
auto l = s->second.listeners.find(token);
|
||||
if (l == s->second.listeners.end())
|
||||
return;
|
||||
if (not opstate->stop and not l->second.cache.onValuesExpired(ids, sendTime))
|
||||
if (not opstate->stop and not l->second.cache.onValuesExpired(ids))
|
||||
opstate->stop = true;
|
||||
});
|
||||
}
|
||||
@@ -1283,7 +1237,6 @@ DhtProxyClient::getPushRequest(Json::Value& body) const
|
||||
{
|
||||
body["key"] = deviceKey_;
|
||||
body["client_id"] = pushClientId_;
|
||||
body["session_id"] = pushSessionId_;
|
||||
#ifdef __ANDROID__
|
||||
body["platform"] = "android";
|
||||
#endif
|
||||
|
||||
+254
-216
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
@@ -36,7 +36,6 @@
|
||||
#include <iostream>
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
|
||||
namespace restinio {
|
||||
@@ -105,13 +104,6 @@ private:
|
||||
std::shared_ptr<Logger> m_logger;
|
||||
};
|
||||
|
||||
restinio::request_handling_status_t
|
||||
DhtProxyServer::serverError(restinio::request_t& request) {
|
||||
auto response = initHttpResponse(request.create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
|
||||
// connection listener
|
||||
|
||||
class DhtProxyServer::ConnectionListener
|
||||
@@ -178,9 +170,7 @@ DhtProxyServer::DhtProxyServer(
|
||||
std::shared_ptr<DhtRunner> dht, in_port_t port, const std::string& pushServer,
|
||||
std::shared_ptr<Logger> logger
|
||||
)
|
||||
: ioContext_(std::make_shared<asio::io_context>()),
|
||||
dht_(dht), logger_(logger),
|
||||
printStatsTimer_(std::make_unique<asio::steady_timer>(*ioContext_, 3s)),
|
||||
: dht_(dht), logger_(logger),
|
||||
connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
|
||||
pushServer_(pushServer)
|
||||
{
|
||||
@@ -244,7 +234,7 @@ DhtProxyServer::DhtProxyServer(
|
||||
settings.port(port);
|
||||
settings.tls_context(std::move(tls_context));
|
||||
httpsServer_ = std::make_unique<restinio::http_server_t<RestRouterTraitsTls>>(
|
||||
ioContext_,
|
||||
restinio::own_io_context(),
|
||||
std::forward<restinio::run_on_this_thread_settings_t<RestRouterTraitsTls>>(std::move(settings))
|
||||
);
|
||||
// run http server
|
||||
@@ -260,7 +250,7 @@ DhtProxyServer::DhtProxyServer(
|
||||
addServerSettings(settings);
|
||||
settings.port(port);
|
||||
httpServer_ = std::make_unique<restinio::http_server_t<RestRouterTraits>>(
|
||||
ioContext_,
|
||||
restinio::own_io_context(),
|
||||
std::forward<restinio::run_on_this_thread_settings_t<RestRouterTraits>>(std::move(settings))
|
||||
);
|
||||
// run http server
|
||||
@@ -272,14 +262,20 @@ DhtProxyServer::DhtProxyServer(
|
||||
});
|
||||
}
|
||||
dht->forwardAllMessages(true);
|
||||
updateStats();
|
||||
|
||||
printStatsTimer_ = std::make_unique<asio::steady_timer>(io_context(), PRINT_STATS_PERIOD);
|
||||
printStatsTimer_->async_wait(std::bind(&DhtProxyServer::handlePrintStats, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
asio::io_context&
|
||||
DhtProxyServer::io_context() const
|
||||
{
|
||||
return *ioContext_;
|
||||
if (httpsServer_)
|
||||
return httpsServer_->io_context();
|
||||
else if (httpServer_)
|
||||
return httpServer_->io_context();
|
||||
throw std::runtime_error("No available server");
|
||||
}
|
||||
|
||||
DhtProxyServer::~DhtProxyServer()
|
||||
@@ -307,7 +303,10 @@ DhtProxyServer::~DhtProxyServer()
|
||||
}
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] closing http server");
|
||||
ioContext_->stop();
|
||||
if (httpServer_)
|
||||
httpServer_->io_context().stop();
|
||||
if (httpsServer_)
|
||||
httpsServer_->io_context().stop();
|
||||
if (serverThread_.joinable())
|
||||
serverThread_.join();
|
||||
if (logger_)
|
||||
@@ -341,40 +340,24 @@ DhtProxyServer::addServerSettings(ServerSettings& settings, const unsigned int m
|
||||
// socket options
|
||||
settings.socket_options_setter([](auto & options){
|
||||
options.set_option(asio::ip::tcp::no_delay{true});
|
||||
options.set_option(asio::socket_base::keep_alive{true});
|
||||
});
|
||||
settings.connection_state_listener(connListener_);
|
||||
}
|
||||
|
||||
std::shared_ptr<DhtProxyServer::ServerStats>
|
||||
DhtProxyServer::updateStats(std::shared_ptr<NodeInfo> info) const
|
||||
void
|
||||
DhtProxyServer::updateStats() const
|
||||
{
|
||||
auto now = clock::now();
|
||||
auto last = lastStatsReset_.exchange(now);
|
||||
auto count = requestNum_.exchange(0);
|
||||
auto dt = std::chrono::duration<double>(now - last);
|
||||
auto sstats = std::make_shared<ServerStats>();
|
||||
auto& stats = *sstats;
|
||||
stats.requestRate = count / dt.count();
|
||||
stats_.requestRate = count / dt.count();
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
stats.pushListenersCount = pushListeners_.size();
|
||||
stats_.pushListenersCount = pushListeners_.size();
|
||||
#endif
|
||||
stats.putCount = puts_.size();
|
||||
stats.listenCount = listeners_.size();
|
||||
stats.nodeInfo = std::move(info);
|
||||
return sstats;
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyServer::updateStats() {
|
||||
dht_->getNodeInfo([this](std::shared_ptr<NodeInfo> newInfo){
|
||||
stats_ = updateStats(newInfo);
|
||||
nodeInfo_ = newInfo;
|
||||
if (logger_) {
|
||||
auto str = Json::writeString(jsonBuilder_, newInfo->toJson());
|
||||
logger_->d("[proxy:server] [stats] %s", str.c_str());
|
||||
}
|
||||
});
|
||||
stats_.putCount = puts_.size();
|
||||
stats_.listenCount = listeners_.size();
|
||||
stats_.nodeInfo = nodeInfo_;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -382,13 +365,30 @@ DhtProxyServer::handlePrintStats(const asio::error_code &ec)
|
||||
{
|
||||
if (ec == asio::error::operation_aborted)
|
||||
return;
|
||||
updateStats();
|
||||
else if (ec){
|
||||
if (logger_)
|
||||
logger_->e("[proxy:server] [stats] error printing: %s", ec.message().c_str());
|
||||
}
|
||||
if (io_context().stopped())
|
||||
return;
|
||||
|
||||
if (dht_){
|
||||
updateStats();
|
||||
// Refresh stats cache
|
||||
auto newInfo = dht_->getNodeInfo();
|
||||
std::lock_guard<std::mutex> lck(statsMutex_);
|
||||
nodeInfo_ = std::move(newInfo);
|
||||
auto json = nodeInfo_.toJson();
|
||||
auto str = Json::writeString(jsonBuilder_, json);
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [stats] %s", str.c_str());
|
||||
}
|
||||
printStatsTimer_->expires_at(printStatsTimer_->expiry() + PRINT_STATS_PERIOD);
|
||||
printStatsTimer_->async_wait(std::bind(&DhtProxyServer::handlePrintStats, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
template <typename HttpResponse>
|
||||
HttpResponse DhtProxyServer::initHttpResponse(HttpResponse response)
|
||||
HttpResponse DhtProxyServer::initHttpResponse(HttpResponse response) const
|
||||
{
|
||||
response.append_header("Server", "RESTinio");
|
||||
response.append_header(restinio::http_field::content_type, "application/json");
|
||||
@@ -476,21 +476,20 @@ RequestStatus
|
||||
DhtProxyServer::getNodeInfo(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t /*params*/) const
|
||||
{
|
||||
try {
|
||||
if (auto nodeInfo = nodeInfo_) {
|
||||
auto result = nodeInfo->toJson();
|
||||
// [ipv6:ipv4]:port or ipv4:port
|
||||
result["public_ip"] = request->remote_endpoint().address().to_string();
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(Json::writeString(jsonBuilder_, result) + "\n");
|
||||
return response.done();
|
||||
}
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
} catch (...) {
|
||||
return serverError(*request);
|
||||
Json::Value result;
|
||||
std::lock_guard<std::mutex> lck(statsMutex_);
|
||||
if (nodeInfo_.ipv4.good_nodes == 0 &&
|
||||
nodeInfo_.ipv6.good_nodes == 0){
|
||||
nodeInfo_ = dht_->getNodeInfo();
|
||||
}
|
||||
result = nodeInfo_.toJson();
|
||||
// [ipv6:ipv4]:port or ipv4:port
|
||||
result["public_ip"] = request->remote_endpoint().address().to_string();
|
||||
auto output = Json::writeString(jsonBuilder_, result) + "\n";
|
||||
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(output);
|
||||
return response.done();
|
||||
}
|
||||
|
||||
RequestStatus
|
||||
@@ -499,18 +498,24 @@ DhtProxyServer::getStats(restinio::request_handle_t request,
|
||||
{
|
||||
requestNum_++;
|
||||
try {
|
||||
if (auto stats = stats_) {
|
||||
if (dht_){
|
||||
auto output = Json::writeString(jsonBuilder_, stats_.toJson()) + "\n";
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(Json::writeString(jsonBuilder_, stats->toJson()) + "\n");
|
||||
return response.done();
|
||||
response.append_body(output);
|
||||
response.done();
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_service_unavailable()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
} catch (...){
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
RequestStatus
|
||||
@@ -518,29 +523,37 @@ DhtProxyServer::get(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params)
|
||||
{
|
||||
requestNum_++;
|
||||
InfoHash infoHash(params["hash"].to_string());
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
try {
|
||||
InfoHash infoHash(params["hash"].to_string());
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
dht_->get(infoHash, [this, response](const std::vector<Sp<Value>>& values) {
|
||||
std::stringstream output;
|
||||
for (const auto& value : values) {
|
||||
output << Json::writeString(jsonBuilder_, value->toJson()) << "\n";
|
||||
}
|
||||
response->append_chunk(output.str());
|
||||
dht_->get(infoHash, [this, response](const Sp<Value>& value){
|
||||
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
|
||||
response->append_chunk(output);
|
||||
response->flush();
|
||||
return true;
|
||||
},
|
||||
[response] (bool /*ok*/){
|
||||
response->done();
|
||||
});
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
} catch (const std::exception& e){
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
RequestStatus
|
||||
@@ -548,14 +561,20 @@ DhtProxyServer::listen(restinio::request_handle_t request,
|
||||
restinio::router::route_params_t params)
|
||||
{
|
||||
requestNum_++;
|
||||
InfoHash infoHash(params["hash"].to_string());
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
try {
|
||||
InfoHash infoHash(params["hash"].to_string());
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
std::lock_guard<std::mutex> lock(lockListener_);
|
||||
// save the listener to handle a disconnect
|
||||
auto &session = listeners_[request->connection_id()];
|
||||
@@ -567,15 +586,20 @@ DhtProxyServer::listen(restinio::request_handle_t request,
|
||||
auto jsonVal = value->toJson();
|
||||
if (expired)
|
||||
jsonVal["expired"] = true;
|
||||
response->append_chunk(Json::writeString(jsonBuilder_, jsonVal) + "\n");
|
||||
auto output = Json::writeString(jsonBuilder_, jsonVal) + "\n";
|
||||
response->append_chunk(output);
|
||||
response->flush();
|
||||
}
|
||||
response->flush();
|
||||
return true;
|
||||
});
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
|
||||
} catch (const std::exception& e){
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
@@ -590,56 +614,59 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
try {
|
||||
std::string err;
|
||||
Json::Value r;
|
||||
Json::Value root;
|
||||
auto* char_data = reinterpret_cast<const char*>(request->body().data());
|
||||
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
|
||||
if (!reader->parse(char_data, char_data + request->body().size(), &r, &err)){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
if (!reader->parse(char_data, char_data + request->body().size(), &root, &err)){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_JSON_INCORRECT);
|
||||
return response.done();
|
||||
}
|
||||
const Json::Value& root(r); // parse using const Json so [] never creates element
|
||||
auto pushToken = root["key"].asString();
|
||||
if (pushToken.empty()){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_NO_TOKEN);
|
||||
return response.done();
|
||||
}
|
||||
auto isAndroid = root["platform"].asString() == "android";
|
||||
auto clientId = root["client_id"].asString();
|
||||
auto sessionId = root["session_id"].asString();
|
||||
auto platform = root["platform"].asString();
|
||||
auto isAndroid = platform == "android";
|
||||
auto clientId = root.isMember("client_id") ? root["client_id"].asString() : std::string();
|
||||
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [subscribe %s] [client %s] [session %s]", infoHash.toString().c_str(), clientId.c_str(), sessionId.c_str());
|
||||
logger_->d("[proxy:server] [subscribe %s] [client %s]", infoHash.toString().c_str(), clientId.c_str());
|
||||
// ================ Search for existing listener ===================
|
||||
// start the timer
|
||||
auto timeout = std::chrono::steady_clock::now() + proxy::OP_TIMEOUT;
|
||||
std::lock_guard<std::mutex> lock(lockPushListeners_);
|
||||
|
||||
// Insert new or return existing push listeners of a token
|
||||
auto& pushListener = pushListeners_[pushToken];
|
||||
auto& pushListeners = pushListener.listeners[infoHash];
|
||||
auto pushListener = pushListeners_.emplace(pushToken, PushListener{}).first;
|
||||
auto pushListeners = pushListener->second.listeners.emplace(infoHash, std::vector<Listener>{}).first;
|
||||
|
||||
for (auto &listener: pushListeners) {
|
||||
for (auto &listener: pushListeners->second){
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [subscribe] found [client %s]", listener.clientId.c_str());
|
||||
// Found -> Resubscribe
|
||||
if (listener.clientId == clientId) {
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [subscribe] found [client %s]", listener.clientId.c_str());
|
||||
if (listener.clientId == clientId){
|
||||
// Reset timers
|
||||
listener.expireTimer->expires_at(timeout);
|
||||
listener.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
|
||||
{
|
||||
std::lock_guard<std::mutex> l(listener.sessionCtx->lock);
|
||||
listener.sessionCtx->sessionId = sessionId;
|
||||
}
|
||||
// Send response header
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
if (!root["refresh"].asBool()) {
|
||||
// No Refresh
|
||||
// No Refresh
|
||||
if (!root.isMember("refresh") or !root["refresh"].asBool()){
|
||||
dht_->get(infoHash, [this, response](const Sp<Value>& value){
|
||||
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
|
||||
response->append_chunk(output);
|
||||
@@ -649,8 +676,8 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
[response] (bool){
|
||||
response->done();
|
||||
});
|
||||
// Refresh
|
||||
} else {
|
||||
// Refresh
|
||||
response->append_chunk("{}\n");
|
||||
response->done();
|
||||
}
|
||||
@@ -659,25 +686,18 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
}
|
||||
// =========== No existing listener for an infoHash ============
|
||||
// Add new listener to list of listeners
|
||||
pushListeners.emplace_back(Listener{});
|
||||
auto &listener = pushListeners.back();
|
||||
pushListeners->second.emplace_back(Listener{});
|
||||
auto &listener = pushListeners->second.back();
|
||||
listener.clientId = clientId;
|
||||
listener.sessionCtx = std::make_shared<PushSessionContext>();
|
||||
listener.sessionCtx->sessionId = sessionId;
|
||||
|
||||
// Add listen on dht
|
||||
listener.internalToken = dht_->listen(infoHash,
|
||||
[this, infoHash, pushToken, isAndroid, clientId, sessionCtx = listener.sessionCtx]
|
||||
[this, infoHash, pushToken, isAndroid, clientId]
|
||||
(const std::vector<std::shared_ptr<Value>>& values, bool expired){
|
||||
// Build message content
|
||||
Json::Value json;
|
||||
json["key"] = infoHash.toString();
|
||||
json["to"] = clientId;
|
||||
json["t"] = Json::Value::Int64(std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
|
||||
{
|
||||
std::lock_guard<std::mutex> l(sessionCtx->lock);
|
||||
json["s"] = sessionCtx->sessionId;
|
||||
}
|
||||
if (expired and values.size() < 2){
|
||||
std::stringstream ss;
|
||||
for(size_t i = 0; i < values.size(); ++i){
|
||||
@@ -686,31 +706,25 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
}
|
||||
json["exp"] = ss.str();
|
||||
}
|
||||
auto maxPrio = 1000u;
|
||||
for (const auto& v : values)
|
||||
maxPrio = std::min(maxPrio, v->priority);
|
||||
sendPushNotification(pushToken, std::move(json), isAndroid, !expired and maxPrio == 0);
|
||||
sendPushNotification(pushToken, std::move(json), isAndroid);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
// Launch timers
|
||||
auto &ctx = io_context();
|
||||
// expire notify
|
||||
if (!listener.expireNotifyTimer)
|
||||
listener.expireNotifyTimer = std::make_unique<asio::steady_timer>(io_context(), timeout - proxy::OP_MARGIN);
|
||||
listener.expireNotifyTimer = std::make_unique<asio::steady_timer>(ctx, timeout - proxy::OP_MARGIN);
|
||||
else
|
||||
listener.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
|
||||
auto jsonProvider = [infoHash, clientId, sessionCtx = listener.sessionCtx](){
|
||||
Json::Value json;
|
||||
json["timeout"] = infoHash.toString();
|
||||
json["to"] = clientId;
|
||||
std::lock_guard<std::mutex> l(sessionCtx->lock);
|
||||
json["s"] = sessionCtx->sessionId;
|
||||
return json;
|
||||
};
|
||||
Json::Value json;
|
||||
json["timeout"] = infoHash.toString();
|
||||
json["to"] = clientId;
|
||||
listener.expireNotifyTimer->async_wait(std::bind(&DhtProxyServer::handleNotifyPushListenExpire, this,
|
||||
std::placeholders::_1, pushToken, std::move(jsonProvider), isAndroid));
|
||||
std::placeholders::_1, pushToken, json, isAndroid));
|
||||
// cancel push listen
|
||||
if (!listener.expireTimer)
|
||||
listener.expireTimer = std::make_unique<asio::steady_timer>(io_context(), timeout);
|
||||
listener.expireTimer = std::make_unique<asio::steady_timer>(ctx, timeout);
|
||||
else
|
||||
listener.expireTimer->expires_at(timeout);
|
||||
listener.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPushListen, this,
|
||||
@@ -720,7 +734,10 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
|
||||
return response.done();
|
||||
}
|
||||
catch (...) {
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
@@ -735,6 +752,12 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [unsubscribe %s]", infoHash.toString().c_str());
|
||||
|
||||
@@ -760,23 +783,26 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
|
||||
return response.done();
|
||||
}
|
||||
catch (...) {
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyServer::handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
|
||||
std::function<Json::Value()> jsonProvider, const bool isAndroid)
|
||||
Json::Value json, const bool isAndroid)
|
||||
{
|
||||
if (ec == asio::error::operation_aborted)
|
||||
return;
|
||||
else if (ec) {
|
||||
else if (ec){
|
||||
if (logger_)
|
||||
logger_->e("[proxy:server] [subscribe] error sending put refresh: %s", ec.message().c_str());
|
||||
}
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] [subscribe] sending put refresh to %s token", pushToken.c_str());
|
||||
sendPushNotification(pushToken, jsonProvider(), isAndroid, false);
|
||||
sendPushNotification(pushToken, std::move(json), isAndroid);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -818,7 +844,7 @@ DhtProxyServer::handleCancelPushListen(const asio::error_code &ec, const std::st
|
||||
}
|
||||
|
||||
void
|
||||
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, bool isAndroid, bool highPriority)
|
||||
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, bool isAndroid)
|
||||
{
|
||||
if (pushServer_.empty())
|
||||
return;
|
||||
@@ -842,7 +868,7 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
|
||||
notification["tokens"] = std::move(tokens);
|
||||
notification["platform"] = isAndroid ? 2 : 1;
|
||||
notification["data"] = std::move(json);
|
||||
notification["priority"] = highPriority ? "high" : "normal";
|
||||
notification["priority"] = "high";
|
||||
notification["time_to_live"] = 600;
|
||||
|
||||
Json::Value notifications(Json::arrayValue);
|
||||
@@ -914,7 +940,12 @@ DhtProxyServer::put(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (request->body().empty()){
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
else if (request->body().empty()){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_MISSING_PARAMS);
|
||||
return response.done();
|
||||
@@ -933,63 +964,36 @@ DhtProxyServer::put(restinio::request_handle_t request,
|
||||
logger_->d("[proxy:server] [put %s] %s %s", infoHash.toString().c_str(),
|
||||
value->toString().c_str(), (permanent ? "permanent" : ""));
|
||||
if (permanent) {
|
||||
std::string pushToken, clientId, sessionId, platform;
|
||||
std::string pushToken, clientId, platform;
|
||||
auto& pVal = root["permanent"];
|
||||
if (pVal.isObject()){
|
||||
pushToken = pVal["key"].asString();
|
||||
clientId = pVal["client_id"].asString();
|
||||
platform = pVal["platform"].asString();
|
||||
sessionId = pVal["session_id"].asString();
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(lockSearchPuts_);
|
||||
auto timeout = std::chrono::steady_clock::now() + proxy::OP_TIMEOUT;
|
||||
auto& sPuts = puts_[infoHash];
|
||||
if (value->id == Value::INVALID_ID) {
|
||||
for (auto& pp : sPuts.puts) {
|
||||
if (pp.second.pushToken == pushToken
|
||||
and pp.second.clientId == clientId
|
||||
and pp.second.value->contentEquals(*value))
|
||||
{
|
||||
pp.second.expireTimer->expires_at(timeout);
|
||||
pp.second.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPermamentPut, this,
|
||||
std::placeholders::_1, infoHash, pp.second.value->id));
|
||||
if (not sessionId.empty()) {
|
||||
if (not pp.second.sessionCtx)
|
||||
pp.second.sessionCtx = std::make_shared<PushSessionContext>();
|
||||
std::lock_guard<std::mutex> l(pp.second.sessionCtx->lock);
|
||||
pp.second.sessionCtx->sessionId = sessionId;
|
||||
}
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
|
||||
return response.done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto vid = value->id;
|
||||
auto& pput = sPuts.puts[vid];
|
||||
pput.value = value;
|
||||
if (not pput.expireTimer) {
|
||||
auto sPuts = puts_.emplace(infoHash, SearchPuts{}).first;
|
||||
auto r = sPuts->second.puts.emplace(vid, PermanentPut{});
|
||||
auto& pput = r.first->second;
|
||||
if (r.second){
|
||||
auto &ctx = io_context();
|
||||
// cancel permanent put
|
||||
pput.expireTimer = std::make_unique<asio::steady_timer>(ctx, timeout);
|
||||
if (!pput.expireTimer)
|
||||
pput.expireTimer = std::make_unique<asio::steady_timer>(ctx, timeout);
|
||||
else
|
||||
pput.expireTimer->expires_at(timeout);
|
||||
pput.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPermamentPut, this,
|
||||
std::placeholders::_1, infoHash, vid));
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
if (not pushToken.empty()){
|
||||
pput.pushToken = pushToken;
|
||||
pput.clientId = clientId;
|
||||
pput.sessionCtx = std::make_shared<PushSessionContext>();
|
||||
pput.sessionCtx->sessionId = sessionId;
|
||||
// notify push listen expire
|
||||
bool isAndroid = platform == "android";
|
||||
auto jsonProvider = [infoHash, clientId, vid, sessionCtx = pput.sessionCtx](){
|
||||
Json::Value json;
|
||||
json["timeout"] = infoHash.toString();
|
||||
json["to"] = clientId;
|
||||
json["vid"] = std::to_string(vid);
|
||||
std::lock_guard<std::mutex> l(sessionCtx->lock);
|
||||
json["s"] = sessionCtx->sessionId;
|
||||
return json;
|
||||
};
|
||||
Json::Value json;
|
||||
json["timeout"] = infoHash.toString();
|
||||
json["to"] = clientId;
|
||||
json["vid"] = std::to_string(vid);
|
||||
if (!pput.expireNotifyTimer)
|
||||
pput.expireNotifyTimer = std::make_unique<asio::steady_timer>(ctx,
|
||||
timeout - proxy::OP_MARGIN);
|
||||
@@ -997,45 +1001,43 @@ DhtProxyServer::put(restinio::request_handle_t request,
|
||||
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
|
||||
pput.expireNotifyTimer->async_wait(std::bind(
|
||||
&DhtProxyServer::handleNotifyPushListenExpire, this,
|
||||
std::placeholders::_1, pushToken, std::move(jsonProvider), isAndroid));
|
||||
std::placeholders::_1, pushToken, json, isAndroid));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (not sessionId.empty()) {
|
||||
if (not pput.sessionCtx)
|
||||
pput.sessionCtx = std::make_shared<PushSessionContext>();
|
||||
std::lock_guard<std::mutex> l(pput.sessionCtx->lock);
|
||||
pput.sessionCtx->sessionId = sessionId;
|
||||
}
|
||||
pput.expireTimer->expires_at(timeout);
|
||||
if (pput.expireNotifyTimer)
|
||||
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
|
||||
}
|
||||
pput.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPermamentPut, this,
|
||||
std::placeholders::_1, infoHash, vid));
|
||||
}
|
||||
dht_->put(infoHash, value, [this, request, value](bool ok){
|
||||
if (ok){
|
||||
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
|
||||
response.append_body(output);
|
||||
response.done();
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_gateway()));
|
||||
auto response = initHttpResponse(request->create_response(
|
||||
restinio::status_bad_gateway()));
|
||||
response.set_body(RESP_MSG_PUT_FAILED);
|
||||
response.done();
|
||||
}
|
||||
}, time_point::max(), permanent);
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_JSON_INCORRECT);
|
||||
return response.done();
|
||||
}
|
||||
} catch (const std::exception& e){
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] error in put: %s", e.what());
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
|
||||
@@ -1049,8 +1051,15 @@ DhtProxyServer::putSigned(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (request->body().empty()){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
if (!dht_) {
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
else if (request->body().empty()){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_MISSING_PARAMS);
|
||||
return response.done();
|
||||
}
|
||||
@@ -1072,22 +1081,27 @@ DhtProxyServer::putSigned(restinio::request_handle_t request,
|
||||
response.append_body(output);
|
||||
response.done();
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_gateway()));
|
||||
auto response = initHttpResponse(request->create_response(
|
||||
restinio::status_bad_gateway()));
|
||||
response.set_body(RESP_MSG_PUT_FAILED);
|
||||
response.done();
|
||||
}
|
||||
});
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_JSON_INCORRECT);
|
||||
return response.done();
|
||||
}
|
||||
} catch (const std::exception& e){
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] error in putSigned: %s", e.what());
|
||||
return serverError(*request);
|
||||
logger_->d("[proxy:server] error in put: %s", e.what());
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
RequestStatus
|
||||
@@ -1099,8 +1113,15 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (request->body().empty()){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
else if (request->body().empty()){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_MISSING_PARAMS);
|
||||
return response.done();
|
||||
}
|
||||
@@ -1114,33 +1135,40 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request,
|
||||
if (reader->parse(char_data, char_data + request->body().size(), &root, &err)){
|
||||
InfoHash to(root["to"].asString());
|
||||
if (!to){
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_DESTINATION_NOT_FOUND);
|
||||
return response.done();
|
||||
}
|
||||
auto value = std::make_shared<Value>(root);
|
||||
dht_->putEncrypted(infoHash, to, value, [this, request, value](bool ok){
|
||||
if (ok){
|
||||
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
|
||||
auto response = initHttpResponse(request->create_response());
|
||||
response.append_body(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
|
||||
response.append_body(output);
|
||||
response.done();
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_gateway()));
|
||||
auto response = initHttpResponse(request->create_response(
|
||||
restinio::status_bad_gateway()));
|
||||
response.set_body(RESP_MSG_PUT_FAILED);
|
||||
response.done();
|
||||
}
|
||||
});
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
} else {
|
||||
auto response = initHttpResponse(request->create_response(restinio::status_bad_request()));
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_bad_request()));
|
||||
response.set_body(RESP_MSG_JSON_INCORRECT);
|
||||
return response.done();
|
||||
}
|
||||
} catch (const std::exception& e){
|
||||
if (logger_)
|
||||
logger_->d("[proxy:server] error in put: %s", e.what());
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
#endif // OPENDHT_PROXY_SERVER_IDENTITY
|
||||
@@ -1172,10 +1200,17 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request,
|
||||
if (!infoHash)
|
||||
infoHash = InfoHash::get(params["hash"].to_string());
|
||||
|
||||
if (!dht_){
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_service_unavailable()));
|
||||
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
|
||||
return response.done();
|
||||
}
|
||||
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
try {
|
||||
auto response = std::make_shared<ResponseByPartsBuilder>(
|
||||
initHttpResponse(request->create_response<ResponseByParts>()));
|
||||
response->flush();
|
||||
dht_->get(infoHash,
|
||||
[this, response](const Sp<Value>& value) {
|
||||
response->append_chunk(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
|
||||
@@ -1186,10 +1221,13 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request,
|
||||
response->done();
|
||||
},
|
||||
{}, value);
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
} catch (const std::exception& e){
|
||||
return serverError(*request);
|
||||
auto response = initHttpResponse(
|
||||
request->create_response(restinio::status_internal_server_error()));
|
||||
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
|
||||
return response.done();
|
||||
}
|
||||
return restinio::request_handling_status_t::accepted;
|
||||
}
|
||||
|
||||
}
|
||||
+118
-81
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -32,9 +32,17 @@
|
||||
#include "dht_proxy_client.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <cstring>
|
||||
#define close(x) closesocket(x)
|
||||
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
|
||||
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
|
||||
static constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
|
||||
static constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(500);
|
||||
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
|
||||
|
||||
struct DhtRunner::Listener {
|
||||
@@ -99,7 +107,7 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& con
|
||||
{
|
||||
if (running == State::Idle) {
|
||||
if (not context.sock)
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
|
||||
run(config, std::move(context));
|
||||
}
|
||||
}
|
||||
@@ -117,25 +125,20 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
logger_->d("[runner %p] state changed to Running", this);
|
||||
}
|
||||
|
||||
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
|
||||
net::PacketList ret;
|
||||
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
|
||||
while (rcv.size() > maxSize) {
|
||||
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
|
||||
if (logger_)
|
||||
logger_->e("Dropping packet: queue is full!");
|
||||
rcv.pop_front();
|
||||
rcv.pop();
|
||||
}
|
||||
|
||||
rcv.splice(rcv.end(), std::move(pkts));
|
||||
ret = std::move(rcv_free);
|
||||
rcv.emplace(std::move(pkt));
|
||||
}
|
||||
cv.notify_all();
|
||||
return ret;
|
||||
});
|
||||
|
||||
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
|
||||
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger ? *context.logger : Logger{}));
|
||||
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
|
||||
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
@@ -143,7 +146,7 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
#endif
|
||||
enableProxy(not config.proxy_server.empty());
|
||||
if (context.logger and dht_via_proxy_) {
|
||||
dht_via_proxy_->setLogger(context.logger);
|
||||
dht_via_proxy_->setLogger(*context.logger);
|
||||
}
|
||||
if (context.statusChangedCallback) {
|
||||
statusCb = std::move(context.statusChangedCallback);
|
||||
@@ -174,7 +177,7 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
if (not pending_ops_prio.empty())
|
||||
return true;
|
||||
auto s = getStatus();
|
||||
if (not pending_ops.empty() and (s == NodeStatus::Connected or s == NodeStatus::Disconnected))
|
||||
if (not pending_ops.empty() and (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -212,13 +215,13 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
adc.net = netId;
|
||||
adc.nodeId = dht_->getNodeId();
|
||||
// IPv4
|
||||
if (const auto& bound4 = dht_->getSocket()->getBoundRef(AF_INET)) {
|
||||
if (auto bound4 = dht_->getSocket()->getBound(AF_INET)) {
|
||||
adc.port = bound4.getPort();
|
||||
msgpack::pack(sbuf_node, adc);
|
||||
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
|
||||
}
|
||||
// IPv6
|
||||
if (const auto& bound6 = dht_->getSocket()->getBoundRef(AF_INET6)) {
|
||||
if (auto bound6 = dht_->getSocket()->getBound(AF_INET6)) {
|
||||
adc.port = bound6.getPort();
|
||||
sbuf_node.clear();
|
||||
msgpack::pack(sbuf_node, adc);
|
||||
@@ -300,6 +303,7 @@ DhtRunner::join()
|
||||
if (running.exchange(State::Idle) == State::Idle)
|
||||
return;
|
||||
cv.notify_all();
|
||||
bootstrap_cv.notify_all();
|
||||
#ifdef OPENDHT_PEER_DISCOVERY
|
||||
if (peerDiscovery_)
|
||||
peerDiscovery_->stop();
|
||||
@@ -314,6 +318,9 @@ DhtRunner::join()
|
||||
if (dht_thread.joinable())
|
||||
dht_thread.join();
|
||||
|
||||
if (bootstrap_thread.joinable())
|
||||
bootstrap_thread.join();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops = decltype(pending_ops)();
|
||||
@@ -403,9 +410,8 @@ DhtRunner::exportValues() const {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLogger(const Sp<Logger>& logger) {
|
||||
DhtRunner::setLogger(const Logger& logger) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
logger_ = logger;
|
||||
if (dht_)
|
||||
dht_->setLogger(logger);
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
@@ -423,6 +429,7 @@ DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
|
||||
void
|
||||
DhtRunner::setLogFilter(const InfoHash& f) {
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
activeDht()->setLogFilter(f);
|
||||
if (dht_)
|
||||
dht_->setLogFilter(f);
|
||||
#ifdef OPENDHT_PROXY_CLIENT
|
||||
@@ -480,25 +487,6 @@ DhtRunner::getNodeInfo() const {
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ongoing_ops++;
|
||||
pending_ops_prio.emplace([cb = std::move(cb), this](SecureDht& dht){
|
||||
auto sinfo = std::make_shared<NodeInfo>();
|
||||
auto& info = *sinfo;
|
||||
info.id = dht.getId();
|
||||
info.node_id = dht.getNodeId();
|
||||
info.ipv4 = dht.getNodesStats(AF_INET);
|
||||
info.ipv6 = dht.getNodesStats(AF_INET6);
|
||||
info.ongoing_ops = ongoing_ops;
|
||||
cb(std::move(sinfo));
|
||||
opEnded();
|
||||
});
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
std::vector<unsigned>
|
||||
DhtRunner::getNodeMessageStats(bool in) const
|
||||
{
|
||||
@@ -580,7 +568,7 @@ DhtRunner::loop_()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
auto s = getStatus();
|
||||
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or s == NodeStatus::Disconnected)) ?
|
||||
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or (s == NodeStatus::Disconnected and not bootstraping))) ?
|
||||
std::move(pending_ops) : std::move(pending_ops_prio);
|
||||
}
|
||||
while (not ops.empty()) {
|
||||
@@ -590,7 +578,6 @@ DhtRunner::loop_()
|
||||
|
||||
time_point wakeup {};
|
||||
decltype(rcv) received {};
|
||||
decltype(rcv) received_treated {};
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
// move to stack
|
||||
@@ -600,46 +587,45 @@ DhtRunner::loop_()
|
||||
// Discard old packets
|
||||
size_t dropped {0};
|
||||
if (not received.empty()) {
|
||||
auto limit = clock::now() - net::RX_QUEUE_MAX_DELAY;
|
||||
auto it = received.begin();
|
||||
while (it != received.end() and it->received < limit) {
|
||||
it->data.clear();
|
||||
++it;
|
||||
auto now = clock::now();
|
||||
while (not received.empty() and now - received.front()->received > RX_QUEUE_MAX_DELAY) {
|
||||
received.pop();
|
||||
dropped++;
|
||||
}
|
||||
received_treated.splice(received_treated.end(), received, received.begin(), it);
|
||||
}
|
||||
|
||||
// Handle packets
|
||||
if (not received.empty()) {
|
||||
for (auto& pkt : received) {
|
||||
auto now = clock::now();
|
||||
if (now - pkt.received > net::RX_QUEUE_MAX_DELAY)
|
||||
while (not received.empty()) {
|
||||
auto& pck = received.front();
|
||||
if (clock::now() - pck->received > RX_QUEUE_MAX_DELAY)
|
||||
dropped++;
|
||||
else
|
||||
wakeup = dht->periodic(pkt.data.data(), pkt.data.size(), std::move(pkt.from), now);
|
||||
pkt.data.clear();
|
||||
wakeup = dht->periodic(pck->data.data(), pck->data.size(), std::move(pck->from));
|
||||
received.pop();
|
||||
}
|
||||
received_treated.splice(received_treated.end(), std::move(received));
|
||||
} else {
|
||||
// Or just run the scheduler
|
||||
wakeup = dht->periodic(nullptr, 0, nullptr, 0, clock::now());
|
||||
}
|
||||
|
||||
if (not received_treated.empty()) {
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
if (rcv_free.size() < net::RX_QUEUE_MAX_SIZE)
|
||||
rcv_free.splice(rcv_free.end(), std::move(received_treated));
|
||||
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
if (dropped)
|
||||
std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl;
|
||||
|
||||
NodeStatus nstatus4 = dht->updateStatus(AF_INET);
|
||||
NodeStatus nstatus6 = dht->updateStatus(AF_INET6);
|
||||
NodeStatus nstatus4 = dht->getStatus(AF_INET);
|
||||
NodeStatus nstatus6 = dht->getStatus(AF_INET6);
|
||||
if (nstatus4 != status4 || nstatus6 != status6) {
|
||||
status4 = nstatus4;
|
||||
status6 = nstatus6;
|
||||
if (status4 == NodeStatus::Disconnected and status6 == NodeStatus::Disconnected) {
|
||||
// We have lost connection with the DHT. Try to recover using bootstrap nodes.
|
||||
std::unique_lock<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes = bootstrap_nodes_all;
|
||||
tryBootstrapContinuously();
|
||||
} else {
|
||||
std::unique_lock<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes.clear();
|
||||
}
|
||||
if (statusCb)
|
||||
statusCb(status4, status6);
|
||||
}
|
||||
@@ -886,34 +872,89 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
|
||||
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb), permanent);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::tryBootstrapContinuously()
|
||||
{
|
||||
if (bootstrap_thread.joinable()) {
|
||||
if (bootstraping)
|
||||
return; // already running
|
||||
else
|
||||
bootstrap_thread.join();
|
||||
}
|
||||
bootstraping = true;
|
||||
bootstrap_thread = std::thread([this]() {
|
||||
auto next = clock::now();
|
||||
do {
|
||||
decltype(bootstrap_nodes) nodes;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
nodes = bootstrap_nodes;
|
||||
}
|
||||
|
||||
next += BOOTSTRAP_PERIOD;
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::unique_lock<std::mutex> blck(mtx);
|
||||
unsigned ping_count(0);
|
||||
// Reverse: try last inserted bootstrap nodes first
|
||||
for (auto it = nodes.rbegin(); it != nodes.rend(); it++) {
|
||||
++ping_count;
|
||||
try {
|
||||
bootstrap(SockAddr::resolve(it->first, it->second), [&](bool) {
|
||||
if (running != State::Running)
|
||||
return;
|
||||
{
|
||||
std::unique_lock<std::mutex> blck(mtx);
|
||||
--ping_count;
|
||||
}
|
||||
bootstrap_cv.notify_all();
|
||||
});
|
||||
} catch (std::invalid_argument& e) {
|
||||
--ping_count;
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
// wait at least until the next BOOTSTRAP_PERIOD
|
||||
bootstrap_cv.wait_until(blck, next, [&]() { return running != State::Running; });
|
||||
// wait for bootstrap requests to end.
|
||||
if (running != State::Running)
|
||||
bootstrap_cv.wait(blck, [&]() { return running != State::Running or ping_count == 0; });
|
||||
}
|
||||
// update state
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
bootstraping = running == State::Running and
|
||||
status4 == NodeStatus::Disconnected and
|
||||
status6 == NodeStatus::Disconnected;
|
||||
}
|
||||
} while (bootstraping);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const std::string& host, const std::string& service)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([host, service] (SecureDht& dht) mutable {
|
||||
dht.addBootstrap(host, service);
|
||||
});
|
||||
cv.notify_all();
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes_all.emplace_back(host, service);
|
||||
bootstrap_nodes.emplace_back(host, service);
|
||||
tryBootstrapContinuously();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::bootstrap(const std::string& hostService)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([host_service = splitPort(hostService)] (SecureDht& dht) mutable {
|
||||
dht.addBootstrap(host_service.first, host_service.second);
|
||||
});
|
||||
cv.notify_all();
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
auto host_service = splitPort(hostService);
|
||||
bootstrap_nodes_all.emplace_back(host_service.first, host_service.second);
|
||||
bootstrap_nodes.emplace_back(std::move(host_service.first), std::move(host_service.second));
|
||||
tryBootstrapContinuously();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::clearBootstrap()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([] (SecureDht& dht) mutable {
|
||||
dht.clearBootstrap();
|
||||
});
|
||||
cv.notify_all();
|
||||
std::lock_guard<std::mutex> lck(bootstrap_mtx);
|
||||
bootstrap_nodes_all.clear();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -992,10 +1033,6 @@ DhtRunner::connectivityChanged()
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht& dht) {
|
||||
dht.connectivityChanged();
|
||||
#ifdef OPENDHT_PEER_DISCOVERY
|
||||
if (peerDiscovery_)
|
||||
peerDiscovery_->connectivityChanged();
|
||||
#endif
|
||||
});
|
||||
cv.notify_all();
|
||||
}
|
||||
@@ -1078,11 +1115,11 @@ DhtRunner::enableProxy(bool proxify)
|
||||
},
|
||||
config_.proxy_server, config_.push_node_id, logger_)
|
||||
);
|
||||
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
|
||||
#ifdef OPENDHT_PUSH_NOTIFICATIONS
|
||||
if (not config_.push_token.empty())
|
||||
dht_via_proxy->setPushNotificationToken(config_.push_token);
|
||||
dht_via_proxy_->setPushNotificationToken(config_.push_token);
|
||||
#endif
|
||||
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
|
||||
// add current listeners
|
||||
for (auto& l: listeners_)
|
||||
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
|
||||
|
||||
+23
-78
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -31,7 +31,6 @@ namespace http {
|
||||
|
||||
constexpr char HTTP_HEADER_CONTENT_TYPE_JSON[] = "application/json";
|
||||
constexpr char HTTP_HEADER_DELIM[] = "\r\n\r\n";
|
||||
constexpr unsigned MAX_REDIRECTS {5};
|
||||
|
||||
Url::Url(const std::string& url): url(url)
|
||||
{
|
||||
@@ -131,7 +130,6 @@ Connection::~Connection() {
|
||||
void
|
||||
Connection::close()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
asio::error_code ec;
|
||||
if (ssl_socket_) {
|
||||
if (ssl_socket_->is_open())
|
||||
@@ -162,7 +160,6 @@ Connection::is_ssl() const
|
||||
void
|
||||
Connection::set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ssl_socket_ and verify_mode != asio::ssl::verify_none) {
|
||||
ssl_socket_->asio_ssl_stream().set_verify_mode(verify_mode);
|
||||
ssl_socket_->asio_ssl_stream().set_verify_callback([
|
||||
@@ -195,7 +192,6 @@ Connection::input()
|
||||
std::string
|
||||
Connection::read_bytes(size_t bytes)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (bytes == 0)
|
||||
bytes = read_buf_.in_avail();
|
||||
std::string content;
|
||||
@@ -216,7 +212,6 @@ Connection::read_until(const char delim)
|
||||
void
|
||||
Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ssl_socket_)
|
||||
asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(cb)));
|
||||
else if (socket_)
|
||||
@@ -228,7 +223,6 @@ Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, Conn
|
||||
void
|
||||
Connection::async_handshake(HandlerCb cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ssl_socket_) {
|
||||
std::weak_ptr<Connection> wthis = shared_from_this();
|
||||
ssl_socket_->async_handshake(asio::ssl::stream<asio::ip::tcp::socket>::client,
|
||||
@@ -260,61 +254,44 @@ Connection::async_handshake(HandlerCb cb)
|
||||
void
|
||||
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); });
|
||||
return;
|
||||
}
|
||||
if (!is_open()) return;
|
||||
if (ssl_socket_) asio::async_write(*ssl_socket_, write_buf_, wrapCallabck(std::move(cb)));
|
||||
else if (socket_) asio::async_write(*socket_, write_buf_, wrapCallabck(std::move(cb)));
|
||||
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
|
||||
else if (cb) cb(asio::error::operation_aborted, 0);
|
||||
}
|
||||
|
||||
void
|
||||
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); });
|
||||
return;
|
||||
}
|
||||
if (!is_open()) return;
|
||||
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
|
||||
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
|
||||
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
|
||||
else if (cb) cb(asio::error::operation_aborted, 0);
|
||||
}
|
||||
|
||||
void
|
||||
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); });
|
||||
return;
|
||||
}
|
||||
if (!is_open()) return;
|
||||
if (ssl_socket_) asio::async_read_until(*ssl_socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
|
||||
else if (socket_) asio::async_read_until(*socket_, read_buf_, delim, wrapCallabck(std::move(cb)));
|
||||
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
|
||||
else if (cb) cb(asio::error::operation_aborted, 0);
|
||||
}
|
||||
|
||||
void
|
||||
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); });
|
||||
return;
|
||||
}
|
||||
if (!is_open()) return;
|
||||
if (ssl_socket_) asio::async_read(*ssl_socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallabck(std::move(cb)));
|
||||
else if (socket_) asio::async_read(*socket_, read_buf_, asio::transfer_exactly(bytes), wrapCallabck(std::move(cb)));
|
||||
else if (cb) ctx_.post([cb](){ cb(asio::error::operation_aborted, 0); });
|
||||
else if (cb) cb(asio::error::operation_aborted, 0);
|
||||
}
|
||||
|
||||
void
|
||||
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) cb(asio::error::operation_aborted, 0);
|
||||
return;
|
||||
}
|
||||
auto buf = read_buf_.prepare(bytes);
|
||||
@@ -527,7 +504,7 @@ Request::Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, cons
|
||||
: logger_(resolver->getLogger()), id_(Request::ids_++), ctx_(ctx), family_(family), resolver_(resolver)
|
||||
{
|
||||
set_header_field(restinio::http_field_t::host, get_url().host + ":" + get_url().service);
|
||||
set_target(Url(target).target);
|
||||
set_target(target);
|
||||
}
|
||||
|
||||
Request::~Request()
|
||||
@@ -695,8 +672,6 @@ Request::notify_state_change(State state) {
|
||||
void
|
||||
Request::init_parser()
|
||||
{
|
||||
response_.request = shared_from_this();
|
||||
|
||||
if (!parser_)
|
||||
parser_ = std::make_unique<http_parser>();
|
||||
http_parser_init(parser_.get(), HTTP_RESPONSE);
|
||||
@@ -779,7 +754,6 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb)
|
||||
if (not sthis)
|
||||
return;
|
||||
auto& this_ = *sthis;
|
||||
std::lock_guard<std::mutex> lock(this_.mutex_);
|
||||
if (ec == asio::error::operation_aborted){
|
||||
this_.terminate(ec);
|
||||
return;
|
||||
@@ -836,7 +810,6 @@ Request::send()
|
||||
std::vector<asio::ip::tcp::endpoint> endpoints) {
|
||||
if (auto sthis = wthis.lock()) {
|
||||
auto& this_ = *sthis;
|
||||
std::lock_guard<std::mutex> lock(this_.mutex_);
|
||||
if (ec){
|
||||
if (this_.logger_)
|
||||
this_.logger_->e("[http:request:%i] resolve error: %s", this_.id_, ec.message().c_str());
|
||||
@@ -909,7 +882,6 @@ Request::terminate(const asio::error_code& ec)
|
||||
void
|
||||
Request::handle_request(const asio::error_code& ec)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ec and ec != asio::error::eof){
|
||||
terminate(ec);
|
||||
return;
|
||||
@@ -933,7 +905,6 @@ Request::handle_request(const asio::error_code& ec)
|
||||
void
|
||||
Request::handle_response(const asio::error_code& ec, size_t n_bytes)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (ec && ec != asio::error::eof){
|
||||
terminate(ec);
|
||||
return;
|
||||
@@ -977,44 +948,18 @@ void
|
||||
Request::onHeadersComplete() {
|
||||
notify_state_change(State::HEADER_RECEIVED);
|
||||
|
||||
if (response_.status_code == restinio::status_code::moved_permanently.raw_code() or
|
||||
response_.status_code == restinio::status_code::found.raw_code())
|
||||
{
|
||||
auto location_it = response_.headers.find(restinio::field_to_string(restinio::http_field_t::location));
|
||||
if (location_it == response_.headers.end()){
|
||||
if (logger_)
|
||||
logger_->e("[http:client] [request:%i] got redirect without location", id_);
|
||||
terminate(asio::error::connection_aborted);
|
||||
}
|
||||
|
||||
if (follow_redirect and num_redirect < MAX_REDIRECTS) {
|
||||
auto next = std::make_shared<Request>(ctx_, location_it->second, logger_);
|
||||
next->set_method(header_.method());
|
||||
next->headers_ = std::move(headers_);
|
||||
next->body_ = std::move(body_);
|
||||
next->cbs_ = std::move(cbs_);
|
||||
next->num_redirect = num_redirect + 1;
|
||||
next_ = next;
|
||||
next->prev_ = shared_from_this();
|
||||
next->send();
|
||||
} else {
|
||||
if (logger_)
|
||||
logger_->e("[http:client] [request:%i] got redirect without location", id_);
|
||||
terminate(asio::error::connection_aborted);
|
||||
}
|
||||
} else {
|
||||
auto expect_it = headers_.find(restinio::http_field_t::expect);
|
||||
if (expect_it != headers_.end() and (expect_it->second == "100-continue") and response_.status_code != 200){
|
||||
notify_state_change(State::SENDING);
|
||||
request_.append(body_);
|
||||
std::ostream request_stream(&conn_->input());
|
||||
request_stream << body_ << "\r\n";
|
||||
std::weak_ptr<Request> wthis = shared_from_this();
|
||||
conn_->async_write([wthis](const asio::error_code& ec, size_t) {
|
||||
if (auto sthis = wthis.lock())
|
||||
sthis->handle_request(ec);
|
||||
});
|
||||
}
|
||||
auto expect_it = headers_.find(restinio::http_field_t::expect);
|
||||
if (expect_it != headers_.end() and (expect_it->second == "100-continue") and response_.status_code != 200){
|
||||
notify_state_change(State::SENDING);
|
||||
request_.append(body_);
|
||||
std::ostream request_stream(&conn_->input());
|
||||
request_stream << body_ << "\r\n";
|
||||
std::weak_ptr<Request> wthis = shared_from_this();
|
||||
conn_->async_write([wthis](const asio::error_code& ec, size_t) {
|
||||
if (auto sthis = wthis.lock())
|
||||
sthis->handle_request(ec);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -115,22 +115,22 @@ getSyslogLogger(const char* name) {
|
||||
|
||||
void
|
||||
enableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLogger(getStdLogger());
|
||||
dht.setLogger(*getStdLogger());
|
||||
}
|
||||
|
||||
void
|
||||
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
|
||||
dht.setLogger(getFileLogger(path));
|
||||
dht.setLogger(*getFileLogger(path));
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC void
|
||||
enableSyslog(dht::DhtRunner &dht, const char* name) {
|
||||
dht.setLogger(getSyslogLogger(name));
|
||||
dht.setLogger(*getSyslogLogger(name));
|
||||
}
|
||||
|
||||
void
|
||||
disableLogging(dht::DhtRunner &dht) {
|
||||
dht.setLogger();
|
||||
dht.setLogger({});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+57
-100
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
const std::string DhtProtocolException::GET_NO_INFOHASH {"Get_values with no info_hash"};
|
||||
const std::string DhtProtocolException::LISTEN_NO_INFOHASH {"Listen with no info_hash"};
|
||||
@@ -99,15 +98,11 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
|
||||
nodes6(std::move(msg.nodes6))
|
||||
{}
|
||||
|
||||
NetworkEngine::NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
|
||||
: myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler)
|
||||
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
|
||||
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), rate_limiter((size_t)-1), scheduler(scheduler)
|
||||
{}
|
||||
|
||||
NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
|
||||
std::unique_ptr<DatagramSocket>&& sock,
|
||||
const Sp<Logger>& log,
|
||||
std::mt19937_64& rand,
|
||||
Scheduler& scheduler,
|
||||
NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
|
||||
decltype(NetworkEngine::onError)&& onError,
|
||||
decltype(NetworkEngine::onNewNode)&& onNewNode,
|
||||
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
|
||||
@@ -126,8 +121,7 @@ NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
|
||||
onListen(std::move(onListen)),
|
||||
onAnnounce(std::move(onAnnounce)),
|
||||
onRefresh(std::move(onRefresh)),
|
||||
myid(myid), config(c), dht_socket(std::move(sock)), logger_(log), rd(rand),
|
||||
cache(rd),
|
||||
myid(myid), config(c), dht_socket(std::move(sock)), DHT_LOG(log),
|
||||
rate_limiter(config.max_req_per_sec),
|
||||
scheduler(scheduler)
|
||||
{}
|
||||
@@ -146,8 +140,7 @@ NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash,
|
||||
try {
|
||||
sendNodesValues(node->getAddr(), socket_id, nnodes.first, nnodes.second, values, query, ntoken);
|
||||
} catch (const std::overflow_error& e) {
|
||||
if (logger_)
|
||||
logger_->e("Can't send value: buffer not large enough !");
|
||||
DHT_LOG.e("Can't send value: buffer not large enough !");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +160,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
|
||||
if (not values.empty()) {
|
||||
pk.pack(KEY_REQ_REFRESHED);
|
||||
pk.pack(values);
|
||||
if (logger_)
|
||||
logger_->d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
|
||||
DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
|
||||
}
|
||||
|
||||
pk.pack(KEY_TID); pk.pack(socket_id);
|
||||
@@ -198,8 +190,7 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
|
||||
if (not values.empty()) {
|
||||
pk.pack(KEY_REQ_EXPIRED);
|
||||
pk.pack(values);
|
||||
if (logger_)
|
||||
logger_->d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
|
||||
DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
|
||||
}
|
||||
|
||||
pk.pack(KEY_TID); pk.pack(socket_id);
|
||||
@@ -255,8 +246,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
|
||||
auto now = scheduler.time();
|
||||
auto& node = *req.node;
|
||||
if (req.isExpired(now)) {
|
||||
// if (logger_)
|
||||
// logger_->d(node.id, "[node %s] expired !", node.toString().c_str());
|
||||
// DHT_LOG.d(node.id, "[node %s] expired !", node.toString().c_str());
|
||||
node.setExpired();
|
||||
if (not node.id)
|
||||
requests.erase(req.tid);
|
||||
@@ -276,17 +266,12 @@ NetworkEngine::requestStep(Sp<Request> sreq)
|
||||
if (not node.id)
|
||||
requests.erase(req.tid);
|
||||
} else {
|
||||
req.last_try = now;
|
||||
if (err != EAGAIN) {
|
||||
++req.attempt_count;
|
||||
req.attempt_duration +=
|
||||
req.attempt_duration + uniform_duration_distribution<>(0ms, ((duration)Node::MAX_RESPONSE_TIME)/4)(rd);
|
||||
if (not req.parts.empty()){
|
||||
sendValueParts(req.tid, req.parts, node.getAddr());
|
||||
}
|
||||
}
|
||||
req.last_try = now;
|
||||
std::weak_ptr<Request> wreq = sreq;
|
||||
scheduler.add(req.last_try + req.attempt_duration, [this,wreq] {
|
||||
scheduler.add(req.last_try + Node::MAX_RESPONSE_TIME, [this,wreq] {
|
||||
if (auto req = wreq.lock())
|
||||
requestStep(req);
|
||||
});
|
||||
@@ -381,14 +366,12 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
{
|
||||
auto from = f.getMappedIPv4();
|
||||
if (isMartian(from)) {
|
||||
if (logger_)
|
||||
logger_->w("Received packet from martian node %s", from.toString().c_str());
|
||||
DHT_LOG.w("Received packet from martian node %s", from.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNodeBlacklisted(from)) {
|
||||
if (logger_)
|
||||
logger_->w("Received packet from blacklisted node %s", from.toString().c_str());
|
||||
DHT_LOG.w("Received packet from blacklisted node %s", from.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -397,16 +380,13 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
msgpack::unpacked msg_res = msgpack::unpack((const char*)buf, buflen);
|
||||
msg->msgpack_unpack(msg_res.get());
|
||||
} catch (const std::exception& e) {
|
||||
if (logger_)
|
||||
logger_->w("Can't parse message of size %lu: %s", buflen, e.what());
|
||||
// if (logger_)
|
||||
// logger_->DBG.logPrintable(buf, buflen);
|
||||
DHT_LOG.w("Can't parse message of size %lu: %s", buflen, e.what());
|
||||
//DHT_LOG.DBG.logPrintable(buf, buflen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->network != config.network) {
|
||||
if (logger_)
|
||||
logger_->d("Received message from other config.network %u", msg->network);
|
||||
DHT_LOG.d("Received message from other config.network %u", msg->network);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -417,14 +397,12 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
auto pmsg_it = partial_messages.find(msg->tid);
|
||||
if (pmsg_it == partial_messages.end()) {
|
||||
if (logIncoming_)
|
||||
if (logger_)
|
||||
logger_->d("Can't find partial message");
|
||||
DHT_LOG.d("Can't find partial message");
|
||||
rateLimit(from);
|
||||
return;
|
||||
}
|
||||
if (!pmsg_it->second.from.equals(from)) {
|
||||
if (logger_)
|
||||
logger_->d("Received partial message data from unexpected IP address");
|
||||
DHT_LOG.d("Received partial message data from unexpected IP address");
|
||||
rateLimit(from);
|
||||
return;
|
||||
}
|
||||
@@ -443,16 +421,14 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
}
|
||||
|
||||
if (msg->id == myid or not msg->id) {
|
||||
if (logger_)
|
||||
logger_->d("Received message from self");
|
||||
DHT_LOG.d("Received message from self");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->type > MessageType::Reply) {
|
||||
/* Rate limit requests. */
|
||||
if (!rateLimit(from)) {
|
||||
if (logger_)
|
||||
logger_->w("Dropping request due to rate limiting");
|
||||
DHT_LOG.w("Dropping request due to rate limiting");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -471,8 +447,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
|
||||
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
|
||||
} else
|
||||
if (logger_)
|
||||
logger_->e("Partial message with given TID already exists");
|
||||
DHT_LOG.e("Partial message with given TID already exists");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,8 +481,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
node->received(now, req);
|
||||
if (not node->isClient())
|
||||
onNewNode(node, 1);
|
||||
if (logger_)
|
||||
logger_->d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
|
||||
DHT_LOG.d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -519,8 +493,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
onReportedAddr(msg->id, msg->addr);
|
||||
|
||||
if (req and (req->cancelled() or req->expired() or req->completed())) {
|
||||
if (logger_)
|
||||
logger_->w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
|
||||
DHT_LOG.w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -536,8 +509,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
onError(req, DhtProtocolException {msg->error_code});
|
||||
} else {
|
||||
if (logIncoming_)
|
||||
if (logger_)
|
||||
logger_->w(msg->id, "[node %s %s] received unknown error message %u",
|
||||
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
|
||||
msg->id.toString().c_str(), from.toString().c_str(), msg->error_code);
|
||||
}
|
||||
break;
|
||||
@@ -569,14 +541,12 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
case MessageType::Ping:
|
||||
++in_stats.ping;
|
||||
if (logIncoming_)
|
||||
if (logger_)
|
||||
logger_->d(node->id, "[node %s] sending pong", node->toString().c_str());
|
||||
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
|
||||
onPing(node);
|
||||
sendPong(from, msg->tid);
|
||||
break;
|
||||
case MessageType::FindNode: {
|
||||
// if (logger_)
|
||||
// logger_->d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
|
||||
//DHT_LOG.d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
|
||||
++in_stats.find;
|
||||
RequestAnswer answer = onFindNode(node, msg->target, msg->want);
|
||||
auto nnodes = bufferNodes(from.getFamily(), msg->target, msg->want, answer.nodes4, answer.nodes6);
|
||||
@@ -584,8 +554,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
case MessageType::GetValues: {
|
||||
// if (logger_)
|
||||
// logger_->d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
//DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
++in_stats.get;
|
||||
RequestAnswer answer = onGetValues(node, msg->info_hash, msg->want, msg->query);
|
||||
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
|
||||
@@ -593,8 +562,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
case MessageType::AnnounceValue: {
|
||||
if (logIncoming_ and logger_)
|
||||
logger_->d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
++in_stats.put;
|
||||
onAnnounce(node, msg->info_hash, msg->token, msg->values, msg->created);
|
||||
|
||||
@@ -607,15 +576,15 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
case MessageType::Refresh:
|
||||
if (logIncoming_ and logger_)
|
||||
logger_->d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
onRefresh(node, msg->info_hash, msg->token, msg->value_id);
|
||||
/* Same note as above in MessageType::AnnounceValue applies. */
|
||||
sendValueAnnounced(from, msg->tid, msg->value_id);
|
||||
break;
|
||||
case MessageType::Listen: {
|
||||
if (logIncoming_ and logger_)
|
||||
logger_->d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
if (logIncoming_)
|
||||
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
|
||||
++in_stats.listen;
|
||||
RequestAnswer answer = onListen(node, msg->info_hash, msg->token, msg->socket_id, std::move(msg->query));
|
||||
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
|
||||
@@ -626,8 +595,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
|
||||
break;
|
||||
}
|
||||
} catch (const std::overflow_error& e) {
|
||||
if (logger_)
|
||||
logger_->e("Can't send value: buffer not large enough !");
|
||||
DHT_LOG.e("Can't send value: buffer not large enough !");
|
||||
} catch (DhtProtocolException& e) {
|
||||
sendError(from, msg->tid, e.getCode(), e.getMsg().c_str(), true);
|
||||
}
|
||||
@@ -674,8 +642,7 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
|
||||
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
|
||||
Blob(buffer.data(), buffer.data() + buffer.size()),
|
||||
[=](const Request& req_status, ParsedMessage&&) {
|
||||
if (logger_)
|
||||
logger_->d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
|
||||
DHT_LOG.d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
|
||||
if (on_done) {
|
||||
on_done(req_status, {});
|
||||
}
|
||||
@@ -767,27 +734,22 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(config.network?1:0));
|
||||
|
||||
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
|
||||
unsigned sendWant = (want > 0) ? 1 : 0;
|
||||
|
||||
pk.pack(KEY_A); pk.pack_map(2 + sendQuery + sendWant);
|
||||
pk.pack(KEY_A); pk.pack_map(2 +
|
||||
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
|
||||
(want>0?1:0));
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(info_hash);
|
||||
if (sendQuery) {
|
||||
pk.pack(KEY_Q); pk.pack(query);
|
||||
}
|
||||
if (sendWant) {
|
||||
pk.pack(KEY_REQ_WANT);
|
||||
unsigned sendWant4 = (want & WANT4) ? 1 : 0;
|
||||
unsigned sendWant6 = (want & WANT6) ? 1 : 0;
|
||||
pk.pack_array(sendWant4 + sendWant6);
|
||||
if (sendWant4) pk.pack(AF_INET);
|
||||
if (sendWant6) pk.pack(AF_INET6);
|
||||
}
|
||||
pk.pack(KEY_Q); pk.pack(query);
|
||||
if (want > 0) {
|
||||
pk.pack(KEY_REQ_WANT);
|
||||
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
|
||||
if (want & WANT4) pk.pack(AF_INET);
|
||||
if (want & WANT6) pk.pack(AF_INET6);
|
||||
}
|
||||
|
||||
pk.pack(KEY_Q); pk.pack(QUERY_GET);
|
||||
pk.pack(KEY_TID); pk.pack_bin(tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack_bin_body((const char*)tid.data(), tid.size());
|
||||
pk.pack(KEY_Y); pk.pack(KEY_Q);
|
||||
pk.pack(KEY_UA); pk.pack(my_v);
|
||||
if (config.network) {
|
||||
@@ -885,8 +847,7 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
|
||||
if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
|
||||
for (const auto& b : svals)
|
||||
buffer.write((const char*)b.data(), b.size());
|
||||
// if (logger_)
|
||||
// logger_->d("sending %lu bytes of values", total_size);
|
||||
// DHT_LOG.d("sending %lu bytes of values", total_size);
|
||||
svals.clear();
|
||||
} else {
|
||||
for (const auto& b : svals)
|
||||
@@ -952,10 +913,10 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
|
||||
}
|
||||
std::vector<Blob> svals {};
|
||||
if (not st.empty()) { /* pack complete values */
|
||||
if (query.select.empty()) {
|
||||
auto fields = query.select.getSelection();
|
||||
if (fields.empty()) {
|
||||
svals = packValueHeader(buffer, st);
|
||||
} else { /* pack fields */
|
||||
auto fields = query.select.getSelection();
|
||||
pk.pack(KEY_REQ_FIELDS);
|
||||
pk.pack_map(2);
|
||||
pk.pack(std::string("f")); pk.pack(fields);
|
||||
@@ -1050,14 +1011,12 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
socket = previous->getSocket();
|
||||
} else {
|
||||
if (previous)
|
||||
if (logger_)
|
||||
logger_->e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
|
||||
DHT_LOG.e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
|
||||
socket = n->openSocket(std::move(socket_cb));
|
||||
}
|
||||
|
||||
if (not socket) {
|
||||
if (logger_)
|
||||
logger_->e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
|
||||
DHT_LOG.e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
|
||||
return {};
|
||||
}
|
||||
TransId sid(socket);
|
||||
@@ -1066,7 +1025,7 @@ NetworkEngine::sendListen(Sp<Node> n,
|
||||
msgpack::packer<msgpack::sbuffer> pk(&buffer);
|
||||
pk.pack_map(5+(config.network?1:0));
|
||||
|
||||
auto has_query = not query.where.empty() or not query.select.empty();
|
||||
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
|
||||
pk.pack(KEY_A); pk.pack_map(4 + has_query);
|
||||
pk.pack(KEY_REQ_ID); pk.pack(myid);
|
||||
pk.pack(KEY_REQ_H); pk.pack(hash);
|
||||
@@ -1162,8 +1121,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
|
||||
Blob(buffer.data(), buffer.data() + buffer.size()),
|
||||
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
|
||||
if (msg.value_id == Value::INVALID_ID) {
|
||||
if (logger_)
|
||||
logger_->d(infohash, "Unknown search or announce!");
|
||||
DHT_LOG.d(infohash, "Unknown search or announce!");
|
||||
} else {
|
||||
if (on_done) {
|
||||
RequestAnswer answer {};
|
||||
@@ -1178,8 +1136,9 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
|
||||
}
|
||||
}
|
||||
);
|
||||
req->parts = std::move(v);
|
||||
sendRequest(req);
|
||||
if (not v.empty())
|
||||
sendValueParts(tid, v, n->getAddr());
|
||||
++out_stats.put;
|
||||
return req;
|
||||
}
|
||||
@@ -1216,8 +1175,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
|
||||
Blob(buffer.data(), buffer.data() + buffer.size()),
|
||||
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
|
||||
if (msg.value_id == Value::INVALID_ID) {
|
||||
if (logger_)
|
||||
logger_->d(infohash, "Unknown search or announce!");
|
||||
DHT_LOG.d(infohash, "Unknown search or announce!");
|
||||
} else {
|
||||
if (on_done) {
|
||||
RequestAnswer answer {};
|
||||
@@ -1300,8 +1258,7 @@ NetworkEngine::maintainRxBuffer(Tid tid)
|
||||
const auto& now = scheduler.time();
|
||||
if (msg->second.start + RX_MAX_PACKET_TIME < now
|
||||
|| msg->second.last_part + RX_TIMEOUT < now) {
|
||||
if (logger_)
|
||||
logger_->w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
|
||||
DHT_LOG.w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
|
||||
partial_messages.erase(msg);
|
||||
}
|
||||
}
|
||||
|
||||
+43
-63
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -106,7 +106,7 @@ void udpPipe(int fds[2])
|
||||
}
|
||||
#endif
|
||||
|
||||
UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(l) {
|
||||
UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
|
||||
SockAddr bind4;
|
||||
bind4.setFamily(AF_INET);
|
||||
bind4.setPort(port);
|
||||
@@ -117,7 +117,7 @@ UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(
|
||||
openSockets(bind4, bind6);
|
||||
}
|
||||
|
||||
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l) : logger(l)
|
||||
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
openSockets(bind4, bind6);
|
||||
@@ -155,8 +155,7 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
|
||||
|
||||
if (sendto(s, (const char*)data, size, flags, dest.get(), dest.getLength()) == -1) {
|
||||
int err = errno;
|
||||
if (logger)
|
||||
logger->d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
|
||||
logger.d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
|
||||
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
auto bind4 = std::move(bound4), bind6 = std::move(bound6);
|
||||
@@ -195,8 +194,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
try {
|
||||
s4 = bindSocket(bind4, bound4);
|
||||
} catch (const DhtException& e) {
|
||||
if (logger)
|
||||
logger->e("Can't bind inet socket: %s", e.what());
|
||||
logger.e("Can't bind inet socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,8 +209,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
try {
|
||||
s6 = bindSocket(b6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
if (logger)
|
||||
logger->e("Can't bind inet6 socket: %s", e.what());
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,8 +217,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
try {
|
||||
s6 = bindSocket(bind6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
if (logger)
|
||||
logger->e("Can't bind inet6 socket: %s", e.what());
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,8 +244,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
|
||||
if (rc < 0) {
|
||||
if (errno != EINTR) {
|
||||
if (logger)
|
||||
logger->e("Select error: %s", strerror(errno));
|
||||
logger.e("Select error: %s", strerror(errno));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
@@ -264,8 +259,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
|
||||
if (FD_ISSET(stop_readfd, &readfds)) {
|
||||
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
|
||||
if (logger)
|
||||
logger->e("Got stop packet error: %s", strerror(errno));
|
||||
logger.e("Got stop packet error: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -277,54 +271,43 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
continue;
|
||||
|
||||
if (rc > 0) {
|
||||
auto pkts = getNewPacket();
|
||||
auto& pkt = pkts.front();
|
||||
pkt.data.insert(pkt.data.end(), buf.begin(), buf.begin()+rc);
|
||||
pkt.from = {from, from_len};
|
||||
pkt.received = clock::now();
|
||||
onReceived(std::move(pkts));
|
||||
auto pkt = std::unique_ptr<ReceivedPacket>(new ReceivedPacket);
|
||||
pkt->data = {buf.begin(), buf.begin()+rc};
|
||||
pkt->from = {from, from_len};
|
||||
pkt->received = clock::now();
|
||||
onReceived(std::move(pkt));
|
||||
} else if (rc == -1) {
|
||||
if (logger)
|
||||
logger->e("Error receiving packet: %s", strerror(errno));
|
||||
logger.e("Error receiving packet: %s", strerror(errno));
|
||||
int err = errno;
|
||||
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
|
||||
if (not running) break;
|
||||
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
|
||||
if (lk.owns_lock()) {
|
||||
if (not running) break;
|
||||
if (ls4 >= 0) {
|
||||
close(ls4);
|
||||
try {
|
||||
ls4 = bindSocket(bound4, bound4);
|
||||
} catch (const DhtException& e) {
|
||||
if (logger)
|
||||
logger->e("Can't bind inet socket: %s", e.what());
|
||||
}
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
if (ls4 >= 0) {
|
||||
close(ls4);
|
||||
try {
|
||||
ls4 = bindSocket(bound4, bound4);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet socket: %s", e.what());
|
||||
}
|
||||
if (ls6 >= 0) {
|
||||
close(ls6);
|
||||
try {
|
||||
ls6 = bindSocket(bound6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
if (logger)
|
||||
logger->e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
if (ls4 < 0 && ls6 < 0)
|
||||
break;
|
||||
s4 = ls4;
|
||||
s6 = ls6;
|
||||
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (ls6 >= 0) {
|
||||
close(ls6);
|
||||
try {
|
||||
ls6 = bindSocket(bound6, bound6);
|
||||
} catch (const DhtException& e) {
|
||||
logger.e("Can't bind inet6 socket: %s", e.what());
|
||||
}
|
||||
}
|
||||
if (ls4 < 0 && ls6 < 0)
|
||||
break;
|
||||
s4 = ls4;
|
||||
s6 = ls6;
|
||||
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
if (logger)
|
||||
logger->e("Error in UdpSocket rx thread: %s", e.what());
|
||||
logger.e("Error in UdpSocket rx thread: %s", e.what());
|
||||
}
|
||||
if (ls4 >= 0)
|
||||
close(ls4);
|
||||
@@ -332,16 +315,14 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
|
||||
close(ls6);
|
||||
if (stop_readfd != -1)
|
||||
close(stop_readfd);
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
bound4 = {};
|
||||
bound6 = {};
|
||||
if (stopfd != -1)
|
||||
close(stopfd);
|
||||
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
|
||||
if (lk.owns_lock()) {
|
||||
s4 = -1;
|
||||
s6 = -1;
|
||||
bound4 = {};
|
||||
bound6 = {};
|
||||
stopfd = -1;
|
||||
}
|
||||
stopfd = -1;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -351,8 +332,7 @@ UdpSocket::stop()
|
||||
if (running.exchange(false)) {
|
||||
auto sfd = stopfd;
|
||||
if (sfd != -1 && write(sfd, "\0", 1) == -1) {
|
||||
if (logger)
|
||||
logger->e("Can't write to stop fd");
|
||||
logger.e("Can't write to stop fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -30,15 +30,17 @@ constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME;
|
||||
constexpr std::chrono::minutes Node::NODE_GOOD_TIME;
|
||||
constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME;
|
||||
|
||||
Node::Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client)
|
||||
Node::Node(const InfoHash& id, const SockAddr& addr, bool client)
|
||||
: id(id), addr(addr), is_client(client), sockets_()
|
||||
{
|
||||
thread_local crypto::random_device rd {};
|
||||
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
|
||||
}
|
||||
|
||||
Node::Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client)
|
||||
Node::Node(const InfoHash& id, SockAddr&& addr, bool client)
|
||||
: id(id), addr(std::move(addr)), is_client(client), sockets_()
|
||||
{
|
||||
thread_local crypto::random_device rd {};
|
||||
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -37,8 +37,8 @@ NodeCache::getNode(const InfoHash& id, sa_family_t family) {
|
||||
Sp<Node>
|
||||
NodeCache::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client) {
|
||||
if (not id)
|
||||
return std::make_shared<Node>(id, addr, rd, client);
|
||||
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client, rd);
|
||||
return std::make_shared<Node>(id, addr);
|
||||
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client);
|
||||
}
|
||||
|
||||
std::vector<Sp<Node>>
|
||||
@@ -104,13 +104,13 @@ NodeCache::NodeMap::getNode(const InfoHash& id)
|
||||
}
|
||||
|
||||
Sp<Node>
|
||||
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client, std::mt19937_64& rd)
|
||||
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client)
|
||||
{
|
||||
auto& nref = (*this)[id];
|
||||
auto node = nref.lock();
|
||||
auto it = emplace(id, std::weak_ptr<Node>{});
|
||||
auto node = it.first->second.lock();
|
||||
if (not node) {
|
||||
node = std::make_shared<Node>(id, addr, rd, client);
|
||||
nref = node;
|
||||
node = std::make_shared<Node>(id, addr, client);
|
||||
it.first->second = node;
|
||||
if (cleanup_counter++ == CLEANUP_FREQ) {
|
||||
cleanup();
|
||||
cleanup_counter = 0;
|
||||
|
||||
+4
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,7 +22,7 @@ namespace dht {
|
||||
constexpr const std::chrono::seconds OpCache::EXPIRATION;
|
||||
|
||||
bool
|
||||
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
|
||||
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
|
||||
std::vector<Sp<Value>> newValues;
|
||||
for (const auto& v : vals) {
|
||||
auto viop = values.emplace(v->id, v);
|
||||
@@ -31,21 +31,16 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clo
|
||||
} else {
|
||||
viop.first->second.refCount++;
|
||||
}
|
||||
viop.first->second.updated = t;
|
||||
}
|
||||
return newValues.empty() ? true : callback(newValues, false);
|
||||
}
|
||||
|
||||
bool
|
||||
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
|
||||
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
|
||||
std::vector<Sp<Value>> expiredValues;
|
||||
for (const auto& v : vals) {
|
||||
auto vit = values.find(v->id);
|
||||
if (vit != values.end()) {
|
||||
if (vit->second.updated > t)
|
||||
continue;
|
||||
|
||||
vit->second.updated = t;
|
||||
vit->second.refCount--;
|
||||
if (not vit->second.refCount) {
|
||||
expiredValues.emplace_back(std::move(vit->second.data));
|
||||
@@ -57,16 +52,12 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals, const system_c
|
||||
}
|
||||
|
||||
bool
|
||||
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids, const system_clock::time_point& t)
|
||||
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
|
||||
{
|
||||
std::vector<Sp<Value>> expiredValues;
|
||||
for (const auto& vid : vids) {
|
||||
auto vit = values.find(vid);
|
||||
if (vit != values.end()) {
|
||||
if (vit->second.updated > t)
|
||||
continue;
|
||||
|
||||
vit->second.updated = t;
|
||||
vit->second.refCount--;
|
||||
if (not vit->second.refCount) {
|
||||
expiredValues.emplace_back(std::move(vit->second.data));
|
||||
|
||||
+7
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -27,7 +27,6 @@ struct OpCacheValueStorage
|
||||
{
|
||||
Sp<Value> data {};
|
||||
unsigned refCount {1};
|
||||
system_clock::time_point updated {system_clock::time_point::min()};
|
||||
OpCacheValueStorage(Sp<Value> val) : data(val) {}
|
||||
};
|
||||
|
||||
@@ -48,16 +47,16 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
|
||||
bool onValue(const std::vector<Sp<Value>>& vals, bool expired) {
|
||||
if (expired)
|
||||
return onValuesExpired(vals, t);
|
||||
return onValuesExpired(vals);
|
||||
else
|
||||
return onValuesAdded(vals, t);
|
||||
return onValuesAdded(vals);
|
||||
}
|
||||
|
||||
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
|
||||
bool onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
|
||||
bool onValuesExpired(const std::vector<Value::Id>& vals, const system_clock::time_point& t = system_clock::time_point::min());
|
||||
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
|
||||
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
|
||||
bool onValuesExpired(const std::vector<Value::Id>& vals);
|
||||
|
||||
void onNodeChanged(ListenSyncStatus status) {
|
||||
switch (status) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+48
-111
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace dht {
|
||||
|
||||
// Organization-local Scope multicast
|
||||
@@ -44,8 +46,6 @@ public:
|
||||
bool stopDiscovery(const std::string &type);
|
||||
bool stopPublish(const std::string &type);
|
||||
|
||||
void connectivityChanged();
|
||||
|
||||
private:
|
||||
Sp<Logger> logger_;
|
||||
//dmtx_ for callbackmap_ and drunning_ (write)
|
||||
@@ -55,6 +55,7 @@ private:
|
||||
std::shared_ptr<asio::io_context> ioContext_;
|
||||
asio::ip::udp::socket sockFd_;
|
||||
asio::ip::udp::endpoint sockAddrSend_;
|
||||
asio::steady_timer publishTimer_;
|
||||
|
||||
std::array<char, 64 * 1024> receiveBuf_;
|
||||
asio::ip::udp::endpoint receiveFrom_;
|
||||
@@ -66,15 +67,11 @@ private:
|
||||
bool drunning_ {false};
|
||||
|
||||
void loopListener();
|
||||
void query(const asio::ip::udp::endpoint& peer);
|
||||
void reloadMessages();
|
||||
|
||||
void stopDiscovery();
|
||||
void stopPublish();
|
||||
|
||||
void publish(const asio::ip::udp::endpoint& peer);
|
||||
|
||||
void reDiscover();
|
||||
void publish();
|
||||
};
|
||||
|
||||
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
|
||||
@@ -83,16 +80,11 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
|
||||
, sockFd_(*ioContext_, domain)
|
||||
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
|
||||
: MULTICAST_ADDRESS_IPV6), port)
|
||||
, publishTimer_(*ioContext)
|
||||
{
|
||||
try {
|
||||
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()));
|
||||
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||
sockFd_.bind({domain, port});
|
||||
} catch (const std::exception& e) {
|
||||
if (logger_)
|
||||
logger_->e("Can't start peer discovery for %s: %s",
|
||||
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
|
||||
}
|
||||
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()));
|
||||
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
|
||||
sockFd_.bind({domain, port});
|
||||
}
|
||||
|
||||
PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
|
||||
@@ -108,10 +100,7 @@ PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, Serv
|
||||
callbackmap_[type] = callback;
|
||||
if (not drunning_) {
|
||||
drunning_ = true;
|
||||
ioContext_->post([this] () {
|
||||
loopListener();
|
||||
query(sockAddrSend_);
|
||||
});
|
||||
ioContext_->post(std::bind(&PeerDiscovery::DomainPeerDiscovery::loopListener, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,30 +121,25 @@ PeerDiscovery::DomainPeerDiscovery::loopListener()
|
||||
auto rcv = msgpack::unpack(receiveBuf_.data(), bytes);
|
||||
msgpack::object obj = rcv.get();
|
||||
|
||||
if (obj.type == msgpack::type::STR) {
|
||||
if (lrunning_ and obj.as<std::string>() == "q")
|
||||
publish(receiveFrom_);
|
||||
} else if (obj.type == msgpack::type::MAP) {
|
||||
for (unsigned i = 0; i < obj.via.map.size; i++) {
|
||||
auto& o = obj.via.map.ptr[i];
|
||||
if (o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
auto key = o.key.as<std::string>();
|
||||
ServiceDiscoveredCallback cb;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (drunning_) {
|
||||
auto callback = callbackmap_.find(key);
|
||||
if (callback != callbackmap_.end())
|
||||
cb = callback->second;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
if (cb)
|
||||
cb(std::move(o.val), SockAddr{ receiveFrom_.data(), (socklen_t)receiveFrom_.size() });
|
||||
}
|
||||
} else {
|
||||
if (obj.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error{};
|
||||
for (unsigned i = 0; i < obj.via.map.size; i++) {
|
||||
auto& o = obj.via.map.ptr[i];
|
||||
if (o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
auto key = o.key.as<std::string>();
|
||||
ServiceDiscoveredCallback cb;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (drunning_) {
|
||||
auto callback = callbackmap_.find(key);
|
||||
if (callback != callbackmap_.end())
|
||||
cb = callback->second;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
if (cb)
|
||||
cb(std::move(o.val), SockAddr{ receiveFrom_.data(), (socklen_t)receiveFrom_.size() });
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
if (logger_)
|
||||
@@ -166,45 +150,21 @@ PeerDiscovery::DomainPeerDiscovery::loopListener()
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::query(const asio::ip::udp::endpoint& peer)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dmtx_);
|
||||
if (not drunning_)
|
||||
return;
|
||||
|
||||
msgpack::sbuffer pbuf_request;
|
||||
msgpack::pack(pbuf_request, "q");
|
||||
|
||||
sockFd_.async_send_to(asio::buffer(pbuf_request.data(), pbuf_request.size()), peer,
|
||||
[logger=logger_, peer] (const asio::error_code& ec, size_t)
|
||||
{
|
||||
if (ec and (ec != asio::error::operation_aborted) and logger)
|
||||
logger->w("Error sending packet to: %s with err: %s",
|
||||
peer.address().to_string().c_str(),
|
||||
ec.message().c_str());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
|
||||
PeerDiscovery::DomainPeerDiscovery::publish()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mtx_);
|
||||
if (not lrunning_)
|
||||
return;
|
||||
|
||||
sockFd_.async_send_to(asio::buffer(sbuf_.data(), sbuf_.size()), peer,
|
||||
[logger=logger_, peer] (const asio::error_code& ec, size_t)
|
||||
{
|
||||
if (ec and (ec != asio::error::operation_aborted) and logger)
|
||||
logger->w("Error sending packet to: %s with err: %s",
|
||||
peer.address().to_string().c_str(),
|
||||
ec.message().c_str());
|
||||
if (lrunning_) {
|
||||
sockFd_.async_send_to(asio::buffer(sbuf_.data(), sbuf_.size()), sockAddrSend_, [logger=logger_](const asio::error_code& ec, size_t){
|
||||
if (ec and ec != asio::error::operation_aborted) {
|
||||
if (logger)
|
||||
logger->w("Error sending packet: %s", ec.message().c_str());
|
||||
}
|
||||
);
|
||||
});
|
||||
publishTimer_.expires_after(3s);
|
||||
publishTimer_.async_wait(std::bind(&PeerDiscovery::DomainPeerDiscovery::publish, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
|
||||
{
|
||||
@@ -214,8 +174,10 @@ PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const
|
||||
std::lock_guard<std::mutex> lck(mtx_);
|
||||
messages_[type] = std::move(pack_buf_c);
|
||||
reloadMessages();
|
||||
lrunning_ = true;
|
||||
ioContext_->post([this] () { publish(sockAddrSend_); });
|
||||
if (not lrunning_) {
|
||||
lrunning_ = true;
|
||||
ioContext_->post(std::bind(&PeerDiscovery::DomainPeerDiscovery::publish, this));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -247,13 +209,17 @@ PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
|
||||
{
|
||||
drunning_ = false;
|
||||
if (drunning_)
|
||||
drunning_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::stopPublish()
|
||||
{
|
||||
lrunning_ = false;
|
||||
if (lrunning_) {
|
||||
lrunning_ = false;
|
||||
publishTimer_.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -281,26 +247,6 @@ PeerDiscovery::DomainPeerDiscovery::reloadMessages()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::reDiscover()
|
||||
{
|
||||
asio::error_code ec;
|
||||
|
||||
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()), ec);
|
||||
if (ec and logger_)
|
||||
logger_->w("can't multicast on %s: %s",
|
||||
sockAddrSend_.address().to_string().c_str(),
|
||||
ec.message().c_str());
|
||||
query(sockAddrSend_);
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
|
||||
{
|
||||
reDiscover();
|
||||
publish(sockAddrSend_);
|
||||
}
|
||||
|
||||
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
|
||||
{
|
||||
if (not ioContext) {
|
||||
@@ -402,13 +348,4 @@ PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
PeerDiscovery::connectivityChanged()
|
||||
{
|
||||
if (peerDiscovery4_)
|
||||
peerDiscovery4_->connectivityChanged();
|
||||
if (peerDiscovery6_)
|
||||
peerDiscovery6_->connectivityChanged();
|
||||
}
|
||||
|
||||
} /* namespace dht */
|
||||
+3
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -108,14 +108,13 @@ private:
|
||||
static const constexpr size_t MAX_ATTEMPT_COUNT {3};
|
||||
|
||||
bool isExpired(time_point now) const {
|
||||
return pending() and now > last_try + attempt_duration and attempt_count >= Request::MAX_ATTEMPT_COUNT;
|
||||
return pending() and now > last_try + Node::MAX_RESPONSE_TIME and attempt_count >= Request::MAX_ATTEMPT_COUNT;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
on_done = {};
|
||||
on_expired = {};
|
||||
msg = {};
|
||||
parts = {};
|
||||
msg.clear();
|
||||
}
|
||||
|
||||
const Tid tid {0}; /* the request id. */
|
||||
@@ -123,7 +122,6 @@ private:
|
||||
State state_ {State::PENDING};
|
||||
|
||||
unsigned attempt_count {0}; /* number of attempt to process the request. */
|
||||
duration attempt_duration {((duration)Node::MAX_RESPONSE_TIME)/2};
|
||||
time_point start {time_point::min()}; /* time when the request is created. */
|
||||
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
|
||||
|
||||
@@ -131,7 +129,6 @@ private:
|
||||
std::function<void(const Request&, bool)> on_expired {};
|
||||
|
||||
Blob msg {}; /* the serialized message. */
|
||||
std::vector<Blob> parts;
|
||||
Tid socket; /* the socket used for further reponses. */
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,7 +25,7 @@ namespace dht {
|
||||
namespace crypto {
|
||||
|
||||
random_device::random_device() :
|
||||
gen(std::chrono::system_clock::now().time_since_epoch().count() ^ std::chrono::high_resolution_clock::now().count())
|
||||
gen(std::chrono::system_clock::now().time_since_epoch().count())
|
||||
{}
|
||||
|
||||
random_device::result_type
|
||||
|
||||
+10
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,8 +25,15 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
static std::mt19937 rd{ dht::crypto::random_device{}() };
|
||||
#ifdef _WIN32
|
||||
static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
|
||||
#else
|
||||
static std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#endif
|
||||
|
||||
Sp<Node>
|
||||
Bucket::randomNode(std::mt19937_64& rd)
|
||||
Bucket::randomNode()
|
||||
{
|
||||
if (nodes.empty())
|
||||
return nullptr;
|
||||
@@ -58,7 +65,7 @@ void Bucket::sendCachedPing(net::NetworkEngine& ne)
|
||||
}
|
||||
|
||||
InfoHash
|
||||
RoutingTable::randomId(const RoutingTable::const_iterator& it, std::mt19937_64& rd) const
|
||||
RoutingTable::randomId(const RoutingTable::const_iterator& it) const
|
||||
{
|
||||
int bit1 = it->first.lowbit();
|
||||
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
|
||||
@@ -67,12 +74,6 @@ RoutingTable::randomId(const RoutingTable::const_iterator& it, std::mt19937_64&
|
||||
if (bit >= 8*(int)HASH_LEN)
|
||||
return it->first;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
|
||||
#else
|
||||
std::uniform_int_distribution<uint8_t> rand_byte;
|
||||
#endif
|
||||
|
||||
int b = bit/8;
|
||||
InfoHash id_return;
|
||||
std::copy_n(it->first.cbegin(), b, id_return.begin());
|
||||
|
||||
+57
-107
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -67,8 +67,9 @@ struct Dht::SearchNode {
|
||||
Sp<net::Request> req {};
|
||||
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
|
||||
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
|
||||
CachedListenStatus(CachedListenStatus&&) = delete;
|
||||
CachedListenStatus(CachedListenStatus&&) = default;
|
||||
CachedListenStatus(const CachedListenStatus&) = delete;
|
||||
CachedListenStatus& operator=(const CachedListenStatus&) = delete;
|
||||
};
|
||||
using NodeListenerStatus = std::map<Sp<Query>, CachedListenStatus>;
|
||||
|
||||
@@ -85,15 +86,15 @@ struct Dht::SearchNode {
|
||||
|
||||
Blob token {}; /* last token the node sent to us after a get request */
|
||||
time_point last_get_reply {time_point::min()}; /* last time received valid token */
|
||||
Sp<Scheduler::Job> syncJob {};
|
||||
bool candidate {false}; /* A search node is candidate if the search is/was synced and this
|
||||
node is a new candidate for inclusion. */
|
||||
Sp<Scheduler::Job> syncJob {};
|
||||
|
||||
SearchNode() : node() {}
|
||||
SearchNode(const SearchNode&) = delete;
|
||||
SearchNode(SearchNode&&) = delete;
|
||||
SearchNode(SearchNode&&) = default;
|
||||
SearchNode& operator=(const SearchNode&) = delete;
|
||||
SearchNode& operator=(SearchNode&&) = delete;
|
||||
SearchNode& operator=(SearchNode&&) = default;
|
||||
|
||||
SearchNode(const Sp<Node>& node) : node(node) {}
|
||||
~SearchNode() {
|
||||
@@ -262,7 +263,7 @@ struct Dht::SearchNode {
|
||||
* @return true if there exists an expired request, else false.
|
||||
*/
|
||||
static bool pending(const SyncStatus& status) {
|
||||
return std::find_if(status.cbegin(), status.cend(),
|
||||
return std::find_if(status.begin(), status.end(),
|
||||
[](const SyncStatus::value_type& r){
|
||||
return r.second and r.second->pending();
|
||||
}) != status.end();
|
||||
@@ -292,26 +293,26 @@ struct Dht::SearchNode {
|
||||
acked.clear();
|
||||
}
|
||||
|
||||
inline bool isListening(time_point now, duration listen_expire) const {
|
||||
bool isListening(time_point now) const {
|
||||
auto ls = listenStatus.begin();
|
||||
for ( ; ls != listenStatus.end() ; ++ls) {
|
||||
if (isListening(now, ls, listen_expire)) {
|
||||
if (isListening(now, ls)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ls != listenStatus.end();
|
||||
}
|
||||
inline bool isListening(time_point now, const Sp<Query>& q, duration listen_expire) const {
|
||||
bool isListening(time_point now, const Sp<Query>& q) const {
|
||||
const auto& ls = listenStatus.find(q);
|
||||
if (ls == listenStatus.end())
|
||||
return false;
|
||||
else
|
||||
return isListening(now, ls, listen_expire);
|
||||
return isListening(now, ls);
|
||||
}
|
||||
inline bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status, duration listen_expire) const {
|
||||
bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status) const {
|
||||
if (listen_status == listenStatus.end() or not listen_status->second.req)
|
||||
return false;
|
||||
return listen_status->second.req->reply_time + listen_expire > now;
|
||||
return listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME > now;
|
||||
}
|
||||
void cancelListen() {
|
||||
for (const auto& status : listenStatus)
|
||||
@@ -344,12 +345,12 @@ struct Dht::SearchNode {
|
||||
* Assuming the node is synced, should the "listen" request with Query q be
|
||||
* sent to this node now ?
|
||||
*/
|
||||
time_point getListenTime(const Sp<Query>& q, duration listen_expire) const {
|
||||
time_point getListenTime(const Sp<Query>& q) const {
|
||||
auto listen_status = listenStatus.find(q);
|
||||
if (listen_status == listenStatus.end() or not listen_status->second.req)
|
||||
return time_point::min();
|
||||
return listen_status->second.req->pending() ? time_point::max() :
|
||||
listen_status->second.req->reply_time + listen_expire - REANNOUNCE_MARGIN;
|
||||
listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME - REANNOUNCE_MARGIN;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +376,7 @@ struct Dht::Search {
|
||||
|
||||
bool expired {false}; /* no node, or all nodes expired */
|
||||
bool done {false}; /* search is over, cached for later */
|
||||
std::vector<std::unique_ptr<SearchNode>> nodes {};
|
||||
std::vector<SearchNode> nodes {};
|
||||
|
||||
/* pending puts */
|
||||
std::vector<Announce> announce {};
|
||||
@@ -415,17 +416,17 @@ struct Dht::Search {
|
||||
bool insertNode(const Sp<Node>& n, time_point now, const Blob& token={});
|
||||
|
||||
SearchNode* getNode(const Sp<Node>& n) {
|
||||
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](std::unique_ptr<SearchNode>& sn) {
|
||||
return n == sn->node;
|
||||
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](SearchNode& sn) {
|
||||
return n == sn.node;
|
||||
});
|
||||
return (srn == nodes.end()) ? nullptr : (*srn).get();
|
||||
return (srn == nodes.end()) ? nullptr : &(*srn);
|
||||
}
|
||||
|
||||
/* number of concurrent sync requests */
|
||||
unsigned currentlySolicitedNodeCount() const {
|
||||
unsigned count = 0;
|
||||
for (const auto& n : nodes)
|
||||
if (not n->isBad() and n->pendingGet())
|
||||
if (not n.isBad() and n.pendingGet())
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
@@ -459,12 +460,12 @@ struct Dht::Search {
|
||||
*/
|
||||
void setDone(const Get& get) {
|
||||
for (auto& n : nodes) {
|
||||
auto pqs = n->pagination_queries.find(get.query);
|
||||
if (pqs != n->pagination_queries.cend()) {
|
||||
auto pqs = n.pagination_queries.find(get.query);
|
||||
if (pqs != n.pagination_queries.cend()) {
|
||||
for (auto& pq : pqs->second)
|
||||
n->getStatus.erase(pq);
|
||||
n.getStatus.erase(pq);
|
||||
}
|
||||
n->getStatus.erase(get.query);
|
||||
n.getStatus.erase(get.query);
|
||||
}
|
||||
if (get.done_cb)
|
||||
get.done_cb(true, getNodes());
|
||||
@@ -477,15 +478,15 @@ struct Dht::Search {
|
||||
*/
|
||||
void setDone() {
|
||||
for (auto& n : nodes) {
|
||||
n->getStatus.clear();
|
||||
n->listenStatus.clear();
|
||||
n->acked.clear();
|
||||
n.getStatus.clear();
|
||||
n.listenStatus.clear();
|
||||
n.acked.clear();
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
|
||||
bool isAnnounced(Value::Id id) const;
|
||||
bool isListening(time_point now, duration exp) const;
|
||||
bool isListening(time_point now) const;
|
||||
|
||||
void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
|
||||
if (gcb or qcb) {
|
||||
@@ -521,9 +522,9 @@ struct Dht::Search {
|
||||
}
|
||||
for (auto& sn : nodes) {
|
||||
if (listeners.empty())
|
||||
sn->cancelListen();
|
||||
sn.cancelListen();
|
||||
else if (query)
|
||||
sn->cancelListen(query);
|
||||
sn.cancelListen(query);
|
||||
}
|
||||
});
|
||||
scheduler.edit(opExpirationJob, nextExpire);
|
||||
@@ -557,66 +558,21 @@ struct Dht::Search {
|
||||
else
|
||||
++it;
|
||||
}
|
||||
for (auto& n : nodes) {
|
||||
auto ackIt = n->acked.find(vid);
|
||||
if (ackIt != n->acked.end()) {
|
||||
if (ackIt->second.first)
|
||||
ackIt->second.first->cancel();
|
||||
n->acked.erase(ackIt);
|
||||
}
|
||||
}
|
||||
return canceled;
|
||||
}
|
||||
|
||||
void put(const Sp<Value>& value, DoneCallback callback, time_point created, bool permanent) {
|
||||
done = false;
|
||||
expired = false;
|
||||
auto a_sr = std::find_if(announce.begin(), announce.end(), [&](const Announce& a){
|
||||
return a.value->id == value->id;
|
||||
});
|
||||
if (a_sr == announce.end()) {
|
||||
announce.emplace_back(Announce {permanent, value, created, callback});
|
||||
for (auto& n : nodes) {
|
||||
n->probe_query.reset();
|
||||
n->acked[value->id].first.reset();
|
||||
}
|
||||
} else {
|
||||
a_sr->permanent = permanent;
|
||||
a_sr->created = created;
|
||||
if (a_sr->value != value) {
|
||||
a_sr->value = value;
|
||||
for (auto& n : nodes) {
|
||||
n->acked[value->id].first.reset();
|
||||
n->probe_query.reset();
|
||||
}
|
||||
}
|
||||
if (isAnnounced(value->id)) {
|
||||
if (a_sr->callback)
|
||||
a_sr->callback(true, {});
|
||||
a_sr->callback = {};
|
||||
if (callback)
|
||||
callback(true, {});
|
||||
return;
|
||||
} else {
|
||||
if (a_sr->callback)
|
||||
a_sr->callback(false, {});
|
||||
a_sr->callback = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of non-good search nodes.
|
||||
*/
|
||||
unsigned getNumberOfBadNodes() const {
|
||||
return std::count_if(nodes.begin(), nodes.end(), [](const std::unique_ptr<SearchNode>& sn) {
|
||||
return sn->isBad();
|
||||
return std::count_if(nodes.begin(), nodes.end(), [](const SearchNode& sn) {
|
||||
return sn.isBad();
|
||||
});
|
||||
}
|
||||
unsigned getNumberOfConsecutiveBadNodes() const {
|
||||
unsigned count = 0;
|
||||
std::find_if(nodes.begin(), nodes.end(), [&count](const std::unique_ptr<SearchNode>& sn) {
|
||||
if (not sn->node->isExpired())
|
||||
std::find_if(nodes.begin(), nodes.end(), [&count](const SearchNode& sn) {
|
||||
if (not sn.isBad())
|
||||
return true;
|
||||
++count;
|
||||
return false;
|
||||
@@ -635,7 +591,7 @@ struct Dht::Search {
|
||||
*/
|
||||
bool removeExpiredNode(const time_point& now) {
|
||||
for (auto e = nodes.cend(); e != nodes.cbegin();) {
|
||||
const Node& n = *(*(--e))->node;
|
||||
const Node& n = *(--e)->node;
|
||||
if (n.isRemovable(now)) {
|
||||
//std::cout << "Removing expired node " << n.id << " from IPv" << (af==AF_INET?'4':'6') << " search " << id << std::endl;
|
||||
nodes.erase(e);
|
||||
@@ -707,14 +663,8 @@ struct Dht::Search {
|
||||
});
|
||||
// remove acked for cleared annouces
|
||||
for (auto it = announced; it != announce.end(); ++it) {
|
||||
for (auto& n : nodes) {
|
||||
auto ackIt = n->acked.find(it->value->id);
|
||||
if (ackIt != n->acked.end()) {
|
||||
if (ackIt->second.first)
|
||||
ackIt->second.first->cancel();
|
||||
n->acked.erase(ackIt);
|
||||
}
|
||||
}
|
||||
for (auto& n : nodes)
|
||||
n.acked.erase(it->value->id);
|
||||
}
|
||||
announce.erase(announced, announce.end());
|
||||
}
|
||||
@@ -747,13 +697,13 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
|
||||
auto n = nodes.end();
|
||||
while (n != nodes.begin()) {
|
||||
--n;
|
||||
if ((*n)->node == snode) {
|
||||
if (n->node == snode) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Node not found. We could insert it after this one. */
|
||||
if (id.xorCmp(nid, (*n)->node->id) > 0) {
|
||||
if (id.xorCmp(nid, n->node->id) > 0) {
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
@@ -777,7 +727,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
|
||||
full = nodes.size() - bad >= SEARCH_NODES;
|
||||
while (std::distance(nodes.cbegin(), t) - bad > SEARCH_NODES) {
|
||||
--t;
|
||||
if ((*t)->isBad())
|
||||
if (t->isBad())
|
||||
bad--;
|
||||
}
|
||||
}
|
||||
@@ -793,7 +743,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
|
||||
if (nodes.empty()) {
|
||||
step_time = time_point::min();
|
||||
}
|
||||
n = nodes.emplace(n, std::make_unique<SearchNode>(snode));
|
||||
n = nodes.insert(n, SearchNode(snode));
|
||||
node.setTime(now);
|
||||
new_search_node = true;
|
||||
if (node.isExpired()) {
|
||||
@@ -805,16 +755,16 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
|
||||
}
|
||||
|
||||
while (nodes.size() - bad > SEARCH_NODES) {
|
||||
if (not expired and nodes.back()->isBad())
|
||||
if (not expired and nodes.back().isBad())
|
||||
bad--;
|
||||
nodes.pop_back();
|
||||
}
|
||||
}
|
||||
if (not token.empty()) {
|
||||
(*n)->candidate = false;
|
||||
(*n)->last_get_reply = now;
|
||||
n->candidate = false;
|
||||
n->last_get_reply = now;
|
||||
if (token.size() <= 64)
|
||||
(*n)->token = token;
|
||||
n->token = token;
|
||||
expired = false;
|
||||
}
|
||||
if (new_search_node)
|
||||
@@ -828,7 +778,7 @@ Dht::Search::getNodes() const
|
||||
std::vector<Sp<Node>> ret {};
|
||||
ret.reserve(nodes.size());
|
||||
for (const auto& sn : nodes)
|
||||
ret.emplace_back(sn->node);
|
||||
ret.emplace_back(sn.node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -837,9 +787,9 @@ Dht::Search::isSynced(time_point now) const
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (const auto& n : nodes) {
|
||||
if (n->isBad())
|
||||
if (n.isBad())
|
||||
continue;
|
||||
if (not n->isSynced(now))
|
||||
if (not n.isSynced(now))
|
||||
return false;
|
||||
if (++i == TARGET_NODES)
|
||||
break;
|
||||
@@ -870,9 +820,9 @@ Dht::Search::isDone(const Get& get) const
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (const auto& sn : nodes) {
|
||||
if (sn->isBad())
|
||||
if (sn.isBad())
|
||||
continue;
|
||||
if (not sn->isDone(get))
|
||||
if (not sn.isDone(get))
|
||||
return false;
|
||||
if (++i == TARGET_NODES)
|
||||
break;
|
||||
@@ -887,9 +837,9 @@ Dht::Search::isAnnounced(Value::Id id) const
|
||||
return false;
|
||||
unsigned i = 0;
|
||||
for (const auto& n : nodes) {
|
||||
if (n->isBad())
|
||||
if (n.isBad())
|
||||
continue;
|
||||
if (not n->isAnnounced(id))
|
||||
if (not n.isAnnounced(id))
|
||||
return false;
|
||||
if (++i == TARGET_NODES)
|
||||
return true;
|
||||
@@ -898,20 +848,20 @@ Dht::Search::isAnnounced(Value::Id id) const
|
||||
}
|
||||
|
||||
bool
|
||||
Dht::Search::isListening(time_point now, duration listen_expire) const
|
||||
Dht::Search::isListening(time_point now) const
|
||||
{
|
||||
if (nodes.empty() or listeners.empty())
|
||||
return false;
|
||||
unsigned i = 0;
|
||||
for (const auto& n : nodes) {
|
||||
if (n->isBad())
|
||||
if (n.isBad())
|
||||
continue;
|
||||
SearchNode::NodeListenerStatus::const_iterator ls {};
|
||||
for (ls = n->listenStatus.begin(); ls != n->listenStatus.end() ; ++ls) {
|
||||
if (n->isListening(now, ls, listen_expire))
|
||||
for (ls = n.listenStatus.begin(); ls != n.listenStatus.end() ; ++ls) {
|
||||
if (n.isListening(now, ls))
|
||||
break;
|
||||
}
|
||||
if (ls == n->listenStatus.end())
|
||||
if (ls == n.listenStatus.end())
|
||||
return false;
|
||||
if (++i == LISTEN_NODES)
|
||||
break;
|
||||
|
||||
+26
-54
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
@@ -37,7 +37,7 @@ extern "C" {
|
||||
namespace dht {
|
||||
|
||||
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
|
||||
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
|
||||
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second)
|
||||
{
|
||||
if (!dht_) return;
|
||||
for (const auto& type : DEFAULT_TYPES)
|
||||
@@ -49,7 +49,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
|
||||
registerInsecureType(CERTIFICATE_TYPE);
|
||||
|
||||
if (certificate_) {
|
||||
auto certId = certificate_->getId();
|
||||
auto certId = certificate_->getPublicKey().getId();
|
||||
if (key_ and certId != key_->getPublicKey().getId())
|
||||
throw DhtException("SecureDht: provided certificate doesn't match private key.");
|
||||
|
||||
@@ -59,8 +59,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
|
||||
1
|
||||
}, [this, certId](bool ok) {
|
||||
if (ok)
|
||||
if (logger_)
|
||||
logger_->d(certId, "SecureDht: public key announced successfully");
|
||||
DHT_LOG.d(certId, "SecureDht: public key announced successfully");
|
||||
}, {}, true);
|
||||
}
|
||||
}
|
||||
@@ -77,8 +76,7 @@ SecureDht::secureType(ValueType&& type)
|
||||
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
|
||||
}
|
||||
if (!v->signatureValid) {
|
||||
if (logger_)
|
||||
logger_->w("Signature verification failed");
|
||||
DHT_LOG.w("Signature verification failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -88,8 +86,7 @@ SecureDht::secureType(ValueType&& type)
|
||||
if (!o->isSigned())
|
||||
return type.editPolicy(id, o, n, nid, a);
|
||||
if (o->owner != n->owner) {
|
||||
if (logger_)
|
||||
logger_->w("Edition forbidden: owner changed.");
|
||||
DHT_LOG.w("Edition forbidden: owner changed.");
|
||||
return false;
|
||||
}
|
||||
if (!n->signatureChecked) {
|
||||
@@ -97,16 +94,14 @@ SecureDht::secureType(ValueType&& type)
|
||||
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
|
||||
}
|
||||
if (!n->signatureValid) {
|
||||
if (logger_)
|
||||
logger_->w("Edition forbidden: signature verification failed.");
|
||||
DHT_LOG.w("Edition forbidden: signature verification failed.");
|
||||
return false;
|
||||
}
|
||||
if (o->seq == n->seq) {
|
||||
// If the data is exactly the same,
|
||||
// it can be reannounced, possibly by someone else.
|
||||
if (o->getToSign() != n->getToSign()) {
|
||||
if (logger_)
|
||||
logger_->w("Edition forbidden: sequence number must be increasing.");
|
||||
DHT_LOG.w("Edition forbidden: sequence number must be increasing.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -152,8 +147,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
|
||||
}
|
||||
InfoHash h = crt->getPublicKey().getId();
|
||||
if (node == h) {
|
||||
if (logger_)
|
||||
logger_->d("Registering certificate for %s", h.toString().c_str());
|
||||
DHT_LOG.d("Registering certificate for %s", h.toString().c_str());
|
||||
auto it = nodesCertificates_.find(h);
|
||||
if (it == nodesCertificates_.end())
|
||||
std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
|
||||
@@ -161,8 +155,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
|
||||
it->second = std::move(crt);
|
||||
return it->second;
|
||||
} else {
|
||||
if (logger_)
|
||||
logger_->w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
|
||||
DHT_LOG.w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -179,8 +172,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
|
||||
{
|
||||
Sp<crypto::Certificate> b = getCertificate(node);
|
||||
if (b && *b) {
|
||||
if (logger_)
|
||||
logger_->d("Using certificate from cache for %s", node.to_c_str());
|
||||
DHT_LOG.d("Using certificate from cache for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(b);
|
||||
return;
|
||||
@@ -188,8 +180,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
|
||||
if (localQueryMethod_) {
|
||||
auto res = localQueryMethod_(node);
|
||||
if (not res.empty()) {
|
||||
if (logger_)
|
||||
logger_->d("Registering certificate from local store for %s", node.to_c_str());
|
||||
DHT_LOG.d("Registering certificate from local store for %s", node.toString().c_str());
|
||||
nodesCertificates_.emplace(node, res.front());
|
||||
if (cb)
|
||||
cb(res.front());
|
||||
@@ -204,8 +195,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
|
||||
for (const auto& v : vals) {
|
||||
if (auto cert = registerCertificate(node, v->data)) {
|
||||
*found = true;
|
||||
if (logger_)
|
||||
logger_->d(node, "Found certificate for %s", node.to_c_str());
|
||||
DHT_LOG.d("Found certificate for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(cert);
|
||||
return false;
|
||||
@@ -223,8 +213,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
|
||||
{
|
||||
auto pk = getPublicKey(node);
|
||||
if (pk && *pk) {
|
||||
if (logger_)
|
||||
logger_->d(node, "Found public key from cache for %s", node.to_c_str());
|
||||
DHT_LOG.d("Found public key from cache for %s", node.toString().c_str());
|
||||
if (cb)
|
||||
cb(pk);
|
||||
return;
|
||||
@@ -268,8 +257,7 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
}
|
||||
// Ignore values belonging to other people
|
||||
} catch (const std::exception& e) {
|
||||
if (logger_)
|
||||
logger_->w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
|
||||
DHT_LOG.w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
|
||||
}
|
||||
}
|
||||
// Check signed values
|
||||
@@ -280,12 +268,11 @@ SecureDht::checkValue(const Sp<Value>& v)
|
||||
v->signatureChecked = true;
|
||||
if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
|
||||
v->signatureValid = true;
|
||||
if (enableCache_)
|
||||
nodesPubKeys_[v->owner->getId()] = v->owner;
|
||||
nodesPubKeys_[v->owner->getId()] = v->owner;
|
||||
return v;
|
||||
}
|
||||
else if (logger_)
|
||||
logger_->w("Signature verification failed for %s", v->toString().c_str());
|
||||
else
|
||||
DHT_LOG.w("Signature verification failed for %s", v->toString().c_str());
|
||||
}
|
||||
// Forward normal values
|
||||
else {
|
||||
@@ -353,11 +340,6 @@ SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
|
||||
void
|
||||
SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent)
|
||||
{
|
||||
if (not key_) {
|
||||
if (callback)
|
||||
callback(false, {});
|
||||
return;
|
||||
}
|
||||
if (val->id == Value::INVALID_ID) {
|
||||
crypto::random_device rdev;
|
||||
std::uniform_int_distribution<Value::Id> rand_id;
|
||||
@@ -373,16 +355,13 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
|
||||
// Check if data already exists on the dht
|
||||
get(hash,
|
||||
[val,this] (const std::vector<Sp<Value>>& vals) {
|
||||
if (logger_)
|
||||
logger_->d("Found online previous value being announced.");
|
||||
DHT_LOG.d("Found online previous value being announced.");
|
||||
for (const auto& v : vals) {
|
||||
if (!v->isSigned()) {
|
||||
if (logger_)
|
||||
logger_->e("Existing non-signed value seems to exists at this location.");
|
||||
} else if (not v->owner or v->owner->getId() != getId()) {
|
||||
if (logger_)
|
||||
logger_->e("Existing signed value belonging to someone else seems to exists at this location.");
|
||||
} else if (val->seq <= v->seq)
|
||||
if (!v->isSigned())
|
||||
DHT_LOG.e("Existing non-signed value seems to exists at this location.");
|
||||
else if (not v->owner or v->owner->getId() != getId())
|
||||
DHT_LOG.e("Existing signed value belonging to someone else seems to exists at this location.");
|
||||
else if (val->seq <= v->seq)
|
||||
val->seq = v->seq + 1;
|
||||
}
|
||||
return true;
|
||||
@@ -399,24 +378,17 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
|
||||
void
|
||||
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
|
||||
{
|
||||
if (not key_) {
|
||||
if (callback)
|
||||
callback(false, {});
|
||||
return;
|
||||
}
|
||||
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
|
||||
if(!pk || !*pk) {
|
||||
if (callback)
|
||||
callback(false, {});
|
||||
return;
|
||||
}
|
||||
if (logger_)
|
||||
logger_->w("Encrypting data for PK: %s", pk->getId().toString().c_str());
|
||||
DHT_LOG.w("Encrypting data for PK: %s", pk->getId().toString().c_str());
|
||||
try {
|
||||
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
|
||||
} catch (const std::exception& e) {
|
||||
if (logger_)
|
||||
logger_->e("Error putting encrypted data: %s", e.what());
|
||||
DHT_LOG.e("Error putting encrypted data: %s", e.what());
|
||||
if (callback)
|
||||
callback(false, {});
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
+12
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -76,8 +76,11 @@ SockAddr::resolve(const std::string& host, const std::string& service)
|
||||
if(rc != 0)
|
||||
throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
|
||||
|
||||
for (addrinfo* infop = info; infop; infop = infop->ai_next)
|
||||
addrinfo* infop = info;
|
||||
while (infop) {
|
||||
ips.emplace_back(infop->ai_addr, infop->ai_addrlen);
|
||||
infop = infop->ai_next;
|
||||
}
|
||||
freeaddrinfo(info);
|
||||
return ips;
|
||||
}
|
||||
@@ -233,27 +236,17 @@ bool operator==(const SockAddr& a, const SockAddr& b) {
|
||||
}
|
||||
|
||||
time_point from_time_t(std::time_t t) {
|
||||
auto dt = system_clock::from_time_t(t) - system_clock::now();
|
||||
auto now = clock::now();
|
||||
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
|
||||
return time_point::max();
|
||||
else if (dt < system_clock::duration(0) and now < time_point::min() - dt)
|
||||
return time_point::min();
|
||||
return now + dt;
|
||||
return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now());
|
||||
}
|
||||
|
||||
std::time_t to_time_t(time_point t) {
|
||||
auto dt = t - clock::now();
|
||||
auto now = system_clock::now();
|
||||
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::max());
|
||||
else if (dt < duration(0) and now <= system_clock::time_point::min() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::min());
|
||||
return system_clock::to_time_t(now + std::chrono::duration_cast<system_clock::duration>(dt));
|
||||
return std::chrono::system_clock::to_time_t(
|
||||
std::chrono::system_clock::now() +
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(t - clock::now()));
|
||||
}
|
||||
|
||||
Blob
|
||||
unpackBlob(const msgpack::object& o) {
|
||||
unpackBlob(msgpack::object& o) {
|
||||
switch (o.type) {
|
||||
case msgpack::type::BIN:
|
||||
return {o.via.bin.ptr, o.via.bin.ptr+o.via.bin.size};
|
||||
@@ -277,25 +270,11 @@ unpackMsg(Blob b) {
|
||||
}
|
||||
|
||||
msgpack::object*
|
||||
findMapValue(const msgpack::object& map, const char* key) {
|
||||
findMapValue(msgpack::object& map, const std::string& key) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if (o.key.type == msgpack::type::STR
|
||||
&& std::strncmp(o.key.via.str.ptr, key, o.key.via.str.size) == 0)
|
||||
return &o.val;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
msgpack::object*
|
||||
findMapValue(const msgpack::object& map, const std::string& key) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if (o.key.type == msgpack::type::STR
|
||||
&& key.size() == o.key.via.str.size
|
||||
&& std::strncmp(o.key.via.str.ptr, key.data(), o.key.via.str.size) == 0)
|
||||
if (o.key.type == msgpack::type::STR && o.key.as<std::string>() == key)
|
||||
return &o.val;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
+244
-195
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
|
||||
*
|
||||
@@ -22,9 +22,12 @@
|
||||
#endif
|
||||
|
||||
#include "value.h"
|
||||
|
||||
#include "default_types.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
#include "securedht.h" // print certificate ID
|
||||
#endif
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
#include "base64.h"
|
||||
@@ -42,10 +45,50 @@ Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data) {
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
Value::Filter
|
||||
Value::OwnerFilter(const crypto::PublicKey& pk) {
|
||||
return OwnerFilter(pk.getId());
|
||||
}
|
||||
|
||||
|
||||
Value::Filter
|
||||
Value::OwnerFilter(const InfoHash& pkh) {
|
||||
return [pkh](const Value& v) {
|
||||
return v.owner and v.owner->getId() == pkh;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
Value::sign(const crypto::PrivateKey& key) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Can't sign encrypted data.");
|
||||
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
|
||||
signature = key.sign(getToSign());
|
||||
}
|
||||
|
||||
bool
|
||||
Value::checkSignature() const {
|
||||
return isSigned() and owner->checkSignature(getToSign(), signature);
|
||||
}
|
||||
|
||||
Value
|
||||
Value::encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
|
||||
if (isEncrypted())
|
||||
throw DhtException("Data is already encrypted.");
|
||||
setRecipient(to.getId());
|
||||
sign(from);
|
||||
Value nv {id};
|
||||
nv.setCypher(to.encrypt(getToEncrypt()));
|
||||
return nv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
{
|
||||
auto flags(s.flags());
|
||||
s << "Value[id:" << std::hex << v.id << std::dec << ' ';
|
||||
s << "Value[id:" << std::hex << v.id << std::dec << " ";
|
||||
if (v.isEncrypted())
|
||||
s << "encrypted ";
|
||||
else if (v.isSigned()) {
|
||||
@@ -56,7 +99,9 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
if (not v.isEncrypted()) {
|
||||
if (v.type == IpServiceAnnouncement::TYPE.id) {
|
||||
s << IpServiceAnnouncement(v.data);
|
||||
} else if (v.type == CERTIFICATE_TYPE.id) {
|
||||
}
|
||||
#ifndef OPENDHT_LIGHT
|
||||
else if (v.type == CERTIFICATE_TYPE.id) {
|
||||
s << "Certificate";
|
||||
#ifdef OPENDHT_LOG_CRT_ID
|
||||
try {
|
||||
@@ -66,26 +111,17 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
s << " (invalid)";
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (v.user_type.empty())
|
||||
s << "data:";
|
||||
else
|
||||
s << "data(" << v.user_type << "):";
|
||||
if (v.user_type == "text/plain") {
|
||||
s << '"';
|
||||
s.write((const char*)v.data.data(), v.data.size());
|
||||
s << '"';
|
||||
} else if (v.data.size() < 1024) {
|
||||
s << std::hex;
|
||||
for (auto i : v.data)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)i;
|
||||
s << std::dec;
|
||||
} else {
|
||||
s << v.data.size() << " bytes";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
s << "Data (type: " << v.type << " ): ";
|
||||
s << std::hex;
|
||||
for (auto i : v.data)
|
||||
s << std::setfill('0') << std::setw(2) << (unsigned)i;
|
||||
s << std::dec;
|
||||
}
|
||||
}
|
||||
s << ']';
|
||||
s << "]";
|
||||
s.flags(flags);
|
||||
return s;
|
||||
}
|
||||
@@ -98,6 +134,20 @@ ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const
|
||||
return v->size() <= MAX_VALUE_SIZE;
|
||||
}
|
||||
|
||||
msgpack::object*
|
||||
findMapValue(const msgpack::object& map, const std::string& key) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if(o.key.type != msgpack::type::STR)
|
||||
continue;
|
||||
if (o.key.as<std::string>() == key) {
|
||||
return &o.val;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t
|
||||
Value::size() const
|
||||
{
|
||||
@@ -105,24 +155,20 @@ Value::size() const
|
||||
}
|
||||
|
||||
void
|
||||
Value::msgpack_unpack(const msgpack::object& o)
|
||||
Value::msgpack_unpack(msgpack::object o)
|
||||
{
|
||||
if (o.type != msgpack::type::MAP or o.via.map.size < 2)
|
||||
throw msgpack::type_error();
|
||||
if (o.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
if (o.via.map.size < 2) throw msgpack::type_error();
|
||||
|
||||
if (auto rid = findMapValue(o, VALUE_KEY_ID)) {
|
||||
if (auto rid = findMapValue(o, "id")) {
|
||||
id = rid->as<Id>();
|
||||
} else
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (auto rdat = findMapValue(o, VALUE_KEY_DAT)) {
|
||||
if (auto rdat = findMapValue(o, "dat")) {
|
||||
msgpack_unpack_body(*rdat);
|
||||
} else
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (auto rprio = findMapValue(o, VALUE_KEY_PRIO)) {
|
||||
priority = rprio->as<unsigned>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -141,37 +187,40 @@ Value::msgpack_unpack_body(const msgpack::object& o)
|
||||
} else {
|
||||
if (o.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
auto rbody = findMapValue(o, VALUE_KEY_BODY);
|
||||
auto rbody = findMapValue(o, "body");
|
||||
if (not rbody)
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (auto rdata = findMapValue(*rbody, VALUE_KEY_DATA)) {
|
||||
if (auto rdata = findMapValue(*rbody, "data")) {
|
||||
data = unpackBlob(*rdata);
|
||||
} else
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (auto rtype = findMapValue(*rbody, VALUE_KEY_TYPE)) {
|
||||
if (auto rtype = findMapValue(*rbody, "type")) {
|
||||
type = rtype->as<ValueType::Id>();
|
||||
} else
|
||||
throw msgpack::type_error();
|
||||
|
||||
if (auto rutype = findMapValue(*rbody, VALUE_KEY_USERTYPE)) {
|
||||
if (auto rutype = findMapValue(*rbody, "utype")) {
|
||||
user_type = rutype->as<std::string>();
|
||||
}
|
||||
|
||||
if (auto rowner = findMapValue(*rbody, VALUE_KEY_OWNER)) {
|
||||
if (auto rseq = findMapValue(*rbody, VALUE_KEY_SEQ))
|
||||
if (auto rowner = findMapValue(*rbody, "owner")) {
|
||||
if (auto rseq = findMapValue(*rbody, "seq"))
|
||||
seq = rseq->as<decltype(seq)>();
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
|
||||
#ifndef OPENDHT_LIGHT
|
||||
crypto::PublicKey new_owner;
|
||||
new_owner.msgpack_unpack(*rowner);
|
||||
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
|
||||
if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) {
|
||||
#endif
|
||||
if (auto rrecipient = findMapValue(*rbody, "to")) {
|
||||
recipient = rrecipient->as<InfoHash>();
|
||||
}
|
||||
|
||||
if (auto rsig = findMapValue(o, VALUE_KEY_SIGNATURE)) {
|
||||
if (auto rsig = findMapValue(o, "sig")) {
|
||||
signature = unpackBlob(*rsig);
|
||||
} else
|
||||
throw msgpack::type_error();
|
||||
@@ -180,65 +229,65 @@ Value::msgpack_unpack_body(const msgpack::object& o)
|
||||
}
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
Value::Value(const Json::Value& json)
|
||||
Value::Value(Json::Value& json)
|
||||
{
|
||||
id = Value::Id(unpackId(json, VALUE_KEY_ID));
|
||||
const auto& jcypher = json["cypher"];
|
||||
if (jcypher.isString())
|
||||
cypher = base64_decode(jcypher.asString());
|
||||
const auto& jsig = json[VALUE_KEY_SIGNATURE];
|
||||
if (jsig.isString())
|
||||
signature = base64_decode(jsig.asString());
|
||||
const auto& jseq = json[VALUE_KEY_SEQ];
|
||||
if (!jseq.isNull())
|
||||
seq = jseq.asInt();
|
||||
const auto& jowner = json[VALUE_KEY_OWNER];
|
||||
if (jowner.isString()) {
|
||||
auto ownerStr = jowner.asString();
|
||||
id = Value::Id(unpackId(json, "id"));
|
||||
if (json.isMember("cypher")) {
|
||||
auto cypherStr = json["cypher"].asString();
|
||||
cypherStr = base64_decode(cypherStr);
|
||||
cypher = std::vector<unsigned char>(cypherStr.begin(), cypherStr.end());
|
||||
}
|
||||
if (json.isMember("sig")) {
|
||||
auto sigStr = json["sig"].asString();
|
||||
sigStr = base64_decode(sigStr);
|
||||
signature = std::vector<unsigned char>(sigStr.begin(), sigStr.end());
|
||||
}
|
||||
if (json.isMember("seq"))
|
||||
seq = json["seq"].asInt();
|
||||
#ifndef OPENDHT_LIGHT
|
||||
if (json.isMember("owner")) {
|
||||
auto ownerStr = json["owner"].asString();
|
||||
auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end());
|
||||
owner = std::make_shared<const crypto::PublicKey>(ownerBlob);
|
||||
}
|
||||
const auto& jto = json[VALUE_KEY_TO];
|
||||
if (jto.isString())
|
||||
recipient = InfoHash(jto.asString());
|
||||
const auto& jtype = json[VALUE_KEY_TYPE];
|
||||
if (!jtype.isNull())
|
||||
type = jtype.asInt();
|
||||
const auto& jdata = json[VALUE_KEY_DATA];
|
||||
if (jdata.isString())
|
||||
data = base64_decode(jdata.asString());
|
||||
const auto& jutype = json[VALUE_KEY_USERTYPE];
|
||||
if (jutype.isString())
|
||||
user_type = jutype.asString();
|
||||
const auto& jprio = json["prio"];
|
||||
if (jprio.isIntegral())
|
||||
priority = jprio.asUInt();
|
||||
#endif
|
||||
if (json.isMember("to")) {
|
||||
auto toStr = json["to"].asString();
|
||||
recipient = InfoHash(toStr);
|
||||
}
|
||||
if (json.isMember("type"))
|
||||
type = json["type"].asInt();
|
||||
if (json.isMember("data")){
|
||||
auto dataStr = json["data"].asString();
|
||||
dataStr = base64_decode(dataStr);
|
||||
data = std::vector<unsigned char>(dataStr.begin(), dataStr.end());
|
||||
}
|
||||
if (json.isMember("utype"))
|
||||
user_type = json["utype"].asString();
|
||||
}
|
||||
|
||||
Json::Value
|
||||
Value::toJson() const
|
||||
{
|
||||
Json::Value val;
|
||||
val[VALUE_KEY_ID] = std::to_string(id);
|
||||
val["id"] = std::to_string(id);
|
||||
if (isEncrypted()) {
|
||||
val["cypher"] = base64_encode(cypher);
|
||||
} else {
|
||||
if (isSigned())
|
||||
val[VALUE_KEY_SIGNATURE] = base64_encode(signature);
|
||||
val["sig"] = base64_encode(signature);
|
||||
bool has_owner = owner && *owner;
|
||||
if (has_owner) { // isSigned
|
||||
val[VALUE_KEY_SEQ] = seq;
|
||||
val[VALUE_KEY_OWNER] = owner->toString();
|
||||
val["seq"] = seq;
|
||||
val["owner"] = owner->toString();
|
||||
if (recipient)
|
||||
val[VALUE_KEY_TO] = recipient.toString();
|
||||
val["to"] = recipient.toString();
|
||||
}
|
||||
val[VALUE_KEY_TYPE] = type;
|
||||
val[VALUE_KEY_DATA] = base64_encode(data);
|
||||
val["type"] = type;
|
||||
val["data"] = base64_encode(data);
|
||||
if (not user_type.empty())
|
||||
val[VALUE_KEY_USERTYPE] = user_type;
|
||||
val["utype"] = user_type;
|
||||
}
|
||||
if (priority)
|
||||
val["prio"] = priority;
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -246,11 +295,13 @@ uint64_t
|
||||
unpackId(const Json::Value& json, const std::string& key) {
|
||||
uint64_t ret = 0;
|
||||
try {
|
||||
const auto& t = json[key];
|
||||
if (t.isString()) {
|
||||
ret = std::stoull(t.asString());
|
||||
} else {
|
||||
ret = t.asLargestUInt();
|
||||
if (json.isMember(key)) {
|
||||
const auto& t = json[key];
|
||||
if (t.isString()) {
|
||||
ret = std::stoull(t.asString());
|
||||
} else {
|
||||
ret = t.asLargestUInt();
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
return ret;
|
||||
@@ -263,18 +314,18 @@ FieldValue::operator==(const FieldValue& vfd) const
|
||||
if (field != vfd.field)
|
||||
return false;
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
return intValue == vfd.intValue;
|
||||
case Value::Field::OwnerPk:
|
||||
return hashValue == vfd.hashValue;
|
||||
case Value::Field::UserType:
|
||||
return blobValue == vfd.blobValue;
|
||||
case Value::Field::None:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
return intValue == vfd.intValue;
|
||||
case Value::Field::OwnerPk:
|
||||
return hashValue == vfd.hashValue;
|
||||
case Value::Field::UserType:
|
||||
return blobValue == vfd.blobValue;
|
||||
case Value::Field::None:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,25 +333,25 @@ Value::Filter
|
||||
FieldValue::getLocalFilter() const
|
||||
{
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
return Value::IdFilter(intValue);
|
||||
case Value::Field::ValueType:
|
||||
return Value::TypeFilter(intValue);
|
||||
case Value::Field::OwnerPk:
|
||||
return Value::OwnerFilter(hashValue);
|
||||
case Value::Field::SeqNum:
|
||||
return Value::SeqNumFilter(intValue);
|
||||
case Value::Field::UserType:
|
||||
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
|
||||
default:
|
||||
return {};
|
||||
case Value::Field::Id:
|
||||
return Value::IdFilter(intValue);
|
||||
case Value::Field::ValueType:
|
||||
return Value::TypeFilter(intValue);
|
||||
case Value::Field::OwnerPk:
|
||||
return Value::OwnerFilter(hashValue);
|
||||
case Value::Field::SeqNum:
|
||||
return Value::SeqNumFilter(intValue);
|
||||
case Value::Field::UserType:
|
||||
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
{
|
||||
if (not s.empty()) {
|
||||
auto selection = s.getSelection();
|
||||
auto selection = s.getSelection();
|
||||
if (not selection.empty()) {
|
||||
std::transform(selection.begin(), selection.end(), std::inserter(index, index.end()),
|
||||
[](const std::set<Value::Field>::value_type& f) {
|
||||
return std::make_pair(f, FieldValue {});
|
||||
@@ -313,23 +364,25 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
for (const auto& fvp : index) {
|
||||
const auto& f = fvp.first;
|
||||
switch (f) {
|
||||
case Value::Field::Id:
|
||||
index[f] = {f, v.id};
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
index[f] = {f, v.type};
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
index[f] = {f, v.seq};
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id:
|
||||
index[f] = {f, v.id};
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
index[f] = {f, v.type};
|
||||
break;
|
||||
#ifndef OPENDHT_LIGHT
|
||||
case Value::Field::OwnerPk:
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
|
||||
break;
|
||||
#endif
|
||||
case Value::Field::SeqNum:
|
||||
index[f] = {f, v.seq};
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,28 +402,28 @@ std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi) {
|
||||
os << "Index[";
|
||||
for (auto v = fvi.index.begin(); v != fvi.index.end(); ++v) {
|
||||
switch (v->first) {
|
||||
case Value::Field::Id: {
|
||||
auto flags(os.flags());
|
||||
os << "Id:" << std::hex << v->second.getInt();
|
||||
os.flags(flags);
|
||||
break;
|
||||
}
|
||||
case Value::Field::ValueType:
|
||||
os << "ValueType:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
os << "Owner:" << v->second.getHash();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
os << "Seq:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto ut = v->second.getBlob();
|
||||
os << "UserType:" << std::string(ut.begin(), ut.end());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id: {
|
||||
auto flags(os.flags());
|
||||
os << "Id:" << std::hex << v->second.getInt();
|
||||
os.flags(flags);
|
||||
break;
|
||||
}
|
||||
case Value::Field::ValueType:
|
||||
os << "ValueType:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
os << "Owner:" << v->second.getHash().toString();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
os << "Seq:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto ut = v->second.getBlob();
|
||||
os << "UserType:" << std::string(ut.begin(), ut.end());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
os << (std::next(v) != fvi.index.end() ? "," : "");
|
||||
}
|
||||
@@ -386,19 +439,19 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
|
||||
for (const auto& field : fields) {
|
||||
auto& field_value = o.via.array.ptr[offset+(j++)];
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
index[field] = FieldValue(field, field_value.as<uint64_t>());
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[field] = FieldValue(field, field_value.as<InfoHash>());
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[field] = FieldValue(field, field_value.as<Blob>());
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
index[field] = FieldValue(field, field_value.as<uint64_t>());
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[field] = FieldValue(field, field_value.as<InfoHash>());
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[field] = FieldValue(field, field_value.as<Blob>());
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,13 +473,13 @@ Select::Select(const std::string& q_str) {
|
||||
|
||||
while (std::getline(fields, token, ',')) {
|
||||
trim_str(token);
|
||||
if (token == VALUE_KEY_ID)
|
||||
if (token == "id")
|
||||
field(Value::Field::Id);
|
||||
else if (token == "value_type")
|
||||
field(Value::Field::ValueType);
|
||||
else if (token == "owner_pk")
|
||||
field(Value::Field::OwnerPk);
|
||||
if (token == VALUE_KEY_SEQ)
|
||||
if (token == "seq")
|
||||
field(Value::Field::SeqNum);
|
||||
else if (token == "user_type")
|
||||
field(Value::Field::UserType);
|
||||
@@ -462,13 +515,13 @@ Where::Where(const std::string& q_str) {
|
||||
s = value_str.substr(1, value_str.size()-2);
|
||||
else
|
||||
s = value_str;
|
||||
if (field_str == VALUE_KEY_ID)
|
||||
if (field_str == "id")
|
||||
id(v);
|
||||
else if (field_str == "value_type")
|
||||
valueType(v);
|
||||
else if (field_str == "owner_pk")
|
||||
owner(InfoHash(s));
|
||||
else if (field_str == VALUE_KEY_SEQ)
|
||||
else if (field_str == "seq")
|
||||
seq(v);
|
||||
else if (field_str == "user_type")
|
||||
userType(s);
|
||||
@@ -524,14 +577,11 @@ bool Query::isSatisfiedBy(const Query& q) const {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
s << "SELECT ";
|
||||
if (select.fieldSelection_.empty())
|
||||
s << '*';
|
||||
else
|
||||
for (auto fs = select.fieldSelection_.begin(); fs != select.fieldSelection_.end();) {
|
||||
switch (*fs) {
|
||||
s << "SELECT " << (select.fieldSelection_.empty() ? "*" : "");
|
||||
for (auto fs = select.fieldSelection_.begin() ; fs != select.fieldSelection_.end() ; ++fs) {
|
||||
switch (*fs) {
|
||||
case Value::Field::Id:
|
||||
s << VALUE_KEY_ID;
|
||||
s << "id";
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
s << "value_type";
|
||||
@@ -543,14 +593,13 @@ std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
s << "owner_public_key";
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
s << VALUE_KEY_SEQ;
|
||||
s << "seq";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (++fs != select.fieldSelection_.end())
|
||||
s << ',';
|
||||
}
|
||||
s << (std::next(fs) != select.fieldSelection_.end() ? "," : "");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -559,25 +608,25 @@ std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
|
||||
s << "WHERE ";
|
||||
for (auto f = where.filters_.begin() ; f != where.filters_.end() ; ++f) {
|
||||
switch (f->getField()) {
|
||||
case Value::Field::Id:
|
||||
s << VALUE_KEY_ID << '=' << f->getInt();
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
s << "value_type=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
s << "owner_pk_hash=" << f->getHash();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
s << VALUE_KEY_SEQ << '=' << f->getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto b = f->getBlob();
|
||||
s << "user_type=" << std::string {b.begin(), b.end()};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id:
|
||||
s << "id=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
s << "value_type=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
s << "owner_pk_hash=" << f->getHash().toString();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
s << "seq=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto b = f->getBlob();
|
||||
s << "user_type=" << std::string {b.begin(), b.end()};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s << (std::next(f) != where.filters_.end() ? "," : "");
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
@@ -34,13 +34,10 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DhtProxyTester);
|
||||
|
||||
void
|
||||
DhtProxyTester::setUp() {
|
||||
clientConfig.dht_config.node_config.max_peer_req_per_sec = -1;
|
||||
clientConfig.dht_config.node_config.max_req_per_sec = -1;
|
||||
|
||||
nodePeer.run(0, clientConfig);
|
||||
nodePeer.run(0);
|
||||
|
||||
nodeProxy = std::make_shared<dht::DhtRunner>();
|
||||
nodeProxy->run(0, clientConfig);
|
||||
nodeProxy->run(0);
|
||||
nodeProxy->bootstrap(nodePeer.getBound());
|
||||
|
||||
auto serverCAIdentity = dht::crypto::generateEcIdentity("DHT Node CA");
|
||||
@@ -53,6 +50,8 @@ DhtProxyTester::setUp() {
|
||||
|
||||
clientConfig.server_ca = serverCAIdentity.second;
|
||||
clientConfig.client_identity = dht::crypto::generateIdentity("DhtProxyTester");
|
||||
clientConfig.dht_config.node_config.maintain_storage = false;
|
||||
clientConfig.threaded = true;
|
||||
clientConfig.push_node_id = "dhtnode";
|
||||
clientConfig.proxy_server = "https://127.0.0.1:8080";
|
||||
}
|
||||
@@ -281,7 +280,7 @@ DhtProxyTester::testFuzzy()
|
||||
},[&](bool ok){
|
||||
CPPUNIT_ASSERT(ok);
|
||||
});
|
||||
std::this_thread::sleep_for(5ms);
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
@@ -29,12 +29,8 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester);
|
||||
|
||||
void
|
||||
DhtRunnerTester::setUp() {
|
||||
dht::DhtRunner::Config config;
|
||||
config.dht_config.node_config.max_peer_req_per_sec = -1;
|
||||
config.dht_config.node_config.max_req_per_sec = -1;
|
||||
|
||||
node1.run(42222, config);
|
||||
node2.run(42232, config);
|
||||
node1.run(42222);
|
||||
node2.run(42232);
|
||||
node2.bootstrap(node1.getBound());
|
||||
}
|
||||
|
||||
@@ -88,9 +84,7 @@ DhtRunnerTester::testListen() {
|
||||
auto a = dht::InfoHash::get("234");
|
||||
auto b = dht::InfoHash::get("2345");
|
||||
auto c = dht::InfoHash::get("23456");
|
||||
auto d = dht::InfoHash::get("234567");
|
||||
constexpr unsigned N = 256;
|
||||
constexpr unsigned SZ = 56 * 1024;
|
||||
constexpr unsigned N = 32;
|
||||
|
||||
auto ftokena = node1.listen(a, [&](const std::shared_ptr<dht::Value>&) {
|
||||
valueCount++;
|
||||
@@ -107,16 +101,6 @@ DhtRunnerTester::testListen() {
|
||||
return true;
|
||||
});
|
||||
|
||||
auto ftokend = node1.listen(d, [&](const std::shared_ptr<dht::Value>&) {
|
||||
valueCount++;
|
||||
return true;
|
||||
});
|
||||
|
||||
std::vector<uint8_t> mtu;
|
||||
mtu.reserve(SZ);
|
||||
for (size_t i = 0; i < SZ; i++)
|
||||
mtu.emplace_back((i % 2) ? 'T' : 'M');
|
||||
|
||||
for (unsigned i=0; i<N; i++) {
|
||||
node2.put(a, dht::Value("v1"), [&](bool ok) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
@@ -130,41 +114,29 @@ DhtRunnerTester::testListen() {
|
||||
if (ok) putOkCount++;
|
||||
cv.notify_all();
|
||||
});
|
||||
auto bigVal = std::make_shared<dht::Value>();
|
||||
bigVal->data = mtu;
|
||||
node2.put(c, bigVal, [&](bool ok) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
putCount++;
|
||||
if (ok) putOkCount++;
|
||||
cv.notify_all();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 3u; }));
|
||||
CPPUNIT_ASSERT_EQUAL(N * 3u, putOkCount);
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 2u; }));
|
||||
CPPUNIT_ASSERT_EQUAL(N * 2u, putOkCount);
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT(ftokena.valid());
|
||||
CPPUNIT_ASSERT(ftokenb.valid());
|
||||
CPPUNIT_ASSERT(ftokenc.valid());
|
||||
CPPUNIT_ASSERT(ftokend.valid());
|
||||
|
||||
auto tokena = ftokena.get();
|
||||
auto tokenc = ftokenc.get();
|
||||
auto tokend = ftokend.get();
|
||||
// tokenb might be 0 since the callback returns false.
|
||||
|
||||
CPPUNIT_ASSERT(tokena);
|
||||
CPPUNIT_ASSERT(tokenc);
|
||||
CPPUNIT_ASSERT(tokend);
|
||||
CPPUNIT_ASSERT_EQUAL(N * 2u + 1u, valueCount.load());
|
||||
CPPUNIT_ASSERT_EQUAL(N + 1u, valueCount.load());
|
||||
|
||||
node1.cancelListen(a, tokena);
|
||||
node1.cancelListen(b, std::move(ftokenb));
|
||||
node1.cancelListen(c, tokenc);
|
||||
node1.cancelListen(d, tokend);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
|
||||
* Copyright (C) 2019 Savoir-faire Linux Inc.
|
||||
*
|
||||
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
*
|
||||
|
||||
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user