Compare commits

...
92 Commits
Author SHA1 Message Date
Adrien Béraud 8c29848ba1 build: add light mode 2019-12-13 17:10:05 -05:00
Adrien Béraud c1e2a368a8 docker: add ssl, install http-parser to /usr 2019-12-13 16:24:46 -05:00
Adrien Béraud c62f27c929 tools: add missing include 2019-12-12 17:00:35 -05:00
Adrien Béraud ec0c3d4d25 docker: build asio without tests and examples 2019-12-12 15:04:45 -05:00
Adrien Béraud 17a1178054 tools: add missing includes for indexation support 2019-12-12 15:00:17 -05:00
Adrien Béraud 6256c576c9 configure: cleanup 2019-12-12 14:51:59 -05:00
Adrien Béraud 9565adf693 proxy server: always depend on jsoncpp 2019-12-12 14:51:59 -05:00
Adrien Béraud c10aa32596 cpp: include config.h when necessary 2019-12-12 14:51:59 -05:00
Adrien Béraud 21c294f352 docker: update asio 2019-12-12 14:51:59 -05:00
Adrien Béraud 4654f78e08 autotools: allow to build without peer discovery 2019-12-12 14:51:59 -05:00
Adrien Béraud 38644fc934 includes: don't include proxy server, pht by default 2019-12-12 14:44:53 -05:00
Adrien Béraud fa8dc4c835 callbacks: add missing header 2019-12-12 14:33:00 -05:00
Adrien Béraud 6dab10cac2 github: disable tests and examples when building asio 2019-12-12 12:24:56 -05:00
Adrien Béraud 77a1c27f2b github: build asio 2019-12-12 11:52:43 -05:00
Adrien Béraud e8577bfd05 dhtrunner: fix build without peer discovery 2019-12-12 11:42:06 -05:00
Adrien Béraud c0327a9881 dhtrunner: fix build without peer discovery 2019-12-11 11:43:20 -05:00
Adrien Béraud 2a1eacc949 tests: only link with ssl if required 2019-12-09 16:23:15 -05:00
Adrien Béraud e705bebc25 github: don't build proxy 2019-12-09 16:06:39 -05:00
Adrien Béraud a330762f40 build: always use standalone asio 2019-12-09 15:40:48 -05:00
Adrien Béraud e7972ae897 dockerfiles: update 2019-12-09 15:34:26 -05:00
Adrien Béraud 8d2d40cb7f peer discovery: simplify includes 2019-12-09 14:53:27 -05:00
Adrien Béraud aceb548c26 cmake: make peer discovery build optional 2019-12-09 14:43:04 -05:00
Adrien Béraud afce4639e1 tests/peerdiscover: add missing includes 2019-12-09 14:07:42 -05:00
Adrien Béraud e5d248bcd0 peer discovery: use asio 2019-12-09 03:28:45 -05:00
Adrien Béraud 0fbebf8e03 http: cleanup, fix handling error when no logger is set 2019-12-08 10:48:34 -05:00
Adrien Béraud 24efa37846 http: cleanup 2019-12-08 00:25:21 -05:00
Linas Vepstas c0f14ca59d Fix duplicated, non-functional log message.
Inside the if-statement, the log message will always print zero.
Confusingly, its the same message as the one in the loop above it.
Make the message distinct.
2019-12-07 22:28:35 -05:00
Adrien Béraud 05a66cc1f1 proxy client: use common jsonReader 2019-12-07 22:22:37 -05:00
Adrien Béraud ed6df8869c proxy: don't use keep-alive by default 2019-12-07 22:22:37 -05:00
Adrien Béraud b7d410e1aa tests: add http tester 2019-12-07 16:23:08 -05:00
Adrien Béraud 77a377a406 http: add OnDone callback 2019-12-07 16:23:08 -05:00
Adrien Béraud e0b6f152f1 proxy client: add LineSplitter 2019-12-07 16:23:08 -05:00
Adrien Béraud dd3c789916 proxy server: 0-initialize fields 2019-12-07 16:23:08 -05:00
Adrien Béraud 333087bcba dhtrunner: fix getNodeInfo using proxy client 2019-12-07 16:23:08 -05:00
Adrien Béraud 5b87090cab http: use http_parser parsing logic 2019-12-07 16:23:08 -05:00
Adrien Béraud fffee634f1 proxy client: avoid destroying twice 2019-12-05 18:39:39 -05:00
Adrien Béraud c4aa272dbb http/request: add constructor 2019-12-05 18:39:39 -05:00
Adrien Béraud 4ce78bdb4d c wrapper: link statically when required 2019-12-05 18:35:43 -05:00
Adrien Béraud f331f39c77 c wrapper: add dht_privatekey_export 2019-12-05 18:35:43 -05:00
Adrien Béraud 17fb92654e http: check parser before use 2019-12-03 16:45:19 -05:00
Adrien Béraud 294034f00f proxy client: don't report connectivity failure for aborted requests 2019-12-03 16:21:33 -05:00
Adrien Béraud 36857c1f3d http/request: add aborted flag and actual status code 2019-12-03 16:21:04 -05:00
Adrien Béraud 7e9f5303bd github: don't run distcheck 2019-12-02 01:30:56 -05:00
Adrien Béraud c2780b1ca9 build/autoconf: always build python Makefile 2019-12-02 01:15:38 -05:00
Adrien Béraud 16b798324d github: disable python 2019-12-02 00:53:27 -05:00
Adrien Béraud bc850bf00c build/autotools: use proper path for tools build include 2019-12-02 00:30:37 -05:00
Adrien Béraud 0d8d302128 update argon2 2019-12-02 00:11:08 -05:00
Adrien Béraud 97013badfa github: install argon2 before configure 2019-12-02 00:06:49 -05:00
Adrien Béraud 31185c24f0 build/autoconf: always build doc Makefile 2019-12-01 23:49:04 -05:00
Adrien Béraud 2f6f8e2ac1 cmake/tools: link with readline dependenciess 2019-12-01 22:46:41 -05:00
zhengfish 8f141951ce fixed a compiling error in openwrt-18.04.5
Signed-off-by: zhengfish <zhengfish@gmail.com>
2019-12-01 22:41:29 -05:00
zhengfish 43d111b7dc fixed a linking error in openwrt-18.06: undefined reference to 'tgetnum'
Signed-off-by: zhengfish <zhengfish@gmail.com>
2019-12-01 22:41:29 -05:00
Adrien Béraud 620ba2a89b proxy server: fix warning 2019-12-01 21:01:42 -05:00
Adrien Béraud d1598380db proxy server: fix build without push notifications 2019-12-01 21:00:27 -05:00
Adrien Béraud 69fe399db0 proxy server: cancelListen on destroy 2019-12-01 20:54:48 -05:00
Adrien Béraud a60dde2e13 tests: use shutdown 2019-12-01 19:41:02 -05:00
Adrien Béraud 201982b1a9 dhtrunner: don't count cancel as ops 2019-12-01 19:40:44 -05:00
Adrien Béraud 83f2b272a7 dhtrunner: add ongoing op count to node info 2019-12-01 15:07:35 -05:00
Adrien Béraud 7e47d0458a tests/proxy: cleanup 2019-12-01 14:53:50 -05:00
Adrien Béraud f6d26757fa dhtrunner: wait for current ops to complete on shutdown 2019-12-01 14:53:36 -05:00
Adrien Béraud 476d0bca4f proxy client: lock while canceling requests 2019-12-01 14:52:42 -05:00
Adrien Béraud 259986e786 network engine: don't throw in case of unknown transaction 2019-12-01 14:52:21 -05:00
Adrien Béraud 8ff0c979d4 proxy server: cleanup 2019-11-30 20:36:20 -05:00
Adrien Béraud 913cb543c8 crypto: improve exception types 2019-11-30 19:42:02 -05:00
Adrien Béraud b380c9ffba http: cleanup 2019-11-30 18:47:29 -05:00
Adrien Béraud 8c717085b4 cmake: cleanup 2019-11-30 18:11:00 -05:00
Adrien Béraud 48742a1058 tests: fix catching exception 2019-11-30 18:11:00 -05:00
Adrien Béraud fe11285a03 http: close on request end with Connection: close, cleanup 2019-11-30 18:11:00 -05:00
Adrien Béraud fb34770a54 http: reuse connection istream, cleanup 2019-11-30 17:21:52 -05:00
Adrien Béraud 4a909419e9 http: handle Request lifetime when sharing resolver/connection 2019-11-30 17:21:52 -05:00
Adrien Béraud dab7099369 proxy server: cleanup 2019-11-28 22:16:22 -05:00
Adrien Béraud 9c84e59bbf autotools: update to C++14 2019-11-27 12:12:29 -05:00
Adrien Béraud eae383b3ed autotools: remove unneeded macros 2019-11-26 12:46:26 -05:00
Adrien Béraud 28bf78408d network utils: fix some race conditions 2019-11-26 12:24:37 -05:00
Adrien Béraud 7ed6f74e6b proxy_server: add mutex to protect requests 2019-11-26 12:24:28 -05:00
Adrien Béraud cf6d9fd8c2 proxy client: add lock for requests 2019-11-25 15:43:23 -05:00
Adrien Béraud 5df34bb752 http: use atomic ids 2019-11-25 15:42:45 -05:00
Adrien Béraud bebb66490d tests: fix proxy tester 2019-11-25 13:44:55 -05:00
Adrien Béraud 5f361748eb Update ccpp.yml 2019-11-19 13:59:55 -05:00
Adrien Béraud 984745624c Update ccpp.yml 2019-11-19 13:58:46 -05:00
Adrien Béraud f9e860fdc8 docker/github: use deps base image 2019-11-19 13:52:40 -05:00
Adrien Béraud 06ea3d23e5 docker: add dockerfiles for Ubuntu 18.04 (Bionic) 2019-11-19 13:44:45 -05:00
Adrien Béraud f0857a5925 Update ccpp.yml 2019-11-19 11:05:00 -05:00
Adrien Béraud 5a993fb902 Create ccpp.yml 2019-11-19 11:02:54 -05:00
Adrien Béraud 8a18c591e9 http: initialize connection type, cleanup 2019-11-12 16:45:00 -05:00
Adrien Béraud 9daa7ec283 dhtrunner: default peer request rate to global/8 2019-11-11 12:58:11 -05:00
Adrien Béraud 01f2ad9ea4 tools: show connectivity change in log 2019-11-11 11:54:44 -05:00
Adrien Béraud 2dd4cde035 tools: factorize print_node_info 2019-11-08 16:52:27 -05:00
Adrien Béraud cb0005d0eb tools: factor configuration parsing 2019-11-08 16:12:04 -05:00
Adrien Béraud eca340b785 tools: add argument to disable rate limiting 2019-11-08 15:29:53 -05:00
Adrien Béraud cdd035b801 rate limiter: cleanup 2019-11-07 19:17:27 -05:00
Adrien Béraud cb7d7f6614 dht: allow to configure rate limiter 2019-11-07 16:43:04 -05:00
60 changed files with 2443 additions and 1834 deletions

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: deps
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev
- name: autogen
run: ./autogen.sh
- name: argon2
run: |
cd argon2 && make && sudo make install && cd ..
- name: asio
run: |
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& sudo make install \
&& cd ../../ && rm -rf asio*
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
+141 -88
View File
@@ -7,83 +7,105 @@ 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)
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_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
find_package(Restinio REQUIRED)
if (Restinio_FOUND)
add_definitions(-DASIO_STANDALONE)
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()
endif()
@@ -95,6 +117,7 @@ if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
@@ -155,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
@@ -173,12 +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/peer_discovery.cpp
src/network_utils.cpp
src/thread_pool.cpp
)
list (APPEND opendht_HEADERS
@@ -186,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
@@ -202,12 +218,33 @@ list (APPEND opendht_HEADERS
include/opendht/securedht.h
include/opendht/log.h
include/opendht/log_enable.h
include/opendht/peer_discovery.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)
add_definitions(-DOPENDHT_PEER_DISCOVERY)
endif()
if (OPENDHT_PYTHON)
message("Indexation enabled since it is required for Python support")
set(OPENDHT_INDEX ON)
@@ -321,7 +358,12 @@ if (OPENDHT_C)
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
target_link_libraries(opendht-c opendht)
if (OPENDHT_SHARED)
target_link_libraries(opendht-c opendht)
else ()
target_link_libraries(opendht-c opendht-static)
endif ()
# PkgConfig module
configure_file (
opendht-c.pc.in
@@ -362,46 +404,57 @@ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATIO
# Unit tests
if (OPENDHT_TESTS)
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
list (APPEND test_FILES
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.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
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
if (OPENDHT_PEER_DISCOVERY)
list (APPEND test_FILES
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
)
endif()
add_executable(opendht_unit_tests
tests/tests_runner.cpp
${test_FILES}
tests/tests_runner.cpp
${test_FILES}
)
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${CPPUNIT_INCLUDE_DIRS})
if (OPENDHT_SHARED)
target_link_libraries(opendht_unit_tests opendht)
target_link_libraries(opendht_unit_tests opendht)
else ()
target_link_libraries(opendht_unit_tests opendht-static)
target_link_libraries(opendht_unit_tests opendht-static)
endif ()
target_link_libraries(opendht_unit_tests
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
ssl crypto jsoncpp
${Jsoncpp_LIBRARIES}
)
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht_unit_tests ${OPENSSL_LIBRARIES})
endif()
enable_testing()
add_test(TEST opendht_unit_tests)
endif()
-2
View File
@@ -16,9 +16,7 @@ if ENABLE_TESTS
SUBDIRS += tests
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
+1 -1
Submodule argon2 updated: 670229c849...62358ba212.
+8 -1
View File
@@ -122,7 +122,7 @@ void dht_publickey_delete(dht_publickey* pk) {
delete reinterpret_cast<PubkeySp*>(pk);
}
int dht_publickey_pack(dht_publickey* pk, char* out, size_t* outlen) {
int dht_publickey_export(const dht_publickey* pk, char* out, size_t* outlen) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return gnutls_pubkey_export(pkey->pk, GNUTLS_X509_FMT_DER, out, outlen);
}
@@ -164,6 +164,13 @@ dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const
}
}
int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, const char* password) {
if (!out or !out_size or !*out_size)
return -1;
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return key->serialize((uint8_t*)out, out_size, password);
}
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(key->getPublicKey())));
+2 -1
View File
@@ -45,7 +45,7 @@ struct OPENDHT_C_PUBLIC dht_publickey;
typedef struct dht_publickey dht_publickey;
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_publickey_delete(dht_publickey* pk);
OPENDHT_C_PUBLIC int dht_publickey_pack(dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC int dht_publickey_export(const dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC dht_infohash dht_publickey_get_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC dht_pkid dht_publickey_get_long_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size);
@@ -56,6 +56,7 @@ struct OPENDHT_C_PUBLIC dht_privatekey;
typedef struct dht_privatekey dht_privatekey;
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bits);
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password);
OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password);
OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*);
OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*);
+19 -18
View File
@@ -35,10 +35,14 @@ AS_IF([test "x$enable_logs" != "xno"], [
dnl Check for indexation
AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])])
AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno")
AS_IF([test "x$enable_indexation" != "xno"], [
AC_DEFINE([OPENDHT_INDEXATION], [1], [Define if DHT indexation is enabled])
AM_COND_IF(ENABLE_INDEXATION, [
AC_DEFINE([OPENDHT_INDEXATION], [], [Define if DHT indexation is enabled])
])
AC_ARG_ENABLE([peer-discovery], [AS_HELP_STRING([--disable-peer-discovery], [Disable peer-discovery])])
AM_CONDITIONAL(ENABLE_PEER_DISCOVERY, test x$enable_peer_discovery != "xno")
AM_COND_IF(ENABLE_PEER_DISCOVERY, [AC_DEFINE([OPENDHT_PEER_DISCOVERY], [], [Define if peer discovery is enabled])])
dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
@@ -98,7 +102,7 @@ AS_IF([test "x$SYS" = "xandroid"],
LT_INIT()
LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
@@ -135,7 +139,7 @@ AS_IF([test "x$with_jsoncpp" != "xno"],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS+=" -DOPENDHT_JSONCPP=1"
CPPFLAGS+=" -DOPENDHT_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"]))
@@ -154,7 +158,7 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
CPPFLAGS+=" -DOPENDHT_PROXY_HTTP_PARSER_FORK"
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
@@ -205,27 +209,24 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT"], [])
AM_COND_IF(ENABLE_PROXY_SERVER, AC_DEFINE([OPENDHT_PROXY_SERVER], [], [Building with proxy server]))
AM_COND_IF(ENABLE_PROXY_CLIENT, AC_DEFINE([OPENDHT_PROXY_CLIENT], [], [Building with proxy client]))
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF([HAVE_DOXYGEN], [
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
])
dnl Configure setup.py if we build the python module
AM_COND_IF([USE_CYTHON], [
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([python/Makefile python/setup.py])
])
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([Makefile
src/Makefile
tools/Makefile
python/Makefile
python/setup.py
tests/Makefile
doc/Makefile
doc/Doxyfile
opendht.pc])
AC_OUTPUT
+4 -1
View File
@@ -1,7 +1,10 @@
dist_man1_MANS = dhtnode.1
noinst_HEADERS = \
Doxyfile
if HAVE_DOXYGEN
doxyfile.stamp:
doxyfile.stamp: Doxyfile
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
+13
View File
@@ -0,0 +1,13 @@
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.0.0
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_C=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_LTO=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+9 -9
View File
@@ -3,13 +3,13 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update && apt-get install -y \
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 libasio-dev \
autotools-dev autoconf libssl-dev \
&& apt-get clean
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -17,22 +17,22 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 && make install \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& 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*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+28
View File
@@ -0,0 +1,28 @@
FROM ubuntu:18.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
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 \
&& 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/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*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
+10 -10
View File
@@ -2,9 +2,9 @@ FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update \
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev libasio-dev cython3 python3-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip \
autotools-dev autoconf libasio-dev \
autotools-dev autoconf libssl-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
@@ -13,7 +13,7 @@ ENV CXX c++
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -21,14 +21,14 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 && make install \
&& PREFIX=/usr make -j8 install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& 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*
@@ -37,9 +37,9 @@ RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade c
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/Stiffstream/restinio/archive/v.0.5.1.2.tar.gz \
&& ls -l && tar -xzf v.0.5.1.2.tar.gz \
&& cd restinio-v.0.5.1.2/dev \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
-6
View File
@@ -19,10 +19,4 @@
#pragma once
#include "opendht/dhtrunner.h"
#ifdef OPENDHT_PROXY_SERVER
#include "opendht/dht_proxy_server.h"
#endif
#include "opendht/default_types.h"
#ifdef OPENDHT_INDEXATION
#include "opendht/indexation/pht.h"
#endif
+18 -2
View File
@@ -44,6 +44,13 @@ enum class NodeStatus {
Connected // 1+ good nodes
};
inline constexpr const char*
statusToStr(NodeStatus status) {
return status == NodeStatus::Connected ? "connected" : (
status == NodeStatus::Connecting ? "connecting" :
"disconnected");
}
struct OPENDHT_PUBLIC NodeStats {
unsigned good_nodes {0},
dubious_nodes {0},
@@ -69,8 +76,9 @@ struct OPENDHT_PUBLIC NodeStats {
struct OPENDHT_PUBLIC NodeInfo {
InfoHash id;
InfoHash node_id;
NodeStats ipv4;
NodeStats ipv6;
NodeStats ipv4 {};
NodeStats ipv6 {};
size_t ongoing_ops {0};
#ifdef OPENDHT_JSONCPP
/**
@@ -106,8 +114,15 @@ 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. */
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};
};
#ifndef OPENDHT_LIGHT
/**
* SecureDht configuration.
*/
@@ -116,6 +131,7 @@ struct OPENDHT_PUBLIC SecureDhtConfig
Config node_config {};
crypto::Identity id {};
};
#endif
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
+11 -4
View File
@@ -43,16 +43,22 @@ namespace dht {
namespace crypto {
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
public:
CryptoException(const std::string& str) : std::runtime_error(str) {};
public:
explicit CryptoException(const std::string& str) : std::runtime_error(str) {};
explicit CryptoException(const char* str) : std::runtime_error(str) {};
CryptoException(const CryptoException& e) noexcept = default;
CryptoException& operator=(const CryptoException&) noexcept = default;
};
/**
* Exception thrown when a decryption error happened.
*/
class OPENDHT_PUBLIC DecryptError : public CryptoException {
public:
DecryptError(const std::string& str = "") : CryptoException(str) {};
public:
explicit DecryptError(const std::string& str) : CryptoException(str) {};
explicit DecryptError(const char* str) : CryptoException(str) {};
DecryptError(const DecryptError& e) noexcept = default;
DecryptError& operator=(const DecryptError&) noexcept = default;
};
struct PrivateKey;
@@ -154,6 +160,7 @@ struct OPENDHT_PUBLIC PrivateKey
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
/**
+6 -10
View File
@@ -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,16 +177,8 @@ 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(msgpack::object o)
@@ -200,6 +192,7 @@ public:
Value::Id id {0};
Blob ice_data;
};
#endif
/* "Peer" announcement
*/
@@ -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;
+8 -10
View File
@@ -53,9 +53,9 @@ public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<dht::Logger> logger = {});
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
void setHeaderFields(http::Request& request);
@@ -319,10 +319,8 @@ private:
* cancel all Listeners
*/
void cancelAllListeners();
/**
* cancel all Operations
*/
void cancelAllOperations();
std::atomic_bool isDestroying_ {false};
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
@@ -349,7 +347,9 @@ private:
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
mutable std::mutex requestLock_;
std::map<unsigned, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
@@ -403,10 +403,8 @@ private:
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
std::atomic_bool isDestroying_ {false};
Json::StreamWriterBuilder jsonBuilder_;
Json::CharReaderBuilder jsonReaderBuilder_;
std::unique_ptr<Json::CharReader> jsonReader_;
std::shared_ptr<dht::Logger> logger_;
std::shared_ptr<http::Request> buildRequest(const std::string& target = {});
+7 -12
View File
@@ -31,10 +31,7 @@
#include <restinio/all.hpp>
#include <restinio/tls.hpp>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
#include <memory>
#include <mutex>
@@ -54,8 +51,6 @@ class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
using RequestStatus = restinio::request_handling_status_t;
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
/**
* Describes the REST API
@@ -87,15 +82,15 @@ public:
struct ServerStats {
/** Current number of listen operations */
size_t listenCount;
size_t listenCount {0};
/** Current number of permanent put operations */
size_t putCount;
size_t putCount {0};
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount;
size_t pushListenersCount {0};
/** Average requests per second */
double requestRate;
double requestRate {0};
/** Node Info **/
NodeInfo nodeInfo;
NodeInfo nodeInfo {};
std::string toString() const {
std::ostringstream ss;
@@ -113,7 +108,6 @@ public:
return ss.str();
}
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
@@ -126,7 +120,6 @@ public:
result["nodeInfo"] = nodeInfo.toJson();
return result;
}
#endif
};
ServerStats stats() const { return stats_; }
@@ -328,6 +321,8 @@ 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_;
+18 -7
View File
@@ -317,9 +317,7 @@ public:
* Returns the currently bound port, in host byte order.
* @param f: address family of the bound port to retreive.
*/
in_port_t getBoundPort(sa_family_t f = AF_INET) const {
return getBound(f).getPort();
}
in_port_t getBoundPort(sa_family_t f = AF_INET) const;
std::pair<size_t, size_t> getStoreSize() const;
@@ -342,7 +340,7 @@ public:
void importValues(const std::vector<ValuesExport>& values);
bool isRunning() const {
return running;
return running != State::Idle;
}
NodeStats getNodesStats(sa_family_t af) const;
@@ -360,7 +358,7 @@ public:
// securedht methods
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)>);
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
@@ -413,7 +411,7 @@ public:
/**
* Gracefuly disconnect from network.
*/
void shutdown(ShutdownCallback cb);
void shutdown(ShutdownCallback cb = {});
/**
* Quit and wait for all threads to terminate.
@@ -451,6 +449,12 @@ public:
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
enum class State {
Idle,
Running,
Stopping
};
/**
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
* thread and then queue ping requests. This list should contain reliable
@@ -465,6 +469,11 @@ private:
return std::max(status4, status6);
}
bool checkShutdown();
void opEnded();
DoneCallback bindOpDoneCallback(DoneCallback&& cb);
DoneCallbackSimple bindOpDoneCallback(DoneCallbackSimple&& cb);
/** Local DHT instance */
std::unique_ptr<SecureDht> dht_;
@@ -512,7 +521,9 @@ private:
std::queue<std::function<void(SecureDht&)>> pending_ops {};
std::mutex storage_mtx {};
std::atomic_bool running {false};
std::atomic<State> running {State::Idle};
std::atomic_size_t ongoing_ops {0};
std::vector<ShutdownCallback> shutdownCallbacks_;
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
+35 -33
View File
@@ -61,7 +61,7 @@ struct Certificate;
namespace http {
using HandlerCb = std::function<void(const asio::error_code& ec)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, const size_t bytes)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, size_t bytes)>;
using ConnectHandlerCb = std::function<void(const asio::error_code& ec,
const asio::ip::tcp::endpoint& endpoint)>;
@@ -82,7 +82,7 @@ public:
std::string fragment;
};
class OPENDHT_PUBLIC Connection
class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection>
{
public:
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<dht::Logger> l = {});
@@ -90,30 +90,40 @@ public:
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l = {});
~Connection();
unsigned int id();
bool is_open();
bool is_ssl();
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
void set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode);
asio::streambuf& input();
asio::streambuf& data();
std::istream& data() { return istream_; }
std::string read_bytes(const size_t bytes);
std::string read_bytes(size_t bytes = 0);
std::string read_until(const char delim);
void async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb);
void async_handshake(HandlerCb cb);
void async_write(BytesHandlerCb cb);
void async_read_until(const char* delim, BytesHandlerCb cb);
void async_read(const size_t bytes, BytesHandlerCb cb);
void async_read_until(char delim, BytesHandlerCb cb);
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
void close();
private:
template<typename T>
T wrapCallabck(T cb) const {
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
return cb(params...);
};
}
unsigned int id_;
static unsigned int ids_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
std::unique_ptr<socket_t> socket_;
@@ -124,6 +134,7 @@ private:
asio::streambuf write_buf_;
asio::streambuf read_buf_;
std::istream istream_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
@@ -190,12 +201,13 @@ private:
struct Response
{
unsigned int status_code;
unsigned int status_code {0};
std::map<std::string, std::string> headers;
std::string body;
bool aborted {false};
};
class OPENDHT_PUBLIC Request
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
{
public:
enum class State {
@@ -209,6 +221,7 @@ public:
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 int status_code)>;
using OnDoneCb = std::function<void(const Response& response)>;
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
@@ -216,6 +229,7 @@ public:
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger = {});
// user defined resolver
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
@@ -227,7 +241,7 @@ public:
~Request();
unsigned int id() const;
inline unsigned int id() const { return id_; };
void set_connection(std::shared_ptr<Connection> connection);
std::shared_ptr<Connection> get_connection() const;
inline const Url& get_url() const {
@@ -255,6 +269,7 @@ public:
void add_on_status_callback(OnStatusCb cb);
void add_on_body_callback(OnDataCb cb);
void add_on_state_change_callback(OnStateChangeCb cb);
void add_on_done_callback(OnDoneCb cb);
void send();
@@ -267,19 +282,14 @@ private:
using OnCompleteCb = std::function<void()>;
struct Callbacks {
Callbacks(){}
OnStatusCb on_status;
OnDataCb on_header_field;
OnDataCb on_header_value;
OnDataCb on_body;
OnCompleteCb on_headers_complete;
OnCompleteCb on_message_complete;
OnStateChangeCb on_state_change;
};
void notify_state_change(const State state);
void notify_state_change(State state);
void build();
@@ -296,24 +306,19 @@ private:
void post();
void handle_request(const asio::error_code& ec);
void handle_response(const asio::error_code& ec, size_t bytes);
void handle_response_header(const asio::error_code& ec);
void onHeadersComplete();
void onBody(const char* at, size_t length);
void onComplete();
void handle_response_body(const asio::error_code& ec, const size_t bytes);
/**
* Parse the request with http_parser.
* Return how many bytes were parsed.
* Note: we pass requerst.size()==0 to signal that EOF has been received.
*/
size_t parse_request(const std::string& request);
std::shared_ptr<dht::Logger> logger_;
restinio::http_request_header_t header_;
std::map<restinio::http_field_t, std::string> headers_;
restinio::http_connection_header_t connection_type_;
restinio::http_connection_header_t connection_type_ {restinio::http_connection_header_t::close};
std::string body_;
std::mutex cbs_mutex_;
Callbacks cbs_;
State state_;
@@ -323,20 +328,17 @@ private:
std::string host_;
unsigned int id_;
static std::atomic_uint ids_;
asio::io_context& ctx_;
sa_family_t family_ = AF_UNSPEC;
static unsigned int ids_;
std::shared_ptr<Connection> conn_;
std::shared_ptr<Resolver> resolver_;
Response response_ {};
std::string request_;
std::atomic<bool> message_complete_ {false};
std::atomic<bool> finishing_ {false};
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
std::shared_ptr<dht::Logger> logger_;
};
} // namespace http
+1 -1
View File
@@ -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);
}
/**
+3 -3
View File
@@ -71,13 +71,13 @@ OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getStdLogger();
std::shared_ptr<Logger> getStdLogger();
OPENDHT_PUBLIC
std::unique_ptr<Logger> getFileLogger(const std::string &path);
std::shared_ptr<Logger> getFileLogger(const std::string &path);
OPENDHT_PUBLIC
std::unique_ptr<Logger> getSyslogLogger(const char* name);
std::shared_ptr<Logger> getSyslogLogger(const char* name);
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
+17 -7
View File
@@ -48,6 +48,12 @@ struct TransId;
#define MSG_CONFIRM 0
#endif
struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
};
class DhtProtocolException : public DhtException {
public:
// sent to another peer (http-like).
@@ -207,7 +213,12 @@ public:
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
NetworkEngine(
InfoHash& myid,
NetworkConfig config,
std::unique_ptr<DatagramSocket>&& sock,
Logger& log,
Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
@@ -425,7 +436,6 @@ private:
/***************
* Constants *
***************/
static constexpr size_t MAX_REQUESTS_PER_SEC {1600};
/* the length of a node info buffer in ipv4 format */
static const constexpr size_t NODE4_INFO_BUF_LEN {HASH_LEN + sizeof(in_addr) + sizeof(in_port_t)};
/* the length of a node info buffer in ipv6 format */
@@ -513,18 +523,18 @@ private:
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const NetworkConfig config {};
const std::unique_ptr<DatagramSocket> dht_socket;
const Logger& DHT_LOG;
NodeCache cache {};
// global limiting should be triggered by at least 8 different IPs
using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>;
using IpLimiter = RateLimiter;
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
IpLimiterMap address_rate_limiter {};
RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {};
size_t limiter_maintenance {0};
IpLimiterMap address_rate_limiter;
RateLimiter rate_limiter;
ssize_t limiter_maintenance {0};
// requests handling
std::map<Tid, Sp<Request>> requests {};
+23 -7
View File
@@ -35,7 +35,7 @@
#include <functional>
#include <thread>
#include <atomic>
#include <iostream>
#include <mutex>
namespace dht {
namespace net {
@@ -63,24 +63,34 @@ public:
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
inline void setOnReceive(OnReceive&& cb) {
std::lock_guard<std::mutex> lk(lock);
rx_callback = std::move(cb);
}
virtual const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const = 0;
virtual bool hasIPv4() const = 0;
virtual bool hasIPv6() const = 0;
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
return getBound(family).getPort();
SockAddr getBound(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family);
}
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family).getPort();
}
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
virtual void stop() = 0;
protected:
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
std::lock_guard<std::mutex> lk(lock);
if (rx_callback)
rx_callback(std::move(packet));
}
protected:
mutable std::mutex lock;
private:
OnReceive rx_callback;
};
@@ -93,12 +103,18 @@ public:
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const override {
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override {
return (family == AF_INET6) ? bound6 : bound4;
}
bool hasIPv4() const override { return s4 != -1; }
bool hasIPv6() const override { return s6 != -1; }
bool hasIPv4() const override {
std::lock_guard<std::mutex> lk(lock);
return s4 != -1;
}
bool hasIPv6() const override {
std::lock_guard<std::mutex> lk(lock);
return s6 != -1;
}
void stop() override;
private:
+9 -14
View File
@@ -22,10 +22,13 @@
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "log_enable.h"
#include <thread>
#include <mutex>
#include <condition_variable>
namespace asio {
class io_context;
}
namespace dht {
@@ -35,7 +38,7 @@ public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT);
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
@@ -51,7 +54,7 @@ public:
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
* startPublish - Keeping sending data until node is joinned or stop is called
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
@@ -79,20 +82,12 @@ public:
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
std::shared_ptr<asio::io_context> ioContext_;
std::thread ioRunnner_;
};
}
+9 -3
View File
@@ -23,19 +23,23 @@
namespace dht {
template<size_t Quota, unsigned long Period=1>
class RateLimiter {
public:
RateLimiter(size_t quota, const duration& period = std::chrono::seconds(1))
: quota_(quota), period_(period) {}
/** Clear outdated records and return current quota usage */
size_t maintain(const time_point& now) {
auto limit = now - std::chrono::seconds(Period);
auto limit = now - period_;
while (not records.empty() and records.front() < limit)
records.pop();
return records.size();
}
/** Return false if quota is reached, insert record and return true otherwise. */
bool limit(const time_point& now) {
if (maintain(now) >= Quota)
if (quota_ == std::numeric_limits<size_t>::max())
return true;
if (maintain(now) >= quota_)
return false;
records.emplace(now);
return true;
@@ -44,6 +48,8 @@ public:
return records.empty();
}
private:
const size_t quota_;
const duration period_;
std::queue<time_point> records {};
};
+24 -29
View File
@@ -20,7 +20,7 @@
#pragma once
#include "infohash.h"
#include "crypto.h"
//#include "crypto.h"
#include "utils.h"
#include "sockaddr.h"
@@ -46,6 +46,12 @@ namespace dht {
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.
@@ -241,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) {
@@ -341,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);
@@ -363,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() {}
@@ -424,7 +409,11 @@ struct OPENDHT_PUBLIC Value
inline bool operator== (const Value& o) {
return id == o.id &&
(isEncrypted() ? cypher == o.cypher :
((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
(
#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) {
@@ -482,7 +471,8 @@ 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(std::string("seq")); pk.pack(seq);
@@ -491,6 +481,9 @@ struct OPENDHT_PUBLIC Value
pk.pack(std::string("to")); pk.pack(recipient);
}
}
#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());
@@ -535,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:
+419 -30
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
@@ -33,21 +33,23 @@
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 4
#serial 11
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
@@ -59,18 +61,11 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++$1 -std=gnu++0x; do
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
@@ -96,22 +91,27 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
ac_success=yes
done
if test x$ac_success = xyes; then
break
fi
done
@@ -148,6 +148,11 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
@@ -185,11 +190,13 @@ namespace cxx11
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
@@ -518,7 +525,7 @@ namespace cxx14
}
namespace test_digit_seperators
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
@@ -560,3 +567,385 @@ namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])
+3
View File
@@ -458,6 +458,9 @@ cdef class DhtConfig(object):
self._config.dht_config.node_config.network = netid
def setMaintainStorage(self, bool maintain_storage):
self._config.dht_config.node_config.maintain_storage = maintain_storage
def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec):
self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec
self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec
cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
+3
View File
@@ -211,6 +211,9 @@ cdef extern from "opendht/callbacks.h" namespace "dht":
uint32_t network
bool is_bootstrap
bool maintain_storage
string persist_path
size_t max_req_per_sec
size_t max_peer_req_per_sec
cppclass SecureDhtConfig:
Config node_config
Identity id
+5 -3
View File
@@ -19,13 +19,16 @@ import opendht as dht
import time
import asyncio
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
ping_node = dht.DhtRunner()
ping_node.run()
ping_node.run(config=config)
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run()
pong_node.run(config=config)
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound())
@@ -42,7 +45,6 @@ def done(h, ok):
def ping(node, h):
global i
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
+6 -3
View File
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ @OpenSSL_LDFLAGS@ @Fmt_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -27,7 +27,6 @@ libopendht_la_SOURCES = \
dhtrunner.cpp \
default_types.cpp \
log.cpp \
peer_discovery.cpp \
network_utils.cpp \
thread_pool.cpp
@@ -56,7 +55,6 @@ nobase_include_HEADERS = \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/log_enable.h \
../include/opendht/peer_discovery.h \
../include/opendht/network_utils.h \
../include/opendht/rng.h \
../include/opendht/thread_pool.h
@@ -77,6 +75,11 @@ libopendht_la_SOURCES += http.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
endif
if ENABLE_PEER_DISCOVERY
libopendht_la_SOURCES += peer_discovery.cpp
nobase_include_HEADERS += ../include/opendht/peer_discovery.h
endif
if ENABLE_INDEXATION
libopendht_la_SOURCES += indexation/pht.cpp
nobase_include_HEADERS += ../include/opendht/indexation/pht.h
+24
View File
@@ -1,3 +1,25 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "callbacks.h"
namespace dht {
@@ -121,6 +143,7 @@ NodeInfo::toJson() const
val["node_id"] = node_id.toString();
val["ipv4"] = ipv4.toJson();
val["ipv6"] = ipv6.toJson();
val["ops"] = Json::Value::LargestUInt(ongoing_ops);
return val;
}
@@ -131,6 +154,7 @@ NodeInfo::NodeInfo(const Json::Value& v)
node_id = InfoHash(v["node_id"].asString());
ipv4 = NodeStats(v["ipv4"]);
ipv6 = NodeStats(v["ipv6"]);
ongoing_ops = v["ops"].asLargestUInt();
}
#endif
+11 -3
View File
@@ -348,9 +348,7 @@ PrivateKey::serialize(const std::string& password) const
size_t buf_sz = 8192;
Blob buffer;
buffer.resize(buf_sz);
int err = password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, buffer.data(), &buf_sz)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, buffer.data(), &buf_sz);
auto err = serialize(buffer.data(), &buf_sz, password);
if (err != GNUTLS_E_SUCCESS) {
std::cerr << "Could not export private key - " << gnutls_strerror(err) << std::endl;
return {};
@@ -359,6 +357,16 @@ PrivateKey::serialize(const std::string& password) const
return buffer;
}
int
PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password) const
{
if (!x509_key)
return -1;
return password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, out, out_len)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len);
}
PublicKey
PrivateKey::getPublicKey() const
{
+12
View File
@@ -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
+18 -5
View File
@@ -39,6 +39,7 @@ constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME;
constexpr std::chrono::seconds Dht::LISTEN_EXPIRE_TIME;
constexpr std::chrono::seconds Dht::REANNOUNCE_MARGIN;
static constexpr size_t MAX_REQUESTS_PER_SEC {1600};
NodeStatus
Dht::getStatus(sa_family_t af) const
@@ -75,10 +76,10 @@ Dht::shutdown(ShutdownCallback cb)
for (auto& str : store)
*remaining += maintainStorage(str, true, str_donecb);
DHT_LOG.w("shuting down node: after storage, %u ops", *remaining);
if (!*remaining) {
DHT_LOG.w("shuting down node: %u ops remaining", *remaining);
if (cb)
cb();
if (cb) cb();
}
}
@@ -1688,11 +1689,23 @@ Dht::~Dht()
s.second->clear();
}
net::NetworkConfig
fromDhtConfig(const Config& config)
{
net::NetworkConfig netConf;
netConf.network = config.network;
netConf.max_req_per_sec = config.max_req_per_sec ? config.max_req_per_sec : MAX_REQUESTS_PER_SEC;
netConf.max_peer_req_per_sec = config.max_peer_req_per_sec
? config.max_peer_req_per_sec
: netConf.max_req_per_sec/8;
return netConf;
}
Dht::Dht() : store(), network_engine(DHT_LOG, scheduler, {}) {}
Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l)
: DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
network_engine(myid, config.network, std::move(sock), DHT_LOG, scheduler,
network_engine(myid, fromDhtConfig(config), std::move(sock), DHT_LOG, scheduler,
std::bind(&Dht::onError, this, _1, _2),
std::bind(&Dht::onNewNode, this, _1, _2),
std::bind(&Dht::onReportedAddr, this, _1, _2),
@@ -1907,7 +1920,7 @@ Dht::periodic(const uint8_t *buf, size_t buflen, SockAddr from)
try {
network_engine.processMessage(buf, buflen, std::move(from));
} catch (const std::exception& e) {
DHT_LOG.e("Can't process message: %s", e.what());
DHT_LOG.w("Can't process message: %s", e.what());
}
}
return scheduler.run();
+173 -137
View File
@@ -24,6 +24,7 @@
#include "utils.h"
#include <http_parser.h>
#include <deque>
namespace dht {
@@ -69,22 +70,44 @@ struct DhtProxyClient::ProxySearch {
std::map<Value::Id, PermanentPut> puts {};
};
struct LineSplit {
void append(const char* d, size_t l) {
buf_.insert(buf_.end(), d, d+l);
}
bool getLine(char c) {
auto it = buf_.begin();
while (it != buf_.end()) {
if (*it == c) {
line_.clear();
line_.insert(line_.end(), buf_.begin(), ++it);
buf_.erase(buf_.begin(), it);
return true;
}
it++;
}
return false;
}
const std::string& line() const { return line_; }
private:
std::deque<char> buf_ {};
std::string line_ {};
};
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)
:
clientIdentity_(clientIdentity), serverCertificate_(serverCA),
pushClientId_(pushClientId), loopSignal_(signal), logger_(logger)
: proxyUrl_(serverHost)
, clientIdentity_(clientIdentity), serverCertificate_(serverCA)
, pushClientId_(pushClientId), loopSignal_(signal)
, jsonReader_(Json::CharReaderBuilder{}.newCharReader())
, logger_(logger)
{
// build http client
proxyUrl_ = serverHost;
jsonBuilder_["commentStyle"] = "None";
jsonBuilder_["indentation"] = "";
if (logger_){
if (logger_) {
if (serverCertificate_)
logger_->d("[proxy:client] using ca certificate for ssl:\n%s",
serverCertificate_->toString(false/*chain*/).c_str());
@@ -152,13 +175,22 @@ DhtProxyClient::~DhtProxyClient()
void
DhtProxyClient::stop()
{
isDestroying_ = true;
cancelAllOperations();
cancelAllListeners();
if (infoState_)
infoState_->cancel = true;
if (httpClientThread_.joinable())
httpClientThread_.join();
if (not isDestroying_.exchange(true)) {
resolver_.reset();
cancelAllListeners();
if (infoState_)
infoState_->cancel = true;
{
std::lock_guard<std::mutex> lock(requestLock_);
for (auto& request : requests_)
request.second->cancel();
}
if (not httpContext_.stopped())
httpContext_.stop();
if (httpClientThread_.joinable())
httpClientThread_.join();
requests_.clear();
}
}
std::vector<Sp<Value>>
@@ -179,13 +211,6 @@ DhtProxyClient::getLocalById(const InfoHash& k, Value::Id id) const {
return s->second.ops.get(id);
}
void
DhtProxyClient::cancelAllOperations()
{
if (!httpContext_.stopped())
httpContext_.stop();
}
void
DhtProxyClient::cancelAllListeners()
{
@@ -270,28 +295,31 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va
if (logger_)
logger_->d("[proxy:client] [get] [search %s]", key.to_c_str());
auto request = buildRequest("/" + key.toString());
auto reqid = request->id();
if (isDestroying_) {
if (donecb) donecb(false, {});
return;
}
try {
request->set_connection_type(restinio::http_connection_header_t::keep_alive);
auto request = buildRequest("/" + key.toString());
auto reqid = request->id();
//request->set_connection_type(restinio::http_connection_header_t::keep_alive);
request->set_method(restinio::http_method_get());
setHeaderFields(*request);
auto opstate = std::make_shared<OperationState>();
Value::Filter filter = w.empty() ? f : f.chain(w.getFilter());
request->add_on_body_callback([this, key, opstate, filter, cb](const char* at, size_t length){
auto rxBuf = std::make_shared<LineSplit>();
request->add_on_body_callback([this, key, opstate, filter, rxBuf, cb](const char* at, size_t length){
try {
auto body = std::string(at, length);
auto& b = *rxBuf;
b.append(at, length);
// one value per body line
std::string data_line;
std::stringstream body_stream(body);
while (std::getline(body_stream, data_line, '\n') and !(opstate->stop.load())){
while (b.getLine('\n') and !opstate->stop){
std::string err;
Json::Value json;
auto* char_data = static_cast<const char*>(&data_line[0]);
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
if (!reader->parse(char_data, char_data + data_line.size(), &json, &err)){
const auto& line = b.line();
if (!jsonReader_->parse(line.data(), line.data() + line.size(), &json, &err)){
opstate->ok.store(false);
return;
}
@@ -314,45 +342,46 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va
opstate->ok.store(false);
}
});
request->add_on_state_change_callback([this, reqid, opstate, donecb, key]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
if (response.status_code != 200){
if (logger_)
logger_->e("[proxy:client] [get %s] failed with code=%i", key.to_c_str(), response.status_code);
opstate->ok.store(false);
if (response.status_code == 0)
opFailed();
}
if (donecb){
{
std::lock_guard<std::mutex> lock(lockCallbacks_);
callbacks_.emplace_back([donecb, opstate](){
donecb(opstate->ok, {});
opstate->stop.store(true);
});
}
loopSignal_();
request->add_on_done_callback([this, reqid, opstate, donecb, key] (const http::Response& response){
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [get %s] failed with code=%i", key.to_c_str(), response.status_code);
opstate->ok.store(false);
if (not response.aborted and response.status_code == 0)
opFailed();
}
if (donecb) {
{
std::lock_guard<std::mutex> lock(lockCallbacks_);
callbacks_.emplace_back([donecb, opstate](){
donecb(opstate->ok, {});
opstate->stop.store(true);
});
}
loopSignal_();
}
if (not isDestroying_) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
requests_[reqid] = request;
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:client] [get %s] error: %s", key.to_c_str(), e.what());
requests_.erase(reqid);
}
}
void
DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_point created, bool permanent)
{
if (not val){
if (cb)
cb(false, {});
if (not val or isDestroying_) {
if (cb) cb(false, {});
return;
}
if (logger_)
@@ -438,9 +467,9 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
if (logger_)
logger_->d("[proxy:client] [put] [search %s] executing for %s", key.to_c_str(), val->toString().c_str());
auto request = buildRequest("/" + key.toString());
auto reqid = request->id();
try {
auto request = buildRequest("/" + key.toString());
auto reqid = request->id();
request->set_method(restinio::http_method_post());
setHeaderFields(*request);
@@ -459,28 +488,30 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallbackSimple cb,
}
}
request->set_body(Json::writeString(jsonBuilder_, json));
request->add_on_state_change_callback([this, reqid, cb]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
bool ok = response.status_code == 200;
if (not ok) {
if (logger_)
logger_->e("[proxy:client] [status] failed with code=%i", response.status_code);
if (response.status_code == 0)
opFailed();
}
if (cb)
cb(ok);
request->add_on_done_callback([this, reqid, cb] (const http::Response& response){
bool ok = response.status_code == 200;
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)
opFailed();
}
if (cb)
cb(ok);
if (not isDestroying_) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
requests_[reqid] = request;
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:client] [put %s] error: %s", key.to_c_str(), e.what());
requests_.erase(reqid);
}
}
@@ -564,48 +595,48 @@ DhtProxyClient::queryProxyInfo(std::shared_ptr<InfoState> infoState, sa_family_t
{
if (logger_)
logger_->d("[proxy:client] [status] query ipv%i info", family == AF_INET ? 4 : 6);
auto request = std::make_shared<http::Request>(httpContext_, resolver, family);
auto reqid = request->id();
try {
auto request = std::make_shared<http::Request>(httpContext_, resolver, family);
auto reqid = request->id();
request->set_method(restinio::http_method_get());
setHeaderFields(*request);
request->add_on_state_change_callback([this, reqid, family, infoState]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE) {
if (infoState->cancel.load())
request->add_on_done_callback([this, reqid, family, infoState] (const http::Response& response){
if (infoState->cancel.load())
return;
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [status] ipv%i failed with code=%i",
family == AF_INET ? 4 : 6, response.status_code);
// pass along the failures
if ((family == AF_INET and infoState->ipv4 == 0) or (family == AF_INET6 and infoState->ipv6 == 0))
onProxyInfos(Json::Value{}, family);
} else {
std::string err;
Json::Value proxyInfos;
if (!jsonReader_->parse(response.body.data(), response.body.data() + response.body.size(), &proxyInfos, &err)){
onProxyInfos(Json::Value{}, family);
return;
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [status] ipv%i failed with code=%i",
family == AF_INET ? 4 : 6, response.status_code);
// pass along the failures
if ((family == AF_INET and infoState->ipv4 == 0) or (family == AF_INET6 and infoState->ipv6 == 0))
onProxyInfos(Json::Value{}, family);
} else {
std::string err;
Json::Value proxyInfos;
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &proxyInfos, &err)){
onProxyInfos(Json::Value{}, family);
return;
}
if (not infoState->cancel)
onProxyInfos(proxyInfos, family);
}
if (not infoState->cancel)
onProxyInfos(proxyInfos, family);
}
if (not isDestroying_) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
if (infoState->cancel.load())
return;
requests_[reqid] = request;
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:client] [status] error sending request: %s", e.what());
requests_.erase(reqid);
}
}
@@ -688,11 +719,13 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
{
if (logger_)
logger_->d("[proxy:client] [listen] [search %s]", key.to_c_str());
if (isDestroying_)
return 0;
std::lock_guard<std::mutex> lock(searchLock_);
auto& search = searches_[key];
auto query = std::make_shared<Query>(Select{}, std::move(where));
return search.ops.listen(cb, query, filter, [this, key](Sp<Query>, ValueCallback cb, SyncCallback) -> size_t {
std::lock_guard<std::mutex> lock(searchLock_);
// Find search
auto search = searches_.find(key);
if (search == searches_.end()) {
@@ -853,26 +886,28 @@ DhtProxyClient::handleExpireListener(const asio::error_code &ec, const InfoHash&
body["key"] = deviceKey_;
body["client_id"] = pushClientId_;
request->set_body(Json::writeString(jsonBuilder_, body));
request->add_on_state_change_callback([this, reqid, key]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [unsubscribe %s] failed with code=%i",
key.to_c_str(), response.status_code);
if (response.status_code == 0)
opFailed();
}
request->add_on_done_callback([this, reqid, key] (const http::Response& response){
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [unsubscribe %s] failed with code=%i",
key.to_c_str(), response.status_code);
if (not response.aborted and response.status_code == 0)
opFailed();
}
if (not isDestroying_) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
requests_[reqid] = request;
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:client] [unsubscribe %s] failed: %s", key.to_c_str(), e.what());
requests_.erase(reqid);
}
} else {
// stop the request
@@ -901,10 +936,10 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t header,
{
if (logger_)
logger_->e("[proxy:client] [listen] sendListen: %d", (int)method);
auto request = buildRequest();
listener.request = request;
auto reqid = request->id();
try {
auto request = buildRequest();
listener.request = request;
auto reqid = request->id();
request->set_header(header);
setHeaderFields(*request);
if (method == ListenMethod::LISTEN)
@@ -915,19 +950,18 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t header,
body = fillBody(method == ListenMethod::RESUBSCRIBE);
request->set_body(body);
#endif
request->add_on_body_callback([this, reqid, opstate, cb](const char* at, size_t length){
auto rxBuf = std::make_shared<LineSplit>();
request->add_on_body_callback([this, reqid, opstate, rxBuf, cb](const char* at, size_t length){
try {
auto body = std::string(at, length);
auto& b = *rxBuf;
b.append(at, length);
// one value per body line
std::string data_line;
std::stringstream body_stream(body);
while (std::getline(body_stream, data_line, '\n') and !opstate->stop){
while (b.getLine('\n') and !opstate->stop){
std::string err;
Json::Value json;
auto* char_data = static_cast<const char*>(&data_line[0]);
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
if (!reader->parse(char_data, char_data + data_line.size(), &json, &err)){
const auto& line = b.line();
if (!jsonReader_->parse(line.data(), line.data() + line.size(), &json, &err)){
opstate->ok.store(false);
return;
}
@@ -954,27 +988,29 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t header,
opstate->ok.store(false);
}
});
request->add_on_state_change_callback([this, opstate, reqid]
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [listen] send request #%i failed with code=%i",
reqid, response.status_code);
opstate->ok.store(false);
if (response.status_code == 0)
opFailed();
}
request->add_on_done_callback([this, opstate, reqid] (const http::Response& response) {
if (response.status_code != 200) {
if (logger_)
logger_->e("[proxy:client] [listen] send request #%i failed with code=%i",
reqid, response.status_code);
opstate->ok.store(false);
if (not response.aborted and response.status_code == 0)
opFailed();
}
if (not isDestroying_) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
requests_[reqid] = request;
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:client] [listen] request #%i failed: %s", reqid, e.what());
requests_.erase(reqid);
logger_->e("[proxy:client] [listen] request failed: %s", e.what());
}
}
+136 -117
View File
@@ -18,6 +18,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dht_proxy_server.h"
#include "default_types.h"
@@ -68,40 +72,36 @@ constexpr char RESP_MSG_NO_TOKEN[] = "{\"err\":\"No token\"}";
constexpr const std::chrono::minutes PRINT_STATS_PERIOD {2};
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
class opendht_logger_t
{
public:
opendht_logger_t(std::shared_ptr<dht::Logger> logger = {}){
if (logger)
m_logger = logger;
opendht_logger_t(std::shared_ptr<Logger> logger = {}) : m_logger(std::move(logger)) {}
template <typename Builder>
void trace(Builder&& /* msg_builder */) {
/* if (m_logger) m_logger->d("[proxy:server] %s", msg_builder().c_str()); */
}
template <typename Builder>
void trace(Builder && msg_builder){
if (m_logger)
m_logger->d("[proxy:server] %s", msg_builder().c_str());
void info(Builder&& msg_builder) {
if (m_logger) m_logger->d("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void info(Builder && msg_builder){
if (m_logger)
m_logger->d("[proxy:server] %s", msg_builder().c_str());
void warn(Builder&& msg_builder) {
if (m_logger) m_logger->w("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void warn(Builder && msg_builder){
if (m_logger)
m_logger->w("[proxy:server] %s", msg_builder().c_str());
}
template <typename Builder>
void error(Builder && msg_builder){
if (m_logger)
m_logger->e("[proxy:server] %s", msg_builder().c_str());
void error(Builder&& msg_builder) {
if (m_logger) m_logger->e("[proxy:server] %s", msg_builder().c_str());
}
private:
std::shared_ptr<dht::Logger> m_logger;
std::shared_ptr<Logger> m_logger;
};
// connection listener
@@ -166,9 +166,9 @@ struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t
};
DhtProxyServer::DhtProxyServer(
dht::crypto::Identity identity,
crypto::Identity identity,
std::shared_ptr<DhtRunner> dht, in_port_t port, const std::string& pushServer,
std::shared_ptr<dht::Logger> logger
std::shared_ptr<Logger> logger
)
: dht_(dht), logger_(logger),
connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
@@ -280,6 +280,27 @@ DhtProxyServer::io_context() const
DhtProxyServer::~DhtProxyServer()
{
if (dht_) {
std::lock_guard<std::mutex> lock(lockListener_);
for (auto& l : listeners_) {
dht_->cancelListen(l.second.hash, std::move(l.second.token));
if (l.second.response)
l.second.response->done();
}
#ifdef OPENDHT_PUSH_NOTIFICATIONS
for (auto& lm: pushListeners_) {
for (auto& ls: lm.second.listeners)
for (auto& l : ls.second) {
if (l.expireNotifyTimer)
l.expireNotifyTimer->cancel();
if (l.expireTimer)
l.expireTimer->cancel();
dht_->cancelListen(ls.first, std::move(l.internalToken));
}
}
pushListeners_.clear();
#endif
}
if (logger_)
logger_->d("[proxy:server] closing http server");
if (httpServer_)
@@ -372,7 +393,6 @@ HttpResponse DhtProxyServer::initHttpResponse(HttpResponse response) const
response.append_header("Server", "RESTinio");
response.append_header(restinio::http_field::content_type, "application/json");
response.append_header(restinio::http_field::access_control_allow_origin, "*");
response.connection_keep_alive();
return response;
}
@@ -460,14 +480,14 @@ DhtProxyServer::getNodeInfo(restinio::request_handle_t request,
std::lock_guard<std::mutex> lck(statsMutex_);
if (nodeInfo_.ipv4.good_nodes == 0 &&
nodeInfo_.ipv6.good_nodes == 0){
nodeInfo_ = this->dht_->getNodeInfo();
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 = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.append_body(output);
return response.done();
}
@@ -480,17 +500,17 @@ DhtProxyServer::getStats(restinio::request_handle_t request,
try {
if (dht_){
auto output = Json::writeString(jsonBuilder_, stats_.toJson()) + "\n";
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.append_body(output);
response.done();
} else {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_service_unavailable()));
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
return response.done();
}
} catch (...){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -503,22 +523,22 @@ DhtProxyServer::get(restinio::request_handle_t request,
restinio::router::route_params_t params)
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
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>(
this->initHttpResponse(request->create_response<ResponseByParts>()));
initHttpResponse(request->create_response<ResponseByParts>()));
response->flush();
try {
dht_->get(infoHash, [this, response](const dht::Sp<dht::Value>& value){
dht_->get(infoHash, [this, response](const Sp<Value>& value){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
response->append_chunk(output);
response->flush();
@@ -528,7 +548,7 @@ DhtProxyServer::get(restinio::request_handle_t request,
response->done();
});
} catch (const std::exception& e){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -541,18 +561,18 @@ DhtProxyServer::listen(restinio::request_handle_t request,
restinio::router::route_params_t params)
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
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>(
this->initHttpResponse(request->create_response<ResponseByParts>()));
initHttpResponse(request->create_response<ResponseByParts>()));
response->flush();
try {
std::lock_guard<std::mutex> lock(lockListener_);
@@ -561,7 +581,7 @@ DhtProxyServer::listen(restinio::request_handle_t request,
session.hash = infoHash;
session.response = response;
session.token = dht_->listen(infoHash, [this, response]
(const std::vector<dht::Sp<dht::Value>>& values, bool expired){
(const std::vector<Sp<Value>>& values, bool expired){
for (const auto& value: values){
auto jsonVal = value->toJson();
if (expired)
@@ -574,7 +594,7 @@ DhtProxyServer::listen(restinio::request_handle_t request,
});
} catch (const std::exception& e){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -590,12 +610,12 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_service_unavailable()));
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
return response.done();
@@ -606,14 +626,14 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
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(), &root, &err)){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_JSON_INCORRECT);
return response.done();
}
auto pushToken = root["key"].asString();
if (pushToken.empty()){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_NO_TOKEN);
return response.done();
@@ -643,11 +663,11 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
listener.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
// Send response header
auto response = std::make_shared<ResponseByPartsBuilder>(
this->initHttpResponse(request->create_response<ResponseByParts>()));
initHttpResponse(request->create_response<ResponseByParts>()));
response->flush();
// No Refresh
if (!root.isMember("refresh") or !root["refresh"].asBool()){
dht_->get(infoHash, [this, response](const dht::Sp<dht::Value>& value){
dht_->get(infoHash, [this, response](const Sp<Value>& value){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
response->append_chunk(output);
response->flush();
@@ -709,12 +729,12 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
listener.expireTimer->expires_at(timeout);
listener.expireTimer->async_wait(std::bind(&DhtProxyServer::handleCancelPushListen, this,
std::placeholders::_1, pushToken, infoHash, clientId));
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.set_body("{}\n");
return response.done();
}
catch (...) {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -728,12 +748,12 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_service_unavailable()));
response.set_body(RESP_MSG_SERVICE_UNAVAILABLE);
return response.done();
@@ -748,7 +768,7 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
if (!reader->parse(char_data, char_data + request->body().size(), &root, &err)){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_JSON_INCORRECT);
return response.done();
@@ -759,11 +779,11 @@ DhtProxyServer::unsubscribe(restinio::request_handle_t request,
auto clientId = root["client_id"].asString();
handleCancelPushListen(asio::error_code() /*success*/, pushToken, infoHash, clientId);
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
return response.done();
}
catch (...) {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -787,7 +807,7 @@ DhtProxyServer::handleNotifyPushListenExpire(const asio::error_code &ec, const s
void
DhtProxyServer::handleCancelPushListen(const asio::error_code &ec, const std::string pushToken,
const dht::InfoHash key, const std::string clientId)
const InfoHash key, const std::string clientId)
{
if (ec == asio::error::operation_aborted)
return;
@@ -829,13 +849,13 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
if (pushServer_.empty())
return;
auto request = std::make_shared<http::Request>(io_context(), pushHostPort_.first, pushHostPort_.second,
httpsServer_ ? true : false, logger_);
auto reqid = request->id();
unsigned reqid = 0;
try {
auto request = std::make_shared<http::Request>(io_context(), pushHostPort_.first, pushHostPort_.second,
httpsServer_ ? true : false, logger_);
reqid = request->id();
request->set_target("/api/push");
request->set_method(restinio::http_method_post());
request->set_header_field(restinio::http_field_t::host, pushServer_.c_str());
request->set_header_field(restinio::http_field_t::user_agent, "RESTinio client");
request->set_header_field(restinio::http_field_t::accept, "*/*");
@@ -856,29 +876,29 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
Json::Value content;
content["notifications"] = std::move(notifications);
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto body = Json::writeString(wbuilder, content);
request->set_body(body);
request->set_body(Json::writeString(jsonBuilder_, content));
request->add_on_state_change_callback([this, reqid]
(const http::Request::State state, const http::Response response){
(http::Request::State state, const http::Response& response){
if (state == http::Request::State::DONE){
if (logger_ and response.status_code != 200)
logger_->e("[proxy:server] [notification] push failed: %i", response.status_code);
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
});
{
std::lock_guard<std::mutex> l(requestLock_);
requests_[reqid] = request;
}
request->send();
requests_[reqid] = request;
}
catch (const std::exception &e){
if (logger_)
logger_->e("[proxy:server] [notification] error send push: %i", e.what());
requests_.erase(reqid);
if (reqid) {
std::lock_guard<std::mutex> l(requestLock_);
requests_.erase(reqid);
}
}
}
@@ -916,9 +936,9 @@ DhtProxyServer::put(restinio::request_handle_t request,
restinio::router::route_params_t params)
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = initHttpResponse(request->create_response(restinio::status_service_unavailable()));
@@ -938,12 +958,12 @@ DhtProxyServer::put(restinio::request_handle_t request,
auto reader = std::unique_ptr<Json::CharReader>(jsonReaderBuilder_.newCharReader());
if (reader->parse(char_data, char_data + request->body().size(), &root, &err)){
auto value = std::make_shared<dht::Value>(root);
auto value = std::make_shared<Value>(root);
bool permanent = root.isMember("permanent");
if (logger_)
logger_->d("[proxy:server] [put %s] %s %s", infoHash.toString().c_str(),
value->toString().c_str(), (permanent ? "permanent" : ""));
if (permanent){
if (permanent) {
std::string pushToken, clientId, platform;
auto& pVal = root["permanent"];
if (pVal.isObject()){
@@ -989,23 +1009,22 @@ DhtProxyServer::put(restinio::request_handle_t request,
if (pput.expireNotifyTimer)
pput.expireNotifyTimer->expires_at(timeout - proxy::OP_MARGIN);
}
lock.unlock();
}
dht_->put(infoHash, value, [this, request, value](bool ok){
if (ok){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.append_body(output);
response.done();
} else {
auto response = this->initHttpResponse(request->create_response(
auto response = initHttpResponse(request->create_response(
restinio::status_bad_gateway()));
response.set_body(RESP_MSG_PUT_FAILED);
response.done();
}
}, dht::time_point::max(), permanent);
}, time_point::max(), permanent);
} else {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_JSON_INCORRECT);
return response.done();
@@ -1013,7 +1032,7 @@ DhtProxyServer::put(restinio::request_handle_t request,
} catch (const std::exception& e){
if (logger_)
logger_->d("[proxy:server] error in put: %s", e.what());
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -1023,22 +1042,23 @@ DhtProxyServer::put(restinio::request_handle_t request,
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
RequestStatus DhtProxyServer::putSigned(restinio::request_handle_t request,
restinio::router::route_params_t params) const
RequestStatus
DhtProxyServer::putSigned(restinio::request_handle_t request,
restinio::router::route_params_t params) const
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
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 = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_MISSING_PARAMS);
return response.done();
@@ -1057,18 +1077,18 @@ RequestStatus DhtProxyServer::putSigned(restinio::request_handle_t request,
dht_->putSigned(infoHash, value, [this, request, value](bool ok){
if (ok){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.append_body(output);
response.done();
} else {
auto response = this->initHttpResponse(request->create_response(
auto response = initHttpResponse(request->create_response(
restinio::status_bad_gateway()));
response.set_body(RESP_MSG_PUT_FAILED);
response.done();
}
});
} else {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_JSON_INCORRECT);
return response.done();
@@ -1076,7 +1096,7 @@ RequestStatus DhtProxyServer::putSigned(restinio::request_handle_t request,
} catch (const std::exception& e){
if (logger_)
logger_->d("[proxy:server] error in put: %s", e.what());
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -1089,18 +1109,18 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request,
restinio::router::route_params_t params)
{
requestNum_++;
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
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 = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_MISSING_PARAMS);
return response.done();
@@ -1115,7 +1135,7 @@ 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 = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_DESTINATION_NOT_FOUND);
return response.done();
@@ -1124,18 +1144,18 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request,
dht_->putEncrypted(infoHash, to, value, [this, request, value](bool ok){
if (ok){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
auto response = this->initHttpResponse(request->create_response());
auto response = initHttpResponse(request->create_response());
response.append_body(output);
response.done();
} else {
auto response = this->initHttpResponse(request->create_response(
auto response = initHttpResponse(request->create_response(
restinio::status_bad_gateway()));
response.set_body(RESP_MSG_PUT_FAILED);
response.done();
}
});
} else {
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_bad_request()));
response.set_body(RESP_MSG_JSON_INCORRECT);
return response.done();
@@ -1143,7 +1163,7 @@ DhtProxyServer::putEncrypted(restinio::request_handle_t request,
} catch (const std::exception& e){
if (logger_)
logger_->d("[proxy:server] error in put: %s", e.what());
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
@@ -1157,7 +1177,7 @@ RequestStatus
DhtProxyServer::options(restinio::request_handle_t request,
restinio::router::route_params_t /*params*/)
{
this->requestNum_++;
requestNum_++;
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
const auto methods = "OPTIONS, GET, POST, LISTEN, SIGN, ENCRYPT";
#else
@@ -1176,34 +1196,33 @@ DhtProxyServer::getFiltered(restinio::request_handle_t request,
{
requestNum_++;
auto value = params["value"].to_string();
dht::InfoHash infoHash(params["hash"].to_string());
InfoHash infoHash(params["hash"].to_string());
if (!infoHash)
infoHash = dht::InfoHash::get(params["hash"].to_string());
infoHash = InfoHash::get(params["hash"].to_string());
if (!dht_){
auto response = this->initHttpResponse(
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>(
this->initHttpResponse(request->create_response<ResponseByParts>()));
initHttpResponse(request->create_response<ResponseByParts>()));
response->flush();
try {
dht_->get(infoHash, [this, response](const dht::Sp<dht::Value>& value){
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
response->append_chunk(output);
response->flush();
return true;
},
[response] (bool /*ok*/){
response->done();
},
{}, value
);
dht_->get(infoHash,
[this, response](const Sp<Value>& value) {
response->append_chunk(Json::writeString(jsonBuilder_, value->toJson()) + "\n");
response->flush();
return true;
},
[response] (bool /*ok*/){
response->done();
},
{}, value);
} catch (const std::exception& e){
auto response = this->initHttpResponse(
auto response = initHttpResponse(
request->create_response(restinio::status_internal_server_error()));
response.set_body(RESP_MSG_INTERNAL_SERVER_ERRROR);
return response.done();
+270 -159
View File
@@ -18,11 +18,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dhtrunner.h"
#include "securedht.h"
#include "peer_discovery.h"
#include "network_utils.h"
#ifdef OPENDHT_PEER_DISCOVERY
#include "peer_discovery.h"
#endif
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
@@ -100,7 +105,7 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Conf
void
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context)
{
if (not running) {
if (running == State::Idle) {
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
run(config, std::move(context));
@@ -111,17 +116,21 @@ void
DhtRunner::run(const Config& config, Context&& context)
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (running)
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running))
return;
if (context.logger)
if (context.logger) {
logger_ = context.logger;
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
{
std::lock_guard<std::mutex> lck(sock_mtx);
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
std::cerr << "Dropping packet: queue is full!" << std::endl;
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop();
}
rcv.emplace(std::move(pkt));
@@ -148,16 +157,15 @@ DhtRunner::run(const Config& config, Context&& context)
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
}
running = true;
if (not config.threaded)
return;
dht_thread = std::thread([this]() {
while (running) {
while (running != State::Idle) {
std::unique_lock<std::mutex> lk(dht_mtx);
time_point wakeup = loop_();
auto hasJobToDo = [this]() {
if (not running)
if (running == State::Idle)
return true;
{
std::lock_guard<std::mutex> lck(sock_mtx);
@@ -182,11 +190,16 @@ DhtRunner::run(const Config& config, Context&& context)
});
if (config.peer_discovery or config.peer_publish) {
#ifdef OPENDHT_PEER_DISCOVERY
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
#else
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
#endif
}
#ifdef OPENDHT_PEER_DISCOVERY
auto netId = config.dht_config.node_config.network;
if (config.peer_discovery) {
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
@@ -215,40 +228,91 @@ DhtRunner::run(const Config& config, Context&& context)
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
#endif
}
void
DhtRunner::shutdown(ShutdownCallback cb) {
if (not running) {
cb();
auto expected = State::Running;
if (not running.compare_exchange_strong(expected, State::Stopping)) {
if (expected == State::Stopping and ongoing_ops) {
std::lock_guard<std::mutex> lck(storage_mtx);
shutdownCallbacks_.emplace_back(std::move(cb));
}
else if (cb) cb();
return;
}
if (logger_)
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops_prio.emplace([=](SecureDht&) mutable {
auto onShutdown = [this]{ opEnded(); };
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
dht_via_proxy_->shutdown(onShutdown);
#endif
if (dht_)
dht_->shutdown(cb);
dht_->shutdown(onShutdown);
});
cv.notify_all();
}
void
DhtRunner::opEnded() {
if (--ongoing_ops == 0)
checkShutdown();
}
DoneCallback
DhtRunner::bindOpDoneCallback(DoneCallback&& cb) {
return [this, cb = std::move(cb)](bool ok, const std::vector<std::shared_ptr<Node>>& nodes){
if (cb) cb(ok, nodes);
opEnded();
};
}
DoneCallbackSimple
DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) {
return [this, cb = std::move(cb)](bool ok){
if (cb) cb(ok);
opEnded();
};
}
bool
DhtRunner::checkShutdown() {
if (running != State::Stopping or ongoing_ops)
return false;
decltype(shutdownCallbacks_) cbs;
{
std::lock_guard<std::mutex> lck(storage_mtx);
cbs = std::move(shutdownCallbacks_);
}
for (auto& cb : cbs)
if (cb) cb();
return true;
}
void
DhtRunner::join()
{
if (peerDiscovery_)
peerDiscovery_->stop();
{
std::lock_guard<std::mutex> lck(dht_mtx);
running = false;
if (running.exchange(State::Idle) == State::Idle)
return;
cv.notify_all();
bootstrap_cv.notify_all();
#ifdef OPENDHT_PEER_DISCOVERY
if (peerDiscovery_)
peerDiscovery_->stop();
#endif
if (dht_)
if (auto sock = dht_->getSocket())
sock->stop();
if (logger_)
logger_->d("[runner %p] state changed to Idle", this);
}
if (dht_thread.joinable())
@@ -257,14 +321,11 @@ DhtRunner::join()
if (bootstrap_thread.joinable())
bootstrap_thread.join();
if (peerDiscovery_) {
peerDiscovery_->join();
}
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops = decltype(pending_ops)();
pending_ops_prio = decltype(pending_ops_prio)();
ongoing_ops = 0;
}
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -283,6 +344,15 @@ DhtRunner::getBound(sa_family_t af) const {
return SockAddr{};
}
in_port_t
DhtRunner::getBoundPort(sa_family_t af) const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
if (auto sock = dht_->getSocket())
return sock->getPort(af);
return 0;
}
void
DhtRunner::dumpTables() const
{
@@ -406,11 +476,14 @@ DhtRunner::getNodesStats(sa_family_t af) const
NodeInfo
DhtRunner::getNodeInfo() const {
std::lock_guard<std::mutex> lck(dht_mtx);
NodeInfo info;
info.id = getId();
info.node_id = getNodeId();
info.ipv4 = dht_->getNodesStats(AF_INET);
info.ipv6 = dht_->getNodesStats(AF_INET6);
NodeInfo info {};
if (auto dht = activeDht()) {
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;
return info;
}
@@ -563,12 +636,15 @@ DhtRunner::loop_()
void
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
});
if (running != State::Running) {
if (dcb) dcb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w));
});
cv.notify_all();
}
@@ -579,12 +655,15 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
}
void
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
});
if (running != State::Running) {
if (done_cb) done_cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q));
});
cv.notify_all();
}
@@ -592,32 +671,34 @@ std::future<size_t>
DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
auto ret_token = std::make_shared<std::promise<size_t>>();
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
if (running != State::Running) {
ret_token->set_value(0);
return ret_token->get_future();
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
cv.notify_all();
return ret_token->get_future();
}
@@ -631,73 +712,77 @@ DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Wher
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto sv = std::make_shared<Value>(std::move(value));
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, sv, cb, created, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
sv = std::make_shared<Value>(std::move(value))
] (SecureDht& dht) mutable {
dht.put(hash, sv, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, value, cb, created, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable {
dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
@@ -710,36 +795,38 @@ DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, tim
void
DhtRunner::cancelPut(const InfoHash& h, Value::Id id)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
cv.notify_all();
}
void
DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, value->id);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, value->id);
});
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putSigned(hash, value, cb, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
](SecureDht& dht) mutable {
dht.putSigned(hash, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
@@ -758,12 +845,18 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putEncrypted(hash, to, value, cb, permanent);
});
if (running != State::Running) {
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
@@ -808,7 +901,7 @@ DhtRunner::tryBootstrapContinuously()
++ping_count;
try {
bootstrap(SockAddr::resolve(it->first, it->second), [&](bool) {
if (not running)
if (running != State::Running)
return;
{
std::unique_lock<std::mutex> blck(mtx);
@@ -822,15 +915,15 @@ DhtRunner::tryBootstrapContinuously()
}
}
// wait at least until the next BOOTSTRAP_PERIOD
bootstrap_cv.wait_until(blck, next, [&]() { return not running; });
bootstrap_cv.wait_until(blck, next, [&]() { return running != State::Running; });
// wait for bootstrap requests to end.
if (running)
bootstrap_cv.wait(blck, [&]() { return not running or ping_count == 0; });
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 and
bootstraping = running == State::Running and
status4 == NodeStatus::Disconnected and
status6 == NodeStatus::Disconnected;
}
@@ -867,19 +960,28 @@ DhtRunner::clearBootstrap()
void
DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
ongoing_ops++;
pending_ops_prio.emplace([
cb = bindOpDoneCallback(std::move(cb)),
nodes = std::move(nodes)
] (SecureDht& dht) mutable {
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
for (auto& node : nodes) {
if (node.getPort() == 0)
node.setPort(net::DHT_DEFAULT_PORT);
dht.pingNode(std::move(node), cb ? [rem,cb](bool ok) {
dht.pingNode(std::move(node), [rem,cb](bool ok) {
auto& r = *rem;
r.first--;
r.second |= ok;
if (not r.first)
if (r.first == 0) {
cb(r.second);
} : DoneCallbackSimple{});
}
});
}
});
cv.notify_all();
@@ -888,8 +990,13 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
if (cb) cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([addr, cb](SecureDht& dht) mutable {
ongoing_ops++;
pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
dht.pingNode(std::move(addr), std::move(cb));
});
cv.notify_all();
@@ -898,48 +1005,52 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
{
{
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
}
if (running != State::Running)
return;
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
cv.notify_all();
}
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
}
if (running != State::Running)
return;
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
cv.notify_all();
}
void
DhtRunner::connectivityChanged()
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
cv.notify_all();
}
void
DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.findCertificate(hash, cb);
});
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb) {
if (running != State::Running) {
cb({});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
cb(crt);
opEnded();
});
});
cv.notify_all();
}
+312 -421
View File
File diff suppressed because it is too large. Load diff
+10 -10
View File
@@ -56,9 +56,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
s << std::endl;
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getStdLogger() {
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
@@ -70,22 +70,22 @@ getStdLogger() {
std::cout << def;
},
[](char const *m, va_list args) { printLog(std::cout, m, args); }
));
);
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getFileLogger(const std::string &path) {
auto logfile = std::make_shared<std::ofstream>();
logfile->open(path, std::ios::out);
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
));
);
}
std::unique_ptr<Logger>
std::shared_ptr<Logger>
getSyslogLogger(const char* name) {
#ifndef _WIN32
struct Syslog {
@@ -103,13 +103,13 @@ getSyslogLogger(const char* name) {
logfile = std::make_shared<Syslog>(name);
opened_logfile = logfile;
}
return std::unique_ptr<Logger>(new Logger(
return std::make_shared<Logger>(
[logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
));
);
#else
return std::unique_ptr<Logger>(new Logger());
return std::make_shared<Logger>();
#endif
}
+57 -51
View File
@@ -41,7 +41,6 @@ constexpr std::chrono::seconds NetworkEngine::RX_MAX_PACKET_TIME;
constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
const std::string NetworkEngine::my_v {"RNG1"};
constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC;
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
@@ -100,10 +99,10 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
{}
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), rate_limiter((size_t)-1), scheduler(scheduler)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, 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,
@@ -122,7 +121,9 @@ NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<Datagram
onListen(std::move(onListen)),
onAnnounce(std::move(onAnnounce)),
onRefresh(std::move(onRefresh)),
myid(myid), network(net), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
myid(myid), config(c), dht_socket(std::move(sock)), DHT_LOG(log),
rate_limiter(config.max_req_per_sec),
scheduler(scheduler)
{}
NetworkEngine::~NetworkEngine() {
@@ -148,7 +149,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -165,8 +166,8 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -178,7 +179,7 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -195,8 +196,8 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -245,7 +246,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
auto now = scheduler.time();
auto& node = *req.node;
if (req.isExpired(now)) {
DHT_LOG.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);
@@ -300,7 +301,7 @@ NetworkEngine::rateLimit(const SockAddr& addr)
const auto& now = scheduler.time();
// occasional IP limiter maintenance (a few times every second at max rate)
if (limiter_maintenance++ == MAX_REQUESTS_PER_SEC/8) {
if (limiter_maintenance++ == config.max_peer_req_per_sec) {
for (auto it = address_rate_limiter.begin(); it != address_rate_limiter.end();) {
if (it->second.maintain(now) == 0)
address_rate_limiter.erase(it++);
@@ -311,7 +312,11 @@ NetworkEngine::rateLimit(const SockAddr& addr)
}
// invoke per IP, then global rate limiter
return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now);
return (config.max_peer_req_per_sec < 0
or address_rate_limiter
.emplace(addr, config.max_peer_req_per_sec).first->second
.limit(now))
and rate_limiter.limit(now);
}
bool
@@ -380,8 +385,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
return;
}
if (msg->network != network) {
DHT_LOG.d("Received message from other network %u", msg->network);
if (msg->network != config.network) {
DHT_LOG.d("Received message from other config.network %u", msg->network);
return;
}
@@ -476,7 +481,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
node->received(now, req);
if (not node->isClient())
onNewNode(node, 1);
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find transaction", msg->id};
DHT_LOG.d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
return;
}
}
@@ -619,7 +625,7 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
TransId tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -629,8 +635,8 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
@@ -656,7 +662,7 @@ void
NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -667,8 +673,8 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -680,7 +686,7 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -697,8 +703,8 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -726,7 +732,7 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 +
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
@@ -746,8 +752,8 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -861,9 +867,9 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(network?1:0));
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
pk.pack_map(3+(config.network?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
@@ -886,7 +892,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -927,8 +933,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
// send response
@@ -1017,7 +1023,7 @@ NetworkEngine::sendListen(Sp<Node> n,
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
pk.pack(KEY_A); pk.pack_map(4 + has_query);
@@ -1035,8 +1041,8 @@ NetworkEngine::sendListen(Sp<Node> n,
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1060,7 +1066,7 @@ void
NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1071,8 +1077,8 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -1090,7 +1096,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1107,8 +1113,8 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
@@ -1148,7 +1154,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1161,8 +1167,8 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
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 (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
@@ -1193,7 +1199,7 @@ void
NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1205,8 +1211,8 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
@@ -1237,8 +1243,8 @@ NetworkEngine::sendError(const SockAddr& addr,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
send(addr, buffer.data(), buffer.size());
+33 -25
View File
@@ -26,6 +26,7 @@
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#else
#include <sys/select.h>
#include <fcntl.h>
#endif
@@ -112,11 +113,13 @@ UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
SockAddr bind6;
bind6.setFamily(AF_INET6);
bind6.setPort(port);
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
{
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
@@ -154,6 +157,7 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
int err = errno;
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);
openSockets(bind4, bind6);
return sendTo(dest, data, size, false);
@@ -180,8 +184,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
udpPipe(stopfds);
#endif
int stop_readfd = stopfds[0];
stopfd = stopfds[1];
stopfd = stopfds[1];
s4 = -1;
s6 = -1;
@@ -224,18 +228,18 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
}
running = true;
rcv_thread = std::thread([this, stop_readfd]() {
int selectFd = std::max({s4, s6, stop_readfd}) + 1;
rcv_thread = std::thread([this, stop_readfd, ls4=s4, ls6=s6]() mutable {
int selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
try {
while (running) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
if(s4 >= 0)
FD_SET(s4, &readfds);
if(s6 >= 0)
FD_SET(s6, &readfds);
if(ls4 >= 0)
FD_SET(ls4, &readfds);
if(ls6 >= 0)
FD_SET(ls6, &readfds);
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
if (rc < 0) {
@@ -259,10 +263,10 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
break;
}
}
else if (s4 >= 0 && FD_ISSET(s4, &readfds))
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (s6 >= 0 && FD_ISSET(s6, &readfds))
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (ls4 >= 0 && FD_ISSET(ls4, &readfds))
rc = recvfrom(ls4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (ls6 >= 0 && FD_ISSET(ls6, &readfds))
rc = recvfrom(ls6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else
continue;
@@ -276,25 +280,28 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
logger.e("Error receiving packet: %s", strerror(errno));
int err = errno;
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
if (s4 >= 0) {
close(s4);
std::lock_guard<std::mutex> lk(lock);
if (ls4 >= 0) {
close(ls4);
try {
s4 = bindSocket(bound4, bound4);
ls4 = bindSocket(bound4, bound4);
} catch (const DhtException& e) {
logger.e("Can't bind inet socket: %s", e.what());
}
}
if (s6 >= 0) {
close(s6);
if (ls6 >= 0) {
close(ls6);
try {
s6 = bindSocket(bound6, bound6);
ls6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
if (s4 < 0 && s6 < 0)
if (ls4 < 0 && ls6 < 0)
break;
selectFd = std::max({s4, s6, stop_readfd}) + 1;
s4 = ls4;
s6 = ls6;
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
}
}
}
@@ -302,16 +309,17 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
} catch (const std::exception& e) {
logger.e("Error in UdpSocket rx thread: %s", e.what());
}
if (s4 >= 0)
close(s4);
if (s6 >= 0)
close(s6);
if (ls4 >= 0)
close(ls4);
if (ls6 >= 0)
close(ls6);
if (stop_readfd != -1)
close(stop_readfd);
std::lock_guard<std::mutex> lk(lock);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
if (stop_readfd != -1)
close(stop_readfd);
if (stopfd != -1)
close(stopfd);
stopfd = -1;
+126 -352
View File
@@ -2,6 +2,7 @@
* 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>
*
* 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
@@ -21,402 +22,166 @@
#include "network_utils.h"
#include "utils.h"
#ifdef _WIN32
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#include <cstring>
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#define close(x) closesocket(x)
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#include <asio.hpp>
#ifndef IPV6_JOIN_GROUP
#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
using namespace std::chrono_literals;
namespace dht {
// Organization-local Scope multicast
constexpr char MULTICAST_ADDRESS_IPV4[12] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[10] = "ff08::101";
constexpr char MULTICAST_ADDRESS_IPV4[] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[] = "ff08::101";
class PeerDiscovery::DomainPeerDiscovery
{
public:
DomainPeerDiscovery(sa_family_t domain, in_port_t port);
DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext = {}, Sp<Logger> logger = {});
~DomainPeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
/**
* Thread Stopper
*/
void stop();
/**
* Remove possible callBack to discovery
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
bool stopPublish(const std::string &type);
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join() {
if(listening_.joinable()) listening_.join();
if(sending_.joinable()) sending_.join();
}
private:
Sp<Logger> logger_;
//dmtx_ for callbackmap_ and drunning_ (write)
std::mutex dmtx_;
//mtx_ for messages_ and lrunning (listen)
std::mutex mtx_;
std::condition_variable cv_;
bool lrunning_ {false};
bool drunning_ {false};
sa_family_t domain_ {AF_UNSPEC};
int port_;
int sockFd_ {-1};
int stopWriteFd_ {-1};
std::shared_ptr<asio::io_context> ioContext_;
asio::ip::udp::socket sockFd_;
asio::ip::udp::endpoint sockAddrSend_;
asio::steady_timer publishTimer_;
SockAddr sockAddrSend_;
//Thread export to be joined
std::thread listening_;
std::thread sending_;
std::array<char, 64 * 1024> receiveBuf_;
asio::ip::udp::endpoint receiveFrom_;
msgpack::sbuffer sbuf_;
std::map<std::string, msgpack::sbuffer> messages_;
std::map<std::string, ServiceDiscoveredCallback> callbackmap_;
bool lrunning_ {false};
bool drunning_ {false};
/**
* Multicast Socket Initialization, accept IPV4, IPV6
*/
static int init(sa_family_t domain);
/**
* Receive messages
*/
std::pair<SockAddr, msgpack::object_handle> recvFrom();
/**
* Listener pack thread loop
*/
void loopListener();
/**
* Listener Parameters Setup
*/
void setupListener();
/**
* Sender Parameters Setup
*/
void setupSender();
/**
* Sender Parameters Setup
*/
void reloadMessages();
void stopDiscovery();
void stopPublish();
void publish();
};
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(sa_family_t domain, in_port_t port)
: domain_(domain), port_(port), sockFd_(init(domain))
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
: logger_(logger)
, ioContext_(ioContext)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
, publishTimer_(*ioContext)
{
joinMulticast(sockFd_, domain);
setupListener();
setupSender();
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()
{
stop();
join();
if (sockFd_ != -1)
close(sockFd_);
#ifdef _WIN32
WSACleanup();
#endif
}
int
PeerDiscovery::DomainPeerDiscovery::init(sa_family_t domain)
{
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
throw std::runtime_error(std::string("Can't initialize Winsock2 ") + strerror(errno));
}
#endif
int sockfd = socket(domain, SOCK_DGRAM, 0);
if (sockfd < 0) {
throw std::runtime_error(std::string("Socket Creation Error: ") + strerror(errno));
}
net::setNonblocking(sockfd);
return sockfd;
}
void
PeerDiscovery::DomainPeerDiscovery::setupListener()
{
SockAddr sockAddrListen_;
sockAddrListen_.setFamily(domain_);
sockAddrListen_.setPort(port_);
sockAddrListen_.setAny();
unsigned int opt = 1;
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEADDR failed: " << strerror(errno) << std::endl;
}
#ifdef SO_REUSEPORT
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEPORT failed: " << strerror(errno) << std::endl;
}
#endif
// bind to receive address
if (bind(sockFd_, sockAddrListen_.get(), sockAddrListen_.getLength()) < 0){
throw std::runtime_error(std::string("Error binding socket: ") + strerror(errno));
}
}
void
PeerDiscovery::DomainPeerDiscovery::joinMulticast(int sockfd, sa_family_t family)
{
switch (family)
{
case AF_INET:{
ip_mreq config_ipv4;
//This option can be used to set the interface for sending outbound
//multicast datagrams from the sockets application.
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&config_ipv4.imr_interface, sizeof( struct in_addr )) < 0 ) {
throw std::runtime_error(std::string("Bound Network Interface IPv4 Error: ") + strerror(errno));
}
//The IP_MULTICAST_TTL socket option allows the application to primarily
//limit the lifetime of the packet in the Internet and prevent it from circulating indefinitely
unsigned char ttl4 = 20;
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl4, sizeof( ttl4 )) < 0 ) {
throw std::runtime_error(std::string("TTL Sockopt Error: ") + strerror(errno));
}
// config the listener to be interested in joining in the multicast group
config_ipv4.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS_IPV4);
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&config_ipv4, sizeof(config_ipv4)) < 0){
throw std::runtime_error(std::string(" Member Addition IPv4 Error: ") + strerror(errno));
}
break;
}
case AF_INET6: {
ipv6_mreq config_ipv6;
/* unsigned int outif = 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof(outif)) < 0) {
std::cerr << "Can't assign multicast interface: " << strerror(errno) << std::endl;
} */
unsigned int ttl6 = 20;
if( setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl6, sizeof( ttl6 )) < 0 ) {
throw std::runtime_error(std::string("Hop Count Set Error: ") + strerror(errno));
}
config_ipv6.ipv6mr_interface = 0;
inet_pton(AF_INET6, MULTICAST_ADDRESS_IPV6, &config_ipv6.ipv6mr_multiaddr);
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&config_ipv6, sizeof(config_ipv6)) < 0){
throw std::runtime_error(std::string("Member Addition IPv6 Error: ") + strerror(errno));
}
break;
}
}
sockFd_.close();
}
void
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
std::unique_lock<std::mutex> lck(dmtx_);
std::lock_guard<std::mutex> lck(dmtx_);
callbackmap_[type] = callback;
if (not drunning_) {
if (listening_.joinable())
listening_.join();
drunning_ = true;
listening_ = std::thread(&DomainPeerDiscovery::loopListener, this);
ioContext_->post(std::bind(&PeerDiscovery::DomainPeerDiscovery::loopListener, this));
}
}
std::pair<SockAddr, msgpack::object_handle>
PeerDiscovery::DomainPeerDiscovery::recvFrom()
{
sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
std::array<uint8_t, 64 * 1024> buf;
ssize_t nbytes = recvfrom(
sockFd_,
(char*)buf.data(), buf.size(),
0,
(sockaddr*)&sa, &sa_len
);
if (nbytes < 0)
throw std::runtime_error(std::string("Error receiving packet: ") + strerror(errno));
return { SockAddr { sa, sa_len }, msgpack::unpack(reinterpret_cast<char*>(buf.data()), nbytes) };
}
void
PeerDiscovery::DomainPeerDiscovery::loopListener()
{
int stopfds_pipe[2];
#ifndef _WIN32
if (pipe(stopfds_pipe) == -1)
throw std::runtime_error(std::string("Can't open pipe: ") + strerror(errno));
#else
net::udpPipe(stopfds_pipe);
#endif
int stop_readfd = stopfds_pipe[0];
stopWriteFd_ = stopfds_pipe[1];
while (true) {
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
return;
sockFd_.async_receive_from(asio::buffer(receiveBuf_), receiveFrom_, [this](const asio::error_code& error, size_t bytes) {
if (error == asio::error::operation_aborted)
return;
if (error) {
if (logger_)
logger_->e("Error receiving message: %s", error.message().c_str());
}
try {
auto rcv = msgpack::unpack(receiveBuf_.data(), bytes);
msgpack::object obj = rcv.get();
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
FD_SET(sockFd_, &readfds);
int data_coming = select(std::max(sockFd_, stop_readfd) + 1, &readfds, nullptr, nullptr, nullptr);
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
}
if (data_coming < 0) {
if(errno != EINTR) {
perror("Select Error");
std::this_thread::sleep_for( std::chrono::seconds(1) );
}
} else if (data_coming > 0) {
if (FD_ISSET(stop_readfd, &readfds)) {
std::array<uint8_t, 64 * 1024> buf;
recv(stop_readfd, (char*)buf.data(), buf.size(), 0);
}
try {
auto rcv = recvFrom();
msgpack::object obj = rcv.second.get();
if (obj.type != msgpack::type::MAP)
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;
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_);
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;
}
if (cb)
cb(std::move(o.val), std::move(rcv.first));
} else
return;
}
} catch (const std::exception& e) {
std::cerr << "Error receiving packet: " << e.what() << std::endl;
if (cb)
cb(std::move(o.val), SockAddr{ receiveFrom_.data(), (socklen_t)receiveFrom_.size() });
}
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error receiving packet: %s", e.what());
}
}
if (stop_readfd != -1)
close(stop_readfd);
if (stopWriteFd_ != -1) {
close(stopWriteFd_);
stopWriteFd_ = -1;
}
loopListener();
});
}
void
PeerDiscovery::DomainPeerDiscovery::setupSender()
PeerDiscovery::DomainPeerDiscovery::publish()
{
// Setup sender address
sockAddrSend_.setFamily(domain_);
sockAddrSend_.setAddress(domain_ == AF_INET ? MULTICAST_ADDRESS_IPV4 : MULTICAST_ADDRESS_IPV6);
sockAddrSend_.setPort(port_);
std::lock_guard<std::mutex> lck(mtx_);
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)
{
//Set up New Sending pack
msgpack::sbuffer pack_buf_c;
pack_buf_c.write(pack_buf.data(),pack_buf.size());
std::unique_lock<std::mutex> lck(mtx_);
std::lock_guard<std::mutex> lck(mtx_);
messages_[type] = std::move(pack_buf_c);
reloadMessages();
if (not lrunning_) {
if (sending_.joinable())
sending_.join();
lrunning_ = true;
sending_ = std::thread([this](){
std::unique_lock<std::mutex> lck(mtx_);
while (lrunning_) {
ssize_t nbytes = sendto(
sockFd_,
sbuf_.data(),
sbuf_.size(),
0,
sockAddrSend_.get(),
sockAddrSend_.getLength()
);
if (nbytes < 0) {
std::cerr << "Error sending packet: " << strerror(errno) << std::endl;
}
if (cv_.wait_for(lck,std::chrono::seconds(3),[&]{ return !lrunning_; }))
break;
}
});
ioContext_->post(std::bind(&PeerDiscovery::DomainPeerDiscovery::publish, this));
}
}
bool
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
{
std::lock_guard<std::mutex> lck(dmtx_);
if (callbackmap_.erase(type) > 0) {
@@ -428,7 +193,7 @@ PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
}
bool
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
{
std::lock_guard<std::mutex> lck(mtx_);
if (messages_.erase(type) > 0) {
@@ -444,20 +209,8 @@ PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
void
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
{
#ifdef _WIN32
#define write(s, b, f) send((s), (b), (f), 0)
#endif
if (drunning_) {
if (drunning_)
drunning_ = false;
if (stopWriteFd_ != -1) {
if (write(stopWriteFd_, "\0", 1) == -1) {
std::cerr << "Can't send stop message: " << strerror(errno) << std::endl;
}
}
}
#ifdef _WIN32
#undef write
#endif
}
void
@@ -465,7 +218,7 @@ PeerDiscovery::DomainPeerDiscovery::stopPublish()
{
if (lrunning_) {
lrunning_ = false;
cv_.notify_all();
publishTimer_.cancel();
}
}
@@ -473,11 +226,11 @@ void
PeerDiscovery::DomainPeerDiscovery::stop()
{
{
std::unique_lock<std::mutex> lck(dmtx_);
std::lock_guard<std::mutex> lck(dmtx_);
stopDiscovery();
}
{
std::unique_lock<std::mutex> lck(mtx_);
std::lock_guard<std::mutex> lck(mtx_);
stopPublish();
}
}
@@ -494,38 +247,65 @@ PeerDiscovery::DomainPeerDiscovery::reloadMessages()
}
}
PeerDiscovery::PeerDiscovery(in_port_t port)
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
{
if (not ioContext) {
ioContext = std::make_shared<asio::io_context>();
ioContext_ = ioContext;
ioRunnner_ = std::thread([logger, ioContext] {
try {
if (logger)
logger->d("[peerdiscovery] starting io_context");
auto work = asio::make_work_guard(*ioContext);
ioContext->run();
if (logger)
logger->d("[peerdiscovery] io_context stopped");
}
catch (const std::exception& ex){
if (logger)
logger->e("[peerdiscovery] run error: %s", ex.what());
}
});
}
try {
peerDiscovery4_.reset(new DomainPeerDiscovery(AF_INET, port));
peerDiscovery4_.reset(new DomainPeerDiscovery(asio::ip::udp::v4(), port, ioContext, logger));
} catch(const std::exception& e){
std::cerr << "Can't start peer discovery (IPv4): " << e.what() << std::endl;
if (logger)
logger->e("[peerdiscovery] can't start IPv4: %s", e.what());
}
try {
peerDiscovery6_.reset(new DomainPeerDiscovery(AF_INET6, port));
peerDiscovery6_.reset(new DomainPeerDiscovery(asio::ip::udp::v6(), port, ioContext, logger));
} catch(const std::exception& e) {
std::cerr << "Can't start peer discovery (IPv6): " << e.what() << std::endl;
if (logger)
logger->e("[peerdiscovery] can't start IPv6: %s", e.what());
}
}
PeerDiscovery::~PeerDiscovery(){}
void
PeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
if(peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if(peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
PeerDiscovery::~PeerDiscovery() {
stop();
if (ioContext_)
ioContext_->stop();
if (ioRunnner_.joinable())
ioRunnner_.join();
}
void
PeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
PeerDiscovery::startDiscovery(const std::string& type, ServiceDiscoveredCallback callback)
{
if(peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if(peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
if (peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if (peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf)
PeerDiscovery::startPublish(const std::string& type, const msgpack::sbuffer& pack_buf)
{
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string& type, const msgpack::sbuffer& pack_buf)
{
if (domain == AF_INET) {
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
@@ -537,8 +317,8 @@ PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const m
void
PeerDiscovery::stop()
{
if(peerDiscovery4_) peerDiscovery4_->stop();
if(peerDiscovery6_) peerDiscovery6_->stop();
if (peerDiscovery4_) peerDiscovery4_->stop();
if (peerDiscovery6_) peerDiscovery6_->stop();
}
bool
@@ -558,7 +338,7 @@ PeerDiscovery::stopPublish(const std::string &type)
}
bool
PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
{
if (domain == AF_INET) {
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
@@ -568,10 +348,4 @@ PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
return false;
}
void
PeerDiscovery::join() {
if(peerDiscovery4_) peerDiscovery4_->join();
if(peerDiscovery6_) peerDiscovery6_->join();
}
}
+3
View File
@@ -17,6 +17,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 "securedht.h"
#include "rng.h"
+61 -3
View File
@@ -17,10 +17,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "value.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#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"
@@ -38,6 +45,46 @@ 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());
@@ -52,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 {
@@ -62,7 +111,9 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
s << " (invalid)";
}
#endif
} else {
}
#endif
else {
s << "Data (type: " << v.type << " ): ";
s << std::hex;
for (auto i : v.data)
@@ -159,9 +210,12 @@ Value::msgpack_unpack_body(const msgpack::object& o)
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));
#endif
if (auto rrecipient = findMapValue(*rbody, "to")) {
recipient = rrecipient->as<InfoHash>();
}
@@ -190,11 +244,13 @@ Value::Value(Json::Value& json)
}
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);
}
#endif
if (json.isMember("to")) {
auto toStr = json["to"].asString();
recipient = InfoHash(toStr);
@@ -314,9 +370,11 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
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;
-1
View File
@@ -1 +0,0 @@
g++ -Wall -Wextra -Wfatal-errors -pedantic -g ../src/http.cpp tests_runner.cpp httptester.cpp -o run.out -lopendht -lpthread -lcppunit -ljsoncpp -DOPENDHT_JSONCPP -I../include/opendht -DASIO_STANDALONE
+3 -3
View File
@@ -19,7 +19,7 @@
#include "cryptotester.h"
#include "opendht/crypto.h"
#include <opendht/crypto.h>
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTester);
@@ -61,13 +61,13 @@ CryptoTester::testSignatureEncryption() {
{
std::vector<uint8_t> encrypted = public_key.encrypt(data1);
encrypted[1]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), dht::crypto::DecryptError);
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
{
std::vector<uint8_t> encrypted = public_key.encrypt(data2);
encrypted[2]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), dht::crypto::DecryptError);
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
}
+92 -58
View File
@@ -27,28 +27,26 @@
#include <chrono>
#include <condition_variable>
using namespace std::chrono_literals;
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(DhtProxyTester);
void
DhtProxyTester::setUp() {
logger = dht::log::getStdLogger();
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
nodePeer.run(0);
nodeProxy = std::make_shared<dht::DhtRunner>();
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
nodeProxy->run(0);
nodeProxy->bootstrap(nodePeer.getBound());
auto serverCAIdentity = dht::crypto::generateEcIdentity("DHT Node CA");
auto serverIdentity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
serverProxy = std::unique_ptr<dht::DhtProxyServer>(
new dht::DhtProxyServer(
serverProxy = std::make_unique<dht::DhtProxyServer>(
//dht::crypto::Identity{}, // http
serverIdentity, // https
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090");
clientConfig.server_ca = serverCAIdentity.second;
clientConfig.client_identity = dht::crypto::generateIdentity("DhtProxyTester");
@@ -56,27 +54,31 @@ DhtProxyTester::setUp() {
clientConfig.threaded = true;
clientConfig.push_node_id = "dhtnode";
clientConfig.proxy_server = "https://127.0.0.1:8080";
dht::DhtRunner::Context clientContext {};
clientContext.logger = logger;
nodeClient = std::make_shared<dht::DhtRunner>();
nodeClient->run(0, clientConfig, std::move(clientContext));
}
void
DhtProxyTester::tearDown() {
logger->d("[tester:proxy] stopping peer node");
nodePeer.join();
nodeClient->join();
logger->d("[tester:proxy] stopping proxy server");
serverProxy.reset(nullptr);
logger->d("[tester:proxy] stopping proxy node");
nodeProxy->join();
nodeClient.join();
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
nodeProxy->shutdown([&]{
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done; }));
serverProxy.reset();
nodeProxy.reset();
}
void
DhtProxyTester::testGetPut() {
nodeClient.run(0, clientConfig);
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
@@ -85,22 +87,24 @@ DhtProxyTester::testGetPut() {
dht::Value val {"Hey! It's been a long time. How have you been?"};
auto val_data = val.data;
{
std::unique_lock<std::mutex> lk(cv_m);
nodePeer.put(key, std::move(val), [&](bool) {
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
}
auto vals = nodeClient->get(key).get();
auto vals = nodeClient.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtProxyTester::testListen() {
nodeClient.run(0, clientConfig);
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
@@ -117,11 +121,11 @@ DhtProxyTester::testListen() {
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
done = false;
std::vector<dht::Blob> values;
auto token = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
auto token = nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
for (const auto& value : v)
@@ -131,7 +135,7 @@ DhtProxyTester::testListen() {
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
done = false;
// Here values should contains 1 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 1);
@@ -142,8 +146,8 @@ DhtProxyTester::testListen() {
dht::Value secondVal {"You're a monster"};
auto secondVal_data = secondVal.data;
nodePeer.put(key, std::move(secondVal));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
nodeClient->cancelListen(key, std::move(token));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
nodeClient.cancelListen(key, std::move(token));
// Here values should contains 2 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 2);
CPPUNIT_ASSERT(values.back() == secondVal_data);
@@ -151,7 +155,8 @@ DhtProxyTester::testListen() {
void
DhtProxyTester::testResubscribeGetValues() {
nodeClient->setPushNotificationToken("atlas");
clientConfig.push_token = "atlas";
nodeClient.run(0, clientConfig);
bool done = false;
std::condition_variable cv;
@@ -169,59 +174,55 @@ DhtProxyTester::testResubscribeGetValues() {
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
done = false;
// Send a first subscribe, the value is sent via a push notification
// So ignore values here.
nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
return true;
});
cv.wait_for(lk, std::chrono::seconds(1));
// Reboot node (to avoid cache)
nodeClient->join();
clientConfig.push_token = "atlas";
dht::DhtRunner::Context clientContext {};
clientContext.logger = logger;
nodeClient->run(0, clientConfig, std::move(clientContext));
nodeClient.join();
clientConfig.push_token = "";
nodeClient.run(0, clientConfig);
// For the second subscribe, the proxy will return the value in the body
auto values = std::vector<dht::Blob>();
auto ftoken = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
std::vector<std::shared_ptr<dht::Value>> values;
auto ftoken = nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
for (const auto& value : v)
values.emplace_back(value->data);
values.insert(values.end(), v.begin(), v.end());
done = true;
cv.notify_all();
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
auto token = ftoken.get();
CPPUNIT_ASSERT(token);
nodeClient->cancelListen(key, token);
nodeClient.cancelListen(key, token);
// Here values should still contains 1 values
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
CPPUNIT_ASSERT(firstVal_data == values.front());
CPPUNIT_ASSERT(firstVal_data == values.front()->data);
}
void
DhtProxyTester::testPutGet40KChars()
{
nodeClient.run(0, clientConfig);
constexpr size_t N = 40000;
// Arrange
auto key = dht::InfoHash::get("testPutGet40KChars");
std::vector<std::shared_ptr<dht::Value>> values;
std::string mtu = "";
for (int i = 0; i < 40000; i++){
if (i % 2 == 0)
mtu.append("M");
else
mtu.append("T");
}
std::vector<uint8_t> mtu;
mtu.reserve(N);
for (size_t i = 0; i < N; i++)
mtu.emplace_back((i % 2) ? 'T' : 'M');
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
@@ -230,28 +231,61 @@ DhtProxyTester::testPutGet40KChars()
// Act
dht::Value val {mtu};
nodeClient->put(key, std::move(val), [&](bool ok) {
nodePeer.put(key, std::move(val), [&](bool ok) {
std::lock_guard<std::mutex> lk(cv_m);
done_put = ok;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done_put; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done_put; }));
nodeClient->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values = vals;
nodeClient.get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
return true;
},[&](bool ok){
std::lock_guard<std::mutex> lk(cv_m);
done_get = ok;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done_get; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done_get; }));
// Assert
dht::Value mtu_val {mtu};
for (const auto &value: values){
CPPUNIT_ASSERT(value->data == mtu_val.data);
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
for (const auto &value: values)
CPPUNIT_ASSERT(value->data == mtu);
}
void
DhtProxyTester::testFuzzy()
{
constexpr size_t N = 40000;
// Arrange
auto key = dht::InfoHash::get("testFuzzy");
std::vector<std::shared_ptr<dht::Value>> values;
std::vector<uint8_t> mtu;
mtu.reserve(N);
for (size_t i = 0; i < N; i++)
mtu.emplace_back((i % 2) ? 'T' : 'M');
// Act
for (size_t i = 0; i < 100; i++) {
auto nodeTest = std::make_shared<dht::DhtRunner>();
nodeTest->run(0, clientConfig);
nodeTest->put(key, dht::Value(mtu), [&](bool ok) {
CPPUNIT_ASSERT(ok);
});
nodeTest->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
return true;
},[&](bool ok){
CPPUNIT_ASSERT(ok);
});
std::this_thread::sleep_for(10ms);
}
// Assert
for (const auto &value: values)
CPPUNIT_ASSERT(value->data == mtu);
}
} // namespace test
+6 -6
View File
@@ -35,6 +35,7 @@ class DhtProxyTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testResubscribeGetValues);
CPPUNIT_TEST(testPutGet40KChars);
CPPUNIT_TEST(testFuzzy);
CPPUNIT_TEST_SUITE_END();
public:
@@ -65,15 +66,14 @@ class DhtProxyTester : public CppUnit::TestFixture {
*/
void testPutGet40KChars();
private:
dht::DhtRunner nodePeer;
void testFuzzy();
std::shared_ptr<dht::DhtRunner> nodeClient;
private:
dht::DhtRunner::Config clientConfig {};
dht::DhtRunner nodePeer;
dht::DhtRunner nodeClient;
std::shared_ptr<dht::DhtRunner> nodeProxy;
std::unique_ptr<dht::DhtProxyServer> serverProxy;
dht::DhtRunner::Config clientConfig {};
std::shared_ptr<dht::Logger> logger {};
};
} // namespace test
+22 -14
View File
@@ -22,19 +22,32 @@
#include <chrono>
#include <mutex>
#include <condition_variable>
using namespace std::chrono_literals;
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester);
void
DhtRunnerTester::setUp() {
node1.run(42222, {}, true);
node2.run(42232, {}, true);
node1.run(42222);
node2.run(42232);
node2.bootstrap(node1.getBound());
}
void
DhtRunnerTester::tearDown() {
unsigned done {0};
std::condition_variable cv;
std::mutex cv_m;
auto shutdown = [&]{
std::lock_guard<std::mutex> lk(cv_m);
done++;
cv.notify_all();
};
node1.shutdown(shutdown);
node2.shutdown(shutdown);
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done == 2; }));
node1.join();
node2.join();
}
@@ -90,27 +103,22 @@ DhtRunnerTester::testListen() {
for (unsigned i=0; i<N; i++) {
node2.put(a, dht::Value("v1"), [&](bool ok) {
{
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
}
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
node2.put(b, dht::Value("v2"), [&](bool ok) {
{
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
}
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
}
{
std::unique_lock<std::mutex> lk(mutex);
cv.wait_for(lk, std::chrono::seconds(30), [&]{ return putCount == N * 2u; });
CPPUNIT_ASSERT_EQUAL(N * 2u, putCount);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == N * 2u; }));
CPPUNIT_ASSERT_EQUAL(N * 2u, putOkCount);
}
+71 -36
View File
@@ -19,41 +19,35 @@
#include "httptester.h"
// std
#include <opendht/value.h>
#include <opendht/dhtrunner.h>
#include <iostream>
#include <string>
#include <chrono>
#include <condition_variable>
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(HttpTester);
void
HttpTester::setUp() {
logger = dht::log::getStdLogger();
nodePeer = std::make_shared<dht::DhtRunner>();
nodePeer->run(0);
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
nodeProxy = std::make_shared<dht::DhtRunner>();
auto nodeProxy = std::make_shared<dht::DhtRunner>();
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
nodeProxy->bootstrap(nodePeer.getBound());
nodeProxy->bootstrap(nodePeer->getBound());
serverProxy = std::unique_ptr<dht::DhtProxyServer>(
new dht::DhtProxyServer(
/*http*/dht::crypto::Identity{}, nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
/*http*/dht::crypto::Identity{}, nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090"));
}
void
HttpTester::tearDown() {
logger->d("[tester:http] stopping peer node");
nodePeer.join();
logger->d("[tester:http] stopping proxy server");
serverProxy.reset(nullptr);
logger->d("[tester:http] stopping proxy node");
nodeProxy->join();
serverProxy.reset();
nodePeer->join();
}
void
@@ -234,31 +228,72 @@ HttpTester::test_send_json() {
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
bool done = false;
dht::Value val {"hey"};
auto json = val.toJson();
json["permanent"] = false;
std::cout << "[test_send_json] sending:\n" << json << std::endl;
Json::Value resp_val;
unsigned int status = 0;
std::string url = "http://127.0.0.1:8080/key";
auto json = dht::Value("hey").toJson();
Json::Value resp_val;
// Act
auto request = std::make_shared<dht::http::Request>(serverProxy->io_context(), url, json,
[this, &cv, &done, &status, &resp_val](Json::Value value, unsigned int status_code){
if (status_code != 200 and logger)
logger->e("[tester] [status] failed with code=%i", status_code);
std::cout << "[tester] got response:\n" << value << std::endl;
resp_val = value;
status = status_code;
done = true;
cv.notify_all();
}, logger);
request->set_method(restinio::http_method_post());
auto request = std::make_shared<dht::http::Request>(serverProxy->io_context(),
"http://127.0.0.1:8080/key",
json,
[&](Json::Value value, unsigned int status_code) {
std::lock_guard<std::mutex> lk(cv_m);
resp_val = std::move(value);
status = status_code;
done = true;
cv.notify_all();
});
request->send();
// Assert
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(status == 200);
CPPUNIT_ASSERT(resp_val["data"] == val.toJson()["data"]);
CPPUNIT_ASSERT_EQUAL(200u, status);
CPPUNIT_ASSERT_EQUAL(json["data"].asString(), resp_val["data"].asString());
done = false;
#if 0
request = std::make_shared<dht::http::Request>(serverProxy->io_context(),
"http://google.ca",
[&](const dht::http::Response& response) {
std::lock_guard<std::mutex> lk(cv_m);
status = response.status_code;
done = true;
cv.notify_all();
});
request->send();
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(status != 0);
done = false;
request = std::make_shared<dht::http::Request>(serverProxy->io_context(),
"https://google.ca",
[&](const dht::http::Response& response) {
std::lock_guard<std::mutex> lk(cv_m);
status = response.status_code;
done = true;
cv.notify_all();
});
request->send();
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(status != 0);
done = false;
request = std::make_shared<dht::http::Request>(serverProxy->io_context(),
"https://google.ca/sdbjklwGBIP",
[&](const dht::http::Response& response) {
std::lock_guard<std::mutex> lk(cv_m);
status = response.status_code;
done = true;
cv.notify_all();
});
request->send();
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT_EQUAL(404u, status);
#endif
}
} // namespace test
+5 -8
View File
@@ -23,12 +23,12 @@
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <opendht/value.h>
#include <opendht/log.h>
#include <opendht/http.h>
#include <opendht/dhtrunner.h>
#include <opendht/dht_proxy_server.h>
#include <asio.hpp>
#include <thread>
#include <memory>
namespace test {
@@ -88,10 +88,7 @@ class HttpTester : public CppUnit::TestFixture {
void test_send_json();
private:
std::shared_ptr<dht::Logger> logger {};
dht::DhtRunner nodePeer;
std::shared_ptr<dht::DhtRunner> nodeProxy;
std::shared_ptr<dht::DhtRunner> nodePeer;
std::unique_ptr<dht::DhtProxyServer> serverProxy;
};
+4 -1
View File
@@ -20,9 +20,12 @@
#include "peerdiscoverytester.h"
#include "opendht/value.h"
#include <mutex>
#include <condition_variable>
namespace test {
constexpr int MULTICAST_PORT = 2222;
constexpr unsigned MULTICAST_PORT = 2222;
const std::string DHT_NODE_NAME {"dht"};
const std::string JAMI_NODE_NAME {"jami"};
+4 -4
View File
@@ -3,9 +3,9 @@ add_executable (dhtnode dhtnode.cpp tools_common.h)
add_executable (dhtscanner dhtscanner.cpp tools_common.h)
add_executable (dhtchat dhtchat.cpp tools_common.h)
target_link_libraries (dhtnode LINK_PUBLIC readline)
target_link_libraries (dhtscanner LINK_PUBLIC readline)
target_link_libraries (dhtchat LINK_PUBLIC readline)
target_link_libraries (dhtnode LINK_PUBLIC ${READLINE_LIBRARIES})
target_link_libraries (dhtscanner LINK_PUBLIC ${READLINE_LIBRARIES})
target_link_libraries (dhtchat LINK_PUBLIC ${READLINE_LIBRARIES})
if (OPENDHT_SHARED)
target_link_libraries (dhtnode LINK_PUBLIC opendht)
@@ -19,7 +19,7 @@ endif ()
if (OPENDHT_C)
add_executable (dhtcnode dhtcnode.c)
target_link_libraries (dhtcnode LINK_PUBLIC opendht-c readline)
target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES})
endif ()
if (NOT DEFINED CMAKE_INSTALL_BINDIR)
+1 -1
View File
@@ -1,7 +1,7 @@
bin_PROGRAMS = dhtnode dhtchat dhtscanner
noinst_HEADERS = tools_common.h
AM_CPPFLAGS = -I../include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
dhtnode_SOURCES = dhtnode.cpp
dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
+6 -43
View File
@@ -16,6 +16,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 "tools_common.h"
#include <opendht/rng.h>
@@ -37,11 +40,6 @@ const std::string printTime(const std::time_t& now) {
return buf;
}
void print_node_info(const DhtRunner& dht, const dht_params&) {
std::cout << "OpenDht node " << dht.getNodeId() << " running on port " << dht.getBoundPort() << std::endl;
std::cout << "Public key ID " << dht.getId() << std::endl;
}
void print_usage() {
std::cout << "Usage: dhtchat [-n network_id] [-p local_port] [-b bootstrap_host[:port]]" << std::endl << std::endl;
std::cout << "dhtchat, a simple OpenDHT command line chat client." << std::endl;
@@ -62,48 +60,13 @@ main(int argc, char **argv)
DhtRunner dht;
try {
if (not params.id.first) {
auto node_ca = std::make_unique<dht::crypto::Identity>(dht::crypto::generateEcIdentity("DHT Node CA"));
params.id = dht::crypto::generateIdentity("DHT Chat Node", *node_ca);
if (not params.save_identity.empty()) {
dht::crypto::saveIdentity(*node_ca, params.save_identity + "_ca", params.privkey_pwd);
dht::crypto::saveIdentity(params.id, params.save_identity, params.privkey_pwd);
}
}
dht::DhtRunner::Config config {};
config.dht_config.node_config.network = params.network;
config.dht_config.node_config.maintain_storage = false;
config.dht_config.node_config.persist_path = params.persist_path;
config.dht_config.id = params.id;
config.threaded = true;
config.proxy_server = params.proxyclient;
config.push_node_id = "dhtnode";
config.push_token = params.devicekey;
config.peer_discovery = params.peer_discovery;
config.peer_publish = params.peer_discovery;
dht::DhtRunner::Context context {};
if (params.log) {
if (params.syslog or (params.daemonize and params.logfile.empty()))
context.logger = log::getSyslogLogger("dhtnode");
else if (not params.logfile.empty())
context.logger = log::getFileLogger(params.logfile);
else
context.logger = log::getStdLogger();
}
dht.run(params.port, config, std::move(context));
params.generate_identity = true;
auto dhtConf = getDhtConfig(params);
dht.run(params.port, dhtConf.first, std::move(dhtConf.second));
if (not params.bootstrap.first.empty())
dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
#ifdef OPENDHT_PROXY_CLIENT
if (!params.proxyclient.empty()) {
dht.setProxyServer(params.proxyclient);
dht.enableProxy(true);
}
#endif //OPENDHT_PROXY_CLIENT
print_node_info(dht, params);
std::cout << " type 'c {hash}' to join a channel" << std::endl << std::endl;
+13 -49
View File
@@ -18,6 +18,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 "tools_common.h"
extern "C" {
@@ -48,18 +51,6 @@ void print_id_req() {
std::cout << "An identity is required to perform this operation (run with -i)" << std::endl;
}
void print_node_info(const std::shared_ptr<DhtRunner>& node, const dht_params& params) {
std::cout << "OpenDHT node " << node->getNodeId() << " running on ";
auto port4 = node->getBoundPort(AF_INET);
auto port6 = node->getBoundPort(AF_INET6);
if (port4 == port6)
std::cout << "port " << port4 << std::endl;
else
std::cout << "IPv4 port " << port4 << ", IPv6 port " << port6 << std::endl;
if (params.id.first)
std::cout << "Public key ID " << node->getId() << std::endl;
}
void print_help() {
std::cout << "OpenDHT command line interface (CLI)" << std::endl;
std::cout << "Possible commands:" << std::endl
@@ -123,7 +114,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
#endif
)
{
print_node_info(node, params);
print_node_info(*node, params);
std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
#ifndef WIN32_NATIVE
@@ -152,11 +143,13 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
print_help();
continue;
} else if (op == "ll") {
print_node_info(node, params);
auto nodeInfo = node->getNodeInfo();
print_node_info(*node, params);
std::cout << nodeInfo.ongoing_ops << " ongoing operations" << std::endl;
std::cout << "IPv4 stats:" << std::endl;
std::cout << node->getNodesStats(AF_INET).toString() << std::endl;
std::cout << nodeInfo.ipv4.toString() << std::endl;
std::cout << "IPv6 stats:" << std::endl;
std::cout << node->getNodesStats(AF_INET6).toString() << std::endl;
std::cout << nodeInfo.ipv6.toString() << std::endl;
#ifdef OPENDHT_PROXY_SERVER
for (const auto& proxy : proxies) {
std::cout << "Stats for proxy on port " << proxy.first << std::endl;
@@ -532,37 +525,8 @@ main(int argc, char **argv)
auto node = std::make_shared<DhtRunner>();
try {
if (not params.id.first and params.generate_identity) {
auto node_ca = std::make_unique<dht::crypto::Identity>(dht::crypto::generateEcIdentity("DHT Node CA"));
params.id = dht::crypto::generateIdentity("DHT Node", *node_ca);
if (not params.save_identity.empty()) {
dht::crypto::saveIdentity(*node_ca, params.save_identity + "_ca", params.privkey_pwd);
dht::crypto::saveIdentity(params.id, params.save_identity, params.privkey_pwd);
}
}
dht::DhtRunner::Config config {};
config.dht_config.node_config.network = params.network;
config.dht_config.node_config.maintain_storage = false;
config.dht_config.node_config.persist_path = params.persist_path;
config.dht_config.id = params.id;
config.threaded = true;
config.proxy_server = params.proxyclient;
config.push_node_id = "dhtnode";
config.push_token = params.devicekey;
config.peer_discovery = params.peer_discovery;
config.peer_publish = params.peer_discovery;
dht::DhtRunner::Context context {};
if (params.log) {
if (params.syslog or (params.daemonize and params.logfile.empty()))
context.logger = log::getSyslogLogger("dhtnode");
else if (not params.logfile.empty())
context.logger = log::getFileLogger(params.logfile);
else
context.logger = log::getStdLogger();
}
node->run(params.port, config, std::move(context));
auto dhtConf = getDhtConfig(params);
node->run(params.port, dhtConf.first, std::move(dhtConf.second));
if (not params.bootstrap.first.empty()) {
std::cout << "Bootstrap: " << params.bootstrap.first << ":" << params.bootstrap.second << std::endl;
@@ -576,13 +540,13 @@ main(int argc, char **argv)
#ifdef OPENDHT_PROXY_SERVER
proxies.emplace(params.proxyserverssl, std::unique_ptr<DhtProxyServer>(
new DhtProxyServer(params.proxy_id,
node, params.proxyserverssl, params.pushserver, context.logger)));
node, params.proxyserverssl, params.pushserver, dhtConf.second.logger)));
}
if (params.proxyserver) {
proxies.emplace(params.proxyserver, std::unique_ptr<DhtProxyServer>(
new DhtProxyServer(
dht::crypto::Identity{},
node, params.proxyserver, params.pushserver, context.logger)));
node, params.proxyserver, params.pushserver, dhtConf.second.logger)));
#else
std::cerr << "DHT proxy server requested but OpenDHT built without proxy server support." << std::endl;
exit(EXIT_FAILURE);
+6 -11
View File
@@ -16,6 +16,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 "tools_common.h"
#include <opendht/node.h>
@@ -85,21 +88,13 @@ main(int argc, char **argv)
DhtRunner dht;
try {
dht.run(params.port, {}, true, params.network);
if (params.log) {
if (params.syslog)
log::enableSyslog(dht, "dhtnode");
else if (not params.logfile.empty())
log::enableFileLogging(dht, params.logfile);
else
log::enableLogging(dht);
}
auto dhtConf = getDhtConfig(params);
dht.run(params.port, dhtConf.first, std::move(dhtConf.second));
if (not params.bootstrap.first.empty())
dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
std::cout << "OpenDht node " << dht.getNodeId() << " running on port " << params.port << std::endl;
print_node_info(dht, params);
std::cout << "Scanning network..." << std::endl;
auto all_nodes = std::make_shared<NodeSet>();
+70 -1
View File
@@ -25,6 +25,13 @@
#include <opendht/log.h>
#include <opendht/crypto.h>
#include <opendht/network_utils.h>
#ifdef OPENDHT_INDEXATION
#include <opendht/indexation/pht.h>
#endif
#ifdef OPENDHT_PROXY_SERVER
#include <opendht/dht_proxy_server.h>
#endif
#ifndef WIN32_NATIVE
#include <getopt.h>
#include <readline/readline.h>
@@ -131,8 +138,66 @@ struct dht_params {
std::string privkey_pwd {};
std::string proxy_privkey_pwd {};
std::string save_identity {};
bool no_rate_limit {false};
};
std::pair<dht::DhtRunner::Config, dht::DhtRunner::Context>
getDhtConfig(dht_params& params)
{
if (not params.id.first and params.generate_identity) {
auto node_ca = std::make_unique<dht::crypto::Identity>(dht::crypto::generateEcIdentity("DHT Node CA"));
params.id = dht::crypto::generateIdentity("DHT Node", *node_ca);
if (not params.save_identity.empty()) {
dht::crypto::saveIdentity(*node_ca, params.save_identity + "_ca", params.privkey_pwd);
dht::crypto::saveIdentity(params.id, params.save_identity, params.privkey_pwd);
}
}
dht::DhtRunner::Config config {};
config.dht_config.node_config.network = params.network;
config.dht_config.node_config.maintain_storage = false;
config.dht_config.node_config.persist_path = params.persist_path;
config.dht_config.id = params.id;
config.threaded = true;
config.proxy_server = params.proxyclient;
config.push_node_id = "dhtnode";
config.push_token = params.devicekey;
config.peer_discovery = params.peer_discovery;
config.peer_publish = params.peer_discovery;
if (params.no_rate_limit) {
config.dht_config.node_config.max_req_per_sec = -1;
config.dht_config.node_config.max_peer_req_per_sec = -1;
}
dht::DhtRunner::Context context {};
if (params.log) {
if (params.syslog or (params.daemonize and params.logfile.empty()))
context.logger = dht::log::getSyslogLogger("dhtnode");
else if (not params.logfile.empty())
context.logger = dht::log::getFileLogger(params.logfile);
else
context.logger = dht::log::getStdLogger();
}
if (context.logger) {
context.statusChangedCallback = [logger = *context.logger](dht::NodeStatus status4, dht::NodeStatus status6) {
logger.WARN("Connectivity changed: IPv4: %s, IPv6: %s", dht::statusToStr(status4), dht::statusToStr(status6));
};
}
return {std::move(config), std::move(context)};
}
void print_node_info(const dht::DhtRunner& node, const dht_params& params) {
std::cout << "OpenDHT node " << node.getNodeId() << " running on ";
auto port4 = node.getBoundPort(AF_INET);
auto port6 = node.getBoundPort(AF_INET6);
if (port4 == port6)
std::cout << "port " << port4 << std::endl;
else
std::cout << "IPv4 port " << port4 << ", IPv6 port " << port6 << std::endl;
if (params.id.first)
std::cout << "Public key ID " << node.getId() << std::endl;
}
static const constexpr struct option long_options[] = {
{"help", no_argument , nullptr, 'h'},
{"port", required_argument, nullptr, 'p'},
@@ -147,6 +212,7 @@ static const constexpr struct option long_options[] = {
{"daemonize", no_argument , nullptr, 'd'},
{"service", no_argument , nullptr, 's'},
{"peer-discovery", no_argument , nullptr, 'D'},
{"no-rate-limit", no_argument , nullptr, 'U'},
{"persist", required_argument, nullptr, 'f'},
{"logfile", required_argument, nullptr, 'l'},
{"syslog", no_argument , nullptr, 'L'},
@@ -168,7 +234,7 @@ parseArgs(int argc, char **argv) {
int opt;
std::string privkey;
std::string proxy_privkey;
while ((opt = getopt_long(argc, argv, "hidsvDp:n:b:f:l:", long_options, nullptr)) != -1) {
while ((opt = getopt_long(argc, argv, "hidsvDUp:n:b:f:l:", long_options, nullptr)) != -1) {
switch (opt) {
case 'p': {
int port_arg = atoi(optarg);
@@ -212,6 +278,9 @@ parseArgs(int argc, char **argv) {
case 'n':
params.network = strtoul(optarg, nullptr, 0);
break;
case 'U':
params.no_rate_limit = true;
break;
case 'b':
params.bootstrap = dht::splitPort((optarg[0] == '=') ? optarg+1 : optarg);
if (not params.bootstrap.first.empty() and params.bootstrap.second.empty()) {