Compare commits

..
1 Commits
Author SHA1 Message Date
Adrien Béraud 68485faf58 crypto: improve authenticated encryption performance 2019-10-22 13:04:30 -04:00
124 changed files with 3254 additions and 5047 deletions

No files matched your search

-34
View File
@@ -1,34 +0,0 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: deps
run: |
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev
- name: autogen
run: ./autogen.sh
- name: argon2
run: |
cd argon2 && make && sudo make install && cd ..
- name: asio
run: |
wget https://github.com/aberaud/asio/archive/b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz \
&& tar -xvf b2b7a1c166390459e1c169c8ae9ef3234b361e3f.tar.gz && cd asio-b2b7a1c166390459e1c169c8ae9ef3234b361e3f/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& sudo make install \
&& cd ../../ && rm -rf asio*
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
+32 -57
View File
@@ -1,7 +1,4 @@
cmake_minimum_required (VERSION 3.1)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
project (opendht)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 0.0)
@@ -25,8 +22,6 @@ option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" O
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS "Add unit tests executable" OFF)
option (OPENDHT_C "Build C bindings" OFF)
@@ -65,9 +60,10 @@ if (Jsoncpp_FOUND)
)
endif()
if (OPENDHT_HTTP)
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
find_package(Restinio REQUIRED)
if (Restinio_FOUND)
add_definitions(-DASIO_STANDALONE)
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
find_library(HTTP_PARSER_LIBRARY http_parser)
@@ -89,11 +85,6 @@ if (OPENDHT_HTTP)
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
endif()
else()
set(OPENDHT_PROXY_OPENSSL OFF)
endif()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
endif()
# Build flags
@@ -104,7 +95,6 @@ if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
@@ -186,6 +176,7 @@ list (APPEND opendht_SOURCES
src/securedht.cpp
src/dhtrunner.cpp
src/log.cpp
src/peer_discovery.cpp
src/network_utils.cpp
src/thread_pool.cpp
)
@@ -211,17 +202,12 @@ list (APPEND opendht_HEADERS
include/opendht/securedht.h
include/opendht/log.h
include/opendht/log_enable.h
include/opendht/peer_discovery.h
include/opendht/thread_pool.h
include/opendht/network_utils.h
include/opendht.h
)
if (OPENDHT_PEER_DISCOVERY)
list (APPEND opendht_SOURCES src/peer_discovery.cpp)
list (APPEND opendht_HEADERS include/opendht/peer_discovery.h)
add_definitions(-DOPENDHT_PEER_DISCOVERY)
endif()
if (OPENDHT_PYTHON)
message("Indexation enabled since it is required for Python support")
set(OPENDHT_INDEX ON)
@@ -255,7 +241,7 @@ if (OPENDHT_PROXY_CLIENT)
)
endif ()
if (OPENDHT_HTTP)
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_PUSH_NOTIFICATIONS)
message("Using push notification")
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
@@ -335,12 +321,7 @@ if (OPENDHT_C)
c/opendht_c.h
)
target_compile_definitions(opendht-c PRIVATE OPENDHT_C_BUILD)
if (OPENDHT_SHARED)
target_link_libraries(opendht-c opendht)
else ()
target_link_libraries(opendht-c opendht-static)
endif ()
target_link_libraries(opendht-c opendht)
# PkgConfig module
configure_file (
opendht-c.pc.in
@@ -361,6 +342,7 @@ if (OPENDHT_PYTHON)
endif ()
# CMake module
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake"
VERSION ${opendht_VERSION}
COMPATIBILITY AnyNewerVersion
@@ -380,53 +362,46 @@ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/opendhtConfigVersion.cmake DESTINATIO
# Unit tests
if (OPENDHT_TESTS)
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
FIND_PACKAGE(Cppunit REQUIRED)
# unit testing
list (APPEND test_FILES
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
tests/dhtrunnertester.cpp
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
tests/threadpooltester.h
tests/threadpooltester.cpp
)
if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
if (OPENDHT_PEER_DISCOVERY)
list (APPEND test_FILES
tests/peerdiscoverytester.h
tests/peerdiscoverytester.cpp
)
list (APPEND test_FILES
tests/httptester.h
tests/httptester.cpp
tests/dhtproxytester.h
tests/dhtproxytester.cpp
)
endif()
add_executable(opendht_unit_tests
tests/tests_runner.cpp
${test_FILES}
tests/tests_runner.cpp
${test_FILES}
)
target_include_directories(opendht_unit_tests SYSTEM PRIVATE ${CPPUNIT_INCLUDE_DIRS})
if (OPENDHT_SHARED)
target_link_libraries(opendht_unit_tests opendht)
target_link_libraries(opendht_unit_tests opendht)
else ()
target_link_libraries(opendht_unit_tests opendht-static)
target_link_libraries(opendht_unit_tests opendht-static)
endif ()
target_link_libraries(opendht_unit_tests
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
${Jsoncpp_LIBRARIES}
ssl crypto jsoncpp
)
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht_unit_tests ${OPENSSL_LIBRARIES})
endif()
enable_testing()
add_test(TEST opendht_unit_tests)
endif()
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
+2
View File
@@ -16,7 +16,9 @@ if ENABLE_TESTS
SUBDIRS += tests
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
+4 -4
View File
@@ -14,9 +14,9 @@ Values are distributed over the network, with redundancy.
* High resilience to network disruption
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
* IPv4 and IPv6 support
* Clean and powerful **C++14** map API
* Bindings for **C, Rust & Python 3**
* REST API with optional HTTP client+server with push notification support
* Clean and powerful C++14 map API
* Python 3 bindings
* REST API
## Documentation
See the wiki: <https://github.com/savoirfairelinux/opendht/wiki>
@@ -106,7 +106,7 @@ for r in results:
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## License
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
Copyright (C) 2014-2019 Savoir-faire Linux Inc.
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
+1 -1
Submodule argon2 updated: 62358ba212...670229c849.
+32 -142
View File
@@ -3,7 +3,6 @@
using ValueSp = std::shared_ptr<dht::Value>;
using PrivkeySp = std::shared_ptr<dht::crypto::PrivateKey>;
using PubkeySp = std::shared_ptr<const dht::crypto::PublicKey>;
using CertSp = std::shared_ptr<dht::crypto::Certificate>;
#ifdef __cplusplus
@@ -11,19 +10,6 @@ extern "C" {
#endif
// dht::InfoHash
inline dht_infohash dht_infohash_to_c(const dht::InfoHash& h) {
dht_infohash ret;
*reinterpret_cast<dht::InfoHash*>(&ret) = h;
return ret;
}
inline dht_pkid dht_pkid_to_c(const dht::PkId& h) {
dht_pkid ret;
*reinterpret_cast<dht::PkId*>(&ret) = h;
return ret;
}
const char* dht_infohash_print(const dht_infohash* h) {
return reinterpret_cast<const dht::InfoHash*>(h)->to_c_str();
}
@@ -40,18 +26,10 @@ void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get(dat, dat_size);
}
void dht_infohash_get_from_string(dht_infohash* h, const char* dat) {
*reinterpret_cast<dht::InfoHash*>(h) = dht::InfoHash::get((const uint8_t*)dat, (size_t)strlen(dat));
}
bool dht_infohash_is_zero(const dht_infohash* h) {
return !static_cast<bool>(*reinterpret_cast<const dht::InfoHash*>(h));
}
void dht_infohash_from_hex(dht_infohash* h, const char* dat) {
*h = dht_infohash_to_c(dht::InfoHash(std::string(dat, HASH_LEN*2)));
}
const char* dht_pkid_print(const dht_pkid* h) {
return reinterpret_cast<const dht::PkId*>(h)->to_c_str();
}
@@ -82,21 +60,6 @@ dht_value_id dht_value_get_id(const dht_value* data) {
return vsp->id;
}
dht_publickey* dht_value_get_owner(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->owner ? reinterpret_cast<dht_publickey*>(new PubkeySp(vsp->owner)) : nullptr;
}
dht_infohash dht_value_get_recipient(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return dht_infohash_to_c(vsp->recipient);
}
const char* dht_value_get_user_type(const dht_value* data) {
const ValueSp& vsp(*reinterpret_cast<const ValueSp*>(data));
return vsp->user_type.c_str();
}
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)));
}
@@ -110,46 +73,51 @@ void dht_value_unref(dht_value* v) {
}
// dht::crypto::PublicKey
dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size) {
try {
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<const dht::crypto::PublicKey>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
dht_publickey* dht_publickey_new() {
return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey);
}
void dht_publickey_delete(dht_publickey* pk) {
delete reinterpret_cast<PubkeySp*>(pk);
delete reinterpret_cast<dht::crypto::PublicKey*>(pk);
}
int dht_publickey_export(const dht_publickey* pk, char* out, size_t* outlen) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->pack((uint8_t*)out, outlen);
int dht_publickey_unpack(dht_publickey* pk, const uint8_t* dat, size_t dat_size) {
try {
reinterpret_cast<dht::crypto::PublicKey*>(pk)->unpack(dat, dat_size);
} catch (const dht::crypto::CryptoException& e) {
return -1;
}
return 0;
}
int dht_publickey_pack(dht_publickey* pk, char* out, size_t* outlen) {
return gnutls_pubkey_export(reinterpret_cast<dht::crypto::PublicKey*>(pk)->pk, GNUTLS_X509_FMT_DER, out, outlen);
}
dht_infohash dht_publickey_get_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_infohash_to_c(pkey->getId());
auto pkey = reinterpret_cast<const dht::crypto::PublicKey*>(pk);
dht_infohash h;
*reinterpret_cast<dht::InfoHash*>(&h) = pkey->getId();
return h;
}
dht_pkid dht_publickey_get_long_id(const dht_publickey* pk) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return dht_pkid_to_c(pkey->getLongId());
auto pkey = reinterpret_cast<const dht::crypto::PublicKey*>(pk);
dht_pkid h;
*reinterpret_cast<dht::PkId*>(&h) = pkey->getLongId();
return h;
}
bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
return pkey->checkSignature((const uint8_t*)data, data_size, (const uint8_t*)signature, signature_size);
return reinterpret_cast<const dht::crypto::PublicKey*>(pk)->checkSignature((const uint8_t*)data, data_size, (const uint8_t*)signature, signature_size);
}
dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size) {
const auto& pkey = *reinterpret_cast<const PubkeySp*>(pk);
auto rdata = new dht::Blob;
*rdata = pkey->encrypt((const uint8_t*)data, data_size);
*rdata = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->encrypt((const uint8_t*)data, data_size);
return (dht_blob*)rdata;
}
// dht::crypto::PrivateKey
dht_privatekey* dht_privatekey_generate(unsigned key_length_bits) {
if (key_length_bits == 0)
key_length_bits = 4096;
@@ -164,82 +132,15 @@ dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const
}
}
int dht_privatekey_export(const dht_privatekey* k, char* out, size_t* out_size, const char* password) {
if (!out or !out_size or !*out_size)
return -1;
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return key->serialize((uint8_t*)out, out_size, password);
}
dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(key->getPublicKey())));
return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey(key->getPublicKey()));
}
void dht_privatekey_delete(dht_privatekey* pk) {
delete reinterpret_cast<PrivkeySp*>(pk);
}
// dht::crypto::Certificate
dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size) {
try {
return reinterpret_cast<dht_certificate*>(new CertSp(std::make_shared<dht::crypto::Certificate>(dat, dat_size)));
} catch (const dht::crypto::CryptoException& e) {
return nullptr;
}
}
void dht_certificate_delete(dht_certificate* c) {
delete reinterpret_cast<CertSp*>(c);
}
dht_infohash dht_certificate_get_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_infohash_to_c(cert->getId());
}
dht_pkid dht_certificate_get_long_id(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return dht_pkid_to_c(cert->getLongId());
}
dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
const auto& cert = *reinterpret_cast<const CertSp*>(c);
return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey())));
}
// dht::crypto::Identity
inline dht::crypto::Identity dht_identity_from_c(const dht_identity* cid) {
dht::crypto::Identity id {};
if (cid and cid->privatekey)
id.first = *reinterpret_cast<const PrivkeySp*>(cid->privatekey);
if (cid and cid->certificate)
id.second = *reinterpret_cast<const CertSp*>(cid->certificate);
return id;
}
inline dht_identity dht_identity_to_c(const dht::crypto::Identity& id) {
dht_identity cid {};
cid.privatekey = id.first ? reinterpret_cast<dht_privatekey*>(new PrivkeySp(id.first)) : NULL;
cid.certificate = id.second ? reinterpret_cast<dht_certificate*>(new CertSp(id.second)) : NULL;
return cid;
}
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca) {
return dht_identity_to_c(dht::crypto::generateIdentity(common_name, dht_identity_from_c(ca)));
}
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity* id) {
if (id->certificate) {
dht_certificate_delete(id->certificate);
id->certificate = NULL;
}
if (id->privatekey) {
dht_privatekey_delete(id->privatekey);
id->privatekey = NULL;
}
}
// config
void dht_runner_config_default(dht_runner_config* config) {
bzero(config, sizeof(dht_runner_config));
@@ -270,8 +171,8 @@ void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_confi
config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path
? std::string(conf->dht_config.node_config.persist_path) : std::string{};
if (conf->dht_config.id.privatekey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privatekey);
if (conf->dht_config.id.privkey)
config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privkey);
if (conf->dht_config.id.certificate)
config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
@@ -348,35 +249,24 @@ void dht_op_token_delete(dht_op_token* token) {
delete reinterpret_cast<std::future<size_t>*>(token);
}
void dht_runner_put(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
void dht_runner_put(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->put(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, dht::time_point::max(), permanent);
});
}
void dht_runner_put_signed(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
void dht_runner_put_permanent(dht_runner* r, const dht_infohash* h, const dht_value* v, dht_done_cb done_cb, void* cb_user_data) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putSigned(*hash, *value, [done_cb, cb_user_data](bool ok){
runner->put(*hash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}
void dht_runner_put_encrypted(dht_runner* r, const dht_infohash* h, const dht_infohash* to, const dht_value* v, dht_done_cb done_cb, void* cb_user_data, bool permanent) {
auto runner = reinterpret_cast<dht::DhtRunner*>(r);
auto hash = reinterpret_cast<const dht::InfoHash*>(h);
auto toHash = reinterpret_cast<const dht::InfoHash*>(to);
auto value = reinterpret_cast<const ValueSp*>(v);
runner->putEncrypted(*hash, *toHash, *value, [done_cb, cb_user_data](bool ok){
if (done_cb)
done_cb(ok, cb_user_data);
}, permanent);
}, dht::time_point::max(), true);
}
void dht_runner_cancel_put(dht_runner* r, const dht_infohash* h, dht_value_id value_id) {
+20 -32
View File
@@ -18,6 +18,16 @@ struct OPENDHT_C_PUBLIC dht_data_view {
};
typedef struct dht_data_view dht_data_view;
// dht::Value
struct OPENDHT_C_PUBLIC dht_value;
typedef struct dht_value dht_value;
typedef uint64_t dht_value_id;
OPENDHT_C_PUBLIC dht_data_view dht_value_get_data(const dht_value* data);
OPENDHT_C_PUBLIC dht_value_id dht_value_get_id(const dht_value* data);
OPENDHT_C_PUBLIC dht_value* dht_value_new(const uint8_t* data, size_t size);
OPENDHT_C_PUBLIC dht_value* dht_value_ref(const dht_value*);
OPENDHT_C_PUBLIC void dht_value_unref(dht_value*);
// dht::Blob
struct OPENDHT_C_PUBLIC dht_blob;
typedef struct dht_blob dht_blob;
@@ -29,9 +39,7 @@ struct OPENDHT_C_PUBLIC dht_infohash { uint8_t d[HASH_LEN]; };
typedef struct dht_infohash dht_infohash;
OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_random(dht_infohash* h);
OPENDHT_C_PUBLIC void dht_infohash_from_hex(dht_infohash* h, const char* dat);
OPENDHT_C_PUBLIC void dht_infohash_get(dht_infohash* h, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC void dht_infohash_get_from_string(dht_infohash* h, const char* str);
OPENDHT_C_PUBLIC const char* dht_infohash_print(const dht_infohash* h);
OPENDHT_C_PUBLIC bool dht_infohash_is_zero(const dht_infohash* h);
@@ -43,9 +51,10 @@ OPENDHT_C_PUBLIC const char* dht_pkid_print(const dht_pkid* h);
// dht::crypto::PublicKey
struct OPENDHT_C_PUBLIC dht_publickey;
typedef struct dht_publickey dht_publickey;
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC dht_publickey* dht_publickey_new();
OPENDHT_C_PUBLIC void dht_publickey_delete(dht_publickey* pk);
OPENDHT_C_PUBLIC int dht_publickey_export(const dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC int dht_publickey_unpack(dht_publickey* pk, const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC int dht_publickey_pack(dht_publickey* pk, char* out, size_t* out_size);
OPENDHT_C_PUBLIC dht_infohash dht_publickey_get_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC dht_pkid dht_publickey_get_long_id(const dht_publickey* pk);
OPENDHT_C_PUBLIC bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, size_t data_size, const char* signature, size_t signature_size);
@@ -56,45 +65,24 @@ struct OPENDHT_C_PUBLIC dht_privatekey;
typedef struct dht_privatekey dht_privatekey;
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_generate(unsigned key_length_bits);
OPENDHT_C_PUBLIC dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password);
OPENDHT_C_PUBLIC int dht_privatekey_export(const dht_privatekey*, char* out, size_t* out_size, const char* password);
OPENDHT_C_PUBLIC dht_publickey* dht_privatekey_get_publickey(const dht_privatekey*);
OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*);
// dht::crypto::Certificate
struct OPENDHT_C_PUBLIC dht_certificate;
typedef struct dht_certificate dht_certificate;
OPENDHT_C_PUBLIC dht_certificate* dht_certificate_import(const uint8_t* dat, size_t dat_size);
OPENDHT_C_PUBLIC dht_infohash dht_certificate_get_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_pkid dht_certificate_get_long_id(const dht_certificate*);
OPENDHT_C_PUBLIC dht_publickey* dht_certificate_get_publickey(const dht_certificate*);
OPENDHT_C_PUBLIC void dht_certificate_delete(dht_certificate*);
struct OPENDHT_PUBLIC dht_identity {
dht_privatekey* privatekey;
dht_privatekey* privkey;
dht_certificate* certificate;
};
typedef struct dht_identity dht_identity;
OPENDHT_C_PUBLIC dht_identity dht_identity_generate(const char* common_name, const dht_identity* ca);
OPENDHT_C_PUBLIC void dht_identity_delete(dht_identity*);
// dht::Value
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_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);
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);
// callbacks
typedef bool (*dht_get_cb)(const dht_value* value, void* user_data);
typedef bool (*dht_value_cb)(const dht_value* value, bool expired, void* user_data);
typedef void (*dht_done_cb)(bool ok, void* user_data);
typedef void (*dht_shutdown_cb)(void* user_data);
typedef bool (*dht_done_cb)(bool ok, void* user_data);
typedef bool (*dht_shutdown_cb)(void* user_data);
struct OPENDHT_C_PUBLIC dht_op_token;
typedef struct dht_op_token dht_op_token;
@@ -110,7 +98,8 @@ struct OPENDHT_PUBLIC dht_node_config {
};
typedef struct dht_node_config dht_node_config;
struct OPENDHT_PUBLIC dht_secure_config {
struct OPENDHT_PUBLIC dht_secure_config
{
dht_node_config node_config;
dht_identity id;
};
@@ -142,9 +131,8 @@ OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host,
OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_cancel_listen(dht_runner* runner, const dht_infohash* hash, dht_op_token* token);
OPENDHT_C_PUBLIC void dht_runner_put(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_signed(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put_encrypted(dht_runner* runner, const dht_infohash* hash, const dht_infohash* to, const dht_value* value, dht_done_cb done_cb, void* cb_user_data, bool permanent);
OPENDHT_C_PUBLIC void dht_runner_put(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_put_permanent(dht_runner* runner, const dht_infohash* hash, const dht_value* value, dht_done_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC void dht_runner_cancel_put(dht_runner* runner, const dht_infohash* hash, dht_value_id value_id);
OPENDHT_C_PUBLIC void dht_runner_shutdown(dht_runner* runner, dht_shutdown_cb done_cb, void* cb_user_data);
OPENDHT_C_PUBLIC dht_infohash dht_runner_get_node_id(const dht_runner* runner);
+18 -19
View File
@@ -35,14 +35,10 @@ AS_IF([test "x$enable_logs" != "xno"], [
dnl Check for indexation
AC_ARG_ENABLE([indexation], [AS_HELP_STRING([--disable-indexation], [Disable DHT indexation])])
AM_CONDITIONAL(ENABLE_INDEXATION, test x$enable_indexation != "xno")
AM_COND_IF(ENABLE_INDEXATION, [
AC_DEFINE([OPENDHT_INDEXATION], [], [Define if DHT indexation is enabled])
AS_IF([test "x$enable_indexation" != "xno"], [
AC_DEFINE([OPENDHT_INDEXATION], [1], [Define if DHT indexation is enabled])
])
AC_ARG_ENABLE([peer-discovery], [AS_HELP_STRING([--disable-peer-discovery], [Disable peer-discovery])])
AM_CONDITIONAL(ENABLE_PEER_DISCOVERY, test x$enable_peer_discovery != "xno")
AM_COND_IF(ENABLE_PEER_DISCOVERY, [AC_DEFINE([OPENDHT_PEER_DISCOVERY], [], [Define if peer discovery is enabled])])
dnl Check for Doxygen
AC_ARG_ENABLE([doc], AS_HELP_STRING([--enable-doc], [Enable documentation generation (doxygen)]))
AS_IF([test "x$enable_doc" = "xyes"], [
@@ -102,7 +98,7 @@ AS_IF([test "x$SYS" = "xandroid"],
LT_INIT()
LT_LANG(C++)
AX_CXX_COMPILE_STDCXX(14,[noext],[mandatory])
AX_CXX_COMPILE_STDCXX(11,[noext],[mandatory])
PKG_PROG_PKG_CONFIG()
@@ -139,7 +135,7 @@ AS_IF([test "x$with_jsoncpp" != "xno"],
[have_jsoncpp=no])
AS_IF([test "x$have_jsoncpp" = "xyes"], [
AC_MSG_NOTICE([Using JsonCpp])
CPPFLAGS+=" -DOPENDHT_JSONCPP"
CPPFLAGS+=" -DOPENDHT_JSONCPP=1"
], [
AC_MSG_NOTICE([Not using JsonCpp])
AM_COND_IF(PROXY_CLIENT_OR_SERVER, AC_MSG_ERROR(["JsonCpp is required for proxy/push notification support"]))
@@ -158,7 +154,7 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
CPPFLAGS+=" -DOPENDHT_PROXY_HTTP_PARSER_FORK"
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
@@ -209,24 +205,27 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF(ENABLE_PROXY_SERVER, AC_DEFINE([OPENDHT_PROXY_SERVER], [], [Building with proxy server]))
AM_COND_IF(ENABLE_PROXY_CLIENT, AC_DEFINE([OPENDHT_PROXY_CLIENT], [], [Building with proxy client]))
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT"], [])
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF([HAVE_DOXYGEN], [
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
])
dnl Configure setup.py if we build the python module
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AM_COND_IF([USE_CYTHON], [
AC_SUBST(CURRENT_SOURCE_DIR, ".")
AC_SUBST(CURRENT_BINARY_DIR, ".")
AC_SUBST(PROJECT_SOURCE_DIR, "..")
AC_SUBST(PROJECT_BINARY_DIR, "../src/.libs")
AC_CONFIG_FILES([python/Makefile python/setup.py])
])
AC_CONFIG_FILES([Makefile
src/Makefile
tools/Makefile
python/Makefile
python/setup.py
tests/Makefile
doc/Makefile
doc/Doxyfile
opendht.pc])
AC_OUTPUT
+1 -4
View File
@@ -1,10 +1,7 @@
dist_man1_MANS = dhtnode.1
noinst_HEADERS = \
Doxyfile
if HAVE_DOXYGEN
doxyfile.stamp: Doxyfile
doxyfile.stamp:
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
-13
View File
@@ -1,13 +0,0 @@
FROM docker.pkg.github.com/savoirfairelinux/opendht/opendht-deps-bionic:2.0.0
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN git clone https://github.com/savoirfairelinux/opendht.git \
&& cd opendht && mkdir build && cd build \
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr \
-DOPENDHT_PROXY_CLIENT=On \
-DOPENDHT_PROXY_SERVER=On \
-DOPENDHT_C=On \
-DOPENDHT_PYTHON=On \
-DOPENDHT_LTO=On \
&& make -j8 && make install \
&& cd ../.. && rm -rf opendht
+13 -10
View File
@@ -2,14 +2,14 @@ FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update && apt-get install -y \
build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libssl-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libasio-dev \
&& apt-get clean
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -17,22 +17,25 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 install \
&& PREFIX=/usr make -j8 && make install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& make install \
&& cd ../../ && rm -rf asio*
#patch for https://github.com/Stiffstream/restinio-conan-example/issues/2
RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade cmake
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& wget https://github.com/Stiffstream/restinio/archive/v.0.5.1.2.tar.gz \
&& ls -l && tar -xzf v.0.5.1.2.tar.gz \
&& cd restinio-v.0.5.1.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
-28
View File
@@ -1,28 +0,0 @@
FROM ubuntu:18.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
RUN apt-get update && apt-get install -y \
apt-transport-https build-essential cmake git wget libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev cython3 python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libhttp-parser-dev libmsgpack-dev libssl-dev \
&& apt-get clean
# libasio-dev (1.10) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& make install \
&& cd ../../ && rm -rf asio*
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& ls -l && tar -xzf 8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59.tar.gz \
&& cd restinio-8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
&& make -j8 && make install \
&& cd ../../ && rm -rf restinio*
+10 -10
View File
@@ -2,9 +2,9 @@ FROM ubuntu:16.04
MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
RUN apt-get update \
&& apt-get install -y llvm llvm-dev clang make cmake git wget libncurses5-dev libreadline-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev cython3 python3-dev \
nettle-dev libgnutls28-dev libuv1-dev libmsgpack-dev libjsoncpp-dev libasio-dev cython3 python3-dev \
python3-setuptools libcppunit-dev python3-pip \
autotools-dev autoconf libssl-dev \
autotools-dev autoconf libasio-dev \
&& apt-get remove -y gcc g++ && apt-get autoremove -y && apt-get clean
ENV CC cc
@@ -13,7 +13,7 @@ ENV CXX c++
RUN echo "*** Installing libfmt ***" \
&& wget https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz \
&& tar -xzf 5.3.0.tar.gz && cd fmt-5.3.0/ \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On -DFMT_TEST=Off -DFMT_DOC=Off . \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=On . \
&& make -j8 && make install \
&& cd ../ && rm -rf fmt*
@@ -21,14 +21,14 @@ RUN echo "*** Installing libfmt ***" \
RUN echo "*** Building nodejs/http_parser dependency ***" \
&& wget https://github.com/nodejs/http-parser/archive/v2.9.2.tar.gz \
&& tar xvf v2.9.2.tar.gz && cd http-parser-2.9.2/ \
&& PREFIX=/usr make -j8 install \
&& PREFIX=/usr make -j8 && make install \
&& cd ../ && rm -rf http-parser*
# libasio-dev (1.10.6-3) is too old
RUN echo "** Building a recent version of asio ***" \
&& wget https://github.com/aberaud/asio/archive/a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz \
&& tar -xvf a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571.tar.gz && cd asio-a7d66ef4017d8f1b7f2cef1bb4ba8e23b0961571/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost --disable-examples --disable-tests \
&& wget https://github.com/chriskohlhoff/asio/archive/asio-1-12-2.tar.gz \
&& tar -xvf asio-1-12-2.tar.gz && cd asio-asio-1-12-2/asio \
&& ./autogen.sh && ./configure --prefix=/usr --without-boost \
&& make install \
&& cd ../../ && rm -rf asio*
@@ -37,9 +37,9 @@ RUN apt-get update && apt-get install -y python3-pip && pip3 install --upgrade c
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& ls -l && tar -xzf a7a10e419d9089c5b8ee63f5e3098c892f22fae4.tar.gz \
&& cd restinio-a7a10e419d9089c5b8ee63f5e3098c892f22fae4/dev \
&& wget https://github.com/Stiffstream/restinio/archive/v.0.5.1.2.tar.gz \
&& ls -l && tar -xzf v.0.5.1.2.tar.gz \
&& cd restinio-v.0.5.1.2/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+1 -1
View File
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_LTO=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
+1 -1
View File
@@ -3,5 +3,5 @@ MAINTAINER Adrien Béraud <adrien.beraud@savoirfairelinux.com>
COPY . /root/opendht
RUN cd /root/opendht && mkdir build && cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_C=On -DOPENDHT_TESTS=ON .. \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DOPENDHT_PYTHON=On -DOPENDHT_TESTS=ON .. \
&& make -j8 && ./opendht_unit_tests && make install
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -19,4 +19,10 @@
#pragma once
#include "opendht/dhtrunner.h"
#ifdef OPENDHT_PROXY_SERVER
#include "opendht/dht_proxy_server.h"
#endif
#include "opendht/default_types.h"
#ifdef OPENDHT_INDEXATION
#include "opendht/indexation/pht.h"
#endif
+4 -53
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -26,7 +26,6 @@
#include <vector>
#include <memory>
#include <functional>
#include <string>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
@@ -45,21 +44,12 @@ enum class NodeStatus {
Connected // 1+ good nodes
};
inline constexpr const char*
statusToStr(NodeStatus status) {
return status == NodeStatus::Connected ? "connected" : (
status == NodeStatus::Connecting ? "connecting" :
"disconnected");
}
struct OPENDHT_PUBLIC NodeStats {
unsigned good_nodes {0},
dubious_nodes {0},
cached_nodes {0},
incoming_nodes {0};
unsigned table_depth {0};
unsigned cachedNodes {0};
unsigned searches {0};
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
std::string toString() const;
@@ -73,34 +63,14 @@ struct OPENDHT_PUBLIC NodeStats {
explicit NodeStats(const Json::Value& v);
#endif
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth, searches)
};
struct OPENDHT_PUBLIC NodeMetrics {
size_t scheduler_size {0};
size_t node_cache_size {0};
size_t request_count {0};
size_t rate_limiter_size {0};
size_t reported_addr_num {0};
size_t store_size {0};
size_t store_values {0};
size_t store_quota_size {0};
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
#endif
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth)
};
struct OPENDHT_PUBLIC NodeInfo {
InfoHash id;
InfoHash node_id;
NodeStats ipv4 {};
NodeStats ipv6 {};
size_t ongoing_ops {0};
NodeMetrics metrics {};
NodeStats ipv4;
NodeStats ipv6;
#ifdef OPENDHT_JSONCPP
/**
@@ -136,19 +106,6 @@ struct OPENDHT_PUBLIC Config {
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
std::string persist_path {};
/** If non-0, overrides the default global rate-limit.-1 means no limit. */
ssize_t max_req_per_sec {0};
/** If non-0, overrides the default per-IP address rate-limit. -1 means no limit. */
ssize_t max_peer_req_per_sec {0};
/**
* Use appropriate bahavior for a public IP, stable node:
* - No connectivity change triggered when a search fails
* - Larger listen refresh time
*/
bool public_stable {false};
};
/**
@@ -158,12 +115,6 @@ struct OPENDHT_PUBLIC SecureDhtConfig
{
Config node_config {};
crypto::Identity id {};
/**
* Cache all encountered public keys and certificates,
* for use by the certificate store, putEncrypted and putSigned
*/
bool cert_cache_all {false};
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
+9 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -43,22 +43,16 @@ namespace dht {
namespace crypto {
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
public:
explicit CryptoException(const std::string& str) : std::runtime_error(str) {};
explicit CryptoException(const char* str) : std::runtime_error(str) {};
CryptoException(const CryptoException& e) noexcept = default;
CryptoException& operator=(const CryptoException&) noexcept = default;
public:
CryptoException(const std::string& str) : std::runtime_error(str) {};
};
/**
* Exception thrown when a decryption error happened.
*/
class OPENDHT_PUBLIC DecryptError : public CryptoException {
public:
explicit DecryptError(const std::string& str) : CryptoException(str) {};
explicit DecryptError(const char* str) : CryptoException(str) {};
DecryptError(const DecryptError& e) noexcept = default;
DecryptError& operator=(const DecryptError&) noexcept = default;
public:
DecryptError(const std::string& str = "") : CryptoException(str) {};
};
struct PrivateKey;
@@ -78,8 +72,7 @@ struct OPENDHT_PUBLIC PublicKey
* Takes ownership of an existing gnutls_pubkey.
*/
PublicKey(gnutls_pubkey_t k) : pk(k) {}
PublicKey(const uint8_t* dat, size_t dat_size);
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
PublicKey(const Blob& pk);
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
~PublicKey();
@@ -114,7 +107,6 @@ struct OPENDHT_PUBLIC PublicKey
}
void pack(Blob& b) const;
int pack(uint8_t* out, size_t* out_len) const;
void unpack(const uint8_t* dat, size_t dat_size);
std::string toString() const;
@@ -128,7 +120,7 @@ struct OPENDHT_PUBLIC PublicKey
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
gnutls_digest_algorithm_t getPreferredDigest() const;
@@ -161,7 +153,6 @@ struct OPENDHT_PUBLIC PrivateKey
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
/**
@@ -226,7 +217,7 @@ public:
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
void revoke(const Certificate& crt, time_point t = time_point::min());
@@ -424,7 +415,7 @@ struct OPENDHT_PUBLIC Certificate {
p.pack_bin_body((const char*)b.data(), b.size());
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
explicit operator bool() const { return cert; }
PublicKey getPublicKey() const;
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -189,7 +189,7 @@ public:
#endif
}
virtual void msgpack_unpack(const msgpack::object& o)
virtual void msgpack_unpack(msgpack::object o)
{
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size < 2) throw msgpack::type_error();
@@ -229,7 +229,7 @@ public:
pk.pack_bin_body((const char*)addr.get(), addr.getLength());
}
virtual void msgpack_unpack(const msgpack::object& o)
virtual void msgpack_unpack(msgpack::object o)
{
if (o.type == msgpack::type::BIN)
addr = {(sockaddr*)o.via.bin.ptr, (socklen_t)o.via.bin.size};
+9 -20
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -68,11 +68,7 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l = {});
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {})
: Dht(std::move(sock), config, std::make_shared<Logger>(l)) {}
Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l = {});
virtual ~Dht();
/**
@@ -123,9 +119,9 @@ public:
void pingNode(SockAddr, DoneCallbackSimple&& cb={}) override;
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) override;
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return periodic(buf, buflen, SockAddr(from, fromlen));
}
/**
@@ -273,7 +269,6 @@ public:
void loadState(const std::string& path);
NodeStats getNodesStats(sa_family_t af) const override;
NodeMetrics getNodeMetrics() const override;
std::string getStorageLog() const override;
std::string getStorageLog(const InfoHash&) const override;
@@ -342,10 +337,9 @@ private:
static constexpr std::chrono::minutes SEARCH_EXPIRE_TIME {62};
/* Timeout for listen */
static constexpr duration LISTEN_EXPIRE_TIME {std::chrono::seconds(30)};
static constexpr duration LISTEN_EXPIRE_TIME_PUBLIC {std::chrono::minutes(5)};
static constexpr std::chrono::seconds LISTEN_EXPIRE_TIME {30};
static constexpr duration REANNOUNCE_MARGIN {std::chrono::seconds(10)};
static constexpr std::chrono::seconds REANNOUNCE_MARGIN {10};
static constexpr size_t TOKEN_SIZE {32};
@@ -387,8 +381,6 @@ private:
std::map<size_t, std::tuple<size_t, size_t, size_t>> listeners {};
size_t listener_token {1};
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
// timing
Scheduler scheduler;
Sp<Scheduler::Job> nextNodesConfirmation {};
@@ -401,6 +393,8 @@ private:
using ReportedAddr = std::pair<unsigned, SockAddr>;
std::vector<ReportedAddr> reported_addr;
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
std::string persistPath;
// are we a bootstrap node ?
@@ -409,11 +403,6 @@ private:
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
const bool public_stable {false};
inline const duration& getListenExpiration() const {
return public_stable ? LISTEN_EXPIRE_TIME_PUBLIC : LISTEN_EXPIRE_TIME;
}
void rotateSecrets();
+12 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -30,8 +30,7 @@ namespace net {
class OPENDHT_PUBLIC DhtInterface {
public:
DhtInterface() = default;
DhtInterface(const Logger& l) : logger_(std::make_shared<Logger>(l)) {};
DhtInterface(const std::shared_ptr<Logger>& l) : logger_(l) {};
DhtInterface(const Logger& l) : DHT_LOG(l) {};
virtual ~DhtInterface() = default;
// [[deprecated]]
@@ -79,8 +78,8 @@ public:
virtual void pingNode(SockAddr, DoneCallbackSimple&& cb={}) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr, const time_point& now) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, SockAddr) = 0;
virtual time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) = 0;
/**
* Get a value by searching on all available protocols (IPv4, IPv6),
@@ -194,7 +193,6 @@ public:
virtual void importValues(const std::vector<ValuesExport>&) = 0;
virtual NodeStats getNodesStats(sa_family_t af) const = 0;
virtual NodeMetrics getNodeMetrics() const { return {}; }
virtual std::string getStorageLog() const = 0;
virtual std::string getStorageLog(const InfoHash&) const = 0;
@@ -223,23 +221,15 @@ public:
* Enable or disable logging of DHT internal messages
*/
virtual void setLoggers(LogMethod error = {}, LogMethod warn = {}, LogMethod debug = {}) {
if (logger_) {
logger_->DBG = std::move(debug);
logger_->WARN = std::move(warn);
logger_->ERR = std::move(error);
} else
logger_= std::make_shared<Logger>(std::move(error), std::move(warn), std::move(debug));
DHT_LOG.DBG = debug;
DHT_LOG.WARN = warn;
DHT_LOG.ERR = error;
}
virtual void setLogger(const Logger& l) {
if (logger_)
*logger_ = l;
else
logger_= std::make_shared<Logger>(l);
}
virtual void setLogger(const std::shared_ptr<Logger>& l) {
logger_ = l;
DHT_LOG.DBG = l.DBG;
DHT_LOG.WARN = l.WARN;
DHT_LOG.ERR = l.ERR;
}
/**
@@ -247,8 +237,7 @@ public:
*/
virtual void setLogFilter(const InfoHash& f)
{
if (logger_)
logger_->setFilter(f);
DHT_LOG.setFilter(f);
}
virtual void setPushNotificationToken(const std::string&) {};
@@ -260,7 +249,7 @@ public:
virtual void pushNotificationReceived(const std::map<std::string, std::string>& data) = 0;
protected:
std::shared_ptr<Logger> logger_ {};
Logger DHT_LOG;
};
} // namespace dht
+36 -36
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -53,9 +53,9 @@ public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
const std::string& pushClientId = "", std::shared_ptr<dht::Logger> logger = {});
void setHeaderFields(http::Request& request);
@@ -197,9 +197,9 @@ public:
*/
void pushNotificationReceived(const std::map<std::string, std::string>& notification) override;
time_point periodic(const uint8_t*, size_t, SockAddr, const time_point& now) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return periodic(buf, buflen, SockAddr(from, fromlen), now);
time_point periodic(const uint8_t*, size_t, SockAddr) override;
time_point periodic(const uint8_t* buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return periodic(buf, buflen, SockAddr(from, fromlen));
}
/**
@@ -285,7 +285,9 @@ private:
*/
struct InfoState;
void getProxyInfos();
void queryProxyInfo(const std::shared_ptr<InfoState>& infoState, const std::shared_ptr<http::Resolver>& resolver, sa_family_t family);
void handleProxyStatus(const asio::error_code &ec, std::shared_ptr<InfoState> infoState);
void queryProxyInfo(std::shared_ptr<InfoState> infoState, const sa_family_t family,
std::vector<asio::ip::tcp::endpoint>&& endpoints);
void onProxyInfos(const Json::Value& val, const sa_family_t family);
SockAddr parsePublicAddress(const Json::Value& val);
@@ -300,18 +302,17 @@ private:
SUBSCRIBE,
RESUBSCRIBE,
};
using CacheValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired, system_clock::time_point)>;
/**
* Send Listen with httpClient_
*/
void sendListen(const restinio::http_request_header_t& header, const CacheValueCallback& cb,
void sendListen(const restinio::http_request_header_t header, const ValueCallback& cb,
const Sp<OperationState>& opstate, Listener& listener, ListenMethod method = ListenMethod::LISTEN);
void handleResubscribe(const asio::error_code& ec, const InfoHash& key,
const size_t token, std::shared_ptr<OperationState> opstate);
void doPut(const InfoHash&, Sp<Value>, DoneCallbackSimple, time_point created, bool permanent);
void handleRefreshPut(const asio::error_code& ec, InfoHash key, Value::Id id);
void doPut(const InfoHash&, Sp<Value>, DoneCallback, time_point created, bool permanent);
void handleRefreshPut(const asio::error_code& ec, const InfoHash& key, const Value::Id id,
std::shared_ptr<std::atomic_bool> ok);
/**
* Initialize statusIpvX_
@@ -321,15 +322,27 @@ private:
* cancel all Listeners
*/
void cancelAllListeners();
/**
* cancel all Operations
*/
void cancelAllOperations();
std::atomic_bool isDestroying_ {false};
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
//std::pair<std::string, std::string> serverHostService_;
std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
std::string pushSessionId_;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
mutable std::mutex lockCurrentProxyInfos_;
NodeStatus statusIpv4_ {NodeStatus::Disconnected};
@@ -344,36 +357,24 @@ private:
// registred types
TypeStore types;
/*
* ASIO I/O Context for sockets in httpClient_
* Note: Each context is used in one thread only
*/
asio::io_context httpContext_;
std::shared_ptr<http::Resolver> resolver_;
mutable std::mutex requestLock_;
std::map<unsigned, std::shared_ptr<http::Request>> requests_;
/*
* Thread for executing the http io_context.run() blocking call
*/
std::thread httpClientThread_;
/**
* Store listen requests.
*/
struct ProxySearch;
mutable std::mutex searchLock_;
size_t listenerToken_ {0};
std::map<InfoHash, ProxySearch> searches_;
mutable std::mutex searchLock_;
/**
* Callbacks should be executed in the main thread.
*/
std::mutex lockCallbacks_;
std::vector<std::function<void()>> callbacks_;
std::mutex lockCallbacks_;
Sp<InfoState> infoState_;
Sp<asio::steady_timer> statusTimer_;
mutable std::mutex statusLock_;
/**
* Retrieve if we can connect to the proxy (update statusIpvX_)
@@ -406,10 +407,9 @@ private:
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
Json::StreamWriterBuilder jsonBuilder_;
std::unique_ptr<Json::CharReader> jsonReader_;
std::atomic_bool isDestroying_ {false};
std::shared_ptr<http::Request> buildRequest(const std::string& target = {});
std::shared_ptr<dht::Logger> logger_;
};
}
+33 -39
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -31,7 +31,10 @@
#include <restinio/all.hpp>
#include <restinio/tls.hpp>
#ifdef OPENDHT_JSONCPP
#include <json/json.h>
#endif
#include <memory>
#include <mutex>
@@ -51,6 +54,8 @@ class DhtRunner;
using RestRouter = restinio::router::express_router_t<>;
using RequestStatus = restinio::request_handling_status_t;
using ResponseByParts = restinio::chunked_output_t;
using ResponseByPartsBuilder = restinio::response_builder_t<ResponseByParts>;
/**
* Describes the REST API
@@ -82,31 +87,33 @@ public:
struct ServerStats {
/** Current number of listen operations */
size_t listenCount {0};
size_t listenCount;
/** Current number of permanent put operations */
size_t putCount {0};
size_t putCount;
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount {0};
size_t pushListenersCount;
/** Average requests per second */
double requestRate {0};
double requestRate;
/** Node Info **/
std::shared_ptr<NodeInfo> nodeInfo {};
NodeInfo nodeInfo;
std::string toString() const {
std::ostringstream ss;
ss << "Listens: " << listenCount << " Puts: " << putCount << " PushListeners: " << pushListenersCount << std::endl;
ss << "Requests: " << requestRate << " per second." << std::endl;
if (nodeInfo) {
auto& ipv4 = nodeInfo->ipv4;
if (ipv4.table_depth > 1)
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
auto& ni = nodeInfo;
auto& ipv4 = ni.ipv4;
if (ipv4.table_depth > 1) {
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
}
auto& ipv6 = ni.ipv6;
if (ipv6.table_depth > 1) {
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
}
return ss.str();
}
#ifdef OPENDHT_JSONCPP
/**
* Build a json object from a NodeStats
*/
@@ -116,15 +123,15 @@ public:
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
result["nodeInfo"] = nodeInfo.toJson();
return result;
}
#endif
};
std::shared_ptr<ServerStats> stats() const { return stats_; }
ServerStats stats() const { return stats_; }
std::shared_ptr<ServerStats> updateStats(std::shared_ptr<NodeInfo> info) const;
void updateStats() const;
std::shared_ptr<DhtRunner> getNode() const { return dht_; }
@@ -134,8 +141,7 @@ private:
struct RestRouterTraits;
template <typename HttpResponse>
static HttpResponse initHttpResponse(HttpResponse response);
static restinio::request_handling_status_t serverError(restinio::request_t& request);
HttpResponse initHttpResponse(HttpResponse response) const;
template< typename ServerSettings >
void addServerSettings(ServerSettings& serverSettings,
@@ -143,8 +149,6 @@ private:
std::unique_ptr<RestRouter> createRestRouter();
void onConnectionClosed(restinio::connection_id_t);
/**
* Return the PublicKey id, the node id and node stats
* Method: GET "/"
@@ -282,7 +286,7 @@ private:
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid, bool highPriority);
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid);
/**
* Send push notification with an expire timeout.
@@ -292,7 +296,7 @@ private:
* @param isAndroid
*/
void handleNotifyPushListenExpire(const asio::error_code &ec, const std::string pushToken,
std::function<Json::Value()> json, const bool isAndroid);
Json::Value json, const bool isAndroid);
/**
* Remove a push listener between a client and a hash
@@ -307,15 +311,12 @@ private:
#endif //OPENDHT_PUSH_NOTIFICATIONS
void handlePrintStats(const asio::error_code &ec);
void updateStats();
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
std::shared_ptr<asio::io_context> ioContext_;
std::shared_ptr<DhtRunner> dht_;
Json::StreamWriterBuilder jsonBuilder_;
Json::CharReaderBuilder jsonReaderBuilder_;
// http server
std::thread serverThread_;
@@ -324,35 +325,29 @@ private:
// http client
std::pair<std::string, std::string> pushHostPort_;
mutable std::mutex requestLock_;
std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_;
std::shared_ptr<dht::Logger> logger_;
std::shared_ptr<ServerStats> stats_;
std::shared_ptr<NodeInfo> nodeInfo_ {};
mutable std::mutex statsMutex_;
mutable ServerStats stats_;
mutable NodeInfo nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
// Thread-safe access to listeners map.
std::mutex lockListener_;
std::shared_ptr<std::mutex> lockListener_;
// Shared with connection listener.
std::map<restinio::connection_id_t, http::ListenerSession> listeners_;
std::shared_ptr<std::map<restinio::connection_id_t,
http::ListenerSession>> listeners_;
// Connection Listener observing conn state changes.
std::shared_ptr<ConnectionListener> connListener_;
struct PushSessionContext {
std::mutex lock;
std::string sessionId;
};
struct PermanentPut {
time_point expiration;
std::string pushToken;
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
Sp<Value> value;
};
struct SearchPuts {
std::map<dht::Value::Id, PermanentPut> puts;
@@ -368,7 +363,6 @@ private:
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener {
std::string clientId;
std::shared_ptr<PushSessionContext> sessionCtx;
std::future<size_t> internalToken;
std::unique_ptr<asio::steady_timer> expireTimer;
std::unique_ptr<asio::steady_timer> expireNotifyTimer;
+25 -42
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -230,30 +230,29 @@ public:
}
void put(const std::string& key, Value&& value, DoneCallbackSimple cb={}, time_point created=time_point::max(), bool permanent = false);
void cancelPut(const InfoHash& h, Value::Id id);
void cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value);
void cancelPut(const InfoHash& h, const Value::Id& id);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, value, bindDoneCb(cb), permanent);
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb={});
void putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putSigned(hash, value, bindDoneCb(cb));
}
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={}, bool permanent = false);
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb), permanent);
void putSigned(InfoHash hash, Value&& value, DoneCallback cb={});
void putSigned(InfoHash hash, Value&& value, DoneCallbackSimple cb) {
putSigned(hash, std::forward<Value>(value), bindDoneCb(cb));
}
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={}, bool permanent = false);
void putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb={});
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallbackSimple cb) {
putEncrypted(hash, to, value, bindDoneCb(cb));
}
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb={});
void putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallbackSimple cb) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb));
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
/**
* Insert known nodes to the routing table, without necessarly ping them.
@@ -317,7 +316,9 @@ public:
* Returns the currently bound port, in host byte order.
* @param f: address family of the bound port to retreive.
*/
in_port_t getBoundPort(sa_family_t f = AF_INET) const;
in_port_t getBoundPort(sa_family_t f = AF_INET) const {
return getBound(f).getPort();
}
std::pair<size_t, size_t> getStoreSize() const;
@@ -327,10 +328,7 @@ public:
std::vector<ValuesExport> exportValues() const;
void setLogger(const Sp<Logger>& logger = {});
void setLogger(const Logger& logger) {
setLogger(std::make_shared<Logger>(logger));
}
void setLogger(const Logger& logger = {});
void setLoggers(LogMethod err = {}, LogMethod warn = {}, LogMethod debug = {});
/**
@@ -343,13 +341,12 @@ public:
void importValues(const std::vector<ValuesExport>& values);
bool isRunning() const {
return running != State::Idle;
return running;
}
NodeStats getNodesStats(sa_family_t af) const;
unsigned getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const;
NodeInfo getNodeInfo() const;
void getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)>);
std::vector<unsigned> getNodeMessageStats(bool in = false) const;
std::string getStorageLog() const;
@@ -362,7 +359,7 @@ public:
// securedht methods
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)>);
void findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)>);
void registerCertificate(std::shared_ptr<crypto::Certificate> cert);
void setLocalCertificateStore(CertificateStoreQuery&& query_method);
@@ -415,7 +412,7 @@ public:
/**
* Gracefuly disconnect from network.
*/
void shutdown(ShutdownCallback cb = {});
void shutdown(ShutdownCallback cb);
/**
* Quit and wait for all threads to terminate.
@@ -453,12 +450,6 @@ public:
private:
static constexpr std::chrono::seconds BOOTSTRAP_PERIOD {10};
enum class State {
Idle,
Running,
Stopping
};
/**
* Will try to resolve the list of hostnames `bootstrap_nodes` on seperate
* thread and then queue ping requests. This list should contain reliable
@@ -473,11 +464,6 @@ private:
return std::max(status4, status6);
}
bool checkShutdown();
void opEnded();
DoneCallback bindOpDoneCallback(DoneCallback&& cb);
DoneCallbackSimple bindOpDoneCallback(DoneCallbackSimple&& cb);
/** Local DHT instance */
std::unique_ptr<SecureDht> dht_;
@@ -510,8 +496,7 @@ private:
std::thread dht_thread {};
std::condition_variable cv {};
std::mutex sock_mtx {};
net::PacketList rcv {};
decltype(rcv) rcv_free {};
std::queue<std::unique_ptr<net::ReceivedPacket>> rcv {};
/** true if currently actively boostraping */
std::atomic_bool bootstraping {false};
@@ -526,9 +511,7 @@ private:
std::queue<std::function<void(SecureDht&)>> pending_ops {};
std::mutex storage_mtx {};
std::atomic<State> running {State::Idle};
std::atomic_size_t ongoing_ops {0};
std::vector<ShutdownCallback> shutdownCallbacks_;
std::atomic_bool running {false};
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
+40 -70
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,6 @@
#include <memory>
#include <queue>
#include <mutex>
namespace Json {
class Value;
@@ -62,7 +61,7 @@ struct Certificate;
namespace http {
using HandlerCb = std::function<void(const asio::error_code& ec)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, size_t bytes)>;
using BytesHandlerCb = std::function<void(const asio::error_code& ec, const size_t bytes)>;
using ConnectHandlerCb = std::function<void(const asio::error_code& ec,
const asio::ip::tcp::endpoint& endpoint)>;
@@ -83,7 +82,7 @@ public:
std::string fragment;
};
class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection>
class OPENDHT_PUBLIC Connection
{
public:
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<dht::Logger> l = {});
@@ -91,42 +90,30 @@ public:
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l = {});
~Connection();
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
unsigned int id();
bool is_open();
bool is_ssl();
void set_ssl_verification(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode);
asio::streambuf& input();
std::istream& data() { return istream_; }
asio::streambuf& data();
std::string read_bytes(size_t bytes = 0);
std::string read_bytes(const size_t bytes);
std::string read_until(const char delim);
void async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb);
void async_handshake(HandlerCb cb);
void async_write(BytesHandlerCb cb);
void async_read_until(const char* delim, BytesHandlerCb cb);
void async_read_until(char delim, BytesHandlerCb cb);
void async_read(size_t bytes, BytesHandlerCb cb);
void async_read_some(size_t bytes, BytesHandlerCb cb);
void async_read(const size_t bytes, BytesHandlerCb cb);
void timeout(const std::chrono::seconds timeout, HandlerCb cb = {});
void close();
private:
template<typename T>
T wrapCallabck(T cb) const {
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
cb(params...);
};
}
mutable std::mutex mutex_;
unsigned int id_;
static std::atomic_uint ids_;
static unsigned int ids_;
asio::io_context& ctx_;
std::unique_ptr<socket_t> socket_;
@@ -137,7 +124,6 @@ private:
asio::streambuf write_buf_;
asio::streambuf read_buf_;
std::istream istream_;
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
@@ -161,7 +147,7 @@ class OPENDHT_PUBLIC Resolver
{
public:
using ResolverCb = std::function<void(const asio::error_code& ec,
const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
std::vector<asio::ip::tcp::endpoint> endpoints)>;
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service,
@@ -170,25 +156,19 @@ public:
// use already resolved endpoints with classes using this resolver
Resolver(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint> endpoints,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Resolver(asio::io_context& ctx, const std::string& url, std::vector<asio::ip::tcp::endpoint> endpoints,
std::shared_ptr<dht::Logger> logger = {});
~Resolver();
inline const Url& get_url() const {
return url_;
}
};
void add_callback(ResolverCb cb, sa_family_t family = AF_UNSPEC);
std::shared_ptr<Logger> getLogger() const {
return logger_;
}
void add_callback(ResolverCb cb);
private:
void resolve(const std::string& host, const std::string& service);
mutable std::mutex mutex_;
std::mutex mutex_;
Url url_;
asio::error_code ec_;
@@ -202,18 +182,14 @@ private:
std::shared_ptr<dht::Logger> logger_;
};
class Request;
struct Response
{
unsigned status_code {0};
unsigned int status_code;
std::map<std::string, std::string> headers;
std::string body;
bool aborted {false};
std::weak_ptr<Request> request;
};
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
class OPENDHT_PUBLIC Request
{
public:
enum class State {
@@ -223,11 +199,10 @@ public:
RECEIVING,
DONE
};
using OnStatusCb = std::function<void(unsigned status_code)>;
using OnStatusCb = std::function<void(unsigned int status_code)>;
using OnDataCb = std::function<void(const char* at, size_t length)>;
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned status_code)>;
using OnDoneCb = std::function<void(const Response& response)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned int status_code)>;
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
@@ -235,11 +210,9 @@ public:
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger = {});
// user defined resolver
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, const std::string& target, sa_family_t family = AF_UNSPEC);
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, std::shared_ptr<dht::Logger> logger = {});
// user defined resolved endpoints
Request(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint>&& endpoints,
@@ -247,18 +220,12 @@ public:
~Request();
inline unsigned int id() const { return id_; };
unsigned int id() const;
void set_connection(std::shared_ptr<Connection> connection);
std::shared_ptr<Connection> get_connection() const;
inline const Url& get_url() const {
return resolver_->get_url();
};
/** The previous request in case of redirect following */
std::shared_ptr<Request> getPrevious() const {
return prev_.lock();
}
inline std::string& to_string() {
return request_;
}
@@ -281,7 +248,6 @@ public:
void add_on_status_callback(OnStatusCb cb);
void add_on_body_callback(OnDataCb cb);
void add_on_state_change_callback(OnStateChangeCb cb);
void add_on_done_callback(OnDoneCb cb);
void send();
@@ -294,14 +260,19 @@ private:
using OnCompleteCb = std::function<void()>;
struct Callbacks {
Callbacks(){}
OnStatusCb on_status;
OnDataCb on_header_field;
OnDataCb on_header_value;
OnDataCb on_body;
OnCompleteCb on_headers_complete;
OnCompleteCb on_message_complete;
OnStateChangeCb on_state_change;
};
void notify_state_change(State state);
void notify_state_change(const State state);
void build();
@@ -318,22 +289,25 @@ private:
void post();
void handle_request(const asio::error_code& ec);
void handle_response(const asio::error_code& ec, size_t bytes);
void onHeadersComplete();
void onBody(const char* at, size_t length);
void onComplete();
void handle_response_header(const asio::error_code& ec);
mutable std::mutex mutex_;
void handle_response_body(const asio::error_code& ec, const size_t bytes);
std::shared_ptr<dht::Logger> logger_;
/**
* Parse the request with http_parser.
* Return how many bytes were parsed.
* Note: we pass requerst.size()==0 to signal that EOF has been received.
*/
size_t parse_request(const std::string& request);
restinio::http_request_header_t header_;
std::map<restinio::http_field_t, std::string> headers_;
restinio::http_connection_header_t connection_type_ {restinio::http_connection_header_t::close};
restinio::http_connection_header_t connection_type_;
std::string body_;
Callbacks cbs_;
std::mutex cbs_mutex_;
std::unique_ptr<Callbacks> cbs_;
State state_;
dht::crypto::Identity client_identity_;
@@ -342,23 +316,19 @@ private:
std::string host_;
unsigned int id_;
static std::atomic_uint ids_;
static unsigned int ids_;
asio::io_context& ctx_;
sa_family_t family_ = AF_UNSPEC;
std::shared_ptr<Connection> conn_;
std::shared_ptr<Resolver> resolver_;
Response response_ {};
std::string request_;
std::atomic<bool> message_complete_ {false};
std::atomic<bool> finishing_ {false};
std::unique_ptr<http_parser> parser_;
std::unique_ptr<http_parser_settings> parser_s_;
// Next request in case of redirect following
std::shared_ptr<Request> next_;
std::weak_ptr<Request> prev_;
unsigned num_redirect {0};
bool follow_redirect {true};
std::shared_ptr<dht::Logger> logger_;
};
} // namespace http
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -71,13 +71,13 @@ OPENDHT_PUBLIC void
printLog(std::ostream &s, char const *m, va_list args);
OPENDHT_PUBLIC
std::shared_ptr<Logger> getStdLogger();
std::unique_ptr<Logger> getStdLogger();
OPENDHT_PUBLIC
std::shared_ptr<Logger> getFileLogger(const std::string &path);
std::unique_ptr<Logger> getFileLogger(const std::string &path);
OPENDHT_PUBLIC
std::shared_ptr<Logger> getSyslogLogger(const char* name);
std::unique_ptr<Logger> getSyslogLogger(const char* name);
OPENDHT_PUBLIC void
enableLogging(dht::DhtRunner &dht);
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -64,7 +64,7 @@ struct LogMethod {
func(format, args);
va_end(args);
}
inline void log(char const* format, va_list args) const {
void log(char const* format, va_list args) const {
func(format, args);
}
explicit operator bool() const {
+17 -46
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -48,12 +48,6 @@ struct TransId;
#define MSG_CONFIRM 0
#endif
struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
};
class DhtProtocolException : public DhtException {
public:
// sent to another peer (http-like).
@@ -212,14 +206,8 @@ public:
using RequestCb = std::function<void(const Request&, RequestAnswer&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(
InfoHash& myid,
NetworkConfig config,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
std::mt19937_64& rd,
Scheduler& scheduler,
NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
@@ -275,8 +263,7 @@ public:
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
sendPing(Sp<Node> n, RequestCb&& on_done, RequestExpiredCb&& on_expired);
/**
* Send a "ping" request to a given node.
*
@@ -288,12 +275,11 @@ public:
* @return the request with information concerning its success.
*/
Sp<Request>
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa), rd),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa)),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
/**
* Send a "find node" request to a given node.
*
@@ -432,21 +418,6 @@ public:
return cache.getCachedNodes(id, sa_f, count);
}
size_t getNodeCacheSize() const {
return cache.size();
}
size_t getNodeCacheSize(sa_family_t af) const {
return cache.size(af);
}
size_t getRateLimiterSize() const {
return address_rate_limiter.size();
}
size_t getPartialCount() const {
return partial_messages.size();
}
private:
struct PartialMessage;
@@ -454,6 +425,7 @@ private:
/***************
* Constants *
***************/
static constexpr size_t MAX_REQUESTS_PER_SEC {1600};
/* the length of a node info buffer in ipv4 format */
static const constexpr size_t NODE4_INFO_BUF_LEN {HASH_LEN + sizeof(in_addr) + sizeof(in_port_t)};
/* the length of a node info buffer in ipv6 format */
@@ -541,19 +513,18 @@ private:
/* DHT info */
const InfoHash& myid;
const NetworkConfig config {};
const NetId network {0};
const std::unique_ptr<DatagramSocket> dht_socket;
Sp<Logger> logger_;
std::mt19937_64& rd;
const Logger& DHT_LOG;
NodeCache cache;
NodeCache cache {};
// global limiting should be triggered by at least 8 different IPs
using IpLimiter = RateLimiter;
using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>;
using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>;
IpLimiterMap address_rate_limiter;
RateLimiter rate_limiter;
ssize_t limiter_maintenance {0};
IpLimiterMap address_rate_limiter {};
RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {};
size_t limiter_maintenance {0};
// requests handling
std::map<Tid, Sp<Request>> requests {};
+14 -50
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -35,15 +35,12 @@
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#include <list>
#include <iostream>
namespace dht {
namespace net {
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
static const constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static const constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(650);
int bindSocket(const SockAddr& addr, SockAddr& bound);
@@ -57,88 +54,55 @@ struct ReceivedPacket {
SockAddr from;
time_point received;
};
using PacketList = std::list<ReceivedPacket>;
class OPENDHT_PUBLIC DatagramSocket {
public:
using OnReceive = std::function<PacketList(PacketList&& packets)>;
using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>;
virtual ~DatagramSocket() {};
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
inline void setOnReceive(OnReceive&& cb) {
std::lock_guard<std::mutex> lk(lock);
rx_callback = std::move(cb);
}
virtual const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const = 0;
virtual bool hasIPv4() const = 0;
virtual bool hasIPv6() const = 0;
SockAddr getBound(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family);
}
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
std::lock_guard<std::mutex> lk(lock);
return getBoundRef(family).getPort();
return getBound(family).getPort();
}
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
virtual void stop() = 0;
protected:
PacketList getNewPacket() {
PacketList pkts;
if (toRecycle_.empty()) {
pkts.emplace_back();
} else {
auto begIt = toRecycle_.begin();
auto begItNext = std::next(begIt);
pkts.splice(pkts.end(), toRecycle_, begIt, begItNext);
}
return pkts;
inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) {
if (rx_callback)
rx_callback(std::move(packet));
}
inline void onReceived(PacketList&& packets) {
std::lock_guard<std::mutex> lk(lock);
if (rx_callback) {
auto r = rx_callback(std::move(packets));
if (not r.empty() and toRecycle_.size() < RX_QUEUE_MAX_SIZE)
toRecycle_.splice(toRecycle_.end(), std::move(r));
}
}
protected:
mutable std::mutex lock;
private:
OnReceive rx_callback;
PacketList toRecycle_;
};
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
public:
UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l = {});
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l = {});
UdpSocket(in_port_t port, const Logger& l = {});
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l = {});
~UdpSocket();
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override {
const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const override {
return (family == AF_INET6) ? bound6 : bound4;
}
bool hasIPv4() const override {
std::lock_guard<std::mutex> lk(lock);
return s4 != -1;
}
bool hasIPv6() const override {
std::lock_guard<std::mutex> lk(lock);
return s6 != -1;
}
bool hasIPv4() const override { return s4 != -1; }
bool hasIPv6() const override { return s6 != -1; }
void stop() override;
private:
std::shared_ptr<Logger> logger;
Logger logger;
int s4 {-1};
int s6 {-1};
int stopfd {-1};
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -47,10 +47,10 @@ struct Socket {
struct Node {
const InfoHash id;
Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client=false);
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen, std::mt19937_64& rd)
: Node(id, SockAddr(sa, salen), rd) {}
Node(const InfoHash& id, const SockAddr& addr, bool client=false);
Node(const InfoHash& id, SockAddr&& addr, bool client=false);
Node(const InfoHash& id, const sockaddr* sa, socklen_t salen)
: Node(id, SockAddr(sa, salen)) {}
InfoHash getId() const {
return id;
+2 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,13 +26,6 @@
namespace dht {
struct NodeCache {
size_t size(sa_family_t family) const {
return cache(family).count();
}
size_t size() const {
return size(AF_INET) + size(AF_INET6);
}
Sp<Node> getNode(const InfoHash& id, sa_family_t family);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client=false);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const;
@@ -44,19 +37,17 @@ struct NodeCache {
*/
void clearBadNodes(sa_family_t family = 0);
NodeCache(std::mt19937_64& r) : rd(r) {};
~NodeCache();
private:
class NodeMap : private std::map<InfoHash, std::weak_ptr<Node>> {
public:
Sp<Node> getNode(const InfoHash& id);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client, std::mt19937_64& rd);
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client);
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, size_t count) const;
void clearBadNodes();
void setExpired();
void cleanup();
size_t count() const { return size(); }
private:
size_t cleanup_counter {0};
};
@@ -65,7 +56,6 @@ private:
NodeMap& cache(sa_family_t af) { return af == AF_INET ? cache_4 : cache_6; }
NodeMap cache_4;
NodeMap cache_6;
std::mt19937_64& rd;
};
}
+14 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
*
@@ -22,13 +22,10 @@
#include "def.h"
#include "sockaddr.h"
#include "infohash.h"
#include "log_enable.h"
#include <thread>
namespace asio {
class io_context;
}
#include <mutex>
#include <condition_variable>
namespace dht {
@@ -38,7 +35,7 @@ public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object&&, SockAddr&&)>;
PeerDiscovery(in_port_t port = DEFAULT_PORT, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
PeerDiscovery(in_port_t port = DEFAULT_PORT);
~PeerDiscovery();
/**
@@ -54,7 +51,7 @@ public:
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
@@ -82,14 +79,20 @@ public:
bool stopPublish(const std::string &type);
bool stopPublish(sa_family_t domain, const std::string &type);
void connectivityChanged();
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery6_;
std::shared_ptr<asio::io_context> ioContext_;
std::thread ioRunnner_;
};
}
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,8 @@
namespace dht {
namespace proxy {
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const std::chrono::seconds OP_TIMEOUT {1 * 60 * 60}; // one hour
constexpr const std::chrono::seconds OP_MARGIN {5 * 60}; // 5 minutes
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
+4 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -23,23 +23,19 @@
namespace dht {
template<size_t Quota, unsigned long Period=1>
class RateLimiter {
public:
RateLimiter(size_t quota, const duration& period = std::chrono::seconds(1))
: quota_(quota), period_(period) {}
/** Clear outdated records and return current quota usage */
size_t maintain(const time_point& now) {
auto limit = now - period_;
auto limit = now - std::chrono::seconds(Period);
while (not records.empty() and records.front() < limit)
records.pop();
return records.size();
}
/** Return false if quota is reached, insert record and return true otherwise. */
bool limit(const time_point& now) {
if (quota_ == std::numeric_limits<size_t>::max())
return true;
if (maintain(now) >= quota_)
if (maintain(now) >= Quota)
return false;
records.emplace(now);
return true;
@@ -48,8 +44,6 @@ public:
return records.empty();
}
private:
const size_t quota_;
const duration period_;
std::queue<time_point> records {};
};
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -39,7 +39,7 @@ struct Bucket {
Sp<Node> cached; /* the address of a likely candidate */
/** Return a random node in a bucket. */
Sp<Node> randomNode(std::mt19937_64& rd);
Sp<Node> randomNode();
void sendCachedPing(net::NetworkEngine& ne);
void connectivityChanged() {
@@ -89,7 +89,7 @@ public:
/**
* Return a random id in the bucket's range.
*/
InfoHash randomId(const RoutingTable::const_iterator& bucket, std::mt19937_64& rd) const;
InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
unsigned depth(const RoutingTable::const_iterator& bucket) const;
+2 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -84,6 +84,7 @@ public:
* @return The time for the next job to run.
*/
time_point run() {
syncTime();
while (not timers.empty()) {
auto timer = timers.begin();
/*
@@ -113,9 +114,6 @@ public:
*/
inline const time_point& time() const { return now; }
inline time_point syncTime() { return (now = clock::now()); }
inline void syncTime(const time_point& n) { now = n; }
inline size_t size() const { return timers.size(); }
private:
time_point now {clock::now()};
+6 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -180,9 +180,6 @@ public:
NodeStats getNodesStats(sa_family_t af) const override {
return dht_->getNodesStats(af);
}
NodeMetrics getNodeMetrics() const override {
return dht_->getNodeMetrics();
}
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
return dht_->getNodeMessageStats(in);
}
@@ -198,11 +195,11 @@ public:
std::vector<SockAddr> getPublicAddress(sa_family_t family = 0) override {
return dht_->getPublicAddress(family);
}
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa, const time_point& now) override {
return dht_->periodic(buf, buflen, std::move(sa), now);
time_point periodic(const uint8_t *buf, size_t buflen, SockAddr sa) override {
return dht_->periodic(buf, buflen, std::move(sa));
}
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen, const time_point& now) override {
return dht_->periodic(buf, buflen, from, fromlen, now);
time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) override {
return dht_->periodic(buf, buflen, from, fromlen);
}
NodeStatus getStatus(sa_family_t af) const override {
return dht_->getStatus(af);
@@ -319,16 +316,11 @@ public:
dht_->setLogger(logger);
}
void setLogger(const std::shared_ptr<Logger>& logger) override {
DhtInterface::setLogger(logger);
dht_->setLogger(logger);
}
/**
* Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
*/
void setLogFilter(const InfoHash& f) override {
DhtInterface::setLogFilter(f);
DHT_LOG.setFilter(f);
dht_->setLogFilter(f);
}
@@ -353,7 +345,6 @@ private:
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
};
const ValueType CERTIFICATE_TYPE = {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+4 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -43,15 +43,9 @@ public:
template<class T>
std::future<T> get(std::function<T()>&& cb) {
auto ret = std::make_shared<std::promise<T>>();
run([cb = std::move(cb), ret]() mutable {
try {
ret->set_value(cb());
} catch (...) {
try {
ret->set_exception(std::current_exception());
} catch(...) {}
}
});
run(std::bind([=](std::function<T()>& mcb) mutable {
ret->set_value(mcb());
}, std::move(cb)));
return ret->get_future();
}
template<class T>
+6 -28
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -77,20 +77,12 @@ public:
// Time related definitions and utility functions
using clock = std::chrono::steady_clock;
using system_clock = std::chrono::system_clock;
using time_point = clock::time_point;
using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
@@ -107,27 +99,14 @@ print_duration(DT d) {
return "-" + print_duration(-d);
}
if (d < std::chrono::milliseconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
} else if (d < std::chrono::seconds(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else if (d < std::chrono::minutes(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
} else if (d < std::chrono::hours(1)) {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
return std::to_string(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else {
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
return std::to_string(print_dt(d)) + " s";
}
}
template <class TimePoint>
static std::string
print_time_relative(TimePoint now, TimePoint d) {
if (d == TimePoint::min()) return "never";
if (d == now) return "now";
return (d > now) ? std::string("in ") + print_duration(d - now)
: print_duration(now - d) + std::string(" ago");
}
template <typename Duration = duration>
class uniform_duration_distribution : public std::uniform_int_distribution<typename Duration::rep> {
using Base = std::uniform_int_distribution<typename Duration::rep>;
@@ -154,7 +133,7 @@ using Blob = std::vector<uint8_t>;
/**
* Provides backward compatibility with msgpack 1.0
*/
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object& o);
OPENDHT_PUBLIC Blob unpackBlob(msgpack::object& o);
template <typename Type>
Blob
@@ -174,7 +153,6 @@ unpackMsg(Blob b) {
msgpack::unpacked unpackMsg(Blob b);
msgpack::object* findMapValue(const msgpack::object& map, const char* key);
msgpack::object* findMapValue(const msgpack::object& map, const std::string& key);
msgpack::object* findMapValue(msgpack::object& map, const std::string& key);
} // namespace dht
+25 -62
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -43,19 +43,6 @@
namespace dht {
static const std::string VALUE_KEY_ID("id");
static const std::string VALUE_KEY_DAT("dat");
static const std::string VALUE_KEY_PRIO("p");
static const std::string VALUE_KEY_SIGNATURE("sig");
static const std::string VALUE_KEY_SEQ("seq");
static const std::string VALUE_KEY_DATA("data");
static const std::string VALUE_KEY_OWNER("owner");
static const std::string VALUE_KEY_TYPE("type");
static const std::string VALUE_KEY_TO("to");
static const std::string VALUE_KEY_BODY("body");
static const std::string VALUE_KEY_USERTYPE("utype");
struct Value;
struct Query;
@@ -180,7 +167,7 @@ struct OPENDHT_PUBLIC Value
static Filter chain(Filter&& f1, Filter&& f2) {
if (not f1) return std::move(f2);
if (not f2) return std::move(f1);
return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
return [f1,f2](const Value& v) {
return f1(v) and f2(v);
};
}
@@ -193,12 +180,12 @@ struct OPENDHT_PUBLIC Value
}
static Filter chainAll(std::vector<Filter>&& set) {
if (set.empty()) return {};
return [set = std::move(set)](const Value& v) {
for (const auto& f : set)
return std::bind([](const Value& v, std::vector<Filter>& s) {
for (const auto& f : s)
if (f and not f(v))
return false;
return true;
};
}, std::placeholders::_1, std::move(set));
}
static Filter chain(std::initializer_list<Filter> l) {
return chainAll(std::vector<Filter>(l.begin(), l.end()));
@@ -403,7 +390,7 @@ struct OPENDHT_PUBLIC Value
* Build a value from a json object
* @param json
*/
Value(const Json::Value& json);
Value(Json::Value& json);
#endif
template <typename Type>
@@ -421,9 +408,7 @@ struct OPENDHT_PUBLIC Value
Value(Value&& o) noexcept
: id(o.id), owner(std::move(o.owner)), recipient(o.recipient),
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq)
, signature(std::move(o.signature)), cypher(std::move(o.cypher))
, priority(o.priority) {}
type(o.type), data(std::move(o.data)), user_type(std::move(o.user_type)), seq(o.seq), signature(std::move(o.signature)), cypher(std::move(o.cypher)) {}
template <typename Type>
Value(const Type& vs)
@@ -436,20 +421,10 @@ struct OPENDHT_PUBLIC Value
msgpack_unpack(o);
}
/**
* Returns true if value contents are equals (not considering the value ID)
*/
inline bool contentEquals(const Value& o) {
return isEncrypted() ? cypher == o.cypher :
((owner == o.owner || (owner and o.owner and *owner == *o.owner))
&& type == o.type
&& data == o.data
&& user_type == o.user_type
&& signature == o.signature);
}
inline bool operator== (const Value& o) {
return id == o.id and contentEquals(o);
return id == o.id &&
(isEncrypted() ? cypher == o.cypher :
((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
}
void setRecipient(const InfoHash& r) {
@@ -510,17 +485,17 @@ struct OPENDHT_PUBLIC Value
bool has_owner = owner && *owner;
pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient ? 5 : 4):2));
if (has_owner) { // isSigned
pk.pack(VALUE_KEY_SEQ); pk.pack(seq);
pk.pack(VALUE_KEY_OWNER); owner->msgpack_pack(pk);
pk.pack(std::string("seq")); pk.pack(seq);
pk.pack(std::string("owner")); owner->msgpack_pack(pk);
if (recipient) {
pk.pack(VALUE_KEY_TO); pk.pack(recipient);
pk.pack(std::string("to")); pk.pack(recipient);
}
}
pk.pack(VALUE_KEY_TYPE); pk.pack(type);
pk.pack(VALUE_KEY_DATA); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
pk.pack(std::string("type")); pk.pack(type);
pk.pack(std::string("data")); pk.pack_bin(data.size());
pk.pack_bin_body((const char*)data.data(), data.size());
if (not user_type.empty()) {
pk.pack(VALUE_KEY_USERTYPE); pk.pack(user_type);
pk.pack(std::string("utype")); pk.pack(user_type);
}
}
@@ -532,10 +507,10 @@ struct OPENDHT_PUBLIC Value
pk.pack_bin_body((const char*)cypher.data(), cypher.size());
} else {
pk.pack_map(isSigned() ? 2 : 1);
pk.pack(VALUE_KEY_BODY); msgpack_pack_to_sign(pk);
pk.pack(std::string("body")); msgpack_pack_to_sign(pk);
if (isSigned()) {
pk.pack(VALUE_KEY_SIGNATURE); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
pk.pack(std::string("sig")); pk.pack_bin(signature.size());
pk.pack_bin_body((const char*)signature.data(), signature.size());
}
}
}
@@ -543,12 +518,9 @@ struct OPENDHT_PUBLIC Value
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_map(2 + (priority?1:0));
pk.pack(VALUE_KEY_ID); pk.pack(id);
pk.pack(VALUE_KEY_DAT); msgpack_pack_to_encrypt(pk);
if (priority) {
pk.pack(VALUE_KEY_PRIO); pk.pack(priority);
}
pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(id);
pk.pack(std::string("dat")); msgpack_pack_to_encrypt(pk);
}
template <typename Packer>
@@ -579,7 +551,7 @@ struct OPENDHT_PUBLIC Value
}
}
void msgpack_unpack(const msgpack::object& o);
void msgpack_unpack(msgpack::object o);
void msgpack_unpack_body(const msgpack::object& o);
Blob getPacked() const {
msgpack::sbuffer buffer;
@@ -630,13 +602,6 @@ struct OPENDHT_PUBLIC Value
*/
Blob cypher {};
/**
* Priority of this value (used for push notifications)
* 0 = high priority
* 1 = normal priority
*/
unsigned priority {0};
private:
friend class SecureDht;
/* Cache for crypto ops */
@@ -693,7 +658,7 @@ struct OPENDHT_PUBLIC FieldValue
}
}
void msgpack_unpack(const msgpack::object& msg) {
void msgpack_unpack(msgpack::object msg) {
hashValue = {};
blobValue.clear();
@@ -780,8 +745,6 @@ struct OPENDHT_PUBLIC Select
return ss.str();
}
bool empty() const { return fieldSelection_.empty(); }
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
private:
std::vector<Value::Field> fieldSelection_ {};
+30 -419
View File
@@ -1,5 +1,5 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
@@ -33,23 +33,21 @@
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
#serial 4
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
@@ -61,11 +59,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
for switch in -std=gnu++$1 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
@@ -91,27 +96,22 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
done
if test x$ac_success = xyes; then
ac_success=yes
break
fi
done
@@ -148,11 +148,6 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
@@ -190,13 +185,11 @@ namespace cxx11
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
@@ -525,7 +518,7 @@ namespace cxx14
}
namespace test_digit_separators
namespace test_digit_seperators
{
constexpr auto ten_million = 100'000'000;
@@ -567,385 +560,3 @@ namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])
-3
View File
@@ -458,9 +458,6 @@ cdef class DhtConfig(object):
self._config.dht_config.node_config.network = netid
def setMaintainStorage(self, bool maintain_storage):
self._config.dht_config.node_config.maintain_storage = maintain_storage
def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec):
self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec
self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec
cdef class DhtRunner(_WithID):
cdef cpp.shared_ptr[cpp.DhtRunner] thisptr
-3
View File
@@ -211,9 +211,6 @@ cdef extern from "opendht/callbacks.h" namespace "dht":
uint32_t network
bool is_bootstrap
bool maintain_storage
string persist_path
size_t max_req_per_sec
size_t max_peer_req_per_sec
cppclass SecureDhtConfig:
Config node_config
Identity id
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2020 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+5 -22
View File
@@ -19,40 +19,30 @@ import opendht as dht
import time
import asyncio
config = dht.DhtConfig()
config.setRateLimit(-1, -1)
ping_node = dht.DhtRunner()
ping_node.run(config=config)
ping_node.run()
#ping_node.enableLogging()
#ping_node.bootstrap("bootstrap.ring.cx", "4222")
pong_node = dht.DhtRunner()
pong_node.run(config=config)
pong_node.run()
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
net = []
for i in range(1,10):
node = dht.DhtRunner()
node.run(config=config)
node.ping(ping_node.getBound())
net.append(node)
i = 0
MAX = 2048
loop = asyncio.get_event_loop()
def done(h, ok):
pass
#print(h, "over", ok)
print(h, "over", ok)
def ping(node, h):
global i
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
@@ -60,20 +50,13 @@ def ping(node, h):
loop.stop()
def pong(node, h):
#print(node.getNodeId().decode(), "got ping", h, i)
print(node.getNodeId().decode(), "got ping", h, i)
loop.call_soon_threadsafe(ping, node, h)
return True
t1 = time.time()
ping_node.listen(loc_ping, lambda v, e: pong(pong_node, loc_pong) if not e else True)
pong_node.listen(loc_pong, lambda v, e: pong(ping_node, loc_ping) if not e else True)
ping(pong_node, loc_ping)
loop.run_forever()
t2 = time.time()
print(MAX, "ping-pong done, took", t2 - t1, "s")
print(1000 * (t2 - t1)/MAX, "ms per rt", MAX/(t2 - t1), "rt per s")
+3 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,6 @@ extern crate opendht;
use std::{ thread, time };
use opendht::{ InfoHash, DhtRunner, DhtRunnerConfig, Value };
// use opendht::crypto::*;
fn main() {
println!("{}", InfoHash::random());
@@ -29,24 +28,15 @@ fn main() {
println!("{}", InfoHash::get("alice"));
println!("{}", InfoHash::get("alice").is_zero());
let mut dht = DhtRunner::new();
let /*mut*/ config = DhtRunnerConfig::new();
//// If you want to inject a certificate, uncomment the following lines and previous mut.
//// Note: you can generate a certificate with
//// openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj /CN=example.com
//let cert = DhtCertificate::import("example.crt").ok().expect("Invalid cert file");
//let pk = PrivateKey::import("example.key", "");
//config.set_identity(cert, pk);
let config = DhtRunnerConfig::new();
dht.run_config(1412, config);
dht.bootstrap("bootstrap.jami.net", 4222);
println!("Current node id: {}", dht.node_id());
let /* mut */ data = 42;
let mut get_cb = |v: Box<Value>| {
//data += 1;
println!("GET: VALUE CB - data: {} - v: {}", data, v);
true
};
let mut done_cb = |ok: bool| {
println!("GET: DONE CB - data: {} - ok: {}", data, ok);
@@ -57,13 +47,12 @@ fn main() {
let mut put_done_cb = |ok: bool| {
println!("PUT: DONE CB - data: {} - ok: {}", data, ok);
};
dht.put(&InfoHash::get("bob"), Value::new("hi!"), &mut put_done_cb, false);
dht.put(&InfoHash::get("bob"), Value::new("hi!"), &mut put_done_cb);
println!("Start listening /foo");
let mut value_cb = |v, expired| {
println!("LISTEN: DONE CB - data: {} - v: {} - expired: {}", data, v, expired);
true
};
let token = dht.listen(&InfoHash::get("foo"), &mut value_cb);
let one_min = time::Duration::from_secs(10);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+8 -88
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,17 +18,13 @@
#![allow(dead_code)]
pub use crate::ffi::*;
use crate::ffi::*;
use std::ffi::CString;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::ptr;
impl PublicKey {
pub fn new(data: &str) -> Box<PublicKey> {
pub fn new() -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_publickey_import(data.as_ptr(), data.len()))
Box::from_raw(dht_publickey_new())
}
}
@@ -93,17 +89,11 @@ impl PrivateKey {
}
}
pub fn import(file: &str, password: &str) -> io::Result<Box<PrivateKey>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(PrivateKey::from_bytes(&buffer, password))
}
pub fn from_bytes(buffer: &Vec<u8>, password: &str) -> Box<PrivateKey> {
pub fn import(data: &str, password: &str) -> Box<PrivateKey> {
let password = CString::new(password).unwrap();
unsafe {
Box::from_raw(dht_privatekey_import((&*buffer).as_ptr(), buffer.len(),
password.as_ptr() as *const i8))
Box::from_raw(dht_privatekey_import(data.as_ptr(),
data.as_bytes().len(), password.as_ptr()))
}
}
@@ -121,74 +111,4 @@ impl Drop for PrivateKey {
dht_privatekey_delete(&mut *self)
}
}
}
impl DhtCertificate {
pub fn import(file: &str) -> io::Result<Box<DhtCertificate>> {
let mut f = File::open(file)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
Ok(DhtCertificate::from_bytes(&buffer))
}
pub fn from_bytes(buffer: &Vec<u8>) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn from_slice(buffer: &str) -> Box<DhtCertificate> {
unsafe {
Box::from_raw(dht_certificate_import((&*buffer).as_ptr(), buffer.len()))
}
}
pub fn id(&self) -> InfoHash {
unsafe {
dht_certificate_get_id(&*self)
}
}
pub fn long_id(&self) -> PkId {
unsafe {
dht_certificate_get_long_id(&*self)
}
}
pub fn publickey(&self) -> Box<PublicKey> {
unsafe {
Box::from_raw(dht_certificate_get_publickey(&*self))
}
}
}
impl Drop for DhtCertificate {
fn drop(&mut self) {
unsafe {
dht_certificate_delete(&mut *self)
}
}
}
impl DhtIdentity {
pub fn new(common_name: &str) -> DhtIdentity {
unsafe {
DhtIdentity::generate(common_name, Box::from_raw(ptr::null_mut()))
}
}
pub fn generate(common_name: &str, ca: Box<DhtIdentity>) -> DhtIdentity {
let common_name = CString::new(common_name).unwrap();
unsafe {
dht_identity_generate(common_name.as_ptr(), &*ca)
}
}
}
impl Drop for DhtIdentity {
fn drop(&mut self) {
unsafe {
dht_identity_delete(&mut *self)
}
}
}
+17 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@ impl DhtRunnerConfig {
persist_path: ptr::null(),
},
id: DhtIdentity {
privatekey: ptr::null_mut(),
privkey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
},
@@ -51,7 +51,7 @@ impl DhtRunnerConfig {
peer_publish: false,
server_ca: ptr::null_mut(),
client_identity: DhtIdentity {
privatekey: ptr::null_mut(),
privkey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
});
@@ -73,11 +73,6 @@ impl DhtRunnerConfig {
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
self.dht_config.id.privatekey = Box::into_raw(privatekey);
self.dht_config.id.certificate = Box::into_raw(certificate);
}
}
impl DhtNodeConfig
@@ -89,13 +84,13 @@ impl DhtNodeConfig
struct GetHandler<'a>
{
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
get_cb: &'a mut(dyn FnMut(Box<Value>)),
done_cb: &'a mut(dyn FnMut(bool))
}
impl<'a> GetHandler<'a>
{
fn get_cb(&mut self, v: Box<Value>) -> bool{
fn get_cb(&mut self, v: Box<Value>) {
(self.get_cb)(v)
}
@@ -104,9 +99,9 @@ impl<'a> GetHandler<'a>
}
}
extern fn get_handler_cb(v: *mut Value, ptr: *mut c_void) -> bool {
extern fn get_handler_cb(v: *mut Value, ptr: *mut c_void) {
if ptr.is_null() {
return true;
return;
}
unsafe {
let handler = ptr as *mut GetHandler;
@@ -142,17 +137,17 @@ extern fn put_handler_done(ok: bool, ptr: *mut c_void) {
struct ListenHandler<'a>
{
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)
cb: &'a mut(dyn FnMut(Box<Value>, bool))
}
impl<'a> ListenHandler<'a>
{
fn cb(&mut self, v: Box<Value>, expired: bool) -> bool {
fn cb(&mut self, v: Box<Value>, expired: bool) {
(self.cb)(v, expired)
}
}
extern fn listen_handler(v: *mut Value, expired: bool, ptr: *mut c_void) -> bool {
extern fn listen_handler(v: *mut Value, expired: bool, ptr: *mut c_void) {
unsafe {
let handler = ptr as *mut ListenHandler;
(*handler).cb((*v).boxed(), expired)
@@ -205,7 +200,7 @@ impl DhtRunner {
}
pub fn get<'a>(&mut self, h: &InfoHash,
get_cb: &'a mut(dyn FnMut(Box<Value>) -> bool),
get_cb: &'a mut(dyn FnMut(Box<Value>)),
done_cb: &'a mut(dyn FnMut(bool))) {
let handler = Box::new(GetHandler {
get_cb,
@@ -218,35 +213,24 @@ impl DhtRunner {
}
pub fn put<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
done_cb: &'a mut(dyn FnMut(bool))) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put(&mut *self, h, &*v, put_handler_done, handler, permanent)
dht_runner_put(&mut *self, h, &*v, put_handler_done, handler)
}
}
pub fn put_signed<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
pub fn permanent_put<'a>(&mut self, h: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool))) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_signed(&mut *self, h, &*v, put_handler_done, handler, permanent)
}
}
pub fn put_encrypted<'a>(&mut self, h: &InfoHash, to: &InfoHash, v: Box<Value>,
done_cb: &'a mut(dyn FnMut(bool)), permanent: bool) {
let handler = Box::new(PutHandler {
done_cb,
});
let handler = Box::into_raw(handler) as *mut c_void;
unsafe {
dht_runner_put_encrypted(&mut *self, h, to, &*v, put_handler_done, handler, permanent)
dht_runner_put_permanent(&mut *self, h, &*v, put_handler_done, handler)
}
}
@@ -257,7 +241,7 @@ impl DhtRunner {
}
pub fn listen<'a>(&mut self, h: &InfoHash,
cb: &'a mut(dyn FnMut(Box<Value>, bool) -> bool)) -> Box<OpToken> {
cb: &'a mut(dyn FnMut(Box<Value>, bool))) -> Box<OpToken> {
let handler = Box::new(ListenHandler {
cb,
});
+11 -36
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -44,7 +44,6 @@ pub struct Blob
}
#[repr(C)]
#[derive(PartialEq)]
pub struct InfoHash
{
pub d: [u8; HASH_LEN],
@@ -99,7 +98,7 @@ pub struct DhtCertificate
#[repr(C)]
pub struct DhtIdentity
{
pub privatekey: *mut PrivateKey,
pub privkey: *mut PrivateKey,
pub certificate: *mut DhtCertificate,
}
@@ -128,14 +127,11 @@ pub struct DhtRunnerConfig
#[link(name = "opendht-c")]
extern {
// dht::Value
pub fn dht_value_get_id(data: *const Value) -> u64;
pub fn dht_value_get_data(data: *const Value) -> DataView;
pub fn dht_value_new(data: *const u8, size: size_t) -> *mut Value;
pub fn dht_value_ref(data: *const Value) -> *mut Value;
pub fn dht_value_unref(data: *mut Value);
pub fn dht_value_get_data(data: *const Value) -> DataView;
pub fn dht_value_get_id(data: *const Value) -> u64;
pub fn dht_value_get_owner(data: *const Value) -> *mut PublicKey;
pub fn dht_value_get_recipient(data: *const Value) -> InfoHash;
pub fn dht_value_get_user_type(data: *const Value) -> *const c_char;
// dht::Blob
pub fn dht_blob_get_data(data: *const Blob) -> DataView;
@@ -145,14 +141,13 @@ extern {
pub fn dht_infohash_print(h: *const InfoHash) -> *const c_char;
pub fn dht_infohash_random(h: *mut InfoHash);
pub fn dht_infohash_get(h: *mut InfoHash, dat: *mut u8, dat_size: size_t);
pub fn dht_infohash_from_hex(h: *mut InfoHash, dat: *const c_char);
pub fn dht_infohash_is_zero(j: *const InfoHash) -> bool;
// dht::PkId
pub fn dht_pkid_print(h: *const PkId) -> *const c_char;
// dht::crypto::PublicKey
pub fn dht_publickey_import(dat: *const u8, dat_size: size_t) -> *mut PublicKey;
pub fn dht_publickey_new() -> *mut PublicKey;
pub fn dht_publickey_delete(pk: *mut PublicKey);
pub fn dht_publickey_unpack(pk: *mut PublicKey, dat: *const u8, dat_size: size_t) -> c_int;
pub fn dht_publickey_pack(pk: *mut PublicKey, out: *const c_char, out_size: size_t) -> c_int;
@@ -167,16 +162,6 @@ extern {
pub fn dht_privatekey_get_publickey(pk: *const PrivateKey) -> *mut PublicKey;
pub fn dht_privatekey_delete(pk: *mut PrivateKey);
// dht::crypto::Certificate
pub fn dht_certificate_import(dat: *const u8, dat_size: size_t) -> *mut DhtCertificate;
pub fn dht_certificate_get_id(cert: *const DhtCertificate) -> InfoHash;
pub fn dht_certificate_get_long_id(cert: *const DhtCertificate) -> PkId;
pub fn dht_certificate_get_publickey(cert: *const DhtCertificate) -> *mut PublicKey;
pub fn dht_certificate_delete(cert: *mut DhtCertificate);
pub fn dht_identity_generate(common_name: *const c_char, ca: *const DhtIdentity) -> DhtIdentity;
pub fn dht_identity_delete(ca: *mut DhtIdentity);
// dht::OpToken
pub fn dht_op_token_delete(token: *mut OpToken);
@@ -190,28 +175,18 @@ extern {
pub fn dht_runner_run_config(dht: *mut DhtRunner, port: in_port_t, config: *const DhtRunnerConfig);
pub fn dht_runner_bootstrap(dht: *mut DhtRunner, host: *const c_char, service: *const c_char);
pub fn dht_runner_get(dht: *mut DhtRunner, h: *const InfoHash,
get_cb: extern fn(*mut Value, *mut c_void) -> bool,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
get_cb: extern fn(*mut Value, *mut c_void),
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_put(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_signed(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
pub fn dht_runner_put_encrypted(dht: *mut DhtRunner, h: *const InfoHash,
to: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void,
permanent: bool);
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_put_permanent(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
done_cb: extern fn(bool, *mut c_void),
cb_user_data: *mut c_void);
pub fn dht_runner_cancel_put(dht: *mut DhtRunner, h: *const InfoHash, vid: u64);
pub fn dht_runner_listen(dht: *mut DhtRunner, h: *const InfoHash,
cb: extern fn(*mut Value, bool, *mut c_void) -> bool,
cb: extern fn(*mut Value, bool, *mut c_void),
done_cb: extern fn(*mut c_void),
cb_user_data: *mut c_void) -> *mut OpToken;
pub fn dht_runner_cancel_listen(dht: *mut DhtRunner, h: *const InfoHash,
+1 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -47,23 +47,6 @@ impl InfoHash {
h
}
pub fn from_bytes(data: &Vec<u8>) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
dht_infohash_get(&mut h, data.as_ptr() as *mut u8, data.len());
}
h
}
pub fn from_hex(data: &str) -> InfoHash {
let mut h = InfoHash::new();
unsafe {
let c_str = CString::new(data).unwrap();
dht_infohash_from_hex(&mut h, c_str.as_ptr());
}
h
}
pub fn is_zero(&self) -> bool {
unsafe {
dht_infohash_is_zero(self)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -25
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,11 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(dead_code)]
use crate::ffi::*;
use std::fmt;
use std::ffi::{ CString, IntoStringError };
use std::str;
use std::slice;
@@ -64,28 +62,6 @@ impl Value {
Box::from_raw(dht_value_ref(self))
}
}
pub fn recipient(&self) -> InfoHash {
unsafe {
dht_value_get_recipient(self)
}
}
pub fn owner(&self) -> Option<Box<PublicKey>> {
unsafe {
let ptr = dht_value_get_owner(self);
if ptr.is_null() {
return None;
}
Some(Box::from_raw(ptr))
}
}
pub fn user_type(&self) -> Result<String, IntoStringError> {
unsafe {
CString::from_raw(dht_value_get_user_type(self) as *mut _).into_string()
}
}
}
impl Drop for Value {
+3 -6
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@ @Argon2_LDFLAGS@ @OpenSSL_LDFLAGS@ @Fmt_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -27,6 +27,7 @@ libopendht_la_SOURCES = \
dhtrunner.cpp \
default_types.cpp \
log.cpp \
peer_discovery.cpp \
network_utils.cpp \
thread_pool.cpp
@@ -55,6 +56,7 @@ nobase_include_HEADERS = \
../include/opendht/default_types.h \
../include/opendht/log.h \
../include/opendht/log_enable.h \
../include/opendht/peer_discovery.h \
../include/opendht/network_utils.h \
../include/opendht/rng.h \
../include/opendht/thread_pool.h
@@ -75,11 +77,6 @@ libopendht_la_SOURCES += http.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
endif
if ENABLE_PEER_DISCOVERY
libopendht_la_SOURCES += peer_discovery.cpp
nobase_include_HEADERS += ../include/opendht/peer_discovery.h
endif
if ENABLE_INDEXATION
libopendht_la_SOURCES += indexation/pht.cpp
nobase_include_HEADERS += ../include/opendht/indexation/pht.h
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -131,7 +131,7 @@ base64_encode(const std::vector<unsigned char>& str)
return base64_encode(str.cbegin(), str.cend());
}
std::vector<unsigned char>
std::string
base64_decode(const std::string& str)
{
size_t output_length = str.length() / 4 * 3 + 2;
@@ -139,5 +139,5 @@ base64_decode(const std::string& str)
output.resize(output_length);
base64_decode(str.data(), str.size(), output.data(), &output_length);
output.resize(output_length);
return output;
return std::string(output.begin(), output.end());
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,4 +33,4 @@ std::string base64_encode(const std::vector<unsigned char>& str);
* @param str the input buffer
* @return a base64-decoded buffer
*/
std::vector<unsigned char> base64_decode(const std::string& str);
std::string base64_decode(const std::string& str);
-40
View File
@@ -1,25 +1,3 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "callbacks.h"
namespace dht {
@@ -143,8 +121,6 @@ NodeInfo::toJson() const
val["node_id"] = node_id.toString();
val["ipv4"] = ipv4.toJson();
val["ipv6"] = ipv6.toJson();
val["ops"] = Json::Value::LargestUInt(ongoing_ops);
val["metrics"] = metrics.toJson();
return val;
}
@@ -155,22 +131,6 @@ NodeInfo::NodeInfo(const Json::Value& v)
node_id = InfoHash(v["node_id"].asString());
ipv4 = NodeStats(v["ipv4"]);
ipv6 = NodeStats(v["ipv6"]);
ongoing_ops = v["ops"].asLargestUInt();
}
Json::Value
NodeMetrics::toJson() const
{
Json::Value val;
val["scheduler_size"] = Json::Value::LargestUInt(scheduler_size);
val["node_cache_size"] = Json::Value::LargestUInt(node_cache_size);
val["request_count"] = Json::Value::LargestUInt(request_count);
val["rate_limiter_size"] = Json::Value::LargestUInt(rate_limiter_size);
val["reported_addr_num"] = Json::Value::LargestUInt(reported_addr_num);
val["store_size"] = Json::Value::LargestUInt(store_size);
val["store_values"] = Json::Value::LargestUInt(store_values);
val["store_quota_size"] = Json::Value::LargestUInt(store_quota_size);
return val;
}
#endif
+11 -46
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -52,9 +52,6 @@ static std::uniform_int_distribution<uint8_t> rand_byte;
#define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256
#endif
#define DHT_AES_LEGACY_ENCRYPT 1
#define DHT_AES_LEGACY_DECRYPT 1
namespace dht {
namespace crypto {
@@ -108,9 +105,6 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
#if DHT_AES_LEGACY_ENCRYPT
gcm_aes_update(&aes, data_length, data);
#endif
gcm_aes_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
@@ -145,23 +139,8 @@ Blob aesDecrypt(const Blob& data, const Blob& key)
gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE)) {
#if DHT_AES_LEGACY_DECRYPT
//gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
Blob ret_tmp(data_sz);
struct gcm_aes_ctx aes_d;
gcm_aes_set_key(&aes_d, key.size(), key.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data.data());
gcm_aes_update(&aes_d, ret.size(), ret.data());
gcm_aes_encrypt(&aes_d, ret.size(), ret_tmp.data(), ret.data());
gcm_aes_digest(&aes_d, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE))
throw DecryptError("Can't decrypt data");
#else
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE))
throw DecryptError("Can't decrypt data");
#endif
}
return ret;
}
@@ -348,7 +327,9 @@ PrivateKey::serialize(const std::string& password) const
size_t buf_sz = 8192;
Blob buffer;
buffer.resize(buf_sz);
auto err = serialize(buffer.data(), &buf_sz, password);
int err = password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, buffer.data(), &buf_sz)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, buffer.data(), &buf_sz);
if (err != GNUTLS_E_SUCCESS) {
std::cerr << "Could not export private key - " << gnutls_strerror(err) << std::endl;
return {};
@@ -357,16 +338,6 @@ PrivateKey::serialize(const std::string& password) const
return buffer;
}
int
PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password) const
{
if (!x509_key)
return -1;
return password.empty()
? gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, nullptr, GNUTLS_PKCS_PLAIN, out, out_len)
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len);
}
PublicKey
PrivateKey::getPublicKey() const
{
@@ -382,9 +353,9 @@ PublicKey::PublicKey()
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const uint8_t* dat, size_t dat_size) : PublicKey()
PublicKey::PublicKey(const Blob& dat) : PublicKey()
{
unpack(dat, dat_size);
unpack(dat.data(), dat.size());
}
PublicKey::~PublicKey()
@@ -412,18 +383,12 @@ PublicKey::pack(Blob& b) const
throw CryptoException(std::string("Could not export public key: null key"));
std::vector<uint8_t> tmp(2048);
size_t sz = tmp.size();
if (int err = pack(tmp.data(), &sz))
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
tmp.resize(sz);
b.insert(b.end(), tmp.begin(), tmp.end());
}
int
PublicKey::pack(uint8_t* out, size_t* out_len) const
{
return gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, out, out_len);
}
void
PublicKey::unpack(const uint8_t* data, size_t data_size)
{
@@ -453,7 +418,7 @@ PublicKey::toString() const
}
void
PublicKey::msgpack_unpack(const msgpack::object& o)
PublicKey::msgpack_unpack(msgpack::object o)
{
if (o.type == msgpack::type::BIN)
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
@@ -798,7 +763,7 @@ Certificate::unpack(const uint8_t* dat, size_t dat_size)
}
void
Certificate::msgpack_unpack(const msgpack::object& o)
Certificate::msgpack_unpack(msgpack::object o)
{
if (o.type == msgpack::type::BIN)
unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size);
@@ -1258,7 +1223,7 @@ RevocationList::unpack(const uint8_t* dat, size_t dat_size)
}
void
RevocationList::msgpack_unpack(const msgpack::object& o)
RevocationList::msgpack_unpack(msgpack::object o)
{
try {
if (o.type == msgpack::type::BIN)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+191 -287
View File
File diff suppressed because it is too large. Load diff
+356 -325
View File
File diff suppressed because it is too large. Load diff
+394 -338
View File
File diff suppressed because it is too large. Load diff
+205 -362
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -18,23 +18,26 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dhtrunner.h"
#include "securedht.h"
#include "network_utils.h"
#ifdef OPENDHT_PEER_DISCOVERY
#include "peer_discovery.h"
#endif
#include "network_utils.h"
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
#ifdef _WIN32
#include <cstring>
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#endif
namespace dht {
constexpr std::chrono::seconds DhtRunner::BOOTSTRAP_PERIOD;
static constexpr size_t RX_QUEUE_MAX_SIZE = 1024 * 16;
static constexpr std::chrono::milliseconds RX_QUEUE_MAX_DELAY(500);
static const std::string PEER_DISCOVERY_DHT_SERVICE = "dht";
struct DhtRunner::Listener {
@@ -97,9 +100,9 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Conf
void
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const Config& config, Context&& context)
{
if (running == State::Idle) {
if (not running) {
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
context.sock.reset(new net::UdpSocket(local4, local6, context.logger ? *context.logger : Logger{}));
run(config, std::move(context));
}
}
@@ -108,34 +111,25 @@ void
DhtRunner::run(const Config& config, Context&& context)
{
std::lock_guard<std::mutex> lck(dht_mtx);
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running))
if (running)
return;
if (context.logger) {
if (context.logger)
logger_ = context.logger;
logger_->d("[runner %p] state changed to Running", this);
}
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
net::PacketList ret;
context.sock->setOnReceive([&] (std::unique_ptr<net::ReceivedPacket>&& pkt) {
{
std::lock_guard<std::mutex> lck(sock_mtx);
auto maxSize = net::RX_QUEUE_MAX_SIZE - pkts.size();
while (rcv.size() > maxSize) {
if (logger_)
logger_->e("Dropping packet: queue is full!");
rcv.pop_front();
if (rcv.size() >= RX_QUEUE_MAX_SIZE) {
std::cerr << "Dropping packet: queue is full!" << std::endl;
rcv.pop();
}
rcv.splice(rcv.end(), std::move(pkts));
ret = std::move(rcv_free);
rcv.emplace(std::move(pkt));
}
cv.notify_all();
return ret;
});
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger ? *context.logger : Logger{}));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#ifdef OPENDHT_PROXY_CLIENT
@@ -143,7 +137,7 @@ DhtRunner::run(const Config& config, Context&& context)
#endif
enableProxy(not config.proxy_server.empty());
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(context.logger);
dht_via_proxy_->setLogger(*context.logger);
}
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
@@ -154,15 +148,16 @@ DhtRunner::run(const Config& config, Context&& context)
dht_via_proxy_->setLocalCertificateStore(std::move(context.certificateStore));
}
running = true;
if (not config.threaded)
return;
dht_thread = std::thread([this]() {
while (running != State::Idle) {
while (running) {
std::unique_lock<std::mutex> lk(dht_mtx);
time_point wakeup = loop_();
auto hasJobToDo = [this]() {
if (running == State::Idle)
if (not running)
return true;
{
std::lock_guard<std::mutex> lck(sock_mtx);
@@ -187,16 +182,11 @@ DhtRunner::run(const Config& config, Context&& context)
});
if (config.peer_discovery or config.peer_publish) {
#ifdef OPENDHT_PEER_DISCOVERY
peerDiscovery_ = context.peerDiscovery ?
std::move(context.peerDiscovery) :
std::make_shared<PeerDiscovery>();
#else
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
#endif
}
#ifdef OPENDHT_PEER_DISCOVERY
auto netId = config.dht_config.node_config.network;
if (config.peer_discovery) {
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
@@ -212,104 +202,53 @@ DhtRunner::run(const Config& config, Context&& context)
adc.net = netId;
adc.nodeId = dht_->getNodeId();
// IPv4
if (const auto& bound4 = dht_->getSocket()->getBoundRef(AF_INET)) {
if (auto bound4 = dht_->getSocket()->getBound(AF_INET)) {
adc.port = bound4.getPort();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
// IPv6
if (const auto& bound6 = dht_->getSocket()->getBoundRef(AF_INET6)) {
if (auto bound6 = dht_->getSocket()->getBound(AF_INET6)) {
adc.port = bound6.getPort();
sbuf_node.clear();
msgpack::pack(sbuf_node, adc);
peerDiscovery_->startPublish(AF_INET6, PEER_DISCOVERY_DHT_SERVICE, sbuf_node);
}
}
#endif
}
void
DhtRunner::shutdown(ShutdownCallback cb) {
auto expected = State::Running;
if (not running.compare_exchange_strong(expected, State::Stopping)) {
if (expected == State::Stopping and ongoing_ops) {
std::lock_guard<std::mutex> lck(storage_mtx);
shutdownCallbacks_.emplace_back(std::move(cb));
}
else if (cb) cb();
if (not running) {
cb();
return;
}
if (logger_)
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops_prio.emplace([=](SecureDht&) mutable {
auto onShutdown = [this]{ opEnded(); };
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(onShutdown);
dht_via_proxy_->shutdown(cb);
#endif
if (dht_)
dht_->shutdown(onShutdown);
dht_->shutdown(cb);
});
cv.notify_all();
}
void
DhtRunner::opEnded() {
if (--ongoing_ops == 0)
checkShutdown();
}
DoneCallback
DhtRunner::bindOpDoneCallback(DoneCallback&& cb) {
return [this, cb = std::move(cb)](bool ok, const std::vector<std::shared_ptr<Node>>& nodes){
if (cb) cb(ok, nodes);
opEnded();
};
}
DoneCallbackSimple
DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) {
return [this, cb = std::move(cb)](bool ok){
if (cb) cb(ok);
opEnded();
};
}
bool
DhtRunner::checkShutdown() {
if (running != State::Stopping or ongoing_ops)
return false;
decltype(shutdownCallbacks_) cbs;
{
std::lock_guard<std::mutex> lck(storage_mtx);
cbs = std::move(shutdownCallbacks_);
}
for (auto& cb : cbs)
if (cb) cb();
return true;
}
void
DhtRunner::join()
{
if (peerDiscovery_)
peerDiscovery_->stop();
{
std::lock_guard<std::mutex> lck(dht_mtx);
if (running.exchange(State::Idle) == State::Idle)
return;
running = false;
cv.notify_all();
bootstrap_cv.notify_all();
#ifdef OPENDHT_PEER_DISCOVERY
if (peerDiscovery_)
peerDiscovery_->stop();
#endif
if (dht_)
if (auto sock = dht_->getSocket())
sock->stop();
if (logger_)
logger_->d("[runner %p] state changed to Idle", this);
}
if (dht_thread.joinable())
@@ -318,11 +257,14 @@ DhtRunner::join()
if (bootstrap_thread.joinable())
bootstrap_thread.join();
if (peerDiscovery_) {
peerDiscovery_->join();
}
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops = decltype(pending_ops)();
pending_ops_prio = decltype(pending_ops_prio)();
ongoing_ops = 0;
}
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -341,15 +283,6 @@ DhtRunner::getBound(sa_family_t af) const {
return SockAddr{};
}
in_port_t
DhtRunner::getBoundPort(sa_family_t af) const {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
if (auto sock = dht_->getSocket())
return sock->getPort(af);
return 0;
}
void
DhtRunner::dumpTables() const
{
@@ -407,9 +340,8 @@ DhtRunner::exportValues() const {
}
void
DhtRunner::setLogger(const Sp<Logger>& logger) {
DhtRunner::setLogger(const Logger& logger) {
std::lock_guard<std::mutex> lck(dht_mtx);
logger_ = logger;
if (dht_)
dht_->setLogger(logger);
#ifdef OPENDHT_PROXY_CLIENT
@@ -427,6 +359,7 @@ DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
void
DhtRunner::setLogFilter(const InfoHash& f) {
std::lock_guard<std::mutex> lck(dht_mtx);
activeDht()->setLogFilter(f);
if (dht_)
dht_->setLogFilter(f);
#ifdef OPENDHT_PROXY_CLIENT
@@ -473,39 +406,14 @@ DhtRunner::getNodesStats(sa_family_t af) const
NodeInfo
DhtRunner::getNodeInfo() const {
std::lock_guard<std::mutex> lck(dht_mtx);
NodeInfo info {};
if (auto dht = activeDht()) {
info.id = dht->getId();
info.node_id = dht->getNodeId();
info.ipv4 = dht->getNodesStats(AF_INET);
info.ipv6 = dht->getNodesStats(AF_INET6);
info.metrics = dht->getNodeMetrics();
info.ongoing_ops = ongoing_ops;
}
info.ongoing_ops = ongoing_ops;
NodeInfo info;
info.id = getId();
info.node_id = getNodeId();
info.ipv4 = dht_->getNodesStats(AF_INET);
info.ipv6 = dht_->getNodesStats(AF_INET6);
return info;
}
void
DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
{
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([cb = std::move(cb), this](SecureDht& dht){
auto sinfo = std::make_shared<NodeInfo>();
auto& info = *sinfo;
info.id = dht.getId();
info.node_id = dht.getNodeId();
info.ipv4 = dht.getNodesStats(AF_INET);
info.ipv6 = dht.getNodesStats(AF_INET6);
info.metrics = dht.getNodeMetrics();
info.ongoing_ops = ongoing_ops;
cb(std::move(sinfo));
opEnded();
});
cv.notify_all();
}
std::vector<unsigned>
DhtRunner::getNodeMessageStats(bool in) const
{
@@ -597,7 +505,6 @@ DhtRunner::loop_()
time_point wakeup {};
decltype(rcv) received {};
decltype(rcv) received_treated {};
{
std::lock_guard<std::mutex> lck(sock_mtx);
// move to stack
@@ -607,36 +514,26 @@ DhtRunner::loop_()
// Discard old packets
size_t dropped {0};
if (not received.empty()) {
auto limit = clock::now() - net::RX_QUEUE_MAX_DELAY;
auto it = received.begin();
while (it != received.end() and it->received < limit) {
it->data.clear();
++it;
auto now = clock::now();
while (not received.empty() and now - received.front()->received > RX_QUEUE_MAX_DELAY) {
received.pop();
dropped++;
}
received_treated.splice(received_treated.end(), received, received.begin(), it);
}
// Handle packets
if (not received.empty()) {
for (auto& pkt : received) {
auto now = clock::now();
if (now - pkt.received > net::RX_QUEUE_MAX_DELAY)
while (not received.empty()) {
auto& pck = received.front();
if (clock::now() - pck->received > RX_QUEUE_MAX_DELAY)
dropped++;
else
wakeup = dht->periodic(pkt.data.data(), pkt.data.size(), std::move(pkt.from), now);
pkt.data.clear();
wakeup = dht->periodic(pck->data.data(), pck->data.size(), std::move(pck->from));
received.pop();
}
received_treated.splice(received_treated.end(), std::move(received));
} else {
// Or just run the scheduler
wakeup = dht->periodic(nullptr, 0, nullptr, 0, clock::now());
}
if (not received_treated.empty()) {
std::lock_guard<std::mutex> lck(sock_mtx);
if (rcv_free.size() < net::RX_QUEUE_MAX_SIZE)
rcv_free.splice(rcv_free.end(), std::move(received_treated));
wakeup = dht->periodic(nullptr, 0, nullptr, 0);
}
if (dropped)
@@ -666,15 +563,12 @@ DhtRunner::loop_()
void
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w)
{
if (running != State::Running) {
if (dcb) dcb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w));
});
cv.notify_all();
}
@@ -685,15 +579,12 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
}
void
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
if (running != State::Running) {
if (done_cb) done_cb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q));
});
cv.notify_all();
}
@@ -701,34 +592,32 @@ std::future<size_t>
DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
auto ret_token = std::make_shared<std::promise<size_t>>();
if (running != State::Running) {
ret_token->set_value(0);
return ret_token->get_future();
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
auto tokenbGlobal = listener_token_++;
auto& listener = listeners_[tokenbGlobal];
listener.hash = hash;
listener.f = std::move(f);
listener.w = std::move(w);
listener.gcb = [hash,vcb,tokenbGlobal,this](const std::vector<Sp<Value>>& vals, bool expired) {
if (not vcb(vals, expired)) {
cancelListen(hash, tokenbGlobal);
return false;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
return true;
};
if (auto token = dht.listen(hash, listener.gcb, listener.f, listener.w)) {
if (use_proxy) listener.tokenProxyDht = token;
else listener.tokenClassicDht = token;
}
ret_token->set_value(tokenbGlobal);
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
});
}
cv.notify_all();
return ret_token->get_future();
}
@@ -742,77 +631,73 @@ DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Wher
void
DhtRunner::cancelListen(InfoHash h, size_t token)
{
std::lock_guard<std::mutex> lck(storage_mtx);
{
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, token);
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
std::lock_guard<std::mutex> lck(storage_mtx);
{
std::lock_guard<std::mutex> lck(storage_mtx);
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
if (it->second.tokenClassicDht)
dht_->cancelListen(h, it->second.tokenClassicDht);
if (it->second.tokenProxyDht and dht_via_proxy_)
dht_via_proxy_->cancelListen(h, it->second.tokenProxyDht);
listeners_.erase(it);
});
#else
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelListen(h, ftoken.get());
});
#endif // OPENDHT_PROXY_CLIENT
}
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
{
if (running != State::Running) {
if (cb) cb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
auto sv = std::make_shared<Value>(std::move(value));
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, sv, cb, created, permanent);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
sv = std::make_shared<Value>(std::move(value))
] (SecureDht& dht) mutable {
dht.put(hash, sv, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
void
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
{
if (running != State::Running) {
if (cb) cb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.put(hash, value, cb, created, permanent);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable {
dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent);
});
cv.notify_all();
}
@@ -823,83 +708,63 @@ DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, tim
}
void
DhtRunner::cancelPut(const InfoHash& h, Value::Id id)
DhtRunner::cancelPut(const InfoHash& h , const Value::Id& id)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
cv.notify_all();
}
void
DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, value->id);
});
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
if (running != State::Running) {
if (cb) cb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.cancelPut(h, id);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
](SecureDht& dht) mutable {
dht.putSigned(hash, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb, bool permanent)
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb)
{
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
}
void
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb, bool permanent)
{
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
if (running != State::Running) {
if (cb) cb(false, {});
return;
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putSigned(hash, value, cb);
});
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb, bool permanent)
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb, bool permanent)
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb), permanent);
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.putEncrypted(hash, to, value, cb);
});
}
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
}
void
@@ -931,7 +796,7 @@ DhtRunner::tryBootstrapContinuously()
++ping_count;
try {
bootstrap(SockAddr::resolve(it->first, it->second), [&](bool) {
if (running != State::Running)
if (not running)
return;
{
std::unique_lock<std::mutex> blck(mtx);
@@ -945,15 +810,15 @@ DhtRunner::tryBootstrapContinuously()
}
}
// wait at least until the next BOOTSTRAP_PERIOD
bootstrap_cv.wait_until(blck, next, [&]() { return running != State::Running; });
bootstrap_cv.wait_until(blck, next, [&]() { return not running; });
// wait for bootstrap requests to end.
if (running != State::Running)
bootstrap_cv.wait(blck, [&]() { return running != State::Running or ping_count == 0; });
if (running)
bootstrap_cv.wait(blck, [&]() { return not running or ping_count == 0; });
}
// update state
{
std::lock_guard<std::mutex> lck(dht_mtx);
bootstraping = running == State::Running and
bootstraping = running and
status4 == NodeStatus::Disconnected and
status6 == NodeStatus::Disconnected;
}
@@ -990,28 +855,19 @@ DhtRunner::clearBootstrap()
void
DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([
cb = bindOpDoneCallback(std::move(cb)),
nodes = std::move(nodes)
] (SecureDht& dht) mutable {
pending_ops_prio.emplace([=](SecureDht& dht) mutable {
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
for (auto& node : nodes) {
if (node.getPort() == 0)
node.setPort(net::DHT_DEFAULT_PORT);
dht.pingNode(std::move(node), [rem,cb](bool ok) {
dht.pingNode(std::move(node), cb ? [rem,cb](bool ok) {
auto& r = *rem;
r.first--;
r.second |= ok;
if (r.first == 0) {
if (not r.first)
cb(r.second);
}
});
} : DoneCallbackSimple{});
}
});
cv.notify_all();
@@ -1020,13 +876,8 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
{
if (running != State::Running) {
if (cb) cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
pending_ops_prio.emplace([addr, cb](SecureDht& dht) mutable {
dht.pingNode(std::move(addr), std::move(cb));
});
cv.notify_all();
@@ -1035,56 +886,48 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
{
if (running != State::Running)
return;
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
{
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
}
cv.notify_all();
}
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
if (running != State::Running)
return;
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
});
}
cv.notify_all();
}
void
DhtRunner::connectivityChanged()
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
#ifdef OPENDHT_PEER_DISCOVERY
if (peerDiscovery_)
peerDiscovery_->connectivityChanged();
#endif
});
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
dht.connectivityChanged();
});
}
cv.notify_all();
}
void
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb) {
if (running != State::Running) {
cb({});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
cb(crt);
opEnded();
DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) {
dht.findCertificate(hash, cb);
});
});
}
cv.notify_all();
}
@@ -1149,11 +992,11 @@ DhtRunner::enableProxy(bool proxify)
},
config_.proxy_server, config_.push_node_id, logger_)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not config_.push_token.empty())
dht_via_proxy->setPushNotificationToken(config_.push_token);
dht_via_proxy_->setPushNotificationToken(config_.push_token);
#endif
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
// add current listeners
for (auto& l: listeners_)
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
+457 -419
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+15 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -56,9 +56,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
s << std::endl;
}
std::shared_ptr<Logger>
std::unique_ptr<Logger>
getStdLogger() {
return std::make_shared<Logger>(
return std::unique_ptr<Logger>(new Logger(
[](char const *m, va_list args) {
std::cerr << red;
printLog(std::cerr, m, args);
@@ -70,22 +70,22 @@ getStdLogger() {
std::cout << def;
},
[](char const *m, va_list args) { printLog(std::cout, m, args); }
);
));
}
std::shared_ptr<Logger>
std::unique_ptr<Logger>
getFileLogger(const std::string &path) {
auto logfile = std::make_shared<std::ofstream>();
logfile->open(path, std::ios::out);
return std::make_shared<Logger>(
return std::unique_ptr<Logger>(new Logger(
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); },
[=](char const *m, va_list args) { printLog(*logfile, m, args); }
);
));
}
std::shared_ptr<Logger>
std::unique_ptr<Logger>
getSyslogLogger(const char* name) {
#ifndef _WIN32
struct Syslog {
@@ -103,34 +103,34 @@ getSyslogLogger(const char* name) {
logfile = std::make_shared<Syslog>(name);
opened_logfile = logfile;
}
return std::make_shared<Logger>(
return std::unique_ptr<Logger>(new Logger(
[logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
[logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
);
));
#else
return std::make_shared<Logger>();
return std::unique_ptr<Logger>(new Logger());
#endif
}
void
enableLogging(dht::DhtRunner &dht) {
dht.setLogger(getStdLogger());
dht.setLogger(*getStdLogger());
}
void
enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
dht.setLogger(getFileLogger(path));
dht.setLogger(*getFileLogger(path));
}
OPENDHT_PUBLIC void
enableSyslog(dht::DhtRunner &dht, const char* name) {
dht.setLogger(getSyslogLogger(name));
dht.setLogger(*getSyslogLogger(name));
}
void
disableLogging(dht::DhtRunner &dht) {
dht.setLogger();
dht.setLogger({});
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+100 -147
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -27,7 +27,6 @@
namespace dht {
namespace net {
using namespace std::chrono_literals;
const std::string DhtProtocolException::GET_NO_INFOHASH {"Get_values with no info_hash"};
const std::string DhtProtocolException::LISTEN_NO_INFOHASH {"Listen with no info_hash"};
@@ -42,6 +41,7 @@ constexpr std::chrono::seconds NetworkEngine::RX_MAX_PACKET_TIME;
constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT;
const std::string NetworkEngine::my_v {"RNG1"};
constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC;
static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
@@ -99,15 +99,11 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
nodes6(std::move(msg.nodes6))
{}
NetworkEngine::NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler)
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
std::mt19937_64& rand,
Scheduler& scheduler,
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
@@ -126,10 +122,7 @@ NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
onListen(std::move(onListen)),
onAnnounce(std::move(onAnnounce)),
onRefresh(std::move(onRefresh)),
myid(myid), config(c), dht_socket(std::move(sock)), logger_(log), rd(rand),
cache(rd),
rate_limiter(config.max_req_per_sec),
scheduler(scheduler)
myid(myid), network(net), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler)
{}
NetworkEngine::~NetworkEngine() {
@@ -146,8 +139,7 @@ NetworkEngine::tellListener(Sp<Node> node, Tid socket_id, const InfoHash& hash,
try {
sendNodesValues(node->getAddr(), socket_id, nnodes.first, nnodes.second, values, query, ntoken);
} catch (const std::overflow_error& e) {
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
DHT_LOG.e("Can't send value: buffer not large enough !");
}
}
@@ -156,7 +148,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -167,15 +159,14 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
if (not values.empty()) {
pk.pack(KEY_REQ_REFRESHED);
pk.pack(values);
if (logger_)
logger_->d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
}
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -187,7 +178,7 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -198,15 +189,14 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
if (not values.empty()) {
pk.pack(KEY_REQ_EXPIRED);
pk.pack(values);
if (logger_)
logger_->d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
}
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -255,8 +245,7 @@ NetworkEngine::requestStep(Sp<Request> sreq)
auto now = scheduler.time();
auto& node = *req.node;
if (req.isExpired(now)) {
// if (logger_)
// logger_->d(node.id, "[node %s] expired !", node.toString().c_str());
DHT_LOG.d(node.id, "[node %s] expired !", node.toString().c_str());
node.setExpired();
if (not node.id)
requests.erase(req.tid);
@@ -276,14 +265,12 @@ NetworkEngine::requestStep(Sp<Request> sreq)
if (not node.id)
requests.erase(req.tid);
} else {
req.last_try = now;
if (err != EAGAIN) {
++req.attempt_count;
req.attempt_duration +=
req.attempt_duration + uniform_duration_distribution<>(0ms, ((duration)Node::MAX_RESPONSE_TIME)/4)(rd);
}
req.last_try = now;
std::weak_ptr<Request> wreq = sreq;
scheduler.add(req.last_try + req.attempt_duration, [this,wreq] {
scheduler.add(req.last_try + Node::MAX_RESPONSE_TIME, [this,wreq] {
if (auto req = wreq.lock())
requestStep(req);
});
@@ -313,7 +300,7 @@ NetworkEngine::rateLimit(const SockAddr& addr)
const auto& now = scheduler.time();
// occasional IP limiter maintenance (a few times every second at max rate)
if (limiter_maintenance++ == config.max_peer_req_per_sec) {
if (limiter_maintenance++ == MAX_REQUESTS_PER_SEC/8) {
for (auto it = address_rate_limiter.begin(); it != address_rate_limiter.end();) {
if (it->second.maintain(now) == 0)
address_rate_limiter.erase(it++);
@@ -324,11 +311,7 @@ NetworkEngine::rateLimit(const SockAddr& addr)
}
// invoke per IP, then global rate limiter
return (config.max_peer_req_per_sec < 0
or address_rate_limiter
.emplace(addr, config.max_peer_req_per_sec).first->second
.limit(now))
and rate_limiter.limit(now);
return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now);
}
bool
@@ -378,14 +361,12 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
{
auto from = f.getMappedIPv4();
if (isMartian(from)) {
if (logger_)
logger_->w("Received packet from martian node %s", from.toString().c_str());
DHT_LOG.w("Received packet from martian node %s", from.toString().c_str());
return;
}
if (isNodeBlacklisted(from)) {
if (logger_)
logger_->w("Received packet from blacklisted node %s", from.toString().c_str());
DHT_LOG.w("Received packet from blacklisted node %s", from.toString().c_str());
return;
}
@@ -394,16 +375,13 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
msgpack::unpacked msg_res = msgpack::unpack((const char*)buf, buflen);
msg->msgpack_unpack(msg_res.get());
} catch (const std::exception& e) {
if (logger_)
logger_->w("Can't parse message of size %lu: %s", buflen, e.what());
// if (logger_)
// logger_->DBG.logPrintable(buf, buflen);
DHT_LOG.w("Can't parse message of size %lu: %s", buflen, e.what());
//DHT_LOG.DBG.logPrintable(buf, buflen);
return;
}
if (msg->network != config.network) {
if (logger_)
logger_->d("Received message from other config.network %u", msg->network);
if (msg->network != network) {
DHT_LOG.d("Received message from other network %u", msg->network);
return;
}
@@ -414,14 +392,12 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
auto pmsg_it = partial_messages.find(msg->tid);
if (pmsg_it == partial_messages.end()) {
if (logIncoming_)
if (logger_)
logger_->d("Can't find partial message");
DHT_LOG.d("Can't find partial message");
rateLimit(from);
return;
}
if (!pmsg_it->second.from.equals(from)) {
if (logger_)
logger_->d("Received partial message data from unexpected IP address");
DHT_LOG.d("Received partial message data from unexpected IP address");
rateLimit(from);
return;
}
@@ -440,16 +416,14 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
}
if (msg->id == myid or not msg->id) {
if (logger_)
logger_->d("Received message from self");
DHT_LOG.d("Received message from self");
return;
}
if (msg->type > MessageType::Reply) {
/* Rate limit requests. */
if (!rateLimit(from)) {
if (logger_)
logger_->w("Dropping request due to rate limiting");
DHT_LOG.w("Dropping request due to rate limiting");
return;
}
}
@@ -468,8 +442,7 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
scheduler.add(now + RX_MAX_PACKET_TIME, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, k));
} else
if (logger_)
logger_->e("Partial message with given TID already exists");
DHT_LOG.e("Partial message with given TID already exists");
}
}
@@ -503,9 +476,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
node->received(now, req);
if (not node->isClient())
onNewNode(node, 1);
if (logger_)
logger_->d(node->id, "[node %s] can't find transaction with id %u", node->toString().c_str(), msg->tid);
return;
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find transaction", msg->id};
}
}
@@ -516,8 +487,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
onReportedAddr(msg->id, msg->addr);
if (req and (req->cancelled() or req->expired() or req->completed())) {
if (logger_)
logger_->w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
DHT_LOG.w(node->id, "[node %s] response to expired, cancelled or completed request", node->toString().c_str());
return;
}
@@ -533,8 +503,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
onError(req, DhtProtocolException {msg->error_code});
} else {
if (logIncoming_)
if (logger_)
logger_->w(msg->id, "[node %s %s] received unknown error message %u",
DHT_LOG.w(msg->id, "[node %s %s] received unknown error message %u",
msg->id.toString().c_str(), from.toString().c_str(), msg->error_code);
}
break;
@@ -566,14 +535,12 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
case MessageType::Ping:
++in_stats.ping;
if (logIncoming_)
if (logger_)
logger_->d(node->id, "[node %s] sending pong", node->toString().c_str());
DHT_LOG.d(node->id, "[node %s] sending pong", node->toString().c_str());
onPing(node);
sendPong(from, msg->tid);
break;
case MessageType::FindNode: {
// if (logger_)
// logger_->d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
//DHT_LOG.d(msg->target, node->id, "[node %s] got 'find' request for %s (%d)", node->toString().c_str(), msg->target.toString().c_str(), msg->want);
++in_stats.find;
RequestAnswer answer = onFindNode(node, msg->target, msg->want);
auto nnodes = bufferNodes(from.getFamily(), msg->target, msg->want, answer.nodes4, answer.nodes6);
@@ -581,8 +548,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::GetValues: {
// if (logger_)
// logger_->d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
//DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'get' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.get;
RequestAnswer answer = onGetValues(node, msg->info_hash, msg->want, msg->query);
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
@@ -590,8 +556,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::AnnounceValue: {
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'put' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.put;
onAnnounce(node, msg->info_hash, msg->token, msg->values, msg->created);
@@ -604,15 +570,15 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
case MessageType::Refresh:
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'refresh' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
onRefresh(node, msg->info_hash, msg->token, msg->value_id);
/* Same note as above in MessageType::AnnounceValue applies. */
sendValueAnnounced(from, msg->tid, msg->value_id);
break;
case MessageType::Listen: {
if (logIncoming_ and logger_)
logger_->d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
if (logIncoming_)
DHT_LOG.d(msg->info_hash, node->id, "[node %s] got 'listen' request for %s", node->toString().c_str(), msg->info_hash.toString().c_str());
++in_stats.listen;
RequestAnswer answer = onListen(node, msg->info_hash, msg->token, msg->socket_id, std::move(msg->query));
auto nnodes = bufferNodes(from.getFamily(), msg->info_hash, msg->want, answer.nodes4, answer.nodes6);
@@ -623,8 +589,7 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
break;
}
} catch (const std::overflow_error& e) {
if (logger_)
logger_->e("Can't send value: buffer not large enough !");
DHT_LOG.e("Can't send value: buffer not large enough !");
} catch (DhtProtocolException& e) {
sendError(from, msg->tid, e.getCode(), e.getMsg().c_str(), true);
}
@@ -654,7 +619,7 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
TransId tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -664,15 +629,14 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&&) {
if (logger_)
logger_->d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
DHT_LOG.d(req_status.node->id, "[node %s] got pong !", req_status.node->toString().c_str());
if (on_done) {
on_done(req_status, {});
}
@@ -692,7 +656,7 @@ void
NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -703,8 +667,8 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
send(addr, buffer.data(), buffer.size());
@@ -716,7 +680,7 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -733,8 +697,8 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -762,33 +726,28 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
unsigned sendWant = (want > 0) ? 1 : 0;
pk.pack(KEY_A); pk.pack_map(2 + sendQuery + sendWant);
pk.pack(KEY_A); pk.pack_map(2 +
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
(want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(info_hash);
if (sendQuery) {
pk.pack(KEY_Q); pk.pack(query);
}
if (sendWant) {
pk.pack(KEY_REQ_WANT);
unsigned sendWant4 = (want & WANT4) ? 1 : 0;
unsigned sendWant6 = (want & WANT6) ? 1 : 0;
pk.pack_array(sendWant4 + sendWant6);
if (sendWant4) pk.pack(AF_INET);
if (sendWant6) pk.pack(AF_INET6);
}
pk.pack(KEY_Q); pk.pack(query);
if (want > 0) {
pk.pack(KEY_REQ_WANT);
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
if (want & WANT4) pk.pack(AF_INET);
if (want & WANT6) pk.pack(AF_INET6);
}
pk.pack(KEY_Q); pk.pack(QUERY_GET);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -882,8 +841,7 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
for (const auto& b : svals)
buffer.write((const char*)b.data(), b.size());
// if (logger_)
// logger_->d("sending %lu bytes of values", total_size);
// DHT_LOG.d("sending %lu bytes of values", total_size);
svals.clear();
} else {
for (const auto& b : svals)
@@ -903,9 +861,9 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(config.network?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
pk.pack_map(3+(network?1:0));
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
@@ -928,7 +886,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -949,10 +907,10 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
}
std::vector<Blob> svals {};
if (not st.empty()) { /* pack complete values */
if (query.select.empty()) {
auto fields = query.select.getSelection();
if (fields.empty()) {
svals = packValueHeader(buffer, st);
} else { /* pack fields */
auto fields = query.select.getSelection();
pk.pack(KEY_REQ_FIELDS);
pk.pack_map(2);
pk.pack(std::string("f")); pk.pack(fields);
@@ -969,8 +927,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -1047,23 +1005,21 @@ NetworkEngine::sendListen(Sp<Node> n,
socket = previous->getSocket();
} else {
if (previous)
if (logger_)
logger_->e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
DHT_LOG.e(hash, "[node %s] trying refresh listen contract with wrong node", previous->node->toString().c_str());
socket = n->openSocket(std::move(socket_cb));
}
if (not socket) {
if (logger_)
logger_->e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
DHT_LOG.e(hash, "[node %s] unable to get a valid socket for listen. Aborting listen", n->toString().c_str());
return {};
}
TransId sid(socket);
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
auto has_query = not query.where.empty() or not query.select.empty();
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
pk.pack(KEY_A); pk.pack_map(4 + has_query);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(hash);
@@ -1079,8 +1035,8 @@ NetworkEngine::sendListen(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1104,7 +1060,7 @@ void
NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1115,8 +1071,8 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
send(addr, buffer.data(), buffer.size());
@@ -1134,7 +1090,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1151,16 +1107,15 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
if (msg.value_id == Value::INVALID_ID) {
if (logger_)
logger_->d(infohash, "Unknown search or announce!");
DHT_LOG.d(infohash, "Unknown search or announce!");
} else {
if (on_done) {
RequestAnswer answer {};
@@ -1193,7 +1148,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
TransId tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0));
pk.pack_map(5+(network?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1206,16 +1161,15 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
if (msg.value_id == Value::INVALID_ID) {
if (logger_)
logger_->d(infohash, "Unknown search or announce!");
DHT_LOG.d(infohash, "Unknown search or announce!");
} else {
if (on_done) {
RequestAnswer answer {};
@@ -1239,7 +1193,7 @@ void
NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(config.network?1:0));
pk.pack_map(4+(network?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1251,8 +1205,8 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
send(addr, buffer.data(), buffer.size());
@@ -1283,8 +1237,8 @@ NetworkEngine::sendError(const SockAddr& addr,
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(my_v);
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
if (network) {
pk.pack(KEY_NETID); pk.pack(network);
}
send(addr, buffer.data(), buffer.size());
@@ -1298,8 +1252,7 @@ NetworkEngine::maintainRxBuffer(Tid tid)
const auto& now = scheduler.time();
if (msg->second.start + RX_MAX_PACKET_TIME < now
|| msg->second.last_part + RX_TIMEOUT < now) {
if (logger_)
logger_->w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
DHT_LOG.w("Dropping expired partial message from %s", msg->second.from.toString().c_str());
partial_messages.erase(msg);
}
}
+54 -82
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,6 @@
#define close(x) closesocket(x)
#define write(s, b, f) send(s, b, (int)strlen(b), 0)
#else
#include <sys/select.h>
#include <fcntl.h>
#endif
@@ -106,20 +105,18 @@ void udpPipe(int fds[2])
}
#endif
UdpSocket::UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l) : logger(l) {
UdpSocket::UdpSocket(in_port_t port, const Logger& l) : logger(l) {
SockAddr bind4;
bind4.setFamily(AF_INET);
bind4.setPort(port);
SockAddr bind6;
bind6.setFamily(AF_INET6);
bind6.setPort(port);
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l) : logger(l)
UdpSocket::UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l) : logger(l)
{
std::lock_guard<std::mutex> lk(lock);
openSockets(bind4, bind6);
}
@@ -155,10 +152,8 @@ UdpSocket::sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool r
if (sendto(s, (const char*)data, size, flags, dest.get(), dest.getLength()) == -1) {
int err = errno;
if (logger)
logger->d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
logger.d("Can't send message to %s: %s", dest.toString().c_str(), strerror(err));
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
std::lock_guard<std::mutex> lk(lock);
auto bind4 = std::move(bound4), bind6 = std::move(bound6);
openSockets(bind4, bind6);
return sendTo(dest, data, size, false);
@@ -185,8 +180,8 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
udpPipe(stopfds);
#endif
int stop_readfd = stopfds[0];
stopfd = stopfds[1];
s4 = -1;
s6 = -1;
@@ -195,8 +190,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s4 = bindSocket(bind4, bound4);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet socket: %s", e.what());
logger.e("Can't bind inet socket: %s", e.what());
}
}
@@ -211,8 +205,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s6 = bindSocket(b6, bound6);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
}
@@ -220,8 +213,7 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
try {
s6 = bindSocket(bind6, bound6);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
}
@@ -232,24 +224,23 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
}
running = true;
rcv_thread = std::thread([this, stop_readfd, ls4=s4, ls6=s6]() mutable {
int selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
rcv_thread = std::thread([this, stop_readfd]() {
int selectFd = std::max({s4, s6, stop_readfd}) + 1;
try {
while (running) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
if(ls4 >= 0)
FD_SET(ls4, &readfds);
if(ls6 >= 0)
FD_SET(ls6, &readfds);
if(s4 >= 0)
FD_SET(s4, &readfds);
if(s6 >= 0)
FD_SET(s6, &readfds);
int rc = select(selectFd, &readfds, nullptr, nullptr, nullptr);
if (rc < 0) {
if (errno != EINTR) {
if (logger)
logger->e("Select error: %s", strerror(errno));
logger.e("Select error: %s", strerror(errno));
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
@@ -264,84 +255,66 @@ UdpSocket::openSockets(const SockAddr& bind4, const SockAddr& bind6)
if (FD_ISSET(stop_readfd, &readfds)) {
if (recv(stop_readfd, (char*)buf.data(), buf.size(), 0) < 0) {
if (logger)
logger->e("Got stop packet error: %s", strerror(errno));
logger.e("Got stop packet error: %s", strerror(errno));
break;
}
}
else if (ls4 >= 0 && FD_ISSET(ls4, &readfds))
rc = recvfrom(ls4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (ls6 >= 0 && FD_ISSET(ls6, &readfds))
rc = recvfrom(ls6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (s4 >= 0 && FD_ISSET(s4, &readfds))
rc = recvfrom(s4, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else if (s6 >= 0 && FD_ISSET(s6, &readfds))
rc = recvfrom(s6, (char*)buf.data(), buf.size(), 0, (sockaddr*)&from, &from_len);
else
continue;
if (rc > 0) {
auto pkts = getNewPacket();
auto& pkt = pkts.front();
pkt.data.insert(pkt.data.end(), buf.begin(), buf.begin()+rc);
pkt.from = {from, from_len};
pkt.received = clock::now();
onReceived(std::move(pkts));
auto pkt = std::unique_ptr<ReceivedPacket>(new ReceivedPacket);
pkt->data = {buf.begin(), buf.begin()+rc};
pkt->from = {from, from_len};
pkt->received = clock::now();
onReceived(std::move(pkt));
} else if (rc == -1) {
if (logger)
logger->e("Error receiving packet: %s", strerror(errno));
logger.e("Error receiving packet: %s", strerror(errno));
int err = errno;
if (err == EPIPE || err == ENOTCONN || err == ECONNRESET) {
if (not running) break;
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
if (lk.owns_lock()) {
if (not running) break;
if (ls4 >= 0) {
close(ls4);
try {
ls4 = bindSocket(bound4, bound4);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet socket: %s", e.what());
}
if (s4 >= 0) {
close(s4);
try {
s4 = bindSocket(bound4, bound4);
} catch (const DhtException& e) {
logger.e("Can't bind inet socket: %s", e.what());
}
if (ls6 >= 0) {
close(ls6);
try {
ls6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
if (logger)
logger->e("Can't bind inet6 socket: %s", e.what());
}
}
if (ls4 < 0 && ls6 < 0)
break;
s4 = ls4;
s6 = ls6;
selectFd = std::max({ls4, ls6, stop_readfd}) + 1;
} else {
break;
}
if (s6 >= 0) {
close(s6);
try {
s6 = bindSocket(bound6, bound6);
} catch (const DhtException& e) {
logger.e("Can't bind inet6 socket: %s", e.what());
}
}
if (s4 < 0 && s6 < 0)
break;
selectFd = std::max({s4, s6, stop_readfd}) + 1;
}
}
}
}
} catch (const std::exception& e) {
if (logger)
logger->e("Error in UdpSocket rx thread: %s", e.what());
logger.e("Error in UdpSocket rx thread: %s", e.what());
}
if (ls4 >= 0)
close(ls4);
if (ls6 >= 0)
close(ls6);
if (s4 >= 0)
close(s4);
if (s6 >= 0)
close(s6);
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
if (stop_readfd != -1)
close(stop_readfd);
if (stopfd != -1)
close(stopfd);
std::unique_lock<std::mutex> lk(lock, std::try_to_lock);
if (lk.owns_lock()) {
s4 = -1;
s6 = -1;
bound4 = {};
bound6 = {};
stopfd = -1;
}
stopfd = -1;
});
}
@@ -351,8 +324,7 @@ UdpSocket::stop()
if (running.exchange(false)) {
auto sfd = stopfd;
if (sfd != -1 && write(sfd, "\0", 1) == -1) {
if (logger)
logger->e("Can't write to stop fd");
logger.e("Can't write to stop fd");
}
}
}
+5 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -30,15 +30,17 @@ constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME;
constexpr std::chrono::minutes Node::NODE_GOOD_TIME;
constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME;
Node::Node(const InfoHash& id, const SockAddr& addr, std::mt19937_64& rd, bool client)
Node::Node(const InfoHash& id, const SockAddr& addr, bool client)
: id(id), addr(addr), is_client(client), sockets_()
{
thread_local crypto::random_device rd {};
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
}
Node::Node(const InfoHash& id, SockAddr&& addr, std::mt19937_64& rd, bool client)
Node::Node(const InfoHash& id, SockAddr&& addr, bool client)
: id(id), addr(std::move(addr)), is_client(client), sockets_()
{
thread_local crypto::random_device rd {};
transaction_id = std::uniform_int_distribution<Tid>{1}(rd);
}
+8 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -37,8 +37,8 @@ NodeCache::getNode(const InfoHash& id, sa_family_t family) {
Sp<Node>
NodeCache::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client) {
if (not id)
return std::make_shared<Node>(id, addr, rd, client);
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client, rd);
return std::make_shared<Node>(id, addr);
return cache(addr.getFamily()).getNode(id, addr, now, confirm, client);
}
std::vector<Sp<Node>>
@@ -104,13 +104,13 @@ NodeCache::NodeMap::getNode(const InfoHash& id)
}
Sp<Node>
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client, std::mt19937_64& rd)
NodeCache::NodeMap::getNode(const InfoHash& id, const SockAddr& addr, time_point now, bool confirm, bool client)
{
auto& nref = (*this)[id];
auto node = nref.lock();
auto it = emplace(id, std::weak_ptr<Node>{});
auto node = it.first->second.lock();
if (not node) {
node = std::make_shared<Node>(id, addr, rd, client);
nref = node;
node = std::make_shared<Node>(id, addr, client);
it.first->second = node;
if (cleanup_counter++ == CLEANUP_FREQ) {
cleanup();
cleanup_counter = 0;
+4 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@ namespace dht {
constexpr const std::chrono::seconds OpCache::EXPIRATION;
bool
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
std::vector<Sp<Value>> newValues;
for (const auto& v : vals) {
auto viop = values.emplace(v->id, v);
@@ -31,21 +31,16 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clo
} else {
viop.first->second.refCount++;
}
viop.first->second.updated = t;
}
return newValues.empty() ? true : callback(newValues, false);
}
bool
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t) {
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
std::vector<Sp<Value>> expiredValues;
for (const auto& v : vals) {
auto vit = values.find(v->id);
if (vit != values.end()) {
if (vit->second.updated > t)
continue;
vit->second.updated = t;
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
@@ -57,16 +52,12 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals, const system_c
}
bool
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids, const system_clock::time_point& t)
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
{
std::vector<Sp<Value>> expiredValues;
for (const auto& vid : vids) {
auto vit = values.find(vid);
if (vit != values.end()) {
if (vit->second.updated > t)
continue;
vit->second.updated = t;
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
+7 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,6 @@ struct OpCacheValueStorage
{
Sp<Value> data {};
unsigned refCount {1};
system_clock::time_point updated {system_clock::time_point::min()};
OpCacheValueStorage(Sp<Value> val) : data(val) {}
};
@@ -48,16 +47,16 @@ public:
};
}
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
bool onValue(const std::vector<Sp<Value>>& vals, bool expired) {
if (expired)
return onValuesExpired(vals, t);
return onValuesExpired(vals);
else
return onValuesAdded(vals, t);
return onValuesAdded(vals);
}
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
bool onValuesExpired(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
bool onValuesExpired(const std::vector<Value::Id>& vals, const system_clock::time_point& t = system_clock::time_point::min());
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Value::Id>& vals);
void onNodeChanged(ListenSyncStatus status) {
switch (status) {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+350 -187
View File
@@ -1,8 +1,7 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,120 +21,328 @@
#include "network_utils.h"
#include "utils.h"
#include <asio.hpp>
#ifdef _WIN32
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#include <cstring>
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#define close(x) closesocket(x)
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#ifndef IPV6_JOIN_GROUP
#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
namespace dht {
// Organization-local Scope multicast
constexpr char MULTICAST_ADDRESS_IPV4[] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[] = "ff08::101";
constexpr char MULTICAST_ADDRESS_IPV4[12] = "239.192.0.1";
constexpr char MULTICAST_ADDRESS_IPV6[10] = "ff08::101";
class PeerDiscovery::DomainPeerDiscovery
{
public:
DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext = {}, Sp<Logger> logger = {});
DomainPeerDiscovery(sa_family_t domain, in_port_t port);
~DomainPeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
/**
* startPublish - Keeping sending data until node is joinned or stop is called - msgpack
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
/**
* Thread Stopper
*/
void stop();
/**
* Remove possible callBack to discovery
*/
bool stopDiscovery(const std::string &type);
/**
* Remove different serivce message to send
*/
bool stopPublish(const std::string &type);
void connectivityChanged();
/**
* Configure the sockopt to be able to listen multicast group
*/
static void joinMulticast(int sockfd, sa_family_t family);
/**
* Join the threads
*/
void join() {
if(listening_.joinable()) listening_.join();
if(sending_.joinable()) sending_.join();
}
private:
Sp<Logger> logger_;
//dmtx_ for callbackmap_ and drunning_ (write)
std::mutex dmtx_;
//mtx_ for messages_ and lrunning (listen)
std::mutex mtx_;
std::shared_ptr<asio::io_context> ioContext_;
asio::ip::udp::socket sockFd_;
asio::ip::udp::endpoint sockAddrSend_;
std::condition_variable cv_;
bool lrunning_ {false};
bool drunning_ {false};
sa_family_t domain_ {AF_UNSPEC};
int port_;
int sockFd_ {-1};
int stopWriteFd_ {-1};
std::array<char, 64 * 1024> receiveBuf_;
asio::ip::udp::endpoint receiveFrom_;
SockAddr sockAddrSend_;
//Thread export to be joined
std::thread listening_;
std::thread sending_;
msgpack::sbuffer sbuf_;
std::map<std::string, msgpack::sbuffer> messages_;
std::map<std::string, ServiceDiscoveredCallback> callbackmap_;
bool lrunning_ {false};
bool drunning_ {false};
/**
* Multicast Socket Initialization, accept IPV4, IPV6
*/
static int init(sa_family_t domain);
/**
* Receive messages
*/
std::pair<SockAddr, msgpack::object_handle> recvFrom();
/**
* Listener pack thread loop
*/
void loopListener();
void query(const asio::ip::udp::endpoint& peer);
/**
* Listener Parameters Setup
*/
void setupListener();
/**
* Sender Parameters Setup
*/
void setupSender();
/**
* Sender Parameters Setup
*/
void reloadMessages();
void stopDiscovery();
void stopPublish();
void publish(const asio::ip::udp::endpoint& peer);
void reDiscover();
};
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
: logger_(logger)
, ioContext_(ioContext)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(sa_family_t domain, in_port_t port)
: domain_(domain), port_(port), sockFd_(init(domain))
{
try {
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()));
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
sockFd_.bind({domain, port});
} catch (const std::exception& e) {
if (logger_)
logger_->e("Can't start peer discovery for %s: %s",
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
}
joinMulticast(sockFd_, domain);
setupListener();
setupSender();
}
PeerDiscovery::DomainPeerDiscovery::~DomainPeerDiscovery()
{
stop();
sockFd_.close();
join();
if (sockFd_ != -1)
close(sockFd_);
#ifdef _WIN32
WSACleanup();
#endif
}
int
PeerDiscovery::DomainPeerDiscovery::init(sa_family_t domain)
{
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
throw std::runtime_error(std::string("Can't initialize Winsock2 ") + strerror(errno));
}
#endif
int sockfd = socket(domain, SOCK_DGRAM, 0);
if (sockfd < 0) {
throw std::runtime_error(std::string("Socket Creation Error: ") + strerror(errno));
}
net::setNonblocking(sockfd);
return sockfd;
}
void
PeerDiscovery::DomainPeerDiscovery::setupListener()
{
SockAddr sockAddrListen_;
sockAddrListen_.setFamily(domain_);
sockAddrListen_.setPort(port_);
sockAddrListen_.setAny();
unsigned int opt = 1;
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEADDR failed: " << strerror(errno) << std::endl;
}
#ifdef SO_REUSEPORT
if (setsockopt(sockFd_, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt SO_REUSEPORT failed: " << strerror(errno) << std::endl;
}
#endif
// bind to receive address
if (bind(sockFd_, sockAddrListen_.get(), sockAddrListen_.getLength()) < 0){
throw std::runtime_error(std::string("Error binding socket: ") + strerror(errno));
}
}
void
PeerDiscovery::DomainPeerDiscovery::joinMulticast(int sockfd, sa_family_t family)
{
switch (family)
{
case AF_INET:{
ip_mreq config_ipv4;
//This option can be used to set the interface for sending outbound
//multicast datagrams from the sockets application.
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&config_ipv4.imr_interface, sizeof( struct in_addr )) < 0 ) {
throw std::runtime_error(std::string("Bound Network Interface IPv4 Error: ") + strerror(errno));
}
//The IP_MULTICAST_TTL socket option allows the application to primarily
//limit the lifetime of the packet in the Internet and prevent it from circulating indefinitely
unsigned char ttl4 = 20;
if( setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl4, sizeof( ttl4 )) < 0 ) {
throw std::runtime_error(std::string("TTL Sockopt Error: ") + strerror(errno));
}
// config the listener to be interested in joining in the multicast group
config_ipv4.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS_IPV4);
config_ipv4.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&config_ipv4, sizeof(config_ipv4)) < 0){
throw std::runtime_error(std::string(" Member Addition IPv4 Error: ") + strerror(errno));
}
break;
}
case AF_INET6: {
ipv6_mreq config_ipv6;
/* unsigned int outif = 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof(outif)) < 0) {
std::cerr << "Can't assign multicast interface: " << strerror(errno) << std::endl;
} */
unsigned int ttl6 = 20;
if( setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl6, sizeof( ttl6 )) < 0 ) {
throw std::runtime_error(std::string("Hop Count Set Error: ") + strerror(errno));
}
config_ipv6.ipv6mr_interface = 0;
inet_pton(AF_INET6, MULTICAST_ADDRESS_IPV6, &config_ipv6.ipv6mr_multiaddr);
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&config_ipv6, sizeof(config_ipv6)) < 0){
throw std::runtime_error(std::string("Member Addition IPv6 Error: ") + strerror(errno));
}
break;
}
}
}
void
PeerDiscovery::DomainPeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
std::lock_guard<std::mutex> lck(dmtx_);
std::unique_lock<std::mutex> lck(dmtx_);
callbackmap_[type] = callback;
if (not drunning_) {
if (listening_.joinable())
listening_.join();
drunning_ = true;
ioContext_->post([this] () {
loopListener();
query(sockAddrSend_);
});
listening_ = std::thread(&DomainPeerDiscovery::loopListener, this);
}
}
std::pair<SockAddr, msgpack::object_handle>
PeerDiscovery::DomainPeerDiscovery::recvFrom()
{
sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
std::array<uint8_t, 64 * 1024> buf;
ssize_t nbytes = recvfrom(
sockFd_,
(char*)buf.data(), buf.size(),
0,
(sockaddr*)&sa, &sa_len
);
if (nbytes < 0)
throw std::runtime_error(std::string("Error receiving packet: ") + strerror(errno));
return { SockAddr { sa, sa_len }, msgpack::unpack(reinterpret_cast<char*>(buf.data()), nbytes) };
}
void
PeerDiscovery::DomainPeerDiscovery::loopListener()
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
return;
sockFd_.async_receive_from(asio::buffer(receiveBuf_), receiveFrom_, [this](const asio::error_code& error, size_t bytes) {
if (error == asio::error::operation_aborted)
return;
if (error) {
if (logger_)
logger_->e("Error receiving message: %s", error.message().c_str());
}
try {
auto rcv = msgpack::unpack(receiveBuf_.data(), bytes);
msgpack::object obj = rcv.get();
int stopfds_pipe[2];
#ifndef _WIN32
if (pipe(stopfds_pipe) == -1)
throw std::runtime_error(std::string("Can't open pipe: ") + strerror(errno));
#else
net::udpPipe(stopfds_pipe);
#endif
int stop_readfd = stopfds_pipe[0];
stopWriteFd_ = stopfds_pipe[1];
if (obj.type == msgpack::type::STR) {
if (lrunning_ and obj.as<std::string>() == "q")
publish(receiveFrom_);
} else if (obj.type == msgpack::type::MAP) {
while (true) {
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
}
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(stop_readfd, &readfds);
FD_SET(sockFd_, &readfds);
int data_coming = select(std::max(sockFd_, stop_readfd) + 1, &readfds, nullptr, nullptr, nullptr);
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
break;
}
if (data_coming < 0) {
if(errno != EINTR) {
perror("Select Error");
std::this_thread::sleep_for( std::chrono::seconds(1) );
}
} else if (data_coming > 0) {
if (FD_ISSET(stop_readfd, &readfds)) {
std::array<uint8_t, 64 * 1024> buf;
recv(stop_readfd, (char*)buf.data(), buf.size(), 0);
}
try {
auto rcv = recvFrom();
msgpack::object obj = rcv.second.get();
if (obj.type != msgpack::type::MAP)
continue;
for (unsigned i = 0; i < obj.via.map.size; i++) {
auto& o = obj.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
@@ -144,82 +351,72 @@ PeerDiscovery::DomainPeerDiscovery::loopListener()
ServiceDiscoveredCallback cb;
{
std::lock_guard<std::mutex> lck(dmtx_);
if (drunning_) {
auto callback = callbackmap_.find(key);
if (callback != callbackmap_.end())
cb = callback->second;
} else
return;
auto callback = callbackmap_.find(key);
if (callback != callbackmap_.end())
cb = callback->second;
}
if (cb)
cb(std::move(o.val), SockAddr{ receiveFrom_.data(), (socklen_t)receiveFrom_.size() });
cb(std::move(o.val), std::move(rcv.first));
}
} else {
throw msgpack::type_error{};
} catch (const std::exception& e) {
std::cerr << "Error receiving packet: " << e.what() << std::endl;
}
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error receiving packet: %s", e.what());
}
loopListener();
});
}
if (stop_readfd != -1)
close(stop_readfd);
if (stopWriteFd_ != -1) {
close(stopWriteFd_);
stopWriteFd_ = -1;
}
}
void
PeerDiscovery::DomainPeerDiscovery::query(const asio::ip::udp::endpoint& peer)
PeerDiscovery::DomainPeerDiscovery::setupSender()
{
std::lock_guard<std::mutex> lck(dmtx_);
if (not drunning_)
return;
msgpack::sbuffer pbuf_request;
msgpack::pack(pbuf_request, "q");
sockFd_.async_send_to(asio::buffer(pbuf_request.data(), pbuf_request.size()), peer,
[logger=logger_, peer] (const asio::error_code& ec, size_t)
{
if (ec and (ec != asio::error::operation_aborted) and logger)
logger->w("Error sending packet to: %s with err: %s",
peer.address().to_string().c_str(),
ec.message().c_str());
}
);
// Setup sender address
sockAddrSend_.setFamily(domain_);
sockAddrSend_.setAddress(domain_ == AF_INET ? MULTICAST_ADDRESS_IPV4 : MULTICAST_ADDRESS_IPV6);
sockAddrSend_.setPort(port_);
}
void
PeerDiscovery::DomainPeerDiscovery::publish(const asio::ip::udp::endpoint& peer)
{
std::lock_guard<std::mutex> lck(mtx_);
if (not lrunning_)
return;
sockFd_.async_send_to(asio::buffer(sbuf_.data(), sbuf_.size()), peer,
[logger=logger_, peer] (const asio::error_code& ec, size_t)
{
if (ec and (ec != asio::error::operation_aborted) and logger)
logger->w("Error sending packet to: %s with err: %s",
peer.address().to_string().c_str(),
ec.message().c_str());
}
);
}
void
PeerDiscovery::DomainPeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
{
//Set up New Sending pack
msgpack::sbuffer pack_buf_c;
pack_buf_c.write(pack_buf.data(),pack_buf.size());
std::lock_guard<std::mutex> lck(mtx_);
std::unique_lock<std::mutex> lck(mtx_);
messages_[type] = std::move(pack_buf_c);
reloadMessages();
lrunning_ = true;
ioContext_->post([this] () { publish(sockAddrSend_); });
if (not lrunning_) {
if (sending_.joinable())
sending_.join();
lrunning_ = true;
sending_ = std::thread([this](){
std::unique_lock<std::mutex> lck(mtx_);
while (lrunning_) {
ssize_t nbytes = sendto(
sockFd_,
sbuf_.data(),
sbuf_.size(),
0,
sockAddrSend_.get(),
sockAddrSend_.getLength()
);
if (nbytes < 0) {
std::cerr << "Error sending packet: " << strerror(errno) << std::endl;
}
if (cv_.wait_for(lck,std::chrono::seconds(3),[&]{ return !lrunning_; }))
break;
}
});
}
}
bool
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string &type)
{
std::lock_guard<std::mutex> lck(dmtx_);
if (callbackmap_.erase(type) > 0) {
@@ -231,7 +428,7 @@ PeerDiscovery::DomainPeerDiscovery::stopDiscovery(const std::string& type)
}
bool
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string &type)
{
std::lock_guard<std::mutex> lck(mtx_);
if (messages_.erase(type) > 0) {
@@ -247,24 +444,40 @@ PeerDiscovery::DomainPeerDiscovery::stopPublish(const std::string& type)
void
PeerDiscovery::DomainPeerDiscovery::stopDiscovery()
{
drunning_ = false;
#ifdef _WIN32
#define write(s, b, f) send((s), (b), (f), 0)
#endif
if (drunning_) {
drunning_ = false;
if (stopWriteFd_ != -1) {
if (write(stopWriteFd_, "\0", 1) == -1) {
std::cerr << "Can't send stop message: " << strerror(errno) << std::endl;
}
}
}
#ifdef _WIN32
#undef write
#endif
}
void
PeerDiscovery::DomainPeerDiscovery::stopPublish()
{
lrunning_ = false;
if (lrunning_) {
lrunning_ = false;
cv_.notify_all();
}
}
void
PeerDiscovery::DomainPeerDiscovery::stop()
{
{
std::lock_guard<std::mutex> lck(dmtx_);
std::unique_lock<std::mutex> lck(dmtx_);
stopDiscovery();
}
{
std::lock_guard<std::mutex> lck(mtx_);
std::unique_lock<std::mutex> lck(mtx_);
stopPublish();
}
}
@@ -281,85 +494,38 @@ PeerDiscovery::DomainPeerDiscovery::reloadMessages()
}
}
void
PeerDiscovery::DomainPeerDiscovery::reDiscover()
PeerDiscovery::PeerDiscovery(in_port_t port)
{
asio::error_code ec;
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address()), ec);
if (ec and logger_)
logger_->w("can't multicast on %s: %s",
sockAddrSend_.address().to_string().c_str(),
ec.message().c_str());
query(sockAddrSend_);
}
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
reDiscover();
publish(sockAddrSend_);
}
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
{
if (not ioContext) {
ioContext = std::make_shared<asio::io_context>();
ioContext_ = ioContext;
ioRunnner_ = std::thread([logger, ioContext] {
try {
if (logger)
logger->d("[peerdiscovery] starting io_context");
auto work = asio::make_work_guard(*ioContext);
ioContext->run();
if (logger)
logger->d("[peerdiscovery] io_context stopped");
}
catch (const std::exception& ex){
if (logger)
logger->e("[peerdiscovery] run error: %s", ex.what());
}
});
}
try {
peerDiscovery4_.reset(new DomainPeerDiscovery(asio::ip::udp::v4(), port, ioContext, logger));
peerDiscovery4_.reset(new DomainPeerDiscovery(AF_INET, port));
} catch(const std::exception& e){
if (logger)
logger->e("[peerdiscovery] can't start IPv4: %s", e.what());
std::cerr << "Can't start peer discovery (IPv4): " << e.what() << std::endl;
}
try {
peerDiscovery6_.reset(new DomainPeerDiscovery(asio::ip::udp::v6(), port, ioContext, logger));
peerDiscovery6_.reset(new DomainPeerDiscovery(AF_INET6, port));
} catch(const std::exception& e) {
if (logger)
logger->e("[peerdiscovery] can't start IPv6: %s", e.what());
std::cerr << "Can't start peer discovery (IPv6): " << e.what() << std::endl;
}
}
PeerDiscovery::~PeerDiscovery() {
stop();
if (ioContext_)
ioContext_->stop();
if (ioRunnner_.joinable())
ioRunnner_.join();
}
PeerDiscovery::~PeerDiscovery(){}
void
PeerDiscovery::startDiscovery(const std::string& type, ServiceDiscoveredCallback callback)
PeerDiscovery::startDiscovery(const std::string &type, ServiceDiscoveredCallback callback)
{
if (peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if (peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
if(peerDiscovery4_) peerDiscovery4_->startDiscovery(type, callback);
if(peerDiscovery6_) peerDiscovery6_->startDiscovery(type, callback);
}
void
PeerDiscovery::startPublish(const std::string& type, const msgpack::sbuffer& pack_buf)
PeerDiscovery::startPublish(const std::string &type, const msgpack::sbuffer &pack_buf)
{
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if (peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
if(peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
if(peerDiscovery6_) peerDiscovery6_->startPublish(type, pack_buf);
}
void
PeerDiscovery::startPublish(sa_family_t domain, const std::string& type, const msgpack::sbuffer& pack_buf)
PeerDiscovery::startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf)
{
if (domain == AF_INET) {
if (peerDiscovery4_) peerDiscovery4_->startPublish(type, pack_buf);
@@ -371,8 +537,8 @@ PeerDiscovery::startPublish(sa_family_t domain, const std::string& type, const m
void
PeerDiscovery::stop()
{
if (peerDiscovery4_) peerDiscovery4_->stop();
if (peerDiscovery6_) peerDiscovery6_->stop();
if(peerDiscovery4_) peerDiscovery4_->stop();
if(peerDiscovery6_) peerDiscovery6_->stop();
}
bool
@@ -392,7 +558,7 @@ PeerDiscovery::stopPublish(const std::string &type)
}
bool
PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
PeerDiscovery::stopPublish(sa_family_t domain, const std::string &type)
{
if (domain == AF_INET) {
return peerDiscovery4_ and peerDiscovery4_->stopPublish(type);
@@ -403,12 +569,9 @@ PeerDiscovery::stopPublish(sa_family_t domain, const std::string& type)
}
void
PeerDiscovery::connectivityChanged()
{
if (peerDiscovery4_)
peerDiscovery4_->connectivityChanged();
if (peerDiscovery6_)
peerDiscovery6_->connectivityChanged();
PeerDiscovery::join() {
if(peerDiscovery4_) peerDiscovery4_->join();
if(peerDiscovery6_) peerDiscovery6_->join();
}
} /* namespace dht */
}
+5 -16
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -29,8 +29,6 @@ namespace net {
class NetworkEngine;
struct ParsedMessage;
extern std::atomic<size_t> REQ_COUNT;
/*!
* @class Request
* @brief An atomic request destined to a node.
@@ -69,22 +67,14 @@ struct Request {
}
}
Request(State state = State::PENDING) : state_(state) {
REQ_COUNT++;
}
Request(State state = State::PENDING) : state_(state) {}
Request(MessageType type, Tid tid,
Sp<Node> node,
Blob&& msg,
std::function<void(const Request&, ParsedMessage&&)> on_done,
std::function<void(const Request&, bool)> on_expired,
Tid socket = 0) :
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) {
REQ_COUNT++;
}
~Request() {
REQ_COUNT--;
}
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) { }
Tid getTid() const { return tid; }
MessageType getType() const { return type; }
@@ -118,13 +108,13 @@ private:
static const constexpr size_t MAX_ATTEMPT_COUNT {3};
bool isExpired(time_point now) const {
return pending() and now > last_try + attempt_duration and attempt_count >= Request::MAX_ATTEMPT_COUNT;
return pending() and now > last_try + Node::MAX_RESPONSE_TIME and attempt_count >= Request::MAX_ATTEMPT_COUNT;
}
void clear() {
on_done = {};
on_expired = {};
msg = {};
msg.clear();
}
const Tid tid {0}; /* the request id. */
@@ -132,7 +122,6 @@ private:
State state_ {State::PENDING};
unsigned attempt_count {0}; /* number of attempt to process the request. */
duration attempt_duration {((duration)Node::MAX_RESPONSE_TIME)/2};
time_point start {time_point::min()}; /* time when the request is created. */
time_point last_try {time_point::min()}; /* time of the last attempt to process the request. */
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@ namespace dht {
namespace crypto {
random_device::random_device() :
gen(std::chrono::system_clock::now().time_since_epoch().count() ^ std::chrono::high_resolution_clock::now().count())
gen(std::chrono::system_clock::now().time_since_epoch().count())
{}
random_device::result_type
+10 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,8 +25,15 @@
namespace dht {
static std::mt19937 rd{ dht::crypto::random_device{}() };
#ifdef _WIN32
static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
Sp<Node>
Bucket::randomNode(std::mt19937_64& rd)
Bucket::randomNode()
{
if (nodes.empty())
return nullptr;
@@ -58,7 +65,7 @@ void Bucket::sendCachedPing(net::NetworkEngine& ne)
}
InfoHash
RoutingTable::randomId(const RoutingTable::const_iterator& it, std::mt19937_64& rd) const
RoutingTable::randomId(const RoutingTable::const_iterator& it) const
{
int bit1 = it->first.lowbit();
int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
@@ -67,12 +74,6 @@ RoutingTable::randomId(const RoutingTable::const_iterator& it, std::mt19937_64&
if (bit >= 8*(int)HASH_LEN)
return it->first;
#ifdef _WIN32
std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
#else
std::uniform_int_distribution<uint8_t> rand_byte;
#endif
int b = bit/8;
InfoHash id_return;
std::copy_n(it->first.cbegin(), b, id_return.begin());
+57 -70
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -67,8 +67,9 @@ struct Dht::SearchNode {
Sp<net::Request> req {};
CachedListenStatus(ValueStateCallback&& cb, SyncCallback&& scb)
: cache(std::forward<ValueStateCallback>(cb), std::forward<SyncCallback>(scb)) {}
CachedListenStatus(CachedListenStatus&&) = delete;
CachedListenStatus(CachedListenStatus&&) = default;
CachedListenStatus(const CachedListenStatus&) = delete;
CachedListenStatus& operator=(const CachedListenStatus&) = delete;
};
using NodeListenerStatus = std::map<Sp<Query>, CachedListenStatus>;
@@ -85,15 +86,15 @@ struct Dht::SearchNode {
Blob token {}; /* last token the node sent to us after a get request */
time_point last_get_reply {time_point::min()}; /* last time received valid token */
Sp<Scheduler::Job> syncJob {};
bool candidate {false}; /* A search node is candidate if the search is/was synced and this
node is a new candidate for inclusion. */
Sp<Scheduler::Job> syncJob {};
SearchNode() : node() {}
SearchNode(const SearchNode&) = delete;
SearchNode(SearchNode&&) = delete;
SearchNode(SearchNode&&) = default;
SearchNode& operator=(const SearchNode&) = delete;
SearchNode& operator=(SearchNode&&) = delete;
SearchNode& operator=(SearchNode&&) = default;
SearchNode(const Sp<Node>& node) : node(node) {}
~SearchNode() {
@@ -262,7 +263,7 @@ struct Dht::SearchNode {
* @return true if there exists an expired request, else false.
*/
static bool pending(const SyncStatus& status) {
return std::find_if(status.cbegin(), status.cend(),
return std::find_if(status.begin(), status.end(),
[](const SyncStatus::value_type& r){
return r.second and r.second->pending();
}) != status.end();
@@ -292,26 +293,26 @@ struct Dht::SearchNode {
acked.clear();
}
inline bool isListening(time_point now, duration listen_expire) const {
bool isListening(time_point now) const {
auto ls = listenStatus.begin();
for ( ; ls != listenStatus.end() ; ++ls) {
if (isListening(now, ls, listen_expire)) {
if (isListening(now, ls)) {
break;
}
}
return ls != listenStatus.end();
}
inline bool isListening(time_point now, const Sp<Query>& q, duration listen_expire) const {
bool isListening(time_point now, const Sp<Query>& q) const {
const auto& ls = listenStatus.find(q);
if (ls == listenStatus.end())
return false;
else
return isListening(now, ls, listen_expire);
return isListening(now, ls);
}
inline bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status, duration listen_expire) const {
bool isListening(time_point now, NodeListenerStatus::const_iterator listen_status) const {
if (listen_status == listenStatus.end() or not listen_status->second.req)
return false;
return listen_status->second.req->reply_time + listen_expire > now;
return listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME > now;
}
void cancelListen() {
for (const auto& status : listenStatus)
@@ -344,12 +345,12 @@ struct Dht::SearchNode {
* Assuming the node is synced, should the "listen" request with Query q be
* sent to this node now ?
*/
time_point getListenTime(const Sp<Query>& q, duration listen_expire) const {
time_point getListenTime(const Sp<Query>& q) const {
auto listen_status = listenStatus.find(q);
if (listen_status == listenStatus.end() or not listen_status->second.req)
return time_point::min();
return listen_status->second.req->pending() ? time_point::max() :
listen_status->second.req->reply_time + listen_expire - REANNOUNCE_MARGIN;
listen_status->second.req->reply_time + LISTEN_EXPIRE_TIME - REANNOUNCE_MARGIN;
}
/**
@@ -375,7 +376,7 @@ struct Dht::Search {
bool expired {false}; /* no node, or all nodes expired */
bool done {false}; /* search is over, cached for later */
std::vector<std::unique_ptr<SearchNode>> nodes {};
std::vector<SearchNode> nodes {};
/* pending puts */
std::vector<Announce> announce {};
@@ -415,17 +416,17 @@ struct Dht::Search {
bool insertNode(const Sp<Node>& n, time_point now, const Blob& token={});
SearchNode* getNode(const Sp<Node>& n) {
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](std::unique_ptr<SearchNode>& sn) {
return n == sn->node;
auto srn = std::find_if(nodes.begin(), nodes.end(), [&](SearchNode& sn) {
return n == sn.node;
});
return (srn == nodes.end()) ? nullptr : (*srn).get();
return (srn == nodes.end()) ? nullptr : &(*srn);
}
/* number of concurrent sync requests */
unsigned currentlySolicitedNodeCount() const {
unsigned count = 0;
for (const auto& n : nodes)
if (not n->isBad() and n->pendingGet())
if (not n.isBad() and n.pendingGet())
count++;
return count;
}
@@ -459,12 +460,12 @@ struct Dht::Search {
*/
void setDone(const Get& get) {
for (auto& n : nodes) {
auto pqs = n->pagination_queries.find(get.query);
if (pqs != n->pagination_queries.cend()) {
auto pqs = n.pagination_queries.find(get.query);
if (pqs != n.pagination_queries.cend()) {
for (auto& pq : pqs->second)
n->getStatus.erase(pq);
n.getStatus.erase(pq);
}
n->getStatus.erase(get.query);
n.getStatus.erase(get.query);
}
if (get.done_cb)
get.done_cb(true, getNodes());
@@ -477,15 +478,15 @@ struct Dht::Search {
*/
void setDone() {
for (auto& n : nodes) {
n->getStatus.clear();
n->listenStatus.clear();
n->acked.clear();
n.getStatus.clear();
n.listenStatus.clear();
n.acked.clear();
}
done = true;
}
bool isAnnounced(Value::Id id) const;
bool isListening(time_point now, duration exp) const;
bool isListening(time_point now) const;
void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
if (gcb or qcb) {
@@ -521,9 +522,9 @@ struct Dht::Search {
}
for (auto& sn : nodes) {
if (listeners.empty())
sn->cancelListen();
sn.cancelListen();
else if (query)
sn->cancelListen(query);
sn.cancelListen(query);
}
});
scheduler.edit(opExpirationJob, nextExpire);
@@ -557,14 +558,6 @@ struct Dht::Search {
else
++it;
}
for (auto& n : nodes) {
auto ackIt = n->acked.find(vid);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
n->acked.erase(ackIt);
}
}
return canceled;
}
@@ -572,14 +565,14 @@ struct Dht::Search {
* @return The number of non-good search nodes.
*/
unsigned getNumberOfBadNodes() const {
return std::count_if(nodes.begin(), nodes.end(), [](const std::unique_ptr<SearchNode>& sn) {
return sn->isBad();
return std::count_if(nodes.begin(), nodes.end(), [](const SearchNode& sn) {
return sn.isBad();
});
}
unsigned getNumberOfConsecutiveBadNodes() const {
unsigned count = 0;
std::find_if(nodes.begin(), nodes.end(), [&count](const std::unique_ptr<SearchNode>& sn) {
if (not sn->isBad())
std::find_if(nodes.begin(), nodes.end(), [&count](const SearchNode& sn) {
if (not sn.isBad())
return true;
++count;
return false;
@@ -598,7 +591,7 @@ struct Dht::Search {
*/
bool removeExpiredNode(const time_point& now) {
for (auto e = nodes.cend(); e != nodes.cbegin();) {
const Node& n = *(*(--e))->node;
const Node& n = *(--e)->node;
if (n.isRemovable(now)) {
//std::cout << "Removing expired node " << n.id << " from IPv" << (af==AF_INET?'4':'6') << " search " << id << std::endl;
nodes.erase(e);
@@ -670,14 +663,8 @@ struct Dht::Search {
});
// remove acked for cleared annouces
for (auto it = announced; it != announce.end(); ++it) {
for (auto& n : nodes) {
auto ackIt = n->acked.find(it->value->id);
if (ackIt != n->acked.end()) {
if (ackIt->second.first)
ackIt->second.first->cancel();
n->acked.erase(ackIt);
}
}
for (auto& n : nodes)
n.acked.erase(it->value->id);
}
announce.erase(announced, announce.end());
}
@@ -710,13 +697,13 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
auto n = nodes.end();
while (n != nodes.begin()) {
--n;
if ((*n)->node == snode) {
if (n->node == snode) {
found = true;
break;
}
/* Node not found. We could insert it after this one. */
if (id.xorCmp(nid, (*n)->node->id) > 0) {
if (id.xorCmp(nid, n->node->id) > 0) {
++n;
break;
}
@@ -740,7 +727,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
full = nodes.size() - bad >= SEARCH_NODES;
while (std::distance(nodes.cbegin(), t) - bad > SEARCH_NODES) {
--t;
if ((*t)->isBad())
if (t->isBad())
bad--;
}
}
@@ -756,7 +743,7 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
if (nodes.empty()) {
step_time = time_point::min();
}
n = nodes.emplace(n, std::make_unique<SearchNode>(snode));
n = nodes.insert(n, SearchNode(snode));
node.setTime(now);
new_search_node = true;
if (node.isExpired()) {
@@ -768,16 +755,16 @@ Dht::Search::insertNode(const Sp<Node>& snode, time_point now, const Blob& token
}
while (nodes.size() - bad > SEARCH_NODES) {
if (not expired and nodes.back()->isBad())
if (not expired and nodes.back().isBad())
bad--;
nodes.pop_back();
}
}
if (not token.empty()) {
(*n)->candidate = false;
(*n)->last_get_reply = now;
n->candidate = false;
n->last_get_reply = now;
if (token.size() <= 64)
(*n)->token = token;
n->token = token;
expired = false;
}
if (new_search_node)
@@ -791,7 +778,7 @@ Dht::Search::getNodes() const
std::vector<Sp<Node>> ret {};
ret.reserve(nodes.size());
for (const auto& sn : nodes)
ret.emplace_back(sn->node);
ret.emplace_back(sn.node);
return ret;
}
@@ -800,9 +787,9 @@ Dht::Search::isSynced(time_point now) const
{
unsigned i = 0;
for (const auto& n : nodes) {
if (n->isBad())
if (n.isBad())
continue;
if (not n->isSynced(now))
if (not n.isSynced(now))
return false;
if (++i == TARGET_NODES)
break;
@@ -833,9 +820,9 @@ Dht::Search::isDone(const Get& get) const
{
unsigned i = 0;
for (const auto& sn : nodes) {
if (sn->isBad())
if (sn.isBad())
continue;
if (not sn->isDone(get))
if (not sn.isDone(get))
return false;
if (++i == TARGET_NODES)
break;
@@ -850,9 +837,9 @@ Dht::Search::isAnnounced(Value::Id id) const
return false;
unsigned i = 0;
for (const auto& n : nodes) {
if (n->isBad())
if (n.isBad())
continue;
if (not n->isAnnounced(id))
if (not n.isAnnounced(id))
return false;
if (++i == TARGET_NODES)
return true;
@@ -861,20 +848,20 @@ Dht::Search::isAnnounced(Value::Id id) const
}
bool
Dht::Search::isListening(time_point now, duration listen_expire) const
Dht::Search::isListening(time_point now) const
{
if (nodes.empty() or listeners.empty())
return false;
unsigned i = 0;
for (const auto& n : nodes) {
if (n->isBad())
if (n.isBad())
continue;
SearchNode::NodeListenerStatus::const_iterator ls {};
for (ls = n->listenStatus.begin(); ls != n->listenStatus.end() ; ++ls) {
if (n->isListening(now, ls, listen_expire))
for (ls = n.listenStatus.begin(); ls != n.listenStatus.end() ; ++ls) {
if (n.isListening(now, ls))
break;
}
if (ls == n->listenStatus.end())
if (ls == n.listenStatus.end())
return false;
if (++i == LISTEN_NODES)
break;
+26 -57
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -17,9 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "securedht.h"
#include "rng.h"
@@ -37,7 +34,7 @@ extern "C" {
namespace dht {
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second)
{
if (!dht_) return;
for (const auto& type : DEFAULT_TYPES)
@@ -49,7 +46,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
registerInsecureType(CERTIFICATE_TYPE);
if (certificate_) {
auto certId = certificate_->getId();
auto certId = certificate_->getPublicKey().getId();
if (key_ and certId != key_->getPublicKey().getId())
throw DhtException("SecureDht: provided certificate doesn't match private key.");
@@ -59,8 +56,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
1
}, [this, certId](bool ok) {
if (ok)
if (logger_)
logger_->d(certId, "SecureDht: public key announced successfully");
DHT_LOG.d(certId, "SecureDht: public key announced successfully");
}, {}, true);
}
}
@@ -77,8 +73,7 @@ SecureDht::secureType(ValueType&& type)
v->signatureValid = v->owner and v->owner->checkSignature(v->getToSign(), v->signature);
}
if (!v->signatureValid) {
if (logger_)
logger_->w("Signature verification failed");
DHT_LOG.w("Signature verification failed");
return false;
}
}
@@ -88,8 +83,7 @@ SecureDht::secureType(ValueType&& type)
if (!o->isSigned())
return type.editPolicy(id, o, n, nid, a);
if (o->owner != n->owner) {
if (logger_)
logger_->w("Edition forbidden: owner changed.");
DHT_LOG.w("Edition forbidden: owner changed.");
return false;
}
if (!n->signatureChecked) {
@@ -97,16 +91,14 @@ SecureDht::secureType(ValueType&& type)
n->signatureValid = o->owner and o->owner->checkSignature(n->getToSign(), n->signature);
}
if (!n->signatureValid) {
if (logger_)
logger_->w("Edition forbidden: signature verification failed.");
DHT_LOG.w("Edition forbidden: signature verification failed.");
return false;
}
if (o->seq == n->seq) {
// If the data is exactly the same,
// it can be reannounced, possibly by someone else.
if (o->getToSign() != n->getToSign()) {
if (logger_)
logger_->w("Edition forbidden: sequence number must be increasing.");
DHT_LOG.w("Edition forbidden: sequence number must be increasing.");
return false;
}
}
@@ -152,8 +144,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
}
InfoHash h = crt->getPublicKey().getId();
if (node == h) {
if (logger_)
logger_->d("Registering certificate for %s", h.toString().c_str());
DHT_LOG.d("Registering certificate for %s", h.toString().c_str());
auto it = nodesCertificates_.find(h);
if (it == nodesCertificates_.end())
std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
@@ -161,8 +152,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
it->second = std::move(crt);
return it->second;
} else {
if (logger_)
logger_->w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
DHT_LOG.w("Certificate %s for node %s does not match node id !", h.toString().c_str(), node.toString().c_str());
return nullptr;
}
}
@@ -179,8 +169,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
{
Sp<crypto::Certificate> b = getCertificate(node);
if (b && *b) {
if (logger_)
logger_->d("Using certificate from cache for %s", node.to_c_str());
DHT_LOG.d("Using certificate from cache for %s", node.toString().c_str());
if (cb)
cb(b);
return;
@@ -188,8 +177,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
if (localQueryMethod_) {
auto res = localQueryMethod_(node);
if (not res.empty()) {
if (logger_)
logger_->d("Registering certificate from local store for %s", node.to_c_str());
DHT_LOG.d("Registering certificate from local store for %s", node.toString().c_str());
nodesCertificates_.emplace(node, res.front());
if (cb)
cb(res.front());
@@ -204,8 +192,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
if (logger_)
logger_->d(node, "Found certificate for %s", node.to_c_str());
DHT_LOG.d("Found certificate for %s", node.toString().c_str());
if (cb)
cb(cert);
return false;
@@ -223,8 +210,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
{
auto pk = getPublicKey(node);
if (pk && *pk) {
if (logger_)
logger_->d(node, "Found public key from cache for %s", node.to_c_str());
DHT_LOG.d("Found public key from cache for %s", node.toString().c_str());
if (cb)
cb(pk);
return;
@@ -268,8 +254,7 @@ SecureDht::checkValue(const Sp<Value>& v)
}
// Ignore values belonging to other people
} catch (const std::exception& e) {
if (logger_)
logger_->w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
DHT_LOG.w("Could not decrypt value %s : %s", v->toString().c_str(), e.what());
}
}
// Check signed values
@@ -280,12 +265,11 @@ SecureDht::checkValue(const Sp<Value>& v)
v->signatureChecked = true;
if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
v->signatureValid = true;
if (enableCache_)
nodesPubKeys_[v->owner->getId()] = v->owner;
nodesPubKeys_[v->owner->getId()] = v->owner;
return v;
}
else if (logger_)
logger_->w("Signature verification failed for %s", v->toString().c_str());
else
DHT_LOG.w("Signature verification failed for %s", v->toString().c_str());
}
// Forward normal values
else {
@@ -353,11 +337,6 @@ SecureDht::listen(const InfoHash& id, GetCallback cb, Value::Filter f, Where w)
void
SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
if (val->id == Value::INVALID_ID) {
crypto::random_device rdev;
std::uniform_int_distribution<Value::Id> rand_id;
@@ -373,16 +352,13 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
// Check if data already exists on the dht
get(hash,
[val,this] (const std::vector<Sp<Value>>& vals) {
if (logger_)
logger_->d("Found online previous value being announced.");
DHT_LOG.d("Found online previous value being announced.");
for (const auto& v : vals) {
if (!v->isSigned()) {
if (logger_)
logger_->e("Existing non-signed value seems to exists at this location.");
} else if (not v->owner or v->owner->getId() != getId()) {
if (logger_)
logger_->e("Existing signed value belonging to someone else seems to exists at this location.");
} else if (val->seq <= v->seq)
if (!v->isSigned())
DHT_LOG.e("Existing non-signed value seems to exists at this location.");
else if (not v->owner or v->owner->getId() != getId())
DHT_LOG.e("Existing signed value belonging to someone else seems to exists at this location.");
else if (val->seq <= v->seq)
val->seq = v->seq + 1;
}
return true;
@@ -399,24 +375,17 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
void
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk->getId().toString().c_str());
DHT_LOG.w("Encrypting data for PK: %s", pk->getId().toString().c_str());
try {
dht_->put(hash, encrypt(*val, *pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
DHT_LOG.e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+8 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -34,9 +34,6 @@
#endif
namespace dht {
namespace net {
std::atomic<size_t> REQ_COUNT {0};
}
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
@@ -239,27 +236,17 @@ bool operator==(const SockAddr& a, const SockAddr& b) {
}
time_point from_time_t(std::time_t t) {
auto dt = system_clock::from_time_t(t) - system_clock::now();
auto now = clock::now();
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
return time_point::max();
else if (dt < system_clock::duration(0) and now < time_point::min() - dt)
return time_point::min();
return now + dt;
return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now());
}
std::time_t to_time_t(time_point t) {
auto dt = t - clock::now();
auto now = system_clock::now();
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
return system_clock::to_time_t(system_clock::time_point::max());
else if (dt < duration(0) and now <= system_clock::time_point::min() - dt)
return system_clock::to_time_t(system_clock::time_point::min());
return system_clock::to_time_t(now + std::chrono::duration_cast<system_clock::duration>(dt));
return std::chrono::system_clock::to_time_t(
std::chrono::system_clock::now() +
std::chrono::duration_cast<std::chrono::system_clock::duration>(t - clock::now()));
}
Blob
unpackBlob(const msgpack::object& o) {
unpackBlob(msgpack::object& o) {
switch (o.type) {
case msgpack::type::BIN:
return {o.via.bin.ptr, o.via.bin.ptr+o.via.bin.size};
@@ -283,25 +270,11 @@ unpackMsg(Blob b) {
}
msgpack::object*
findMapValue(const msgpack::object& map, const char* key) {
findMapValue(msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if (o.key.type == msgpack::type::STR
&& std::strncmp(o.key.via.str.ptr, key, o.key.via.str.size) == 0)
return &o.val;
}
return nullptr;
}
msgpack::object*
findMapValue(const msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if (o.key.type == msgpack::type::STR
&& key.size() == o.key.via.str.size
&& std::strncmp(o.key.via.str.ptr, key.data(), o.key.via.str.size) == 0)
if (o.key.type == msgpack::type::STR && o.key.as<std::string>() == key)
return &o.val;
}
return nullptr;
+187 -194
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -17,10 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "value.h"
#include "default_types.h"
@@ -45,7 +41,7 @@ Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data) {
std::ostream& operator<< (std::ostream& s, const Value& v)
{
auto flags(s.flags());
s << "Value[id:" << std::hex << v.id << std::dec << ' ';
s << "Value[id:" << std::hex << v.id << std::dec << " ";
if (v.isEncrypted())
s << "encrypted ";
else if (v.isSigned()) {
@@ -67,23 +63,14 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
}
#endif
} else {
if (v.user_type.empty())
s << "data:";
else
s << "data(" << v.user_type << "):";
if (v.user_type == "text/plain") {
s << '"';
s.write((const char*)v.data.data(), v.data.size());
s << '"';
} else {
s << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
}
s << "Data (type: " << v.type << " ): ";
s << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
}
}
s << ']';
s << "]";
s.flags(flags);
return s;
}
@@ -96,6 +83,20 @@ ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const
return v->size() <= MAX_VALUE_SIZE;
}
msgpack::object*
findMapValue(const msgpack::object& map, const std::string& key) {
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
for (unsigned i = 0; i < map.via.map.size; i++) {
auto& o = map.via.map.ptr[i];
if(o.key.type != msgpack::type::STR)
continue;
if (o.key.as<std::string>() == key) {
return &o.val;
}
}
return nullptr;
}
size_t
Value::size() const
{
@@ -103,24 +104,20 @@ Value::size() const
}
void
Value::msgpack_unpack(const msgpack::object& o)
Value::msgpack_unpack(msgpack::object o)
{
if (o.type != msgpack::type::MAP or o.via.map.size < 2)
throw msgpack::type_error();
if (o.type != msgpack::type::MAP) throw msgpack::type_error();
if (o.via.map.size < 2) throw msgpack::type_error();
if (auto rid = findMapValue(o, VALUE_KEY_ID)) {
if (auto rid = findMapValue(o, "id")) {
id = rid->as<Id>();
} else
throw msgpack::type_error();
if (auto rdat = findMapValue(o, VALUE_KEY_DAT)) {
if (auto rdat = findMapValue(o, "dat")) {
msgpack_unpack_body(*rdat);
} else
throw msgpack::type_error();
if (auto rprio = findMapValue(o, VALUE_KEY_PRIO)) {
priority = rprio->as<unsigned>();
}
}
void
@@ -139,37 +136,37 @@ Value::msgpack_unpack_body(const msgpack::object& o)
} else {
if (o.type != msgpack::type::MAP)
throw msgpack::type_error();
auto rbody = findMapValue(o, VALUE_KEY_BODY);
auto rbody = findMapValue(o, "body");
if (not rbody)
throw msgpack::type_error();
if (auto rdata = findMapValue(*rbody, VALUE_KEY_DATA)) {
if (auto rdata = findMapValue(*rbody, "data")) {
data = unpackBlob(*rdata);
} else
throw msgpack::type_error();
if (auto rtype = findMapValue(*rbody, VALUE_KEY_TYPE)) {
if (auto rtype = findMapValue(*rbody, "type")) {
type = rtype->as<ValueType::Id>();
} else
throw msgpack::type_error();
if (auto rutype = findMapValue(*rbody, VALUE_KEY_USERTYPE)) {
if (auto rutype = findMapValue(*rbody, "utype")) {
user_type = rutype->as<std::string>();
}
if (auto rowner = findMapValue(*rbody, VALUE_KEY_OWNER)) {
if (auto rseq = findMapValue(*rbody, VALUE_KEY_SEQ))
if (auto rowner = findMapValue(*rbody, "owner")) {
if (auto rseq = findMapValue(*rbody, "seq"))
seq = rseq->as<decltype(seq)>();
else
throw msgpack::type_error();
crypto::PublicKey new_owner;
new_owner.msgpack_unpack(*rowner);
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) {
if (auto rrecipient = findMapValue(*rbody, "to")) {
recipient = rrecipient->as<InfoHash>();
}
if (auto rsig = findMapValue(o, VALUE_KEY_SIGNATURE)) {
if (auto rsig = findMapValue(o, "sig")) {
signature = unpackBlob(*rsig);
} else
throw msgpack::type_error();
@@ -178,65 +175,63 @@ Value::msgpack_unpack_body(const msgpack::object& o)
}
#ifdef OPENDHT_JSONCPP
Value::Value(const Json::Value& json)
Value::Value(Json::Value& json)
{
id = Value::Id(unpackId(json, VALUE_KEY_ID));
const auto& jcypher = json["cypher"];
if (jcypher.isString())
cypher = base64_decode(jcypher.asString());
const auto& jsig = json[VALUE_KEY_SIGNATURE];
if (jsig.isString())
signature = base64_decode(jsig.asString());
const auto& jseq = json[VALUE_KEY_SEQ];
if (!jseq.isNull())
seq = jseq.asInt();
const auto& jowner = json[VALUE_KEY_OWNER];
if (jowner.isString()) {
auto ownerStr = jowner.asString();
id = Value::Id(unpackId(json, "id"));
if (json.isMember("cypher")) {
auto cypherStr = json["cypher"].asString();
cypherStr = base64_decode(cypherStr);
cypher = std::vector<unsigned char>(cypherStr.begin(), cypherStr.end());
}
if (json.isMember("sig")) {
auto sigStr = json["sig"].asString();
sigStr = base64_decode(sigStr);
signature = std::vector<unsigned char>(sigStr.begin(), sigStr.end());
}
if (json.isMember("seq"))
seq = json["seq"].asInt();
if (json.isMember("owner")) {
auto ownerStr = json["owner"].asString();
auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end());
owner = std::make_shared<const crypto::PublicKey>(ownerBlob);
}
const auto& jto = json[VALUE_KEY_TO];
if (jto.isString())
recipient = InfoHash(jto.asString());
const auto& jtype = json[VALUE_KEY_TYPE];
if (!jtype.isNull())
type = jtype.asInt();
const auto& jdata = json[VALUE_KEY_DATA];
if (jdata.isString())
data = base64_decode(jdata.asString());
const auto& jutype = json[VALUE_KEY_USERTYPE];
if (jutype.isString())
user_type = jutype.asString();
const auto& jprio = json["prio"];
if (jprio.isIntegral())
priority = jprio.asUInt();
if (json.isMember("to")) {
auto toStr = json["to"].asString();
recipient = InfoHash(toStr);
}
if (json.isMember("type"))
type = json["type"].asInt();
if (json.isMember("data")){
auto dataStr = json["data"].asString();
dataStr = base64_decode(dataStr);
data = std::vector<unsigned char>(dataStr.begin(), dataStr.end());
}
if (json.isMember("utype"))
user_type = json["utype"].asString();
}
Json::Value
Value::toJson() const
{
Json::Value val;
val[VALUE_KEY_ID] = std::to_string(id);
val["id"] = std::to_string(id);
if (isEncrypted()) {
val["cypher"] = base64_encode(cypher);
} else {
if (isSigned())
val[VALUE_KEY_SIGNATURE] = base64_encode(signature);
val["sig"] = base64_encode(signature);
bool has_owner = owner && *owner;
if (has_owner) { // isSigned
val[VALUE_KEY_SEQ] = seq;
val[VALUE_KEY_OWNER] = owner->toString();
val["seq"] = seq;
val["owner"] = owner->toString();
if (recipient)
val[VALUE_KEY_TO] = recipient.toString();
val["to"] = recipient.toString();
}
val[VALUE_KEY_TYPE] = type;
val[VALUE_KEY_DATA] = base64_encode(data);
val["type"] = type;
val["data"] = base64_encode(data);
if (not user_type.empty())
val[VALUE_KEY_USERTYPE] = user_type;
val["utype"] = user_type;
}
if (priority)
val["prio"] = priority;
return val;
}
@@ -244,11 +239,13 @@ uint64_t
unpackId(const Json::Value& json, const std::string& key) {
uint64_t ret = 0;
try {
const auto& t = json[key];
if (t.isString()) {
ret = std::stoull(t.asString());
} else {
ret = t.asLargestUInt();
if (json.isMember(key)) {
const auto& t = json[key];
if (t.isString()) {
ret = std::stoull(t.asString());
} else {
ret = t.asLargestUInt();
}
}
} catch (...) {}
return ret;
@@ -261,18 +258,18 @@ FieldValue::operator==(const FieldValue& vfd) const
if (field != vfd.field)
return false;
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
return intValue == vfd.intValue;
case Value::Field::OwnerPk:
return hashValue == vfd.hashValue;
case Value::Field::UserType:
return blobValue == vfd.blobValue;
case Value::Field::None:
return true;
default:
return false;
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
return intValue == vfd.intValue;
case Value::Field::OwnerPk:
return hashValue == vfd.hashValue;
case Value::Field::UserType:
return blobValue == vfd.blobValue;
case Value::Field::None:
return true;
default:
return false;
}
}
@@ -280,25 +277,25 @@ Value::Filter
FieldValue::getLocalFilter() const
{
switch (field) {
case Value::Field::Id:
return Value::IdFilter(intValue);
case Value::Field::ValueType:
return Value::TypeFilter(intValue);
case Value::Field::OwnerPk:
return Value::OwnerFilter(hashValue);
case Value::Field::SeqNum:
return Value::SeqNumFilter(intValue);
case Value::Field::UserType:
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
default:
return {};
case Value::Field::Id:
return Value::IdFilter(intValue);
case Value::Field::ValueType:
return Value::TypeFilter(intValue);
case Value::Field::OwnerPk:
return Value::OwnerFilter(hashValue);
case Value::Field::SeqNum:
return Value::SeqNumFilter(intValue);
case Value::Field::UserType:
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
default:
return {};
}
}
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
{
if (not s.empty()) {
auto selection = s.getSelection();
auto selection = s.getSelection();
if (not selection.empty()) {
std::transform(selection.begin(), selection.end(), std::inserter(index, index.end()),
[](const std::set<Value::Field>::value_type& f) {
return std::make_pair(f, FieldValue {});
@@ -311,23 +308,23 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
for (const auto& fvp : index) {
const auto& f = fvp.first;
switch (f) {
case Value::Field::Id:
index[f] = {f, v.id};
break;
case Value::Field::ValueType:
index[f] = {f, v.type};
break;
case Value::Field::OwnerPk:
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
break;
case Value::Field::SeqNum:
index[f] = {f, v.seq};
break;
case Value::Field::UserType:
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
break;
default:
break;
case Value::Field::Id:
index[f] = {f, v.id};
break;
case Value::Field::ValueType:
index[f] = {f, v.type};
break;
case Value::Field::OwnerPk:
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
break;
case Value::Field::SeqNum:
index[f] = {f, v.seq};
break;
case Value::Field::UserType:
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
break;
default:
break;
}
}
}
@@ -347,28 +344,28 @@ std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi) {
os << "Index[";
for (auto v = fvi.index.begin(); v != fvi.index.end(); ++v) {
switch (v->first) {
case Value::Field::Id: {
auto flags(os.flags());
os << "Id:" << std::hex << v->second.getInt();
os.flags(flags);
break;
}
case Value::Field::ValueType:
os << "ValueType:" << v->second.getInt();
break;
case Value::Field::OwnerPk:
os << "Owner:" << v->second.getHash();
break;
case Value::Field::SeqNum:
os << "Seq:" << v->second.getInt();
break;
case Value::Field::UserType: {
auto ut = v->second.getBlob();
os << "UserType:" << std::string(ut.begin(), ut.end());
break;
}
default:
break;
case Value::Field::Id: {
auto flags(os.flags());
os << "Id:" << std::hex << v->second.getInt();
os.flags(flags);
break;
}
case Value::Field::ValueType:
os << "ValueType:" << v->second.getInt();
break;
case Value::Field::OwnerPk:
os << "Owner:" << v->second.getHash().toString();
break;
case Value::Field::SeqNum:
os << "Seq:" << v->second.getInt();
break;
case Value::Field::UserType: {
auto ut = v->second.getBlob();
os << "UserType:" << std::string(ut.begin(), ut.end());
break;
}
default:
break;
}
os << (std::next(v) != fvi.index.end() ? "," : "");
}
@@ -384,19 +381,19 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
for (const auto& field : fields) {
auto& field_value = o.via.array.ptr[offset+(j++)];
switch (field) {
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
index[field] = FieldValue(field, field_value.as<uint64_t>());
break;
case Value::Field::OwnerPk:
index[field] = FieldValue(field, field_value.as<InfoHash>());
break;
case Value::Field::UserType:
index[field] = FieldValue(field, field_value.as<Blob>());
break;
default:
throw msgpack::type_error();
case Value::Field::Id:
case Value::Field::ValueType:
case Value::Field::SeqNum:
index[field] = FieldValue(field, field_value.as<uint64_t>());
break;
case Value::Field::OwnerPk:
index[field] = FieldValue(field, field_value.as<InfoHash>());
break;
case Value::Field::UserType:
index[field] = FieldValue(field, field_value.as<Blob>());
break;
default:
throw msgpack::type_error();
}
}
}
@@ -418,13 +415,13 @@ Select::Select(const std::string& q_str) {
while (std::getline(fields, token, ',')) {
trim_str(token);
if (token == VALUE_KEY_ID)
if (token == "id")
field(Value::Field::Id);
else if (token == "value_type")
field(Value::Field::ValueType);
else if (token == "owner_pk")
field(Value::Field::OwnerPk);
if (token == VALUE_KEY_SEQ)
if (token == "seq")
field(Value::Field::SeqNum);
else if (token == "user_type")
field(Value::Field::UserType);
@@ -460,13 +457,13 @@ Where::Where(const std::string& q_str) {
s = value_str.substr(1, value_str.size()-2);
else
s = value_str;
if (field_str == VALUE_KEY_ID)
if (field_str == "id")
id(v);
else if (field_str == "value_type")
valueType(v);
else if (field_str == "owner_pk")
owner(InfoHash(s));
else if (field_str == VALUE_KEY_SEQ)
else if (field_str == "seq")
seq(v);
else if (field_str == "user_type")
userType(s);
@@ -522,14 +519,11 @@ bool Query::isSatisfiedBy(const Query& q) const {
}
std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
s << "SELECT ";
if (select.fieldSelection_.empty())
s << '*';
else
for (auto fs = select.fieldSelection_.begin(); fs != select.fieldSelection_.end();) {
switch (*fs) {
s << "SELECT " << (select.fieldSelection_.empty() ? "*" : "");
for (auto fs = select.fieldSelection_.begin() ; fs != select.fieldSelection_.end() ; ++fs) {
switch (*fs) {
case Value::Field::Id:
s << VALUE_KEY_ID;
s << "id";
break;
case Value::Field::ValueType:
s << "value_type";
@@ -541,14 +535,13 @@ std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
s << "owner_public_key";
break;
case Value::Field::SeqNum:
s << VALUE_KEY_SEQ;
s << "seq";
break;
default:
break;
}
if (++fs != select.fieldSelection_.end())
s << ',';
}
s << (std::next(fs) != select.fieldSelection_.end() ? "," : "");
}
return s;
}
@@ -557,25 +550,25 @@ std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
s << "WHERE ";
for (auto f = where.filters_.begin() ; f != where.filters_.end() ; ++f) {
switch (f->getField()) {
case Value::Field::Id:
s << VALUE_KEY_ID << '=' << f->getInt();
break;
case Value::Field::ValueType:
s << "value_type=" << f->getInt();
break;
case Value::Field::OwnerPk:
s << "owner_pk_hash=" << f->getHash();
break;
case Value::Field::SeqNum:
s << VALUE_KEY_SEQ << '=' << f->getInt();
break;
case Value::Field::UserType: {
auto b = f->getBlob();
s << "user_type=" << std::string {b.begin(), b.end()};
break;
}
default:
break;
case Value::Field::Id:
s << "id=" << f->getInt();
break;
case Value::Field::ValueType:
s << "value_type=" << f->getInt();
break;
case Value::Field::OwnerPk:
s << "owner_pk_hash=" << f->getHash().toString();
break;
case Value::Field::SeqNum:
s << "seq=" << f->getInt();
break;
case Value::Field::UserType: {
auto b = f->getBlob();
s << "user_type=" << std::string {b.begin(), b.end()};
break;
}
default:
break;
}
s << (std::next(f) != where.filters_.end() ? "," : "");
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1
View File
@@ -0,0 +1 @@
g++ -Wall -Wextra -Wfatal-errors -pedantic -g ../src/http.cpp tests_runner.cpp httptester.cpp -o run.out -lopendht -lpthread -lcppunit -ljsoncpp -DOPENDHT_JSONCPP -I../include/opendht -DASIO_STANDALONE
+2 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -19,7 +19,7 @@
#include "cryptotester.h"
#include <opendht/crypto.h>
#include "opendht/crypto.h"
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTester);
@@ -56,19 +56,6 @@ CryptoTester::testSignatureEncryption() {
std::vector<uint8_t> decrypted = key.decrypt(encrypted);
CPPUNIT_ASSERT(data2 == decrypted);
}
// encrypt data (invalid)
{
std::vector<uint8_t> encrypted = public_key.encrypt(data1);
encrypted[1]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
{
std::vector<uint8_t> encrypted = public_key.encrypt(data2);
encrypted[2]++;
CPPUNIT_ASSERT_THROW(key.decrypt(encrypted), std::runtime_error);
}
}
void
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+62 -97
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Vsevolod Ivanov <vsevolod.ivanov@savoirfairelinux.com>
@@ -27,58 +27,56 @@
#include <chrono>
#include <condition_variable>
using namespace std::chrono_literals;
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(DhtProxyTester);
void
DhtProxyTester::setUp() {
nodePeer.run(0);
logger = dht::log::getStdLogger();
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
nodeProxy = std::make_shared<dht::DhtRunner>();
nodeProxy->run(0);
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
nodeProxy->bootstrap(nodePeer.getBound());
auto serverCAIdentity = dht::crypto::generateEcIdentity("DHT Node CA");
auto serverIdentity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
serverProxy = std::make_unique<dht::DhtProxyServer>(
serverProxy = std::unique_ptr<dht::DhtProxyServer>(
new dht::DhtProxyServer(
//dht::crypto::Identity{}, // http
serverIdentity, // https
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090");
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
clientConfig.server_ca = serverCAIdentity.second;
clientConfig.client_identity = dht::crypto::generateIdentity("DhtProxyTester");
clientConfig.dht_config.node_config.maintain_storage = false;
clientConfig.threaded = true;
clientConfig.push_node_id = "dhtnode";
clientConfig.proxy_server = "https://127.0.0.1:8080";
clientContext.logger = logger;
nodeClient = std::make_shared<dht::DhtRunner>();
nodeClient->run(0, clientConfig, std::move(clientContext));
nodeClient->bootstrap(nodePeer.getBound());
nodeClient->setProxyServer("https://127.0.0.1:8080");
nodeClient->enableProxy(true); // creates DhtProxyClient
}
void
DhtProxyTester::tearDown() {
logger->d("[tester:proxy] stopping peer node");
nodePeer.join();
nodeClient.join();
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
nodeProxy->shutdown([&]{
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done; }));
serverProxy.reset();
nodeProxy.reset();
nodeClient->join();
logger->d("[tester:proxy] stopping proxy server");
serverProxy.reset(nullptr);
logger->d("[tester:proxy] stopping proxy node");
nodeProxy->join();
}
void
DhtProxyTester::testGetPut() {
nodeClient.run(0, clientConfig);
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
@@ -87,24 +85,22 @@ DhtProxyTester::testGetPut() {
dht::Value val {"Hey! It's been a long time. How have you been?"};
auto val_data = val.data;
{
std::unique_lock<std::mutex> lk(cv_m);
nodePeer.put(key, std::move(val), [&](bool) {
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
});
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
}
auto vals = nodeClient.get(key).get();
auto vals = nodeClient->get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtProxyTester::testListen() {
nodeClient.run(0, clientConfig);
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
@@ -121,11 +117,11 @@ DhtProxyTester::testListen() {
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
std::vector<dht::Blob> values;
auto token = nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
auto token = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
for (const auto& value : v)
@@ -135,7 +131,7 @@ DhtProxyTester::testListen() {
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
// Here values should contains 1 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 1);
@@ -146,8 +142,8 @@ DhtProxyTester::testListen() {
dht::Value secondVal {"You're a monster"};
auto secondVal_data = secondVal.data;
nodePeer.put(key, std::move(secondVal));
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
nodeClient.cancelListen(key, std::move(token));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
nodeClient->cancelListen(key, std::move(token));
// Here values should contains 2 values
CPPUNIT_ASSERT_EQUAL(static_cast<int>(values.size()), 2);
CPPUNIT_ASSERT(values.back() == secondVal_data);
@@ -155,8 +151,7 @@ DhtProxyTester::testListen() {
void
DhtProxyTester::testResubscribeGetValues() {
clientConfig.push_token = "atlas";
nodeClient.run(0, clientConfig);
nodeClient->setPushNotificationToken("atlas");
bool done = false;
std::condition_variable cv;
@@ -164,65 +159,68 @@ DhtProxyTester::testResubscribeGetValues() {
std::unique_lock<std::mutex> lk(cv_m);
auto key = dht::InfoHash::get("GLaDOs");
// If a peer sent a value, the listen operation from the client
// If a peer send a value, the listen operation from the client
// should retrieve this value
dht::Value firstVal {"Hey! It's been a long time. How have you been?"};
auto firstVal_data = firstVal.data;
nodePeer.put(key, std::move(firstVal), [&](bool ok) {
nodePeer.put(key, std::move(firstVal), [&](bool) {
std::lock_guard<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(ok);
done = true;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
done = false;
// Send a first subscribe, the value is sent via a push notification
// So ignore values here.
nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>&, bool) {
return true;
});
cv.wait_for(lk, std::chrono::seconds(1));
// Reboot node (to avoid cache)
nodeClient.join();
clientConfig.push_token = "";
nodeClient.run(0, clientConfig);
nodeClient->join();
nodeClient->run(0, clientConfig, std::move(clientContext));
nodeClient->bootstrap(nodePeer.getBound());
nodeClient->setProxyServer("https://127.0.0.1:8080");
nodeClient->enableProxy(true);
nodeClient->setPushNotificationToken("atlas");
// For the second subscribe, the proxy will return the value in the body
std::vector<std::shared_ptr<dht::Value>> values;
auto ftoken = nodeClient.listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
auto values = std::vector<dht::Blob>();
auto ftoken = nodeClient->listen(key, [&](const std::vector<std::shared_ptr<dht::Value>>& v, bool expired) {
if (not expired) {
std::lock_guard<std::mutex> lk(cv_m);
values.insert(values.end(), v.begin(), v.end());
for (const auto& value : v)
values.emplace_back(value->data);
done = true;
cv.notify_all();
}
return true;
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
auto token = ftoken.get();
CPPUNIT_ASSERT(token);
nodeClient.cancelListen(key, token);
nodeClient->cancelListen(key, token);
// Here values should still contains 1 values
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
CPPUNIT_ASSERT(firstVal_data == values.front()->data);
CPPUNIT_ASSERT(firstVal_data == values.front());
}
void
DhtProxyTester::testPutGet40KChars()
{
nodeClient.run(0, clientConfig);
constexpr size_t N = 40000;
// Arrange
auto key = dht::InfoHash::get("testPutGet40KChars");
std::vector<std::shared_ptr<dht::Value>> values;
std::vector<uint8_t> mtu;
mtu.reserve(N);
for (size_t i = 0; i < N; i++)
mtu.emplace_back((i % 2) ? 'T' : 'M');
std::string mtu = "";
for (int i = 0; i < 40000; i++){
if (i % 2 == 0)
mtu.append("M");
else
mtu.append("T");
}
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
@@ -231,61 +229,28 @@ DhtProxyTester::testPutGet40KChars()
// Act
dht::Value val {mtu};
nodePeer.put(key, std::move(val), [&](bool ok) {
nodeClient->put(key, std::move(val), [&](bool ok) {
std::lock_guard<std::mutex> lk(cv_m);
done_put = ok;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done_put; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done_put; }));
nodeClient.get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
nodeClient->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values = vals;
return true;
},[&](bool ok){
std::lock_guard<std::mutex> lk(cv_m);
done_get = ok;
cv.notify_all();
});
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done_get; }));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done_get; }));
// Assert
CPPUNIT_ASSERT_EQUAL((size_t)1u, values.size());
for (const auto &value: values)
CPPUNIT_ASSERT(value->data == mtu);
}
void
DhtProxyTester::testFuzzy()
{
constexpr size_t N = 40000;
// Arrange
auto key = dht::InfoHash::get("testFuzzy");
std::vector<std::shared_ptr<dht::Value>> values;
std::vector<uint8_t> mtu;
mtu.reserve(N);
for (size_t i = 0; i < N; i++)
mtu.emplace_back((i % 2) ? 'T' : 'M');
// Act
for (size_t i = 0; i < 100; i++) {
auto nodeTest = std::make_shared<dht::DhtRunner>();
nodeTest->run(0, clientConfig);
nodeTest->put(key, dht::Value(mtu), [&](bool ok) {
CPPUNIT_ASSERT(ok);
});
nodeTest->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
return true;
},[&](bool ok){
CPPUNIT_ASSERT(ok);
});
std::this_thread::sleep_for(10ms);
dht::Value mtu_val {mtu};
for (const auto &value: values){
CPPUNIT_ASSERT(value->data == mtu_val.data);
}
// Assert
for (const auto &value: values)
CPPUNIT_ASSERT(value->data == mtu);
}
} // namespace test
+7 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2020 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
@@ -35,7 +35,6 @@ class DhtProxyTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testResubscribeGetValues);
CPPUNIT_TEST(testPutGet40KChars);
CPPUNIT_TEST(testFuzzy);
CPPUNIT_TEST_SUITE_END();
public:
@@ -66,14 +65,16 @@ class DhtProxyTester : public CppUnit::TestFixture {
*/
void testPutGet40KChars();
void testFuzzy();
private:
dht::DhtRunner::Config clientConfig {};
dht::DhtRunner nodePeer;
dht::DhtRunner nodeClient;
std::shared_ptr<dht::DhtRunner> nodeClient;
std::shared_ptr<dht::DhtRunner> nodeProxy;
std::unique_ptr<dht::DhtProxyServer> serverProxy;
dht::DhtRunner::Context clientContext {};
dht::DhtRunner::Config clientConfig {};
std::shared_ptr<dht::Logger> logger {};
};
} // namespace test
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff. Show more