Compare commits

..
Author SHA1 Message Date
Adrien Béraud 90022ee3e8 build: update version to 2.3.5 2022-03-09 14:33:25 -05:00
Adrien Béraud de68a47a16 dhtrunner: handle exception during initialization 2022-03-09 14:32:22 -05:00
Adrien Béraud 714af68292 c: specify void argument for dht_runner_new 2022-03-03 14:44:52 -05:00
Adrien Béraud e6768edaf0 build: update version to 2.3.4 2022-03-01 19:54:43 -05:00
Adrien Béraud 6145e54543 cmake: update CheckAtomic 2022-02-28 12:37:49 -05:00
Adrien Béraud ac51c2300e dht: remove canceled tasks from scheduler 2022-02-27 03:34:36 -05:00
Adrien Béraud f590980c3e infohash: include cstddef 2022-02-27 03:34:36 -05:00
Adrien Béraud 5dbade3d0b value cache: move to lambda 2022-02-26 22:16:15 -05:00
Adrien Béraud 2028d4b13e build: update version to 2.3.3 2022-02-25 23:52:26 -05:00
Adrien Béraud a6f7b49b92 build: use msgpack cmake 2022-02-25 23:52:15 -05:00
Adrien Béraud c2415f38fa dht: avoid job & search leak 2022-02-24 13:33:42 -05:00
Adrien Béraud 9cf717ab43 tools/c: adapt include directory 2022-02-22 11:49:44 -05:00
Adrien Béraud d4589bb6f6 tools/c: use new api 2022-02-22 11:49:44 -05:00
Adrien Béraud 484878aec3 c: add missing value apis 2022-02-22 11:49:44 -05:00
Adrien Béraud ace3a94e08 scheduler: remove debug log
This reverts commit 5d771e119c.
2022-02-19 16:32:07 -05:00
Adrien Béraud 5d771e119c c: install header to opendht directory 2022-02-19 12:33:31 -05:00
Adrien Béraud 8dcc695947 value: cleanup 2022-02-19 10:53:31 -05:00
Adrien Béraud 1ae28e07b6 storage: cleanup 2022-02-19 10:53:31 -05:00
Adrien Béraud 2de0737443 cmake: support some policies 2022-02-19 10:53:31 -05:00
Adrien Béraud bc32f848cb thread pool: cleanup 2022-02-19 10:53:31 -05:00
Adrien Béraud edee6d63d6 build: use msgpack without boost 2022-02-19 10:49:25 -05:00
Adrien Béraud af3f6f40bb c: install header 2022-02-19 10:48:28 -05:00
Adrien Béraud 32f72c245d dht: add max bootstrap period 2022-02-19 09:23:57 -05:00
Adrien Béraud 043ef8da72 dht: reset bootstrap period on connectivity change
Also starts a bootstrap if disconnected.
2022-02-19 09:23:57 -05:00
Adrien Béraud 6812b733bb dht: respect exponential backoff 2022-02-19 09:23:57 -05:00
Adrien Béraud 2ec28dcb83 dhtrunner: use configured logger for dropped packets 2022-02-19 09:23:57 -05:00
Adrien Béraud db000a2f88 build: update version to 2.3.2 2022-01-26 14:17:57 -05:00
Adrien Béraud 59880df60e perftest: cleanup 2022-01-26 14:16:33 -05:00
Adrien Béraud 75f1b07e7a crypto: cleanup 2022-01-26 14:16:33 -05:00
Adrien Béraud f191c4f636 storage: 0-init size_diff 2022-01-26 14:16:33 -05:00
Sébastien Blin 1b2bc7b1e3 crypto: add parameter to change Certificate's validity period
This allow to create certificate with a different validity than
10 years and be able to change the expiration of a certificate
2022-01-19 14:51:45 -05:00
Bruno Pagani a89e4d626e tests: fix building with GCC11
Fixes `error: ‘sleep_for’ is not a member of ‘std::this_thread’`
2021-11-13 12:31:17 -05:00
Sébastien Blin dbbfdaab0f proxyclient: onConnectedCallbacks must be launched if started by notif 2021-10-27 13:45:30 -04:00
Sébastien Blin 536f30ec84 opendht.cpp: fix build 2021-10-22 11:03:12 -04:00
Adrien Béraud b7aec1310c crypto: make cachedId mutable 2021-09-16 11:28:59 -04:00
Adrien Béraud 31d76b1080 github: remove argon2 build 2021-09-16 11:19:10 -04:00
Adrien Béraud 2fbafc3591 crypto: cache Certificate Id 2021-09-16 11:08:02 -04:00
Adrien Béraud 19fe34415a thread pool: fix build on MSVC 2021-09-15 16:45:56 -04:00
Sébastien Blin 2a50f85a30 proxy_server: set expiration for iOS devices 2021-09-10 10:21:31 -04:00
Sébastien Blin 26b71ab993 proxyclient: do not play with stop when resubscribing
At this point we do not care for the request. Subscribes are
instantaneous, so the request will be terminated at this point.
Changing the stop status can cause some push notifications to be
dropped if coming at this moment.
2021-09-10 10:21:31 -04:00
Sébastien Blin 04a78445c6 dht_proxy_server: increase ttl for push to 24 hours
If the android device is offline during more than 10 minutes, it
can misses push notifications and cause an incorrect state with
values not expired even if the re-subscribe is correct.
2021-09-10 10:21:31 -04:00
Adrien Béraud fa19897016 HexMap: align on 64 bits 2021-08-09 18:20:12 -04:00
Adrien Béraud 3806355509 gitignore: add DS_Store 2021-08-09 18:20:12 -04:00
Adrien Béraud 3f6738185b tests: fix testIdOps() 2021-08-05 12:42:29 -04:00
Adrien Béraud e58d09e5da dht: always display value ID as hex 2021-08-05 12:42:29 -04:00
heroku-miraheze 71cd9d22c6 Moved to Libera.chat. 2021-07-19 11:25:59 -04:00
Adrien Béraud 6c58d4f2e9 build: update version to 2.3.0 2021-06-09 16:56:19 -04:00
Adrien Béraud 4070eecea7 gitignore: add tools 2021-06-09 16:56:19 -04:00
Adrien Béraud ffb53ceb1d thread pool: add ExecutionContext 2021-06-09 13:59:33 -04:00
Adrien Béraud 0c00544798 remove embedded argon2, HTTP_PARSER_FORK 2021-06-09 13:57:10 -04:00
Adrien Béraud 471d443e4a tests: add multithread test 2021-06-07 14:45:58 -04:00
Adrien Béraud ba9a445263 securedht: clenup 2021-06-07 14:45:58 -04:00
Adrien Béraud 056bc2850b test putEncrypted(pk) 2021-06-07 14:45:58 -04:00
Adrien Béraud b668d6ad68 dhtrunner: add putEncrypted with public key 2021-06-07 14:45:58 -04:00
Adrien Béraud 29fab5560f dhtrunner: add getPublicKey() 2021-06-07 14:45:58 -04:00
Adrien Béraud 8aef63ce4a crypto: cache public key 2021-06-07 14:45:58 -04:00
Adrien Béraud 1ea7a2994e value: use non-const PublicKey 2021-06-07 14:45:58 -04:00
Adrien Béraud 208b3fa6fe SignedValue: add owner 2021-06-07 14:45:58 -04:00
Adrien Béraud d9ff95da49 Revert "dhtrunner: force execution of pending ops on shutdown"
This reverts commit c8a0b443f3.
2021-06-07 14:45:58 -04:00
Adrien Béraud c8a0b443f3 dhtrunner: force execution of pending ops on shutdown 2021-06-03 16:54:31 -04:00
Adrien Béraud 00e595d737 dht: fail if op key is null 2021-06-03 16:54:31 -04:00
46 changed files with 656 additions and 588 deletions

No files matched your search

+1 -4
View File
@@ -13,12 +13,9 @@ jobs:
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libargon2-0-dev
- name: autogen
run: ./autogen.sh
- name: argon2
run: |
cd argon2 && make && sudo make install && cd ..
- name: asio
run: |
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
+4
View File
@@ -19,6 +19,9 @@
*.exe
*.out
*.app
**/dhtnode
**/dhtchat
**/dhtscanner
# Autotools
/ac
@@ -73,3 +76,4 @@ doc/Doxyfile
# build dir
build
.DS_Store
-4
View File
@@ -1,4 +0,0 @@
[submodule "argon2"]
path = argon2
url = https://github.com/P-H-C/phc-winner-argon2
ignore = dirty
+24 -51
View File
@@ -1,4 +1,16 @@
cmake_minimum_required (VERSION 3.1)
cmake_minimum_required (VERSION 3.10)
if(POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
if(POLICY CMP0069)
cmake_policy(SET CMP0069 NEW)
endif()
if(POLICY CMP0073)
cmake_policy(SET CMP0073 NEW)
endif()
if(POLICY CMP0074)
cmake_policy(SET CMP0074 NEW)
endif()
project (opendht)
include(CMakePackageConfigHelpers)
@@ -7,7 +19,7 @@ include(FindPkgConfig)
include(cmake/CheckAtomic.cmake)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 2.0)
set (opendht_VERSION_MINOR 3.5)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -20,7 +32,6 @@ option (OPENDHT_PYTHON "Build Python bindings" OFF)
option (OPENDHT_TOOLS "Build DHT tools" ON)
option (OPENDHT_SYSTEMD "Install systemd module" OFF)
option (OPENDHT_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file")
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
@@ -28,7 +39,6 @@ option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
@@ -46,22 +56,12 @@ if (NOT MSVC)
find_package (Threads)
find_package (PkgConfig REQUIRED)
find_package (GnuTLS 3.3 REQUIRED)
pkg_search_module (Nettle nettle)
find_package (Msgpack 1.2 REQUIRED)
pkg_search_module (Nettle REQUIRED nettle)
find_package (msgpack REQUIRED)
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
if (NOT OPENDHT_ARGON2)
pkg_search_module(argon2 libargon2)
if (argon2_FOUND)
message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")")
link_directories (${argon2_LIBRARY_DIRS})
else ()
message("Argon2 not found, using included version.")
set(OPENDHT_ARGON2 ON)
endif()
endif ()
pkg_search_module(argon2 REQUIRED libargon2)
pkg_search_module(Jsoncpp jsoncpp)
if (Jsoncpp_FOUND)
add_definitions(-DOPENDHT_JSONCPP)
@@ -95,9 +95,6 @@ if (NOT MSVC)
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
endif()
endif()
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
endif()
else ()
set(OPENDHT_PROXY_OPENSSL OFF)
endif ()
@@ -146,7 +143,7 @@ else ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DISABLE_MSC_WARNINGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
@@ -187,6 +184,7 @@ if (Jsoncpp_INCLUDE_DIRS)
endif ()
link_directories (${Nettle_LIBRARY_DIRS})
link_directories (${Jsoncpp_LIBRARY_DIRS})
link_directories (${argon2_LIBRARY_DIRS})
include_directories (
./
include/
@@ -314,23 +312,6 @@ if (OPENDHT_HTTP)
)
endif ()
if(OPENDHT_ARGON2)
# make sure argon2 submodule is up to date and initialized
message("Initializing Argon2 submodule")
execute_process(COMMAND git submodule update --init)
# add local argon2 files to build
list (APPEND opendht_SOURCES
argon2/src/argon2.c
argon2/src/core.c
argon2/src/blake2/blake2b.c
argon2/src/thread.c
argon2/src/ref.c
argon2/src/encoding.c
)
include_directories(argon2/include/)
endif()
if (MSVC)
list (APPEND opendht_HEADERS src/compat/msvc/unistd.h)
endif ()
@@ -343,11 +324,7 @@ if (OPENDHT_STATIC)
${opendht_HEADERS}
)
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht")
if (OPENDHT_ARGON2)
target_include_directories(opendht-static SYSTEM PRIVATE argon2)
else ()
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
target_link_libraries(opendht-static
PRIVATE ${argon2_LIBRARIES}
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES}
@@ -412,25 +389,20 @@ if (OPENDHT_SHARED)
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
if (OPENDHT_ARGON2)
target_include_directories(opendht SYSTEM PRIVATE argon2)
else ()
target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES})
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
if (APPLE)
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES}
SYSTEM "-framework CoreFoundation" "-framework Security")
else ()
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES})
endif ()
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
@@ -456,6 +428,7 @@ if (OPENDHT_C)
)
install (TARGETS opendht-c DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht-c)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendht-c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install (FILES c/opendht_c.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/opendht)
endif ()
if (OPENDHT_TOOLS)
+1 -1
View File
@@ -103,7 +103,7 @@ for r in results:
## Contact
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
IRC: join us on Libera.chat at [`#opendht`](https://web.libera.chat/#opendht).
## License
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
Submodule argon2 deleted from 62358ba212.
-1
View File
@@ -1,2 +1 @@
git submodule update --init
autoreconf --install --verbose -Wall
+12 -2
View File
@@ -97,10 +97,20 @@ const char* dht_value_get_user_type(const dht_value* data) {
return vsp->user_type.c_str();
}
void dht_value_set_user_type(dht_value* data, const char* user_type) {
(*reinterpret_cast<ValueSp*>(data))->user_type = user_type;
}
dht_value* dht_value_new(const uint8_t* data, size_t size) {
return reinterpret_cast<dht_value*>(new ValueSp(std::make_shared<dht::Value>(data, size)));
}
dht_value* dht_value_new_from_string(const char* str) {
ValueSp value = std::make_shared<dht::Value>((const uint8_t*)str, strlen(str));
value->user_type = "text/plain";
return reinterpret_cast<dht_value*>(new ValueSp(std::move(value)));
}
dht_value* dht_value_ref(const dht_value* v) {
return reinterpret_cast<dht_value*>(new ValueSp(*reinterpret_cast<const ValueSp*>(v)));
}
@@ -173,7 +183,7 @@ int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size,
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(key->getPublicKey())));
return reinterpret_cast<dht_publickey*>(new PubkeySp(key->getSharedPublicKey()));
}
void dht_privatekey_delete(dht_privatekey* pk) {
@@ -247,7 +257,7 @@ void dht_runner_config_default(dht_runner_config* config) {
}
// dht::DhtRunner
dht_runner* dht_runner_new() {
dht_runner* dht_runner_new(void) {
return reinterpret_cast<dht_runner*>(new dht::DhtRunner);
}
+3 -1
View File
@@ -82,6 +82,7 @@ struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_new_from_string(const char* str);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data);
@@ -89,6 +90,7 @@ OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data);
OPENDHT_C_PUBLIC dht_publickey* dht_value_get_owner(const dht_value* data);
OPENDHT_C_PUBLIC dht_infohash dht_value_get_recipient(const dht_value* data);
OPENDHT_C_PUBLIC const char* dht_value_get_user_type(const dht_value* data);
OPENDHT_C_PUBLIC void dht_value_set_user_type(dht_value* data, const char* user_type);
// callbacks
typedef bool (*dht_get_cb)(const dht_value* value, void* user_data);
@@ -133,7 +135,7 @@ OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config);
// dht::DhtRunner
struct OPENDHT_C_PUBLIC dht_runner;
typedef struct dht_runner dht_runner;
OPENDHT_C_PUBLIC dht_runner* dht_runner_new();
OPENDHT_C_PUBLIC dht_runner* dht_runner_new(void);
OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner);
OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port);
OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config);
+75 -64
View File
@@ -1,95 +1,106 @@
# University of Illinois/NCSA
# Open Source License
#
# Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
# All rights reserved.
#
# Developed by:
#
# LLVM Team
#
# University of Illinois at Urbana-Champaign
#
# http://llvm.org
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal with
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimers.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimers in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of the LLVM Team, University of Illinois at
# Urbana-Champaign, nor the names of its contributors may be used to
# endorse or promote products derived from this Software without specific
# prior written permission.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
# SOFTWARE.
# atomic builtins are required for threading support.
include(CheckCXXSourceCompiles)
include(CheckLibraryExists)
INCLUDE(CheckCXXSourceCompiles)
INCLUDE(CheckLibraryExists)
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
function(check_working_cxx_atomics varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
get_directory_property(compile_options COMPILE_OPTIONS)
set(CMAKE_REQUIRED_FLAGS ${compile_options})
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
#include <cstdint>
std::atomic<int64_t> v1;
std::atomic<int64_t> v2;
int main(int, char**) {
return v1 + v2;
}" ${varname})
std::atomic<int> x;
int main() {
return x;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_working_cxx_atomics)
function(check_working_cxx_atomics64 varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
#include <cstdint>
std::atomic<uint64_t> x (0);
int main() {
uint64_t i = x.load(std::memory_order_relaxed);
return 0;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_working_cxx_atomics64)
if(NOT DEFINED PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
if(CMAKE_COMPILER_IS_GNUCXX)
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
elseif(MSVC)
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE OFF)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel")
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
endif()
endif()
# This isn't necessary on MSVC, so avoid command-line switch annoyance
# by only running on GCC-like hosts.
if(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
# First check if atomics work without the library.
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
if(HAVE_LIBATOMIC)
if( HAVE_LIBATOMIC )
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
list(APPEND CMAKE_CXX_STANDARD_LIBRARIES -latomic)
else()
message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
endif()
# Check for 64 bit atomic operations.
if(MSVC)
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
else()
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
endif()
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
if(HAVE_CXX_LIBATOMICS64)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
endif()
else()
message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
endif()
endif()
## TODO: This define is only used for the legacy atomic operations in
## llvm's Atomic.h, which should be replaced. Other code simply
## assumes C++11 <atomic> works.
CHECK_CXX_SOURCE_COMPILES("
#ifdef _MSC_VER
#include <windows.h>
#endif
int main() {
#ifdef _MSC_VER
volatile LONG val = 1;
MemoryBarrier();
InterlockedCompareExchange(&val, 0, 1);
InterlockedIncrement(&val);
InterlockedDecrement(&val);
#else
volatile unsigned long val = 1;
__sync_synchronize();
__sync_val_compare_and_swap(&val, 1, 0);
__sync_add_and_fetch(&val, 1);
__sync_sub_and_fetch(&val, 1);
#endif
return 0;
}
" LLVM_HAS_ATOMICS)
if( NOT LLVM_HAS_ATOMICS )
message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing")
endif()
-64
View File
@@ -1,64 +0,0 @@
# - Try to find msgpack
# Once done this will define
# MSGPACK_FOUND - System has msgpack
# MSGPACK_INCLUDE_DIRS - The msgpack include directories
# MSGPACK_LIBRARIES - The libraries needed to use msgpack
if(NOT MSGPACK_USE_BUNDLED)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_search_module(PC_MSGPACK QUIET
msgpackc>=${Msgpack_FIND_VERSION}
msgpack>=${Msgpack_FIND_VERSION})
endif()
else()
set(PC_MSGPACK_INCLUDEDIR)
set(PC_MSGPACK_INCLUDE_DIRS)
set(PC_MSGPACK_LIBDIR)
set(PC_MSGPACK_LIBRARY_DIRS)
set(LIMIT_SEARCH NO_DEFAULT_PATH)
endif()
set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER})
find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h
HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS}
${LIMIT_SEARCH})
if(MSGPACK_INCLUDE_DIR)
file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h)
string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}")
string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}")
string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}")
set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}")
else()
set(MSGPACK_VERSION_STRING)
endif()
# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name.
if(MSGPACK_USE_STATIC)
list(APPEND MSGPACK_NAMES
"${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}"
"${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
list(APPEND MSGPACK_NAMES msgpackc msgpack)
find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES}
# Check each directory for all names to avoid using headers/libraries from
# different places.
NAMES_PER_DIR
HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS}
${LIMIT_SEARCH})
mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY)
set(MSGPACK_LIBRARIES ${MSGPACK_LIBRARY})
set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set MSGPACK_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(Msgpack
REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR
VERSION_VAR MSGPACK_VERSION_STRING)
+5 -32
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 2)
m4_define([opendht_patch_version], 0)
m4_define([opendht_minor_version], 3)
m4_define([opendht_patch_version], 5)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -132,6 +132,8 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
PKG_CHECK_MODULES([Argon2], [libargon2])
AC_SUBST(argon2_lib, [", libargon2"])
AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support]))
AS_IF([test "x$with_jsoncpp" != "xno"],
@@ -157,14 +159,6 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_MSG_NOTICE([Not using OpenSSL])
])
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
@@ -181,28 +175,7 @@ AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AS_IF([test "x$http_parser_headers" != "xyes"], AC_MSG_ERROR([Missing HttpParser headers files]))
])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
dnl Check for Argon2
AC_ARG_WITH([argon2], AS_HELP_STRING([--without-argon2], [Use included Argon2]))
AS_IF([test "x$with_argon2" != "xno"],
[PKG_CHECK_MODULES([Argon2], [libargon2], [have_argon2=yes], [have_argon2=no])],
[have_argon2=no])
AS_IF([test "x$have_argon2" = "xyes"], [
AC_MSG_NOTICE([Using system Argon2])
AC_SUBST(argon2_lib, [", libargon2"])
], [
AS_IF([test "x$with_argon2" = "xyes"], [
AC_MSG_ERROR([Argon2 requested but not found])
],[
AC_MSG_NOTICE([Using included Argon2])
AC_SUBST(Argon2_CFLAGS, "-I\${top_srcdir}/argon2/src -I\${top_srcdir}/argon2/include")
AC_SUBST(Argon2_LIBS, "libargon2.la")
AC_SUBST(Argon2_LDFLAGS, "-L\${abs_top_srcdir}/argon2/src/.libs")
])
])
AM_CONDITIONAL([WITH_INCLUDED_ARGON2], [test "x$have_argon2" = "xno"])
CXXFLAGS="${CXXFLAGS} -DMSGPACK_NO_BOOST -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes)
AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes)
+14 -4
View File
@@ -164,7 +164,9 @@ struct OPENDHT_PUBLIC PrivateKey
~PrivateKey();
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
const PublicKey& getPublicKey() const;
const std::shared_ptr<PublicKey>& getSharedPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
@@ -199,7 +201,7 @@ private:
PrivateKey& operator=(const PrivateKey&) = delete;
Blob decryptBloc(const uint8_t* src, size_t src_size) const;
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
mutable std::shared_ptr<PublicKey> publicKey_ {};
};
class OPENDHT_PUBLIC RevocationList
@@ -539,8 +541,8 @@ struct OPENDHT_PUBLIC Certificate {
void addRevocationList(RevocationList&&);
void addRevocationList(std::shared_ptr<RevocationList>);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
static Certificate generate(const CertificateRequest& request, const Identity& ca);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false, int64_t validity = 0);
static Certificate generate(const CertificateRequest& request, const Identity& ca, int64_t validity = 0);
gnutls_x509_crt_t getCopy() const {
if (not cert)
@@ -590,12 +592,20 @@ struct OPENDHT_PUBLIC Certificate {
*/
std::pair<std::string, Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
/**
* Change certificate's expiration
*/
void setValidity(const Identity& ca, int64_t validity);
void setValidity(const PrivateKey& key, int64_t validity);
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
std::shared_ptr<OcspResponse> ocspResponse;
private:
Certificate(const Certificate&) = delete;
Certificate& operator=(const Certificate&) = delete;
mutable InfoHash cachedId_ {};
mutable PkId cachedLongId_ {};
struct crlNumberCmp {
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
+4 -1
View File
@@ -66,8 +66,10 @@ private:
public:
virtual void unpackValue(const Value& v) override {
if (v.owner)
if (v.owner) {
owner = v.owner;
from = v.owner->getId();
}
BaseClass::unpackValue(v);
}
@@ -75,6 +77,7 @@ public:
return [](const Value& v){ return v.isSigned(); };
}
Sp<crypto::PublicKey> owner;
dht::InfoHash from;
};
+9 -4
View File
@@ -114,7 +114,7 @@ public:
void addBootstrap(const std::string& host, const std::string& service) override {
bootstrap_nodes.emplace_back(host, service);
onDisconnected();
startBootstrap();
}
void clearBootstrap() override {
@@ -356,6 +356,8 @@ private:
static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
static constexpr size_t TOKEN_SIZE {32};
// internal structures
@@ -393,7 +395,7 @@ private:
Kad dht6 {};
std::vector<std::pair<std::string,std::string>> bootstrap_nodes {};
std::chrono::steady_clock::duration bootstrap_period {std::chrono::seconds(10)};
std::chrono::steady_clock::duration bootstrap_period {BOOTSTRAP_PERIOD};
Sp<Scheduler::Job> bootstrapJob {};
std::map<InfoHash, Storage> store;
@@ -480,6 +482,9 @@ private:
void sendCachedPing(Bucket& b);
bool bucketMaintenance(RoutingTable&);
void dumpBucket(const Bucket& b, std::ostream& out) const;
void bootstrap();
void startBootstrap();
void stopBootstrap();
// Nodes
void onNewNode(const Sp<Node>& node, int confirm);
@@ -487,7 +492,6 @@ private:
bool trySearchInsert(const Sp<Node>& node);
// Searches
inline SearchMap& searches(sa_family_t af) { return dht(af).searches; }
inline const SearchMap& searches(sa_family_t af) const { return dht(af).searches; }
@@ -569,7 +573,8 @@ private:
*
* @param sr The search to execute its operations.
*/
void searchStep(Sp<Search>);
void searchStep(std::weak_ptr<Search> ws);
void searchSynchedNodeListen(const Sp<Search>&, SearchNode&);
void dumpSearch(const Search& sr, std::ostream& out) const;
+1
View File
@@ -337,6 +337,7 @@ private:
NodeStats stats6_ {};
SockAddr publicAddressV4_;
SockAddr publicAddressV6_;
std::atomic_bool launchConnectedCbs_ {false};
InfoHash myid {};
+12 -2
View File
@@ -257,6 +257,17 @@ public:
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
}
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
@@ -303,6 +314,7 @@ public:
* Get the public key fingerprint if an identity is used with this node, 0 otherwise.
*/
InfoHash getId() const;
std::shared_ptr<crypto::PublicKey> getPublicKey() const;
/**
* Get the ID of the DHT node.
@@ -444,8 +456,6 @@ public:
void forwardAllMessages(bool forward);
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
enum class State {
Idle,
Running,
-12
View File
@@ -375,15 +375,3 @@ private:
} // namespace http
} // namespace dht
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
namespace restinio
{
/* Custom HTTP-methods for RESTinio > 0.5.0.
* https://github.com/Stiffstream/restinio/issues/26
*/
constexpr const restinio::http_method_id_t method_listen {HTTP_LISTEN, "LISTEN"};
constexpr const restinio::http_method_id_t method_stats {HTTP_STATS, "STATS"};
constexpr const restinio::http_method_id_t method_sign {HTTP_SIGN, "SIGN"};
constexpr const restinio::http_method_id_t method_encrypt {HTTP_ENCRYPT, "ENCRYPT"};
} // namespace restinio
#endif
+3 -2
View File
@@ -44,6 +44,7 @@ typedef uint16_t in_port_t;
#include <stdexcept>
#include <sstream>
#include <cstring>
#include <cstddef>
namespace dht {
@@ -342,7 +343,7 @@ Hash<N>::getRandom(Rd& rdev)
return h;
}
struct HexMap : public std::array<std::array<char, 2>, 256> {
struct alignas(std::max_align_t) HexMap : public std::array<std::array<char, 2>, 256> {
HexMap() {
for (size_t i=0; i<size(); i++) {
auto& e = (*this)[i];
@@ -376,7 +377,7 @@ template <size_t N>
const char*
Hash<N>::to_c_str() const
{
thread_local std::array<char, N*2+1> buf;
alignas(std::max_align_t) thread_local std::array<char, N*2+1> buf;
for (size_t i=0; i<N; i++) {
auto b = buf.data()+i*2;
const auto& m = hex_map[data_[i]];
+19 -10
View File
@@ -36,8 +36,9 @@ namespace dht {
class Scheduler {
public:
struct Job {
Job(std::function<void()>&& f) : do_(std::move(f)) {}
Job(std::function<void()>&& f, time_point t) : do_(std::move(f)), t_(t) {}
std::function<void()> do_;
const time_point t_;
void cancel() { do_ = {}; }
};
@@ -50,17 +51,12 @@ public:
* @return pointer to the newly scheduled job.
*/
Sp<Scheduler::Job> add(time_point t, std::function<void()>&& job_func) {
auto job = std::make_shared<Job>(std::move(job_func));
auto job = std::make_shared<Job>(std::move(job_func), t);
if (t != time_point::max())
timers.emplace(std::move(t), job);
return job;
}
void add(const Sp<Scheduler::Job>& job, time_point t) {
if (t != time_point::max())
timers.emplace(std::move(t), job);
}
/**
* Reschedules a job.
*
@@ -68,16 +64,29 @@ public:
* @param t The time at which the job shall be rescheduled.
*/
void edit(Sp<Scheduler::Job>& job, time_point t) {
if (not job) {
if (not job)
return;
}
// std::function move doesn't garantee to leave the object empty.
// Force clearing old value.
auto task = std::move(job->do_);
job->do_ = {};
cancel(job);
job = add(t, std::move(task));
}
bool cancel(Sp<Scheduler::Job>& job) {
if (job) {
job->cancel();
for (auto r = timers.equal_range(job->t_); r.first != r.second; ++r.first) {
if (r.first->second == job) {
timers.erase(r.first);
job.reset();
return true;
}
}
}
return false;
}
/**
* Runs the jobs to do up to now.
*
+12 -5
View File
@@ -61,6 +61,9 @@ public:
PkId getLongId() const {
return key_ ? key_->getPublicKey().getLongId() : PkId();
}
Sp<crypto::PublicKey> getPublicKey() const {
return key_ ? key_->getSharedPublicKey() : Sp<crypto::PublicKey>{};
}
ValueType secureType(ValueType&& type);
@@ -115,6 +118,10 @@ public:
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
/**
* Take ownership of the value and sign it using our private key.
@@ -126,13 +133,13 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb);
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
const Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
const Sp<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
Sp<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
/**
* Allows to set a custom callback called by the library to find a locally-stored certificate.
@@ -354,7 +361,7 @@ private:
// our certificate cache
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
std::map<InfoHash, Sp<crypto::PublicKey>> nodesPubKeys_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
+6 -5
View File
@@ -27,6 +27,8 @@
#include <future>
#include <functional>
#include <ciso646> // fix windows compiler bug
namespace dht {
class OPENDHT_PUBLIC ThreadPool {
@@ -63,15 +65,14 @@ public:
void join();
private:
struct ThreadState;
std::queue<std::function<void()>> tasks_ {};
std::vector<std::unique_ptr<ThreadState>> threads_;
unsigned readyThreads_ {0};
std::mutex lock_ {};
std::condition_variable cv_ {};
std::queue<std::function<void()>> tasks_ {};
std::vector<std::unique_ptr<std::thread>> threads_;
unsigned readyThreads_ {0};
bool running_ {true};
const unsigned maxThreads_;
bool running_ {true};
};
class OPENDHT_PUBLIC Executor : public std::enable_shared_from_this<Executor> {
+5 -5
View File
@@ -117,7 +117,7 @@ struct OPENDHT_PUBLIC ValueType {
Id id {0};
std::string name {};
duration expiration {60 * 10};
duration expiration {std::chrono::minutes(10)};
StorePolicy storePolicy {DEFAULT_STORE_POLICY};
EditPolicy editPolicy {DEFAULT_EDIT_POLICY};
};
@@ -356,7 +356,7 @@ struct OPENDHT_PUBLIC Value
void sign(const crypto::PrivateKey& key) {
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
owner = key.getSharedPublicKey();
signature = key.sign(getToSign());
}
@@ -368,8 +368,8 @@ struct OPENDHT_PUBLIC Value
return isSigned() and owner->checkSignature(getToSign(), signature);
}
std::shared_ptr<const crypto::PublicKey> getOwner() const {
return std::static_pointer_cast<const crypto::PublicKey>(owner);
std::shared_ptr<crypto::PublicKey> getOwner() const {
return std::static_pointer_cast<crypto::PublicKey>(owner);
}
/**
@@ -594,7 +594,7 @@ struct OPENDHT_PUBLIC Value
/**
* Public key of the signer.
*/
std::shared_ptr<const crypto::PublicKey> owner {};
std::shared_ptr<crypto::PublicKey> owner {};
/**
* Hash of the recipient (optional).
+6 -6
View File
@@ -329,11 +329,11 @@ cdef class PrivateKey(_WithID):
cdef shared_ptr[cpp.PrivateKey] _key
def getId(self):
h = InfoHash()
h._infohash = self._key.get().getPublicKey().getId()
h._infohash = self._key.get().getSharedPublicKey().get().getId()
return h
def getPublicKey(self):
pk = PublicKey()
pk._key = self._key.get().getPublicKey()
pk._key = self._key.get().getSharedPublicKey()
return pk
def decrypt(self, bytes dat):
cdef size_t d_len = len(dat)
@@ -358,17 +358,17 @@ cdef class PrivateKey(_WithID):
return k
cdef class PublicKey(_WithID):
cdef cpp.PublicKey _key
cdef cpp.shared_ptr[cpp.PublicKey] _key
def getId(self):
h = InfoHash()
h._infohash = self._key.getId()
h._infohash = self._key.get().getId()
return h
def encrypt(self, bytes dat):
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob encrypted = self._key.encrypt(indat)
cdef cpp.Blob encrypted = self._key.get().encrypt(indat)
cdef char* encrypted_c_str = <char *>encrypted.data()
cdef Py_ssize_t length = encrypted.size()
return encrypted_c_str[:length]
@@ -440,7 +440,7 @@ cdef class Identity(object):
property publickey:
def __get__(self):
k = PublicKey()
k._key = self._id.first.get().getPublicKey()
k._key = self._id.first.get().getSharedPublicKey()
return k
property certificate:
def __get__(self):
+1 -1
View File
@@ -97,7 +97,7 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto":
cdef cppclass PrivateKey:
PrivateKey()
PublicKey getPublicKey() const
shared_ptr[PublicKey] getSharedPublicKey() const
Blob decrypt(Blob data) const
@staticmethod
PrivateKey generate()
+1 -28
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@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_LDFLAGS = @LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -87,30 +87,3 @@ endif
clean-local:
rm -rf libargon2.la
######################
# ARGON2 submodule #
######################
if WITH_INCLUDED_ARGON2
noinst_LTLIBRARIES = libargon2.la
libopendht_la_DEPENDENCIES = libargon2.la
libargon2_la_CFLAGS = -std=c89 -fPIC -pthread -O3 -Wall -I@top_builddir@/argon2/include -I@top_builddir@/argon2/src
libargon2_la_SOURCES = \
@top_builddir@/argon2/src/argon2.c \
@top_builddir@/argon2/src/core.c \
@top_builddir@/argon2/src/blake2/blake2b.c \
@top_builddir@/argon2/src/thread.c \
@top_builddir@/argon2/src/ref.c \
@top_builddir@/argon2/src/encoding.c
noinst_HEADERS = \
@top_builddir@/argon2/include/argon2.h \
@top_builddir@/argon2/src/blake2/blake2.h \
@top_builddir@/argon2/src/blake2/blake2-impl.h \
@top_builddir@/argon2/src/blake2/blamka-round-ref.h \
@top_builddir@/argon2/src/core.h \
@top_builddir@/argon2/src/encoding.h \
@top_builddir@/argon2/src/thread.h
endif
+52 -16
View File
@@ -69,7 +69,7 @@ constexpr gnutls_digest_algorithm_t gnutlsHashAlgo(size_t min_res) {
GNUTLS_DIG_SHA1));
}
constexpr size_t gnutlsHashSize(int algo) {
constexpr size_t gnutlsHashSize(gnutls_digest_algorithm_t algo) {
return (algo == GNUTLS_DIG_SHA512) ? 512/8 : (
(algo == GNUTLS_DIG_SHA256) ? 256/8 : (
(algo == GNUTLS_DIG_SHA1) ? 160/8 : 0 ));
@@ -368,13 +368,22 @@ PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len);
}
PublicKey
const PublicKey&
PrivateKey::getPublicKey() const
{
PublicKey pk;
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
return *getSharedPublicKey();
}
const std::shared_ptr<PublicKey>&
PrivateKey::getSharedPublicKey() const
{
if (publicKey_)
return publicKey_;
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
return pk;
publicKey_ = pk;
return publicKey_;
}
PublicKey::PublicKey()
@@ -540,12 +549,7 @@ PublicKey::getId() const
return {};
InfoHash id;
size_t sz = id.size();
#if GNUTLS_VERSION_NUMBER < 0x030401
const int flags = 0;
#else
const int flags = (id.size() == 32) ? GNUTLS_KEYID_USE_SHA256 : 0;
#endif
if (auto err = gnutls_pubkey_get_key_id(pk, flags, id.data(), &sz))
if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get public key ID: wrong output length.");
@@ -849,12 +853,15 @@ Certificate::getId() const
{
if (not cert)
return {};
if (cachedId_)
return cachedId_;
InfoHash id;
size_t sz = id.size();
if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate public key ID: wrong output length.");
cachedId_ = id;
return id;
}
@@ -863,6 +870,8 @@ Certificate::getLongId() const
{
if (not cert)
return {};
if (cachedLongId_)
return cachedLongId_;
#if GNUTLS_VERSION_NUMBER < 0x030401
throw CryptoException("Can't get certificate 256 bits public key ID: GnuTLS 3.4.1 or higher required.");
#else
@@ -872,6 +881,7 @@ Certificate::getLongId() const
throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length.");
cachedLongId_ = id;
return id;
#endif
}
@@ -1153,14 +1163,14 @@ setRandomSerial(gnutls_x509_crt_t cert)
}
Certificate
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca, int64_t validity)
{
gnutls_x509_crt_t cert;
if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
return {};
Certificate ret {cert};
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity);
if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) {
throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err));
}
@@ -1169,7 +1179,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
}
// TODO: compute the subject key using the recommended RFC method
auto pk = key.getPublicKey();
const auto& pk = key.getPublicKey();
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
@@ -1206,7 +1216,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
}
Certificate
Certificate::generate(const CertificateRequest& request, const Identity& ca)
Certificate::generate(const CertificateRequest& request, const Identity& ca, int64_t validity)
{
gnutls_x509_crt_t cert;
if (auto err = gnutls_x509_crt_init(&cert))
@@ -1219,7 +1229,7 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca)
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
}
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity);
setRandomSerial(cert);
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
@@ -1230,6 +1240,32 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca)
return ret.getPacked();
}
void
Certificate::setValidity(const Identity& ca, int64_t validity)
{
setValidityPeriod(cert, validity);
setRandomSerial(cert);
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
throw CryptoException("Signing certificate must be CA");
}
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
}
void
Certificate::setValidity(const PrivateKey& key, int64_t validity)
{
setValidityPeriod(cert, validity);
setRandomSerial(cert);
const auto& pk = key.getPublicKey();
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
std::vector<std::shared_ptr<RevocationList>>
Certificate::getRevocationLists() const
{
+86 -40
View File
@@ -30,16 +30,20 @@
#include <sstream>
#include <fstream>
#include <inttypes.h>
namespace dht {
using namespace std::placeholders;
constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME;
constexpr std::chrono::seconds Dht::BOOTSTRAP_PERIOD;
constexpr duration Dht::LISTEN_EXPIRE_TIME;
constexpr duration Dht::LISTEN_EXPIRE_TIME_PUBLIC;
constexpr duration Dht::REANNOUNCE_MARGIN;
static constexpr size_t MAX_REQUESTS_PER_SEC {8 * 1024};
static constexpr duration BOOTSTRAP_PERIOD_MAX {std::chrono::hours(24)};
NodeStatus
Dht::updateStatus(sa_family_t af)
@@ -49,9 +53,9 @@ Dht::updateStatus(sa_family_t af)
d.status = d.getStatus(scheduler.time());
if (d.status != old) {
auto& other = dht(af == AF_INET ? AF_INET6 : AF_INET);
if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected)
if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected) {
onDisconnected();
else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) {
} else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) {
onConnected();
}
}
@@ -284,7 +288,7 @@ Dht::searchNodeGetDone(const net::Request& req,
if (srn->syncJob)
scheduler.edit(srn->syncJob, syncTime);
else
srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, sr));
srn->syncJob = scheduler.add(syncTime, std::bind(&Dht::searchStep, this, ws));
}
onGetValuesDone(req.node, answer, sr, query);
}
@@ -486,21 +490,23 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
} catch (std::out_of_range&) { }
auto next_refresh_time = now + getType(a.value->type).expiration;
auto& acked = sn->acked[a.value->id];
scheduler.cancel(acked.refresh);
/* only put the value if the node doesn't already have it */
if (not hasValue or seq_no < a.value->seq) {
if (logger_)
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto created = a.permanent ? time_point::max() : a.created;
sn->acked[a.value->id] = {
acked = {
network_engine.sendAnnounceValue(sn->node, sr->id, a.value, created, sn->token, onDone, onExpired),
next_refresh_time
};
} else if (hasValue and a.permanent) {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %d)",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
sn->acked[a.value->id] = {
acked = {
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
[this, ws, node=sn->node, v=a.value,
onDone,
@@ -528,21 +534,17 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
};
} else {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %d). Aborting.",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %016" PRIx64 "). Aborting.",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto ack_req = std::make_shared<net::Request>(net::Request::State::COMPLETED);
ack_req->reply_time = now;
sn->acked[a.value->id] = std::make_pair(std::move(ack_req), next_refresh_time);
acked = {std::move(ack_req), next_refresh_time};
/* step to clear announces */
scheduler.edit(sr->nextSearchStep, now);
}
if (a.permanent) {
scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, [this,ws] {
if (auto sr = ws.lock()) {
searchStep(sr);
}
});
acked.refresh = scheduler.add(next_refresh_time - REANNOUNCE_MARGIN, std::bind(&Dht::searchStep, this, ws));
}
}
};
@@ -567,7 +569,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
sendQuery = true;
} else {
if (logger_)
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), n.node->toString().c_str(), a.value->id);
n.acked[a.value->id] = {
network_engine.sendAnnounceValue(n.node, sr->id, a.value, a.created, n.token, onDone, onExpired),
@@ -640,8 +642,8 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
if (auto sr = ws.lock()) {
scheduler.edit(sr->nextSearchStep, scheduler.time());
if (auto sn = sr->getNode(req.node)) {
scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, sr));
sn->onListenSynced(query);
auto job = scheduler.add(sn->getListenTime(query, getListenExpiration()), std::bind(&Dht::searchStep, this, ws));
sn->onListenSynced(query, true, std::move(job));
}
onListenDone(req.node, answer, sr);
}
@@ -667,8 +669,9 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
/* When a search is in progress, we periodically call search_step to send
further requests. */
void
Dht::searchStep(Sp<Search> sr)
Dht::searchStep(std::weak_ptr<Search> ws)
{
auto sr = ws.lock();
if (not sr or sr->expired or sr->done) return;
const auto& now = scheduler.time();
@@ -821,7 +824,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
sr->expired = false;
sr->nodes.clear();
sr->nodes.reserve(SEARCH_NODES+1);
sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, sr));
sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr<Search>(sr)));
if (logger_)
logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (search_id == 0)
@@ -873,6 +876,11 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
size_t
Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
{
if (not id) {
if (logger_)
logger_->w(id, "Listen called with invalid key");
return 0;
}
scheduler.syncTime();
auto token = ++listener_token;
@@ -955,7 +963,9 @@ struct GetStatus : public OpStatus {
void
Dht::put(const InfoHash& id, Sp<Value> val, DoneCallback callback, time_point created, bool permanent)
{
if (not val) {
if (not id or not val) {
if (logger_)
logger_->w(id, "Put called with invalid key or value");
if (callback)
callback(false, {});
return;
@@ -1025,6 +1035,13 @@ bool callbackWrapper(Cb get_cb, DoneCallback done_cb, const std::vector<Sp<T>>&
void
Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filter&& filter, Where&& where)
{
if (not id) {
if (logger_)
logger_->w(id, "Get called with invalid key");
if (donecb)
donecb(false, {});
return;
}
scheduler.syncTime();
auto op = std::make_shared<GetStatus<std::map<Value::Id, Sp<Value>>>>();
@@ -1065,6 +1082,13 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt
void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Query&& q)
{
if (not id) {
if (logger_)
logger_->w(id, "Query called with invalid key");
if (done_cb)
done_cb(false, {});
return;
}
scheduler.syncTime();
auto op = std::make_shared<GetStatus<std::vector<Sp<FieldValueIndex>>>>();
auto f = q.where.getFilter();
@@ -1253,8 +1277,9 @@ Dht::storageStore(const InfoHash& id, const Sp<Value>& value, time_point created
if (auto vs = store.first) {
total_store_size += store.second.size_diff;
total_values += store.second.values_diff;
scheduler.cancel(vs->expiration_job);
if (not permanent) {
scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id));
vs->expiration_job = scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id));
}
if (total_store_size > max_store_size) {
expireStore();
@@ -1414,6 +1439,7 @@ Dht::connectivityChanged(sa_family_t af)
reported_addr.erase(std::remove_if(reported_addr.begin(), reported_addr.end(), [&](const ReportedAddr& addr){
return addr.second.getFamily() == af;
}), reported_addr.end());
startBootstrap(); // will only happen if disconnected
}
void
@@ -1595,10 +1621,10 @@ Dht::dumpSearch(const Search& sr, std::ostream& out) const
out << "[";
for (const auto& a : sr.announce) {
auto ack = n.acked.find(a.value->id);
if (ack == n.acked.end() or not ack->second.first) {
if (ack == n.acked.end() or not ack->second.req) {
out << ' ';
} else {
out << ack->second.first->getStateChar();
out << ack->second.req->getStateChar();
}
}
out << "] ";
@@ -1995,11 +2021,7 @@ Dht::expire()
void
Dht::onConnected()
{
if (bootstrapJob) {
bootstrapJob->cancel();
bootstrapJob.reset();
}
bootstrap_period = std::chrono::seconds(10);
stopBootstrap();
auto callbacks = std::move(onConnectCallbacks_);
while (not callbacks.empty()) {
callbacks.front()();
@@ -2009,6 +2031,13 @@ Dht::onConnected()
void
Dht::onDisconnected()
{
if (not bootstrapJob)
bootstrap();
}
void
Dht::bootstrap()
{
if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected)
return;
@@ -2027,10 +2056,23 @@ Dht::onDisconnected()
logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
}
}
if (bootstrapJob)
bootstrapJob->cancel();
bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::onDisconnected, this));
bootstrap_period *= 2;
scheduler.cancel(bootstrapJob);
bootstrapJob = scheduler.add(scheduler.time() + bootstrap_period, std::bind(&Dht::bootstrap, this));
bootstrap_period = std::min(bootstrap_period * 2, BOOTSTRAP_PERIOD_MAX);
}
void
Dht::startBootstrap()
{
stopBootstrap();
bootstrapJob = scheduler.add(scheduler.time(), std::bind(&Dht::bootstrap, this));
}
void
Dht::stopBootstrap()
{
scheduler.cancel(bootstrapJob);
bootstrap_period = BOOTSTRAP_PERIOD;
}
void
@@ -2147,25 +2189,25 @@ Dht::exportNodes() const
if (b4 != dht4.buckets.end()) {
for (auto& n : b4->nodes)
if (n->isGood(now))
nodes.push_back(n->exportNode());
nodes.emplace_back(n->exportNode());
}
const auto b6 = dht6.buckets.findBucket(myid);
if (b6 != dht6.buckets.end()) {
for (auto& n : b6->nodes)
if (n->isGood(now))
nodes.push_back(n->exportNode());
nodes.emplace_back(n->exportNode());
}
for (auto b = dht4.buckets.begin(); b != dht4.buckets.end(); ++b) {
if (b == b4) continue;
for (auto& n : b->nodes)
if (n->isGood(now))
nodes.push_back(n->exportNode());
nodes.emplace_back(n->exportNode());
}
for (auto b = dht6.buckets.begin(); b != dht6.buckets.end(); ++b) {
if (b == b6) continue;
for (auto& n : b->nodes)
if (n->isGood(now))
nodes.push_back(n->exportNode());
nodes.emplace_back(n->exportNode());
}
return nodes;
}
@@ -2438,7 +2480,7 @@ Dht::onAnnounce(Sp<Node> n,
if (*lv == *vc) {
storageRefresh(hash, v->id);
if (logger_)
logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %s", hash.toString().c_str(), node.toString().c_str(), std::to_string(v->id).c_str());
logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
} else {
const auto& type = getType(lv->type);
if (type.editPolicy(hash, lv, vc, node.id, node.getAddr())) {
@@ -2481,7 +2523,7 @@ Dht::onRefresh(Sp<Node> node, const InfoHash& hash, const Blob& token, const Val
}
if (storageRefresh(hash, vid)) {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %s", hash.toString().c_str(), node->toString().c_str(), std::to_string(vid).c_str());
logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
} else {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] got refresh for unknown value",
@@ -2517,8 +2559,12 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
}
auto expiration = s->second.refresh(now, vid, types);
if (expiration != time_point::max())
scheduler.add(expiration, std::bind(&Dht::expireStorage, this, id));
if (expiration.first) {
scheduler.cancel(expiration.first->expiration_job);
if (expiration.second != time_point::max()) {
expiration.first->expiration_job = scheduler.add(expiration.second, std::bind(&Dht::expireStorage, this, id));
}
}
return true;
}
return false;
+6 -16
View File
@@ -720,7 +720,8 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
}
auto newStatus = std::max(statusIpv4_, statusIpv6_);
if (newStatus == NodeStatus::Connected) {
if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting) {
if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting || launchConnectedCbs_) {
launchConnectedCbs_ = false;
listenerRestartTimer_->expires_at(std::chrono::steady_clock::now());
listenerRestartTimer_->async_wait(std::bind(&DhtProxyClient::restartListeners, this, std::placeholders::_1));
if (not onConnectCallbacks_.empty()) {
@@ -829,13 +830,8 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
restinio::http_request_header_t header;
if (deviceKey_.empty()){ // listen
method = ListenMethod::LISTEN;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
header.method(restinio::method_listen);
header.request_target("/" + key.toString());
#else
header.method(restinio::http_method_get());
header.request_target("/key/" + key.toString() + "/listen");
#endif
}
else {
method = ListenMethod::SUBSCRIBE;
@@ -1151,13 +1147,8 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
auto cb = listener.cb;
// define header
restinio::http_request_header_t header;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
header.method(restinio::method_listen);
header.request_target("/" + search.first.toString());
#else
header.method(restinio::http_method_get());
header.request_target("/key/" + search.first.toString() + "/listen");
#endif
sendListen(header, cb, opstate, listener, ListenMethod::LISTEN);
}
}
@@ -1170,6 +1161,9 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
{
// If a push notification is received, the proxy is up and running
std::lock_guard<std::mutex> l(lockCurrentProxyInfos_);
auto oldStatus = std::max(statusIpv4_, statusIpv6_);
if (oldStatus != NodeStatus::Connected)
launchConnectedCbs_ = true;
statusIpv4_ = NodeStatus::Connected;
statusIpv6_ = NodeStatus::Connected;
}
@@ -1275,11 +1269,7 @@ DhtProxyClient::resubscribe(const InfoHash& key, const size_t token, Listener& l
logger_->d("[proxy:client] [resubscribe] [search %s]", key.to_c_str());
auto opstate = listener.opstate;
opstate->stop = true;
if (listener.request){
listener.request.reset();
}
opstate->stop = false;
listener.request.reset(); // This will update ok to false
opstate->ok = true;
restinio::http_request_header_t header;
+7 -45
View File
@@ -39,26 +39,6 @@
using namespace std::placeholders;
using namespace std::chrono_literals;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
namespace restinio {
struct custom_http_methods_t
{
static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept {
if(m == method_listen.raw_id())
return method_listen;
else if(m == method_stats.raw_id())
return method_stats;
else if(m == method_sign.raw_id())
return method_sign;
else if(m == method_encrypt.raw_id())
return method_encrypt;
else
return restinio::default_http_methods_t::from_nodejs(m);
}
};
}
#endif
namespace dht {
constexpr char RESP_MSG_JSON_INCORRECT[] = "{\"err:\":\"Incorrect JSON\"}";
constexpr char RESP_MSG_SERVICE_UNAVAILABLE[] = "{\"err\":\"Incorrect DhtRunner\"}";
@@ -156,9 +136,6 @@ DhtProxyServer::onConnectionClosed(restinio::connection_id_t id)
struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits_t
{
using timer_manager_t = restinio::asio_timer_manager_t;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
using http_methods_mapper_t = restinio::custom_http_methods_t;
#endif
using logger_t = opendht_logger_t;
using request_handler_t = RestRouter;
using connection_state_listener_t = ConnectionListener;
@@ -166,9 +143,6 @@ struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits
struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t
{
using timer_manager_t = restinio::asio_timer_manager_t;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
using http_methods_mapper_t = restinio::custom_http_methods_t;
#endif
using logger_t = opendht_logger_t;
using request_handler_t = RestRouter;
using connection_state_listener_t = ConnectionListener;
@@ -613,11 +587,6 @@ DhtProxyServer::createRestRouter()
// **************************** LEGACY ROUTES ****************************
// node.info
router->http_get("/", std::bind(&DhtProxyServer::getNodeInfo, this, _1, _2));
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// node.stats
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_stats.raw_id()),
"/", std::bind(&DhtProxyServer::getStats, this, _1, _2));
#endif
// key.options
router->add_handler(restinio::http_method_options(),
"/:hash", std::bind(&DhtProxyServer::options, this, _1, _2));
@@ -625,11 +594,6 @@ DhtProxyServer::createRestRouter()
router->http_get("/:hash", std::bind(&DhtProxyServer::get, this, _1, _2));
// key.post
router->http_post("/:hash", std::bind(&DhtProxyServer::put, this, _1, _2));
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// key.listen
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_listen.raw_id()),
"/:hash", std::bind(&DhtProxyServer::listen, this, _1, _2));
#endif
#ifdef OPENDHT_PUSH_NOTIFICATIONS
// key.subscribe
router->add_handler(restinio::http_method_subscribe(),
@@ -639,14 +603,6 @@ DhtProxyServer::createRestRouter()
"/:hash", std::bind(&DhtProxyServer::unsubscribe, this, _1, _2));
#endif //OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// key.sign
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_sign.raw_id()),
"/:hash", std::bind(&DhtProxyServer::putSigned, this, _1, _2));
// key.encrypt
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_encrypt.raw_id()),
"/:hash", std::bind(&DhtProxyServer::putEncrypted, this, _1, _2));
#endif
#endif // OPENDHT_PROXY_SERVER_IDENTITY
// **************************** NEW ROUTES ****************************
@@ -1048,7 +1004,13 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
notification["platform"] = type == PushType::Android ? 2 : 1;
notification["data"] = std::move(json);
notification["priority"] = highPriority ? "high" : "normal";
notification["time_to_live"] = 600;
if (type == PushType::Android)
notification["time_to_live"] = 3600 * 24; // 24 hours
else {
const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24);
uint32_t exp = std::chrono::duration_cast<std::chrono::seconds>(expiration.time_since_epoch()).count();
notification["expiration"] = exp;
}
Json::Value notifications(Json::arrayValue);
notifications[0] = notification;
+112 -65
View File
@@ -36,7 +36,6 @@
namespace dht {
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
struct DhtRunner::Listener {
@@ -106,81 +105,96 @@ DhtRunner::run(const Config& config, Context&& context)
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running)) {
if (context.logger)
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.");
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.", this);
return;
}
auto local4 = config.bind4;
auto local6 = config.bind6;
if (not local4 and not local6) {
if (context.logger)
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses");
local4.setFamily(AF_INET);
local6.setFamily(AF_INET6);
}
auto state_path = config.dht_config.node_config.persist_path;
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
state_path += "_port.txt";
std::ifstream inConfig(state_path);
if (inConfig.is_open()) {
in_port_t port;
if (inConfig >> port) {
if (local4.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port);
local4.setPort(port);
try {
auto local4 = config.bind4;
auto local6 = config.bind6;
if (not local4 and not local6) {
if (context.logger)
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses", this);
local4.setFamily(AF_INET);
local6.setFamily(AF_INET6);
}
auto state_path = config.dht_config.node_config.persist_path;
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
state_path += "_port.txt";
std::ifstream inConfig(state_path);
if (inConfig.is_open()) {
in_port_t port;
if (inConfig >> port) {
if (local4.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port);
local4.setPort(port);
}
}
}
if (inConfig >> port) {
if (local6.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port);
local6.setPort(port);
if (inConfig >> port) {
if (local6.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port);
local6.setPort(port);
}
}
}
}
}
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
if (context.logger) {
logger_ = context.logger;
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
{
std::lock_guard<std::mutex> lck(sock_mtx);
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
while (rcv.size() > maxSize) {
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop_front();
}
rcv.splice(rcv.end(), std::move(pkts));
ret = std::move(rcv_free);
if (context.logger) {
logger_ = context.logger;
}
cv.notify_all();
return ret;
});
if (not context.sock) {
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
}
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
if (context.logger) {
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
{
std::lock_guard<std::mutex> lck(sock_mtx);
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
while (rcv.size() > maxSize) {
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop_front();
}
rcv.splice(rcv.end(), std::move(pkts));
ret = std::move(rcv_free);
}
cv.notify_all();
return ret;
});
#ifdef OPENDHT_PROXY_CLIENT
config_ = config;
identityAnnouncedCb_ = context.identityAnnouncedCb;
config_ = config;
identityAnnouncedCb_ = context.identityAnnouncedCb;
#endif
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger));
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger));
enableProxy(not config.proxy_server.empty());
} catch(const std::exception& e) {
config_ = {};
identityAnnouncedCb_ = {};
dht_.reset();
#ifdef OPENDHT_PROXY_CLIENT
dht_via_proxy_.reset();
#endif
running = State::Idle;
throw std::runtime_error(std::string("Error starting the node: ") + e.what());
}
enableProxy(not config.proxy_server.empty());
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(context.logger);
}
@@ -406,6 +420,14 @@ DhtRunner::getId() const
return {};
}
std::shared_ptr<crypto::PublicKey>
DhtRunner::getPublicKey() const
{
if (auto dht = activeDht())
return dht->getPublicKey();
return {};
}
InfoHash
DhtRunner::getNodeId() const
{
@@ -697,8 +719,8 @@ DhtRunner::loop_()
rcv_free.splice(rcv_free.end(), std::move(received_treated));
}
if (dropped)
std::cerr << "Dropped " << dropped << " packets with high delay" << std::endl;
if (dropped && logger_)
logger_->e("[runner %p] Dropped %zu packets with high delay.", this, dropped);
NodeStatus nstatus4 = dht->updateStatus(AF_INET);
NodeStatus nstatus6 = dht->updateStatus(AF_INET6);
@@ -958,6 +980,31 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, *to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb, bool permanent)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
}
void
DhtRunner::bootstrap(const std::string& host, const std::string& service)
{
+48 -26
View File
@@ -49,12 +49,21 @@ struct Dht::Announce {
};
struct Dht::SearchNode {
struct AnnounceStatus {
Sp<net::Request> req {};
Sp<Scheduler::Job> refresh {};
time_point refresh_time;
AnnounceStatus(){};
AnnounceStatus(Sp<net::Request> r, time_point t): req(std::move(r)), refresh_time(t)
{}
};
/**
* Foreach value id, we keep track of a pair (net::Request, time_point) where the
* request is the request returned by the network engine and the time_point
* is the next time at which the value must be refreshed.
*/
using AnnounceStatus = std::map<Value::Id, std::pair<Sp<net::Request>, time_point>>;
using AnnounceStatusMap = std::map<Value::Id, AnnounceStatus>;
/**
* Foreach Query, we keep track of the request returned by the network
* engine when we sent the "get".
@@ -63,6 +72,7 @@ struct Dht::SearchNode {
struct CachedListenStatus {
ValueCache cache;
Sp<Scheduler::Job> refresh {};
Sp<Scheduler::Job> cacheExpirationJob {};
Sp<net::Request> req {};
Tid socketId {0};
@@ -87,7 +97,7 @@ struct Dht::SearchNode {
SyncStatus getStatus {}; /* get/sync status */
NodeListenerStatus listenStatus {}; /* listen status */
AnnounceStatus acked {}; /* announcement status for a given value id */
AnnounceStatusMap acked {}; /* announcement status for a given value id */
Blob token {}; /* last token the node sent to us after a get request */
time_point last_get_reply {time_point::min()}; /* last time received valid token */
@@ -239,9 +249,12 @@ struct Dht::SearchNode {
}
}
void onListenSynced(const Sp<Query>& q, bool synced = true) {
void onListenSynced(const Sp<Query>& q, bool synced = true, Sp<Scheduler::Job> refreshJob = {}) {
auto l = listenStatus.find(q);
if (l != listenStatus.end()) {
if (l->second.refresh)
l->second.refresh->cancel();
l->second.refresh = std::move(refreshJob);
l->second.cache.onSynced(synced);
}
}
@@ -292,16 +305,18 @@ struct Dht::SearchNode {
bool isAnnounced(Value::Id vid) const {
auto ack = acked.find(vid);
if (ack == acked.end() or not ack->second.first)
if (ack == acked.end() or not ack->second.req)
return false;
return ack->second.first->completed();
return ack->second.req->completed();
}
void cancelAnnounce() {
for (const auto& status : acked) {
const auto& req = status.second.first;
const auto& req = status.second.req;
if (req and req->pending()) {
node->cancelRequest(req);
}
if (status.second.refresh)
status.second.refresh->cancel();
}
acked.clear();
}
@@ -328,14 +343,21 @@ struct Dht::SearchNode {
return listen_status->second.req->reply_time + listen_expire > now;
}
void cancelListen() {
for (const auto& status : listenStatus)
for (const auto& status : listenStatus) {
node->cancelRequest(status.second.req);
listenStatus.clear();
if (status.second.refresh)
status.second.refresh->cancel();
if (status.second.cacheExpirationJob)
status.second.cacheExpirationJob->cancel();
}
listenStatus.clear();
}
void cancelListen(const Sp<Query>& query) {
auto it = listenStatus.find(query);
if (it != listenStatus.end()) {
node->cancelRequest(it->second.req);
if (it->second.refresh)
it->second.refresh->cancel();
listenStatus.erase(it);
}
}
@@ -345,13 +367,13 @@ struct Dht::SearchNode {
*/
time_point getAnnounceTime(Value::Id vid) const {
const auto& ack = acked.find(vid);
if (ack == acked.cend() or not ack->second.first) {
if (ack == acked.cend() or not ack->second.req) {
return time_point::min();
}
if (ack->second.first->completed()) {
return ack->second.second - REANNOUNCE_MARGIN;
if (ack->second.req->completed()) {
return ack->second.refresh_time - REANNOUNCE_MARGIN;
}
return ack->second.first->pending() ? time_point::max() : time_point::min();
return ack->second.req->pending() ? time_point::max() : time_point::min();
}
/**
@@ -541,17 +563,15 @@ struct Dht::Search {
if (not opExpirationJob)
opExpirationJob = scheduler.add(time_point::max(), [this,&scheduler]{
auto nextExpire = cache.expire(scheduler.time(), [&](size_t t){
Sp<Query> query;
const auto& ll = listeners.find(t);
if (ll != listeners.cend()) {
query = ll->second.query;
auto query = ll->second.query;
listeners.erase(ll);
}
for (auto& sn : nodes) {
if (listeners.empty())
sn->cancelListen();
else if (query)
sn->cancelListen(query);
if (listeners.empty()) {
for (auto& sn : nodes) sn->cancelListen();
} else if (query) {
for (auto& sn : nodes) sn->cancelListen(query);
}
}
});
scheduler.edit(opExpirationJob, nextExpire);
@@ -588,8 +608,10 @@ struct Dht::Search {
for (auto& n : nodes) {
auto ackIt = n->acked.find(vid);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
if (ackIt->second.req)
ackIt->second.req->cancel();
if (ackIt->second.refresh)
ackIt->second.refresh->cancel();
n->acked.erase(ackIt);
}
}
@@ -606,7 +628,7 @@ struct Dht::Search {
announce.emplace_back(Announce {permanent, value, created, callback});
for (auto& n : nodes) {
n->probe_query.reset();
n->acked[value->id].first.reset();
n->acked[value->id].req.reset();
}
} else {
a_sr->permanent = permanent;
@@ -614,7 +636,7 @@ struct Dht::Search {
if (a_sr->value != value) {
a_sr->value = value;
for (auto& n : nodes) {
n->acked[value->id].first.reset();
n->acked[value->id].req.reset();
n->probe_query.reset();
}
}
@@ -738,8 +760,8 @@ struct Dht::Search {
for (auto& n : nodes) {
auto ackIt = n->acked.find(it->value->id);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
if (ackIt->second.req)
ackIt->second.req->cancel();
n->acked.erase(ackIt);
}
}
+27 -9
View File
@@ -118,7 +118,7 @@ SecureDht::secureType(ValueType&& type)
return type;
}
const Sp<crypto::Certificate>
Sp<crypto::Certificate>
SecureDht::getCertificate(const InfoHash& node) const
{
if (node == getId())
@@ -130,7 +130,7 @@ SecureDht::getCertificate(const InfoHash& node) const
return it->second;
}
const Sp<const crypto::PublicKey>
Sp<crypto::PublicKey>
SecureDht::getPublicKey(const InfoHash& node) const
{
if (node == getId())
@@ -142,7 +142,7 @@ SecureDht::getPublicKey(const InfoHash& node) const
return it->second;
}
const Sp<crypto::Certificate>
Sp<crypto::Certificate>
SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
{
Sp<crypto::Certificate> crt;
@@ -200,8 +200,6 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
auto found = std::make_shared<bool>(false);
dht_->get(node, [cb,node,found,this](const std::vector<Sp<Value>>& vals) {
if (*found)
return false;
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
@@ -212,7 +210,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
return false;
}
}
return true;
return !*found;
}, [cb,found](bool) {
if (!*found and cb)
cb(nullptr);
@@ -220,7 +218,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
}
void
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
@@ -230,7 +228,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
cb(pk);
return;
}
findCertificate(node, [=](const Sp<crypto::Certificate> crt) {
findCertificate(node, [=](const Sp<crypto::Certificate>& crt) {
if (crt && *crt) {
auto pk = std::make_shared<crypto::PublicKey>(crt->getPublicKey());
if (*pk) {
@@ -405,7 +403,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
callback(false, {});
return;
}
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp<crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
@@ -424,6 +422,26 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk.getLongId().to_c_str());
try {
dht_->put(hash, encrypt(*val, pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
}
void
SecureDht::sign(Value& v) const
{
+14 -10
View File
@@ -37,8 +37,7 @@ public:
storedValues_.emplace(expiration, std::pair<InfoHash, Value::Id>(id, value.id));
}
void erase(const InfoHash& id, const Value& value, time_point expiration) {
auto size = value.size();
totalSize_ -= size;
totalSize_ -= value.size();
auto range = storedValues_.equal_range(expiration);
for (auto rit = range.first; rit != range.second;) {
if (rit->second.first == id && rit->second.second == value.id) {
@@ -59,6 +58,7 @@ struct ValueStorage {
Sp<Value> data {};
time_point created {};
time_point expiration {};
Sp<Scheduler::Job> expiration_job {};
StorageBucket* store_bucket {nullptr};
ValueStorage() {}
@@ -143,14 +143,15 @@ struct Storage {
* @param vid The value id
* @return time of the next expiration, time_point::max() if no expiration
*/
time_point refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) {
std::pair<ValueStorage*, time_point>
refresh(const time_point& now, const Value::Id& vid, const TypeStore& types) {
for (auto& vs : values)
if (vs.data->id == vid) {
vs.created = now;
vs.expiration = std::max(vs.expiration, now + types.getType(vs.data->type).expiration);
return vs.expiration;
return {&vs, vs.expiration};
}
return time_point::max();
return {nullptr, time_point::max()};
}
size_t listen(ValueCallback& cb, Value::Filter& f, const Sp<Query>& q);
@@ -198,9 +199,9 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
if (it != values.end()) {
/* Already there, only need to refresh */
it->created = created;
size_t size_old = it->data->size();
ssize_t size_diff = size_new - (ssize_t)size_old;
if (it->data != value) {
size_t size_old = it->data->size();
ssize_t size_diff = size_new - (ssize_t)size_old;
//DHT_LOG.DEBUG("Updating %s -> %s", id.toString().c_str(), value->toString().c_str());
// clear quota for previous value
if (it->store_bucket)
@@ -214,7 +215,6 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
total_size += size_diff;
return std::make_pair(&(*it), StoreDiff{size_diff, 0, 0});
}
return std::make_pair(nullptr, StoreDiff{});
} else {
//DHT_LOG.DEBUG("Storing %s -> %s", id.toString().c_str(), value->toString().c_str());
if (values.size() < MAX_VALUES) {
@@ -225,8 +225,8 @@ Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, t
sb->insert(id, *value, expiration);
return std::make_pair(&values.back(), StoreDiff{size_new, 1, 0});
}
return std::make_pair(nullptr, StoreDiff{});
}
return std::make_pair(nullptr, StoreDiff{});
}
Storage::StoreDiff
@@ -240,6 +240,8 @@ Storage::remove(const InfoHash& id, Value::Id vid)
ssize_t size = it->data->size();
if (it->store_bucket)
it->store_bucket->erase(id, *it->data, it->expiration);
if (it->expiration_job)
it->expiration_job->cancel();
total_size -= size;
values.erase(it);
return {-size, -1, 0};
@@ -283,11 +285,13 @@ Storage::expire(const InfoHash& id, time_point now)
});
std::vector<Sp<Value>> ret;
ret.reserve(std::distance(r, values.end()));
ssize_t size_diff {};
ssize_t size_diff {0};
std::for_each(r, values.end(), [&](const ValueStorage& v) {
size_diff -= v.data->size();
if (v.store_bucket)
v.store_bucket->erase(id, *v.data, v.expiration);
if (v.expiration_job)
v.expiration_job->cancel();
ret.emplace_back(std::move(v.data));
});
total_size += size_diff;
+11 -24
View File
@@ -28,12 +28,6 @@ namespace dht {
constexpr const size_t IO_THREADS_MAX {64};
struct ThreadPool::ThreadState
{
std::thread thread {};
std::atomic_bool run {true};
};
ThreadPool&
ThreadPool::computation()
{
@@ -67,14 +61,12 @@ void
ThreadPool::run(std::function<void()>&& cb)
{
std::unique_lock<std::mutex> l(lock_);
if (not running_) return;
if (not cb or not running_) return;
// launch new thread if necessary
if (not readyThreads_ && threads_.size() < maxThreads_) {
threads_.emplace_back(new ThreadState());
auto& t = *threads_.back();
t.thread = std::thread([&]() {
while (t.run) {
threads_.emplace_back(std::make_unique<std::thread>([this]() {
while (true) {
std::function<void()> task;
// pick task from queue
@@ -82,10 +74,10 @@ ThreadPool::run(std::function<void()>&& cb)
std::unique_lock<std::mutex> l(lock_);
readyThreads_++;
cv_.wait(l, [&](){
return not t.run or not tasks_.empty();
return not running_ or not tasks_.empty();
});
readyThreads_--;
if (not t.run)
if (not running_)
break;
task = std::move(tasks_.front());
tasks_.pop();
@@ -93,14 +85,13 @@ ThreadPool::run(std::function<void()>&& cb)
// run task
try {
if (task)
task();
task();
} catch (const std::exception& e) {
// LOG_ERR("Exception running task: %s", e.what());
std::cerr << "Exception running task: " << e.what() << std::endl;
}
}
});
}));
}
// push task to queue
@@ -113,12 +104,8 @@ ThreadPool::run(std::function<void()>&& cb)
void
ThreadPool::stop()
{
{
std::lock_guard<std::mutex> l(lock_);
running_ = false;
}
for (auto& t : threads_)
t->run = false;
std::lock_guard<std::mutex> l(lock_);
running_ = false;
cv_.notify_all();
}
@@ -127,7 +114,7 @@ ThreadPool::join()
{
stop();
for (auto& t : threads_)
t->thread.join();
t->join();
threads_.clear();
}
@@ -147,7 +134,7 @@ Executor::run_(std::function<void()>&& task)
{
current_++;
std::weak_ptr<Executor> w = shared_from_this();
threadPool_.get().run([w,task] {
threadPool_.get().run([w,task = std::move(task)] {
try {
task();
} catch (const std::exception& e) {
+2 -2
View File
@@ -163,7 +163,7 @@ Value::msgpack_unpack_body(const msgpack::object& o)
throw msgpack::type_error();
crypto::PublicKey new_owner;
new_owner.msgpack_unpack(*rowner);
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
owner = std::make_shared<crypto::PublicKey>(std::move(new_owner));
if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) {
recipient = rrecipient->as<InfoHash>();
}
@@ -193,7 +193,7 @@ Value::Value(const Json::Value& json)
if (jowner.isString()) {
auto ownerStr = jowner.asString();
auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end());
owner = std::make_shared<const crypto::PublicKey>(ownerBlob);
owner = std::make_shared<crypto::PublicKey>(ownerBlob);
}
const auto& jto = json[VALUE_KEY_TO];
if (jto.isString())
+9 -12
View File
@@ -58,8 +58,7 @@ public:
values.clear();
CallbackQueue ret;
if (not expired_values.empty() and callback) {
auto cb = callback;
ret.emplace_back([expired_values, cb]{
ret.emplace_back([expired_values = std::move(expired_values), cb = callback]{
cb(expired_values, true);
});
}
@@ -103,24 +102,23 @@ public:
}
CallbackQueue ret;
if (not expired_values.empty() and callback) {
auto cb = callback;
ret.emplace_back([cb, expired_values]{
if (cb) cb(expired_values, true);
ret.emplace_back([cb = callback, expired_values = std::move(expired_values)]{
cb(expired_values, true);
});
}
return ret;
}
time_point onValues
(const std::vector<Sp<Value>>& values,
(const std::vector<Sp<Value>>& new_values,
const std::vector<Value::Id>& refreshed_values,
const std::vector<Value::Id>& expired_values,
const TypeStore& types, const time_point& now)
{
CallbackQueue cbs;
time_point ret = time_point::max();
if (not values.empty())
cbs.splice(cbs.end(), addValues(values, types, now));
if (not new_values.empty())
cbs.splice(cbs.end(), addValues(new_values, types, now));
for (const auto& vid : refreshed_values)
refreshValue(vid, types, now);
for (const auto& vid : expired_values)
@@ -184,11 +182,10 @@ private:
v->second.expiration = now + types.getType(v->second.data->type).expiration;
}
}
auto cb = callback;
CallbackQueue ret;
if (not nvals.empty())
ret.emplace_back([cb, nvals]{
if (cb) cb(nvals, false);
if (callback and not nvals.empty())
ret.emplace_back([cb = callback, nvals = std::move(nvals)]{
cb(nvals, false);
});
return ret;
}
+1 -1
View File
@@ -33,7 +33,7 @@ CryptoTester::setUp() {
void
CryptoTester::testSignatureEncryption() {
auto key = dht::crypto::PrivateKey::generate();
auto public_key = key.getPublicKey();
const auto& public_key = key.getPublicKey();
std::vector<uint8_t> data1 {5, 10};
std::vector<uint8_t> data2(64 * 1024, 10);
+47 -3
View File
@@ -19,6 +19,8 @@
#include "dhtrunnertester.h"
#include <opendht/thread_pool.h>
#include <chrono>
#include <mutex>
#include <condition_variable>
@@ -52,7 +54,7 @@ DhtRunnerTester::tearDown() {
node1.shutdown(shutdown);
node2.shutdown(shutdown);
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done == 2; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 12s, [&]{ return done == 2; }));
node1.join();
node2.join();
}
@@ -230,17 +232,24 @@ DhtRunnerTester::testIdOps() {
cv.notify_all();
});
node1.putEncrypted(key, node2.getPublicKey(), dht::Value("yo"), [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
});
node2.listen<std::string>(key, [&](std::string&& value){
CPPUNIT_ASSERT_EQUAL("yo"s, value);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
return false;
return true;
});
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 4; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; }));
}
}
@@ -291,4 +300,39 @@ DhtRunnerTester::testListenLotOfBytes() {
node3.cancelListen(foo, ftokenfoo.get());
}
void
DhtRunnerTester::testMultithread() {
std::mutex mutex;
std::condition_variable cv;
unsigned putCount(0);
unsigned putOkCount(0);
constexpr unsigned N = 2048;
for (unsigned i=0; i<N; i++) {
dht::ThreadPool::computation().run([&]{
node2.put(dht::InfoHash::get("123" + std::to_string(i)), "hehe", [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
node2.get(dht::InfoHash::get("123" + std::to_string(N-i-1)), [](const std::shared_ptr<dht::Value>&){
return true;
}, [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
});
}
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == 2*N; }));
CPPUNIT_ASSERT_EQUAL(2*N, putOkCount);
}
} // namespace test
+5
View File
@@ -67,6 +67,11 @@ class DhtRunnerTester : public CppUnit::TestFixture {
* Test listen method with lot of datas
*/
void testListenLotOfBytes();
/**
* Test multithread
*/
void testMultithread();
};
} // namespace test
+2 -1
View File
@@ -21,6 +21,7 @@
#include "opendht/thread_pool.h"
#include <atomic>
#include <thread>
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(ThreadPoolTester);
@@ -47,7 +48,7 @@ ThreadPoolTester::testThreadPool() {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
pool.join();
CPPUNIT_ASSERT(count.load() == N);
CPPUNIT_ASSERT_EQUAL(N, count.load());
}
void
+1
View File
@@ -30,6 +30,7 @@ endif ()
if (OPENDHT_C)
add_executable (dhtcnode dhtcnode.c)
target_link_libraries (dhtcnode LINK_PUBLIC opendht-c ${READLINE_LIBRARIES})
target_include_directories (dhtcnode SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/c)
endif ()
if (NOT DEFINED CMAKE_INSTALL_BINDIR)
+3 -3
View File
@@ -4,10 +4,10 @@ noinst_HEADERS = tools_common.h
AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
dhtnode_SOURCES = dhtnode.cpp
dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
dhtchat_SOURCES = dhtchat.cpp
dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
dhtscanner_SOURCES = dhtscanner.cpp
dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
+2 -2
View File
@@ -1,4 +1,4 @@
#include <c/opendht_c.h>
#include <opendht_c.h>
#include <stdio.h>
#include <string.h>
@@ -88,7 +88,7 @@ int main()
// Put data
const char* data_str = "yo, this is some data";
dht_value* val = dht_value_new(data_str, strlen(data_str));
dht_value* val = dht_value_new_from_string(data_str);
dht_runner_put(runner, &h, val, dht_done_callback, runner, false);
dht_value_unref(val);
+2 -2
View File
@@ -156,7 +156,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
if (auto stats = proxy.second->stats())
std::cout << " " << stats->toString() << std::endl;
else
std::cout << " (stats not available yet)" << std::endl;
std::cout << " (stats not available yet)" << std::endl;
}
#endif
});
@@ -467,7 +467,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
<< " hash: " << p.hash() << std::endl;
std::cout << " entries:" << std::endl;
for (const auto& v : vals)
std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl;
std::cout << " " << v->first.toString() << "[vid: " << std::hex << v->second << std::dec << "]" << std::endl;
},
[start](bool ok) {
auto end = std::chrono::high_resolution_clock::now();
+1 -1
View File
@@ -102,7 +102,7 @@ benchPingPong(unsigned netSize, unsigned n_parallel) {
auto start = clock::now();
for (unsigned i=0; i<n_parallel; i++)
for (unsigned i=0; i<n_parallel; i++)
ping(pong_node, locs[i].first);
{