Compare commits

..
3 Commits
Author SHA1 Message Date
Adrien Béraud cf378c1a0e update version to 3.2.0 2024-05-25 23:59:20 -04:00
Adrien Béraud 9a987a0586 ci: build proxy client for Autotools build 2024-05-25 23:59:20 -04:00
Adrien Béraud 8806960d2b http: migrate from http-parser to llhttp 2024-05-25 23:59:20 -04:00
44 changed files with 480 additions and 1026 deletions

No files matched your search

+9 -12
View File
@@ -7,13 +7,12 @@ jobs:
name: Ubuntu/GCC Autotools build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-pip python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Cython
run: sudo pip3 install Cython
- name: llhttp
@@ -50,13 +49,12 @@ jobs:
name: Ubuntu/GCC Meson build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt update && \
sudo apt install ninja-build libncurses5-dev libreadline-dev nettle-dev libasio-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools python3-pip \
libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-dev
libcppunit-dev libjsoncpp-dev libfmt-dev libmsgpack-dev libargon2-0-dev
- name: Python dependencies
run: sudo pip3 install meson Cython
- name: Configure
@@ -68,12 +66,11 @@ jobs:
name: Ubuntu/GCC minimal build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Dependencies
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev libfmt-dev \
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-dev
libgnutls28-dev libcppunit-dev libmsgpack-dev libargon2-0-dev
- name: Configure
run: |
mkdir build && cd build
@@ -87,16 +84,16 @@ jobs:
build-macos:
name: macOS/Clang build
runs-on: macOS-15
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Dependencies
run: |
brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
- name: expected-lite
run: |
sudo mkdir -p /usr/local/include/nonstd && \
sudo mkdir /usr/local/include/nonstd && \
sudo wget https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp \
-O /usr/local/include/nonstd/expected.hpp
+2 -3
View File
@@ -6,13 +6,12 @@ jobs:
name: Clang Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: deps
run: |
sudo apt update && \
sudo apt install libncurses5-dev libreadline-dev nettle-dev \
libgnutls28-dev libuv1-dev python3-dev python3-setuptools libcppunit-dev libjsoncpp-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-dev libasio-dev \
autotools-dev autoconf libfmt-dev libmsgpack-dev libargon2-0-dev libasio-dev \
llvm llvm-dev clang clang-tools && \
sudo apt remove gcc g++
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+31 -31
View File
@@ -25,10 +25,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -36,12 +36,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDeps
@@ -58,10 +58,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -69,13 +69,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile
@@ -92,10 +92,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -103,12 +103,12 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DEPS_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDepsLlvm
@@ -125,10 +125,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -136,13 +136,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LLVM }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileLlvm
@@ -159,10 +159,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -170,13 +170,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DHTNODE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDhtnode
@@ -193,10 +193,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -204,13 +204,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE_DEPS }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileDepsAlpine
@@ -227,10 +227,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -238,13 +238,13 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v4
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_ALPINE }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v3
with:
context: .
file: docker/DockerfileAlpine
@@ -262,7 +262,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: cmake
run: |
@@ -280,14 +280,14 @@ jobs:
- name: build
run: cd build && make dist
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: opendht-wheels-linux
path: build/python/dist/*.whl
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
with:
draft: true
files: build/python/dist/*.whl
+7 -19
View File
@@ -33,7 +33,6 @@ option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp"
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_IO_URING "Use io_uring if available on the system (Linux only)" OFF)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
option (OPENDHT_TESTS_NETWORK "Enable unit tests that require network access" ON)
option (OPENDHT_C "Build C bindings" OFF)
@@ -86,9 +85,6 @@ if (NOT MSVC)
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
message(STATUS "Found ASIO ${ASIO_INCLUDE_DIR}")
else()
message(STATUS "ASIO not required")
endif ()
find_package(fmt)
@@ -98,7 +94,7 @@ if (NOT MSVC)
# llhttp
find_path(LLHTTP_INCLUDE_DIR llhttp.h)
find_library(LLHTTP_LIBRARY libllhttp)
find_library(LLHTTP_LIBRARY libllhttp.a)
if (LLHTTP_INCLUDE_DIR AND LLHTTP_LIBRARY)
message(STATUS "Found llhttp ${LLHTTP_INCLUDE_DIR} ${LLHTTP_LIBRARY}")
add_library(llhttp_static STATIC IMPORTED)
@@ -108,7 +104,7 @@ if (NOT MSVC)
)
set(llhttp_target llhttp_static)
else()
FetchContent_Declare(llhttp-local URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.1.tar.gz")
FetchContent_Declare(llhttp-local URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.0.tar.gz")
if (BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "")
else()
@@ -123,7 +119,7 @@ if (NOT MSVC)
endif()
endif()
set(http_lib "-lllhttp")
if (NOT Jsoncpp_FOUND)
message(SEND_ERROR "Jsoncpp is required for DHT proxy support")
endif()
@@ -157,16 +153,13 @@ else ()
${WIN32_DEP_DIR}/openssl/include
${WIN32_DEP_DIR}/restinio/dev
${WIN32_DEP_DIR}/fmt/include
${WIN32_DEP_DIR}/llhttp/include
${WIN32_DEP_DIR}/http_parser
)
endif ()
endif ()
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
add_definitions(-DASIO_STANDALONE)
if (OPENDHT_IO_URING AND UNIX AND NOT APPLE)
pkg_search_module(liburing IMPORTED_TARGET liburing)
endif ()
endif()
if (NOT MSVC)
@@ -344,12 +337,12 @@ if (MSVC)
)
if (OPENDHT_HTTP)
add_obj_lib (win32_fmt ${WIN32_DEP_DIR}/fmt/msvc/Release/fmt.lib)
add_obj_lib (win32_llhttp ${WIN32_DEP_DIR}/llhttp/build/Release/llhttp.lib)
add_obj_lib (win32_http_parser ${WIN32_DEP_DIR}/http_parser/x64/Release/http-parser.lib)
add_obj_lib (win32_ssl ${WIN32_DEP_DIR}/openssl/libssl_static.lib)
add_obj_lib (win32_crypto ${WIN32_DEP_DIR}/openssl/libcrypto_static.lib)
list (APPEND obj_libs
$<TARGET_OBJECTS:win32_fmt>
$<TARGET_OBJECTS:win32_llhttp>
$<TARGET_OBJECTS:win32_http_parser>
$<TARGET_OBJECTS:win32_ssl>
$<TARGET_OBJECTS:win32_crypto>
)
@@ -362,7 +355,7 @@ if (MSVC)
)
list (APPEND win32_Libs
${PROJECT_SOURCE_DIR}/../fmt/msvc/Release/fmt.lib
${PROJECT_SOURCE_DIR}/../llhttp/build/Release/llhttp.lib
${PROJECT_SOURCE_DIR}/../http_parser/x64/Release/http-parser.lib
${PROJECT_SOURCE_DIR}/../openssl/libssl.lib
${PROJECT_SOURCE_DIR}/../openssl/libcrypto.lib
)
@@ -408,11 +401,6 @@ else()
if (OPENDHT_PROXY_OPENSSL)
target_link_libraries(opendht PUBLIC PkgConfig::OPENSSL)
endif()
if (OPENDHT_IO_URING AND liburing_FOUND)
set(iouring_lib ", liburing")
target_link_libraries(opendht PUBLIC PkgConfig::liburing)
target_compile_definitions(opendht PUBLIC ASIO_HAS_IO_URING ASIO_DISABLE_EPOLL)
endif()
endif()
if (BUILD_SHARED_LIBS)
-1
View File
@@ -98,7 +98,6 @@ for r in results:
- Nettle 2.4+, a GnuTLS dependency for crypto.
- {fmt} 9.0+, for log formatting.
- (optional) restinio used for the REST API.
- (optional) llhttp used for the REST API.
- (optional) jsoncpp 1.7.4-3+, used for the REST API.
- Build tested with GCC 7+ (GNU/Linux, Windows with MinGW), Clang/LLVM (GNU/Linux, Android, macOS, iOS).
- Build tested with Microsoft Visual Studio 2019, 2022
-1
View File
@@ -344,7 +344,6 @@ int dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config
config.push_token = conf->push_token ? std::string(conf->push_token) : std::string{};
config.push_topic = conf->push_topic ? std::string(conf->push_topic) : std::string{};
config.push_platform = conf->push_platform ? std::string(conf->push_platform) : std::string{};
config.proxy_user_agent = conf->proxy_user_agent ? std::string(conf->proxy_user_agent) : std::string{};
config.peer_discovery = conf->peer_discovery;
config.peer_publish = conf->peer_publish;
-1
View File
@@ -148,7 +148,6 @@ struct OPENDHT_PUBLIC dht_runner_config {
const char* push_token;
const char* push_topic;
const char* push_platform;
const char* proxy_user_agent;
bool peer_discovery;
bool peer_publish;
dht_certificate* server_ca;
-3
View File
@@ -143,9 +143,6 @@ struct OPENDHT_PUBLIC Config {
* - Larger listen refresh time
*/
bool public_stable {false};
/* Client mode, node will not be used by other nodes to store data. */
bool client_mode {false};
};
/**
+11 -13
View File
@@ -53,21 +53,19 @@ public:
DhtProxyClient();
explicit DhtProxyClient(
std::shared_ptr<crypto::Certificate> serverCA,
crypto::Identity clientIdentity,
std::function<void()> loopSignal,
const std::string& serverHost,
const std::string& userAgent = "",
const std::string& pushClientId = "",
const std::string& pushToken = "",
const std::string& pushTopic = "",
const std::string& pushPlatform = "",
std::shared_ptr<Logger> logger = {}
);
std::shared_ptr<crypto::Certificate> serverCA, crypto::Identity clientIdentity,
std::function<void()> loopSignal, const std::string& serverHost,
const std::string& pushClientId = "", std::shared_ptr<Logger> logger = {});
void setHeaderFields(http::Request& request);
virtual void setPushNotificationToken(const std::string& token) override;
virtual void setPushNotificationToken(const std::string& token) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#else
(void) token;
#endif
}
virtual void setPushNotificationTopic(const std::string& topic) override {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
@@ -353,7 +351,7 @@ private:
std::string proxyUrl_;
dht::crypto::Identity clientIdentity_;
std::shared_ptr<dht::crypto::Certificate> serverCertificate_;
std::string userAgent_ {"OpenDHT"};
//std::pair<std::string, std::string> serverHostService_;
std::string pushClientId_;
std::string pushSessionId_;
+9 -57
View File
@@ -98,32 +98,6 @@ public:
asio::io_context& io_context() const;
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
struct PushStats {
uint64_t highPriorityCount {0};
uint64_t normalPriorityCount {0};
void increment(bool highPriority) {
if (highPriority)
highPriorityCount++;
else
normalPriorityCount++;
}
Json::Value toJson() const {
Json::Value val;
val["highPriorityCount"] = static_cast<Json::UInt64>(highPriorityCount);
val["normalPriorityCount"] = static_cast<Json::UInt64>(normalPriorityCount);
return val;
}
std::string toString() const {
return fmt::format("{} high priority, {} normal priority", highPriorityCount, normalPriorityCount);
}
};
struct ServerStats {
/** Current number of listen operations */
size_t listenCount {0};
@@ -133,39 +107,24 @@ public:
size_t totalPermanentPuts {0};
/** Current number of push tokens with at least one listen operation */
size_t pushListenersCount {0};
/** Time at which the server was started */
time_point serverStartTime;
/** Last time at which the stats were updated */
time_point lastUpdated;
/** Total number of push notification requests that the server attempted to
* send since being started, broken down by type and priority level */
PushStats androidPush;
PushStats iosPush;
PushStats unifiedPush;
/** Average requests per second */
double requestRate {0};
/** Node Info **/
std::shared_ptr<NodeInfo> nodeInfo {};
std::string toString() const {
auto ret = fmt::format("Listens: {}, Puts: {}, PushListeners: {}\n"
"Push requests in the last {}: [Android: {}], [iOS: {}], [Unified: {}]\n"
"Requests: {} per second.",
listenCount, putCount, pushListenersCount,
print_duration(lastUpdated - serverStartTime),
androidPush.toString(), iosPush.toString(), unifiedPush.toString(),
requestRate);
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)
ret += fmt::format("IPv4 Network estimation: {}\n", ipv4.getNetworkSizeEstimation());
ss << "IPv4 Network estimation: " << ipv4.getNetworkSizeEstimation() << std::endl;;
auto& ipv6 = nodeInfo->ipv6;
if (ipv6.table_depth > 1)
ret += fmt::format("IPv6 Network estimation: {}\n", ipv6.getNetworkSizeEstimation());
ss << "IPv6 Network estimation: " << ipv6.getNetworkSizeEstimation() << std::endl;;
}
return ret;
return ss.str();
}
/**
@@ -177,11 +136,6 @@ public:
result["putCount"] = static_cast<Json::UInt64>(putCount);
result["totalPermanentPuts"] = static_cast<Json::UInt64>(totalPermanentPuts);
result["pushListenersCount"] = static_cast<Json::UInt64>(pushListenersCount);
result["serverStartTime"] = static_cast<Json::LargestInt>(to_time_t(serverStartTime));
result["lastUpdated"] = static_cast<Json::LargestInt>(to_time_t(lastUpdated));
result["androidPush"] = androidPush.toJson();
result["iosPush"] = iosPush.toJson();
result["unifiedPush"] = unifiedPush.toJson();
result["requestRate"] = requestRate;
if (nodeInfo)
result["nodeInfo"] = nodeInfo->toJson();
@@ -412,6 +366,9 @@ private:
template <typename Is>
void loadState(Is& is, size_t size);
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_;
@@ -436,11 +393,6 @@ private:
std::shared_ptr<ServerStats> stats_;
std::shared_ptr<NodeInfo> nodeInfo_ {};
std::unique_ptr<asio::steady_timer> printStatsTimer_;
const time_point serverStartTime_;
mutable std::mutex pushStatsMutex_;
PushStats androidPush_;
PushStats iosPush_;
PushStats unifiedPush_;
// Thread-safe access to listeners map.
std::mutex lockListener_;
+2 -5
View File
@@ -64,7 +64,6 @@ public:
std::string push_token {};
std::string push_topic {};
std::string push_platform {};
std::string proxy_user_agent {};
bool peer_discovery {false};
bool peer_publish {false};
std::shared_ptr<dht::crypto::Certificate> server_ca;
@@ -410,8 +409,7 @@ public:
void run(const Config& config, Context&& context);
void setOnStatusChanged(StatusCallback&& cb) {
if (cb)
statusCbs.emplace_back(std::move(cb));
statusCb = std::move(cb);
}
/**
@@ -521,8 +519,7 @@ private:
NodeStatus status4 {NodeStatus::Disconnected},
status6 {NodeStatus::Disconnected};
std::vector<StatusCallback> statusCbs {};
StatusCallback statusCb {nullptr};
/** PeerDiscovery Parameters */
std::shared_ptr<PeerDiscovery> peerDiscovery_;
+1 -1
View File
@@ -72,7 +72,7 @@ class OPENDHT_PUBLIC Url
{
public:
Url() = default;
Url(std::string_view url);
Url(const std::string& url);
std::string url;
std::string protocol {"http"};
std::string host;
+1 -1
View File
@@ -409,7 +409,7 @@ private:
/**
* This mutlimap contains all prefix insert in the tree in time order
* We could then delete the last one if there are too many nodes
* We could then delete the last one if there is too much node
* The tree will self destroy is branch ( thanks to share_ptr )
*/
std::multimap<time_point, std::shared_ptr<Node>> leaves_;
-1
View File
@@ -52,7 +52,6 @@ struct NetworkConfig {
NetId network {0};
ssize_t max_req_per_sec {0};
ssize_t max_peer_req_per_sec {0};
bool is_client {false};
};
class DhtProtocolException : public DhtException {
+14 -21
View File
@@ -23,9 +23,7 @@
#include "sockaddr.h"
#include "infohash.h"
#include "logger.h"
#include "utils.h"
#include <asio/steady_timer.hpp>
#include <thread>
namespace asio {
@@ -38,34 +36,31 @@ class OPENDHT_PUBLIC PeerDiscovery
{
public:
static constexpr in_port_t DEFAULT_PORT = 8888;
using ServiceDiscoveredCallback = std::function<void(msgpack::object &&, SockAddr &&)>;
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, std::shared_ptr<asio::io_context> ioContext = {}, std::shared_ptr<Logger> logger = {});
~PeerDiscovery();
/**
* startDiscovery - Keep Listening data from the sender until node is joinned
* or stop is called
*/
* startDiscovery - Keep Listening data from the sender until node is joinned or stop is called
*/
void startDiscovery(const std::string &type, ServiceDiscoveredCallback callback);
template <typename T>
void startDiscovery(const std::string &type, std::function<void(T &&, SockAddr &&)> cb) {
startDiscovery(type, [cb](msgpack::object &&ob, SockAddr &&addr) {
template<typename T>
void startDiscovery(const std::string &type, std::function<void(T&&, SockAddr&&)> cb) {
startDiscovery(type, [cb](msgpack::object&& ob, SockAddr&& addr) {
cb(ob.as<T>(), std::move(addr));
});
}
/**
* startPublish - Keeping sending data until node is joinned or stop is called
*/
*/
void startPublish(const std::string &type, const msgpack::sbuffer &pack_buf);
void startPublish(sa_family_t domain, const std::string &type, const msgpack::sbuffer &pack_buf);
template <typename T>
void startPublish(const std::string &type, const T &object) {
template<typename T>
void startPublish(const std::string &type, const T& object) {
msgpack::sbuffer buf;
msgpack::pack(buf, object);
startPublish(type, buf);
@@ -73,24 +68,22 @@ public:
/**
* 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);
bool stopPublish(sa_family_t domain, const std::string &type);
void connectivityChanged();
void stopConnectivityChanged();
private:
class DomainPeerDiscovery;
std::unique_ptr<DomainPeerDiscovery> peerDiscovery4_;
@@ -99,4 +92,4 @@ private:
std::thread ioRunnner_;
};
} // namespace dht
}
+1 -1
View File
@@ -24,7 +24,7 @@ namespace proxy {
constexpr const std::chrono::hours OP_TIMEOUT {24}; // one day
constexpr const std::chrono::hours OP_MARGIN {2}; // two hours
constexpr const char* const HTTP_PROTO {"http://"};
using ListenToken = uint64_t;
}
+22 -9
View File
@@ -21,7 +21,6 @@
#include "def.h"
#include <msgpack.hpp>
#include <fmt/format.h>
#include <chrono>
#include <random>
@@ -61,7 +60,7 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition)
* Split "[host]:port" or "host:port" to pair<"host", "port">.
*/
OPENDHT_PUBLIC std::pair<std::string, std::string>
splitPort(std::string_view s);
splitPort(const std::string& s);
class OPENDHT_PUBLIC DhtException : public std::runtime_error {
public:
@@ -85,23 +84,37 @@ using duration = clock::duration;
time_point from_time_t(std::time_t t);
std::time_t to_time_t(time_point t);
inline std::string
to_str(double d) {
char buf[16];
auto ret = snprintf(buf, sizeof(buf), "%.3g", d);
return (ret < 0) ? std::to_string(d) : std::string(buf, ret);
}
/**
* Converts std::chrono::duration to floating-point seconds.
*/
template <class DT>
static double
print_dt(DT d) {
return std::chrono::duration_cast<std::chrono::duration<double>>(d).count();
}
template <class DT>
static std::string
print_duration(DT d) {
if (d < std::chrono::seconds(0)) {
return "-" + print_duration(-d);
} else if (d < std::chrono::milliseconds(1)) {
return fmt::format("{:.3g} us", std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
} else if (d < std::chrono::seconds(1)) {
return fmt::format("{:.3g} ms", std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
} else if (d < std::chrono::minutes(1)) {
return fmt::format("{:.3g} s", std::chrono::duration_cast<std::chrono::duration<double>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
} else if (d < std::chrono::hours(1)) {
return fmt::format("{:.3g} min", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count());
} else if (d < std::chrono::hours(72)) {
return fmt::format("{:.3g} h", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
} else {
return fmt::format("{:.3g} days", std::chrono::duration_cast<std::chrono::duration<double, std::ratio<86400>>>(d).count());
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
}
}
+4 -8
View File
@@ -13,16 +13,10 @@ openssl = dependency('openssl', required: get_option('proxy_client'))
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
fmt = dependency('fmt')
llhttp = dependency('llhttp', 'libllhttp', required: get_option('proxy_client'))
io_uring = dependency('liburing', required: false)
deps = [fmt, gnutls, nettle, msgpack, argon2, openssl, jsoncpp, llhttp, io_uring]
conf_data = configuration_data()
deps = [fmt, gnutls, nettle, msgpack, argon2, openssl, jsoncpp, llhttp]
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language : 'cpp')
if io_uring.found()
add_project_arguments('-DASIO_HAS_IO_URING', '-DASIO_DISABLE_EPOLL', language : 'cpp')
conf_data.set('iouring_lib', ', liburing')
endif
add_project_arguments('-DMSGPACK_NO_BOOST', language : 'cpp')
add_project_arguments(['-Wno-return-type','-Wno-deprecated','-Wnon-virtual-dtor','-pedantic-errors','-fvisibility=hidden'], language : 'cpp')
opendht_inc = include_directories('include/opendht')
@@ -46,6 +40,8 @@ opendht_src = [
'src/thread_pool.cpp',
]
conf_data = configuration_data()
if get_option('indexation').enabled()
opendht_src += 'src/indexation/pht.cpp'
add_project_arguments('-DOPENDHT_INDEXATION', language : 'cpp')
+1 -1
View File
@@ -8,5 +8,5 @@ Version: @VERSION@
Libs: -L${libdir} -lopendht
Libs.private: @http_lib@ -pthread
Requires: gnutls >= 3.3@jsoncpp_lib@@openssl_lib@
Requires.private: nettle >= 2.4@argon2_lib@@iouring_lib@
Requires.private: nettle >= 2.4@argon2_lib@
Cflags: -I${includedir}
+1 -2
View File
@@ -500,13 +500,12 @@ cdef class DhtConfig(object):
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
def setProxyInfo(self, str proxy_server, str push_node_id="", str push_token="", str push_topic="", str push_platform="", str user_agent="", Certificate server_ca = Certificate()):
def setProxyInfo(self, str proxy_server, str push_node_id="", str push_token="", str push_topic="", str push_platform="", Certificate server_ca = Certificate()):
self._config.proxy_server = proxy_server.encode()
self._config.push_node_id = push_node_id.encode()
self._config.push_token = push_token.encode()
self._config.push_topic = push_topic.encode()
self._config.push_platform = push_platform.encode()
self._config.proxy_user_agent = user_agent.encode()
self._config.server_ca = server_ca._cert
def setPeerDiscovery(self, bool peer_discovery, bool peer_publish):
self._config.peer_discovery = peer_discovery
-1
View File
@@ -246,7 +246,6 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
string push_token
string push_topic
string push_platform
string proxy_user_agent
bool peer_discovery
bool peer_publish
shared_ptr[Certificate] server_ca
+5 -5
View File
@@ -2,10 +2,10 @@
name = "opendht"
version = "0.1.0"
authors = ["Sébastien Blin <sebastien.blin@savoirfairelinux.com>"]
edition = "2021"
[dependencies]
libc="0.2"
os_socketaddr="0.2.3"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc="0.2.0"
os_socketaddr="0.2.3"
+8 -14
View File
@@ -49,7 +49,6 @@ impl DhtRunnerConfig {
push_token: ptr::null(),
push_topic: ptr::null(),
push_platform: ptr::null(),
proxy_user_agent: ptr::null(),
peer_discovery: false,
peer_publish: false,
server_ca: ptr::null_mut(),
@@ -57,7 +56,6 @@ impl DhtRunnerConfig {
privatekey: ptr::null_mut(),
certificate: ptr::null_mut(),
},
log: true,
});
unsafe {
dht_runner_config_default(&mut *config);
@@ -66,27 +64,23 @@ impl DhtRunnerConfig {
}
pub fn set_proxy_server(&mut self, proxy_server: &str) {
self.proxy_server = CString::new(proxy_server).unwrap().into_raw();
self.proxy_server = CString::new(proxy_server).unwrap().as_ptr();
}
pub fn set_push_node_id(&mut self, push_node_id: &str) {
self.push_node_id = CString::new(push_node_id).unwrap().into_raw();
self.push_node_id = CString::new(push_node_id).unwrap().as_ptr();
}
pub fn set_push_token(&mut self, push_token: &str) {
self.push_token = CString::new(push_token).unwrap().into_raw();
self.push_token = CString::new(push_token).unwrap().as_ptr();
}
pub fn set_push_topic(&mut self, push_topic: &str) {
self.push_topic = CString::new(push_topic).unwrap().into_raw();
self.push_topic = CString::new(push_topic).unwrap().as_ptr();
}
pub fn set_push_platform(&mut self, push_platform: &str) {
self.push_platform = CString::new(push_platform).unwrap().into_raw();
}
pub fn set_proxy_user_agent(&mut self, proxy_user_agent: &str) {
self.proxy_user_agent = CString::new(proxy_user_agent).unwrap().into_raw();
self.push_platform = CString::new(push_platform).unwrap().as_ptr();
}
pub fn set_identity(&mut self, certificate: Box<DhtCertificate>, privatekey: Box<PrivateKey>) {
@@ -99,7 +93,7 @@ impl DhtRunnerConfig {
impl DhtNodeConfig
{
pub fn set_persist_path(&mut self, persist_path: &str) {
self.persist_path = CString::new(persist_path).unwrap().into_raw();
self.persist_path = CString::new(persist_path).unwrap().as_ptr();
}
}
@@ -203,8 +197,8 @@ impl DhtRunner {
pub fn bootstrap(&mut self, host: &str, service: u16) {
unsafe {
dht_runner_bootstrap(&mut *self,
CString::new(host).unwrap().into_raw(),
CString::new(service.to_string()).unwrap().into_raw())
CString::new(host).unwrap().as_ptr(),
CString::new(service.to_string()).unwrap().as_ptr())
}
}
+1 -2
View File
@@ -120,14 +120,13 @@ pub struct DhtRunnerConfig
pub push_token: *const c_char,
pub push_topic: *const c_char,
pub push_platform: *const c_char,
pub proxy_user_agent: *const c_char,
pub peer_discovery: bool,
pub peer_publish: bool,
pub server_ca: *mut DhtCertificate,
pub client_identity: DhtIdentity,
pub log: bool,
}
#[link(name = "opendht-c")]
extern {
// dht::Value
-39
View File
@@ -1,39 +0,0 @@
//Code from getifaddrs.3 man
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <asio.hpp>
#include <stdexcept>
namespace dht{
namespace workaround{
asio::ip::address_v4
get_interface(){
struct ifaddrs *ifaddr;
if(getifaddrs(&ifaddr) == -1){
throw std::runtime_error("Can't getifaddrs");
}
for (struct ifaddrs *if1 = ifaddr; if1 != NULL; if1 = if1->ifa_next){
if (if1->ifa_addr == NULL)
continue;
if (if1->ifa_addr->sa_family != AF_INET)
continue;
if((if1->ifa_flags & IFF_MULTICAST) == IFF_MULTICAST){
auto sa_data = reinterpret_cast<uint8_t*>(if1->ifa_addr->sa_data);
uint32_t value = sa_data[2] << 24
| sa_data[3] << 16
| sa_data[4] << 8
| sa_data[5];
freeifaddrs(ifaddr);
return asio::ip::address_v4(value);
}
}
freeifaddrs(ifaddr);
throw std::runtime_error("Can't find a interface which supports multicast");
}
} /* namespace workaround */
} /* namespace dht */
+22 -83
View File
@@ -93,27 +93,11 @@ Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key)
std::random_device rdev;
std::generate_n(ret.begin(), GCM_IV_SIZE, std::bind(rand_byte, std::ref(rdev)));
}
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes128_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes192_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, ret.data());
gcm_aes256_encrypt(&aes, data_length, ret.data() + GCM_IV_SIZE, data);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, ret.data() + GCM_IV_SIZE + data_length);
}
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, ret.data());
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);
return ret;
}
@@ -134,28 +118,14 @@ Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
std::array<uint8_t, GCM_DIGEST_SIZE> digest;
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, data);
size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE;
Blob ret(data_sz);
if (key.size() == AES_LENGTHS[0]) {
struct gcm_aes128_ctx aes;
gcm_aes128_set_key(&aes, key.data());
gcm_aes128_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes128_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes128_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[1]) {
struct gcm_aes192_ctx aes;
gcm_aes192_set_key(&aes, key.data());
gcm_aes192_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes192_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes192_digest(&aes, GCM_DIGEST_SIZE, digest.data());
} else if (key.size() == AES_LENGTHS[2]) {
struct gcm_aes256_ctx aes;
gcm_aes256_set_key(&aes, key.data());
gcm_aes256_set_iv(&aes, GCM_IV_SIZE, data);
gcm_aes256_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes256_digest(&aes, GCM_DIGEST_SIZE, digest.data());
}
gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE)) {
throw DecryptError("Can't decrypt data");
@@ -257,7 +227,7 @@ PrivateKey::PrivateKey(const uint8_t* src, size_t src_size, const char* password
throw CryptoException("Can't initialize private key !");
const gnutls_datum_t dt {(uint8_t*)src, static_cast<unsigned>(src_size)};
int flags = (password_ptr == NULL || strlen(password_ptr)==0) ? GNUTLS_PKCS_PLAIN
int flags = password_ptr ? GNUTLS_PKCS_PLAIN
: ( GNUTLS_PKCS_PBES2_AES_128 | GNUTLS_PKCS_PBES2_AES_192 | GNUTLS_PKCS_PBES2_AES_256
| GNUTLS_PKCS_PKCS12_3DES | GNUTLS_PKCS_PKCS12_ARCFOUR | GNUTLS_PKCS_PKCS12_RC2_40);
@@ -1164,17 +1134,11 @@ saveIdentity(const Identity& id, const std::string& path, const std::string& pri
auto ca_key_data = id.first->serialize(privkey_password);
std::ofstream key_file(path + ".pem");
key_file.write((char*)ca_key_data.data(), ca_key_data.size());
// Throw error if the file is not written
if (!key_file)
throw CryptoException("Could not write private key file");
}
{
auto ca_key_data = id.second->getPacked();
std::ofstream crt_file(path + ".crt");
crt_file.write((char*)ca_key_data.data(), ca_key_data.size());
// Throw error if the file is not written
if (!crt_file)
throw CryptoException("Could not write certificate file");
}
}
@@ -1188,19 +1152,12 @@ loadIdentity(const std::string &path,const std::string &privkey_password)
pkStream.close();
// Create a certificate
gnutls_x509_crt_t gnuCert;
if (gnutls_x509_crt_init(&gnuCert))
if (gnutls_x509_crt_init(&gnuCert) != GNUTLS_E_SUCCESS)
throw std::runtime_error("Failed to initialize gnutls certificate struct");
gnutls_datum_t crtContent {nullptr, 0};
// Read the certificate file
int err = gnutls_load_file((path + ".crt").c_str(), &crtContent);
if (err)
throw CryptoException(gnutls_strerror(err));
err = gnutls_x509_crt_import(gnuCert, &crtContent, GNUTLS_X509_FMT_PEM);
if (err)
throw CryptoException(gnutls_strerror(err));
gnutls_load_file((path + ".crt").c_str(), &crtContent);
gnutls_x509_crt_import(gnuCert, &crtContent, GNUTLS_X509_FMT_PEM);
auto cert = std::make_shared<Certificate>(gnuCert);
return {std::move(key), std::move(cert)};
}
@@ -1247,49 +1204,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
int err = gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
if(err) {
throw CryptoException(std::string("Error when setting subject key id ") + gnutls_strerror(err));
}
err = gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
if(err) {
throw CryptoException(std::string("Error when setting dn by oid ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
err = gnutls_x509_crt_set_ca_status(cert, 1);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_ca_status(cert, 1);
key_usage |= GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN;
} else {
key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_DATA_ENCIPHERMENT;
}
err = gnutls_x509_crt_set_key_usage(cert, key_usage);
if(err) {
throw CryptoException(std::string("Error when setting ca status ") + gnutls_strerror(err));
}
gnutls_x509_crt_set_key_usage(cert, key_usage);
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
throw CryptoException("Signing certificate must be CA");
}
err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0);
if (err) {
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
} else {
err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0);
if (err) {
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
+68 -69
View File
@@ -93,7 +93,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
r.second.done_cb(false, {});
sr.second->callbacks.clear();
for (const auto& a : sr.second->announce) {
for (auto& cb : a.callbacks) cb(false, {});
if (a.callback) a.callback(false, {});
}
sr.second->announce.clear();
sr.second->listeners.clear();
@@ -113,7 +113,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
auto str_donecb = [=](bool, const std::vector<Sp<Node>>&) {
--*remaining;
if (logger_)
logger_->w("Shutting down node: %u ops remaining", *remaining);
logger_->w("shuting down node: %u ops remaining", *remaining);
if (!*remaining && cb) { cb(); }
};
@@ -121,7 +121,7 @@ Dht::shutdown(ShutdownCallback cb, bool stop)
*remaining += maintainStorage(str, true, str_donecb);
if (logger_)
logger_->w("Shutting down node: after storage, %u ops", *remaining);
logger_->w("shuting down node: after storage, %u ops", *remaining);
if (!*remaining) {
if (cb) cb();
@@ -147,7 +147,7 @@ Dht::sendCachedPing(Bucket& b)
{
if (b.cached)
if (logger_)
logger_->d(b.cached->id, "[node %s] Sending ping to cached node", b.cached->toString().c_str());
logger_->d(b.cached->id, "[node %s] sending ping to cached node", b.cached->toString().c_str());
b.sendCachedPing(network_engine);
}
@@ -280,7 +280,7 @@ Dht::expireSearches()
auto b = sr.callbacks.empty() && sr.announce.empty() && sr.listeners.empty() && sr.step_time < t;
if (b) {
if (logger_)
logger_->d(srp.first, "[search %s] Removing search", srp.first.toString().c_str());
logger_->d(srp.first, "[search %s] removing search", srp.first.toString().c_str());
sr.clear();
return b;
} else { return false; }
@@ -360,7 +360,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
auto query_for_vid = std::make_shared<Query>(Select {}, Where {}.id(vid));
sn->pagination_queries[query].push_back(query_for_vid);
if (logger_)
logger_->d(id, sn->node->id, "[search %s] [node %s] Sending %s",
logger_->d(id, sn->node->id, "[search %s] [node %s] sending %s",
id.toString().c_str(), sn->node->toString().c_str(), query_for_vid->toString().c_str());
sn->getStatus[query_for_vid] = network_engine.sendGetValues(status.node,
id,
@@ -371,8 +371,8 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
);
} catch (const std::out_of_range&) {
if (logger_)
logger_->e(id, sn->node->id, "[search %s] [node %s] Received non-id field in response to "\
"'SELECT id' request…",
logger_->e(id, sn->node->id, "[search %s] [node %s] received non-id field in response to "\
"'SELECT id' request...",
id.toString().c_str(), sn->node->toString().c_str());
}
}
@@ -381,7 +381,7 @@ void Dht::paginate(std::weak_ptr<Search> ws, Sp<Query> query, SearchNode* n) {
n->pagination_queries[query].push_back(select_q);
if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending %s",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending %s",
sr->id.toString().c_str(), n->node->toString().c_str(), select_q->toString().c_str());
n->getStatus[select_q] = network_engine.sendGetValues(n->node,
sr->id,
@@ -426,7 +426,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
return nullptr;
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'find_node'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'find_node'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendFindNode(n->node,
sr->id,
@@ -439,9 +439,9 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
continue;
if (query and not query->select.empty()) {
/* The request contains a select. No need to paginate… */
/* The request contains a select. No need to paginate... */
/* if (logger_)
logger_->d(sr->id, n->node->id, "[search %s] [node %s] Sending 'get'",
logger_->d(sr->id, n->node->id, "[search %s] [node %s] sending 'get'",
sr->id.toString().c_str(), n->node->toString().c_str());*/
n->getStatus[query] = network_engine.sendGetValues(n->node,
sr->id,
@@ -453,7 +453,7 @@ Dht::searchSendGetValues(Sp<Search> sr, SearchNode* pn, bool update)
paginate(ws, query, n);
}
/* We only attempt to send one request. Return. */
/* We only try to send one request. return. */
return n;
} while (++cb != sr->callbacks.end());
@@ -519,7 +519,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
/* only put the value if the node doesn't already have it */
if (not hasValue or seq_no < a.value->seq) {
if (logger_)
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto created = a.permanent ? time_point::max() : a.created;
acked = {
@@ -528,7 +528,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else if (hasValue and a.permanent) {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Sending 'refresh' (vid: %016" PRIx64 ")",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
acked = {
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
@@ -540,7 +540,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
](const net::Request& /*req*/, net::DhtProtocolException&& e){
if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
if (auto sr = ws.lock()) {
if (auto sn = sr->getNode(node)) {
sn->acked[v->id] = {
@@ -558,7 +558,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
};
} else {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] Already has value (vid: %016" PRIx64 "). Aborting.",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %016" PRIx64 "). Aborting.",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto ack_req = std::make_shared<net::Request>(net::Request::State::COMPLETED);
ack_req->reply_time = now;
@@ -594,7 +594,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
sendQuery = true;
} else {
if (logger_)
logger_->w(sr->id, n.node->id, "[search %s] [node %s] Sending 'put' (vid: %016" PRIx64 ")",
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), n.node->toString().c_str(), a.value->id);
n.acked[a.value->id] = {
network_engine.sendAnnounceValue(n.node, sr->id, a.value, a.created, n.token, onDone, onExpired),
@@ -607,7 +607,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr, unsigned syncLevel) {
if (sendQuery) {
n.probe_query = PROBE_QUERY;
if (logger_)
logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending %s",
logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending %s",
sr->id.toString().c_str(), n.node->toString().c_str(), n.probe_query->toString().c_str());
auto req = network_engine.sendGetValues(n.node,
sr->id,
@@ -634,7 +634,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
if (n.getListenTime(r, listenExp) > scheduler.time())
continue;
// if (logger_)
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] Sending 'listen'",
// logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending 'listen'",
// sr->id.toString().c_str(), n.node->toString().c_str());
if (r == n.listenStatus.end()) {
@@ -706,7 +706,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
auto syncLevel = preSynced ? level - MARGIN : 0;
/*if (auto req_count = sr->currentlySolicitedNodeCount())
if (logger_)
logger_->d(sr->id, "[search %s IPv%c] Step (%d requests)",
logger_->d(sr->id, "[search %s IPv%c] step (%d requests)",
sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6', req_count);*/
sr->step_time = now;
@@ -787,7 +787,7 @@ Dht::searchStep(std::weak_ptr<Search> ws)
if (sr->getNumberOfConsecutiveBadNodes() >= std::min<size_t>(sr->nodes.size(), SEARCH_MAX_BAD_NODES))
{
if (logger_)
logger_->w(sr->id, "[search %s IPv%c] Expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
logger_->w(sr->id, "[search %s IPv%c] expired", sr->id.toString().c_str(), sr->af == AF_INET ? '4' : '6');
sr->expire();
if (not public_stable)
connectivityChanged(sr->af);
@@ -804,7 +804,7 @@ unsigned Dht::refill(Dht::Search& sr) {
if (cached_nodes.empty()) {
if (logger_)
logger_->e(sr.id, "[search %s IPv%c] No nodes from cache while refilling search",
logger_->e(sr.id, "[search %s IPv%c] no nodes from cache while refilling search",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6');
return 0;
}
@@ -816,7 +816,7 @@ unsigned Dht::refill(Dht::Search& sr) {
++inserted;
}
if (logger_)
logger_->d(sr.id, "[search %s IPv%c] Refilled search with %u nodes from node cache",
logger_->d(sr.id, "[search %s IPv%c] refilled search with %u nodes from node cache",
sr.id.toString().c_str(), (sr.af == AF_INET) ? '4' : '6', inserted);
return inserted;
}
@@ -828,7 +828,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
{
if (!isRunning(af)) {
if (logger_)
logger_->e(id, "[search %s IPv%c] Unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] unsupported protocol", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (dcb)
dcb(false, {});
return {};
@@ -856,7 +856,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
}
if (not sr) {
if (logger_)
logger_->e(id, "[search %s IPv%c] Maximum number of searches reached!", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->e(id, "[search %s IPv%c] maximum number of searches reached !", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
return {};
}
}
@@ -870,7 +870,7 @@ Dht::search(const InfoHash& id, sa_family_t af, GetCallback gcb, QueryCallback q
sr->nodes.reserve(SEARCH_NODES+1);
sr->nextSearchStep = scheduler.add(time_point::max(), std::bind(&Dht::searchStep, this, std::weak_ptr<Search>(sr)));
if (logger_)
logger_->w(id, "[search %s IPv%c] New search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] new search", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
if (search_id == 0)
search_id++;
}
@@ -904,16 +904,16 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
{
if (!isRunning(af))
return 0;
// logger__ERR("[search %s IPv%c] Search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_duration(tm-clock::now()));
// logger__ERR("[search %s IPv%c] search_time is now in %lfs", sr->id.toString().c_str(), (sr->af == AF_INET) ? '4' : '6', print_dt(tm-clock::now()));
//logger__WARN("listenTo %s", id.toString().c_str());
auto& srs = searches(af);
auto srp = srs.find(id);
Sp<Search> sr = (srp == srs.end()) ? search(id, af) : srp->second;
if (!sr)
throw DhtException("Unable to create search");
throw DhtException("Can't create search");
if (logger_)
logger_->w(id, "[search %s IPv%c] Listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
logger_->w(id, "[search %s IPv%c] listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
return sr->listen(cb, std::move(f), q, scheduler);
}
@@ -1022,7 +1022,7 @@ Dht::put(const InfoHash& id, Sp<Value> val, DoneCallback callback, time_point cr
storageStore(id, val, created, {}, permanent);
if (logger_)
logger_->d(id, "put: adding %s → %s", id.toString().c_str(), val->toString().c_str());
logger_->d(id, "put: adding %s -> %s", id.toString().c_str(), val->toString().c_str());
auto op = std::make_shared<OpStatus>();
auto donecb = [callback](const std::vector<Sp<Node>>& nodes, OpStatus& op) {
@@ -1265,7 +1265,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
vals.push_back(v);
if (not vals.empty()) {
if (logger_)
logger_->d(id, "[store %s] Sending update local listener with token %lu",
logger_->d(id, "[store %s] sending update local listener with token %lu",
id.toString().c_str(),
l.first);
cbs.emplace_back(l.second.get_cb, std::move(vals));
@@ -1286,7 +1286,7 @@ Dht::storageChanged(const InfoHash& id, Storage& st, const Sp<Value>& v, bool ne
if (f and not f(*v))
continue;
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending update",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending update",
id.toString().c_str(),
node_listeners.first->toString().c_str());
std::vector<Sp<Value>> vals {};
@@ -1392,7 +1392,7 @@ void
Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>>& values, size_t totalSize)
{
if (logger_)
logger_->d(id, "[store %s] Discarded %ld values (%ld bytes)",
logger_->d(id, "[store %s] discarded %ld values (%ld bytes)",
id.toString().c_str(), values.size(), totalSize);
total_store_size -= totalSize;
@@ -1410,7 +1410,7 @@ Dht::storageRemoved(const InfoHash& id, Storage& st, const std::vector<Sp<Value>
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending expired",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending expired",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -1432,7 +1432,7 @@ Dht::expireStore()
if (i->second.empty() && i->second.listeners.empty() && i->second.local_listeners.empty()) {
if (logger_)
logger_->d(i->first, "[store %s] Discarding empty storage", i->first.toString().c_str());
logger_->d(i->first, "[store %s] discarding empty storage", i->first.toString().c_str());
i = store.erase(i);
}
else
@@ -1812,7 +1812,6 @@ fromDhtConfig(const Config& config)
netConf.max_peer_req_per_sec = config.max_peer_req_per_sec
? config.max_peer_req_per_sec
: netConf.max_req_per_sec/8;
netConf.is_client = config.client_mode;
return netConf;
}
@@ -1900,7 +1899,7 @@ Dht::neighbourhoodMaintenance(RoutingTable& list)
auto n = q->randomNode(rd);
if (n) {
if (logger_)
logger_->d(id, n->id, "[node %s] Sending [find %s] for neighborhood maintenance",
logger_->d(id, n->id, "[node %s] sending [find %s] for neighborhood maintenance",
n->toString().c_str(), id.toString().c_str());
/* Since our node-id is the same in both DHTs, it's probably
profitable to query both families. */
@@ -1954,14 +1953,14 @@ Dht::bucketMaintenance(RoutingTable& list)
}
if (logger_)
logger_->d(id, n->id, "[node %s] Sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
logger_->d(id, n->id, "[node %s] sending find %s for bucket maintenance", n->toString().c_str(), id.toString().c_str());
//auto start = scheduler.time();
network_engine.sendFindNode(n, id, want, nullptr, [this,n](const net::Request&, bool over) {
if (over) {
const auto& end = scheduler.time();
// using namespace std::chrono;
// if (logger_)
// logger_->d(n->id, "[node %s] Bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
// logger_->d(n->id, "[node %s] bucket maintenance op expired after %s", n->toString().c_str(), print_duration(end-start).c_str());
scheduler.edit(nextNodesConfirmation, end + Node::MAX_RESPONSE_TIME);
}
});
@@ -1979,7 +1978,7 @@ Dht::dataPersistence(InfoHash id)
auto str = store.find(id);
if (str != store.end() and now > str->second.maintenance_time) {
if (logger_)
logger_->d(id, "[storage %s] Maintenance (%u values, %u bytes)",
logger_->d(id, "[storage %s] maintenance (%u values, %u bytes)",
id.toString().c_str(), str->second.valueCount(), str->second.totalSize());
maintainStorage(*str);
str->second.maintenance_time = now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
@@ -2033,7 +2032,7 @@ Dht::periodic(const uint8_t *buf, size_t buflen, SockAddr from, const time_point
network_engine.processMessage(buf, buflen, std::move(from));
} catch (const std::exception& e) {
if (logger_)
logger_->w("Unable to process message: %s", e.what());
logger_->w("Can't process message: %s", e.what());
}
}
return scheduler.run();
@@ -2087,7 +2086,7 @@ Dht::bootstrap()
}
} catch (const std::exception& e) {
if (logger_)
logger_->e(myid, "Unable to resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
logger_->e(myid, "Can't resolve %s:%s: %s", boootstrap.first.c_str(), boootstrap.second.c_str(), e.what());
}
}
scheduler.cancel(bootstrapJob);
@@ -2118,12 +2117,12 @@ Dht::confirmNodes()
if (dht4.searches.empty() and dht4.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] Initial IPv4 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] initial IPv4 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET);
}
if (dht6.searches.empty() and dht6.status == NodeStatus::Connected) {
if (logger_)
logger_->d(myid, "[confirm nodes] Initial IPv6 'get' for my id (%s)", myid.toString().c_str());
logger_->d(myid, "[confirm nodes] initial IPv6 'get' for my id (%s)", myid.toString().c_str());
search(myid, AF_INET6);
}
@@ -2281,7 +2280,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
const auto& node = req->node;
if (e.getCode() == net::DhtProtocolException::UNAUTHORIZED) {
if (logger_)
logger_->e(node->id, "[node %s] Token flush", node->toString().c_str());
logger_->e(node->id, "[node %s] token flush", node->toString().c_str());
node->authError();
for (auto& srp : searches(node->getFamily())) {
auto& sr = srp.second;
@@ -2296,7 +2295,7 @@ Dht::onError(Sp<net::Request> req, net::DhtProtocolException e) {
}
} else if (e.getCode() == net::DhtProtocolException::NOT_FOUND) {
if (logger_)
logger_->e(node->id, "[node %s] Returned error 404: storage not found", node->toString().c_str());
logger_->e(node->id, "[node %s] returned error 404: storage not found", node->toString().c_str());
node->cancelRequest(req);
}
}
@@ -2347,7 +2346,7 @@ Dht::onGetValues(Sp<Node> node, const InfoHash& hash, want_t, const Query& query
if (st != store.end() && not st->second.empty()) {
answer.values = st->second.get(query.where.getFilter());
if (logger_)
logger_->d(hash, "[node %s] Sending %u values", node->toString().c_str(), answer.values.size());
logger_->d(hash, "[node %s] sending %u values", node->toString().c_str(), answer.values.size());
}
return answer;
}
@@ -2359,18 +2358,18 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
{
if (not sr) {
if (logger_)
logger_->w("[search unknown] Got reply to 'get'. Ignoring.");
logger_->w("[search unknown] got reply to 'get'. Ignoring.");
return;
}
/* if (logger_)
logger_->d(sr->id, "[search %s] [node %s] Got reply to 'get' with %u nodes",
logger_->d(sr->id, "[search %s] [node %s] got reply to 'get' with %u nodes",
sr->id.toString().c_str(), node->toString().c_str(), a.nodes4.size()+a.nodes6.size());*/
if (not a.ntoken.empty()) {
if (not a.values.empty() or not a.fields.empty()) {
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] Found %u values",
logger_->d(sr->id, node->id, "[search %s] [node %s] found %u values",
sr->id.toString().c_str(), node->toString().c_str(), a.values.size());
for (auto& getp : sr->callbacks) { /* call all callbacks for this search */
auto& get = getp.second;
@@ -2419,7 +2418,7 @@ void Dht::onGetValuesDone(const Sp<Node>& node,
}
} else {
if (logger_)
logger_->w(sr->id, "[node %s] No token provided. Ignoring response content.", node->toString().c_str());
logger_->w(sr->id, "[node %s] no token provided. Ignoring response content.", node->toString().c_str());
network_engine.blacklistNode(node);
}
@@ -2436,7 +2435,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
{
if (not hash) {
if (logger_)
logger_->w(node->id, "[node %s] Listen with no info_hash", node->toString().c_str());
logger_->w(node->id, "[node %s] listen with no info_hash", node->toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::LISTEN_NO_INFOHASH
@@ -2444,7 +2443,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
}
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'listen'", node->toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::LISTEN_WRONG_TOKEN};
}
Query q = query;
@@ -2456,7 +2455,7 @@ void
Dht::onListenDone(const Sp<Node>& /* node */, net::RequestAnswer& /* answer */, Sp<Search>& sr)
{
// if (logger_)
// logger_->d(sr->id, node->id, "[search %s] [node %s] Got listen confirmation",
// logger_->d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
// sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
if (not sr->done) {
@@ -2476,7 +2475,7 @@ Dht::onAnnounce(Sp<Node> n,
auto& node = *n;
if (not hash) {
if (logger_)
logger_->w(node.id, "Put with no info_hash");
logger_->w(node.id, "put with no info_hash");
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_NO_INFOHASH
@@ -2484,7 +2483,7 @@ Dht::onAnnounce(Sp<Node> n,
}
if (!tokenMatch(token, node.getAddr())) {
if (logger_)
logger_->w(hash, node.id, "[node %s] Incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
logger_->w(hash, node.id, "[node %s] incorrect token %s for 'put'", node.toString().c_str(), hash.toString().c_str());
throw net::DhtProtocolException {net::DhtProtocolException::UNAUTHORIZED, net::DhtProtocolException::PUT_WRONG_TOKEN};
}
{
@@ -2493,7 +2492,7 @@ Dht::onAnnounce(Sp<Node> n,
auto closest_nodes = buckets(node.getFamily()).findClosestNodes(hash, scheduler.time(), SEARCH_NODES);
if (closest_nodes.size() >= TARGET_NODES and hash.xorCmp(closest_nodes.back()->id, myid) < 0) {
if (logger_)
logger_->w(hash, node.id, "[node %s] Announce too far from the target. Dropping value.", node.toString().c_str());
logger_->w(hash, node.id, "[node %s] announce too far from the target. Dropping value.", node.toString().c_str());
return {};
}
}
@@ -2502,7 +2501,7 @@ Dht::onAnnounce(Sp<Node> n,
for (const auto& v : values) {
if (v->id == Value::INVALID_ID) {
if (logger_)
logger_->w(hash, node.id, "[value %s] Incorrect value id", hash.toString().c_str());
logger_->w(hash, node.id, "[value %s] incorrect value id", hash.toString().c_str());
throw net::DhtProtocolException {
net::DhtProtocolException::NON_AUTHORITATIVE_INFORMATION,
net::DhtProtocolException::PUT_INVALID_ID
@@ -2514,17 +2513,17 @@ Dht::onAnnounce(Sp<Node> n,
if (*lv == *vc) {
storageRefresh(hash, v->id);
if (logger_)
logger_->d(hash, node.id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
logger_->d(hash, node.id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node.toString().c_str(), v->id);
} else {
const auto& type = getType(lv->type);
if (type.editPolicy(hash, lv, vc, node.id, node.getAddr())) {
if (logger_)
logger_->d(hash, node.id, "[store %s] Editing %s",
logger_->d(hash, node.id, "[store %s] editing %s",
hash.toString().c_str(), vc->toString().c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] Rejecting edition of %s because of storage policy",
logger_->d(hash, node.id, "[store %s] rejecting edition of %s because of storage policy",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2533,11 +2532,11 @@ Dht::onAnnounce(Sp<Node> n,
const auto& type = getType(vc->type);
if (type.storePolicy(hash, vc, node.id, node.getAddr())) {
// if (logger_)
// logger_->d(hash, node.id, "[store %s] Storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
// logger_->d(hash, node.id, "[store %s] storing %s", hash.toString().c_str(), std::to_string(vc->id).c_str());
storageStore(hash, vc, created, node.getAddr());
} else {
if (logger_)
logger_->d(hash, node.id, "[store %s] Rejecting storage of %s",
logger_->d(hash, node.id, "[store %s] rejecting storage of %s",
hash.toString().c_str(), vc->toString().c_str());
}
}
@@ -2552,15 +2551,15 @@ Dht::onRefresh(Sp<Node> node, const InfoHash& hash, const Blob& token, const Val
if (not tokenMatch(token, node->getAddr())) {
if (logger_)
logger_->w(hash, node->id, "[node %s] Incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
logger_->w(hash, node->id, "[node %s] incorrect token %s for 'put'", node->toString().c_str(), hash.toString().c_str());
throw DhtProtocolException {DhtProtocolException::UNAUTHORIZED, DhtProtocolException::PUT_WRONG_TOKEN};
}
if (storageRefresh(hash, vid)) {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] Refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
logger_->d(hash, node->id, "[store %s] [node %s] refreshed value %016" PRIx64, hash.toString().c_str(), node->toString().c_str(), vid);
} else {
if (logger_)
logger_->d(hash, node->id, "[store %s] [node %s] Got refresh for unknown value",
logger_->d(hash, node->id, "[store %s] [node %s] got refresh for unknown value",
hash.toString().c_str(), node->toString().c_str());
throw DhtProtocolException {DhtProtocolException::NOT_FOUND, DhtProtocolException::STORAGE_NOT_FOUND};
}
@@ -2583,7 +2582,7 @@ Dht::storageRefresh(const InfoHash& id, Value::Id vid)
for (const auto& node_listeners : st.listeners) {
for (const auto& l : node_listeners.second) {
if (logger_)
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] Sending refresh",
logger_->w(id, node_listeners.first->id, "[store %s] [node %s] sending refresh",
id.toString().c_str(),
node_listeners.first->toString().c_str());
Blob ntoken = makeToken(node_listeners.first->getAddr(), false);
@@ -2608,7 +2607,7 @@ void
Dht::onAnnounceDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>& sr)
{
if (logger_)
logger_->d(sr->id, node->id, "[search %s] [node %s] Got reply to put!",
logger_->d(sr->id, node->id, "[search %s] [node %s] got reply to put!",
sr->id.toString().c_str(), node->toString().c_str());
searchSendGetValues(sr);
sr->checkAnnounced(answer.vid);
+7 -40
View File
@@ -106,26 +106,13 @@ getRandomSessionId(size_t length = 8) {
DhtProxyClient::DhtProxyClient() {}
DhtProxyClient::DhtProxyClient(
std::shared_ptr<dht::crypto::Certificate> serverCA,
dht::crypto::Identity clientIdentity,
std::function<void()> signal,
const std::string& serverHost,
const std::string& userAgent,
const std::string& pushClientId,
const std::string& pushToken,
const std::string& pushTopic,
const std::string& pushPlatform,
std::shared_ptr<dht::Logger> logger
)
std::shared_ptr<dht::crypto::Certificate> serverCA, dht::crypto::Identity clientIdentity,
std::function<void()> signal, const std::string& serverHost,
const std::string& pushClientId, std::shared_ptr<dht::Logger> logger)
: DhtInterface(logger)
, proxyUrl_(serverHost)
, clientIdentity_(clientIdentity), serverCertificate_(serverCA)
, userAgent_(userAgent)
, pushClientId_(pushClientId)
, pushSessionId_(getRandomSessionId())
, deviceKey_(pushToken)
, notificationTopic_(pushTopic)
, platform_(pushPlatform)
, pushClientId_(pushClientId), pushSessionId_(getRandomSessionId())
, loopSignal_(signal)
, jsonReader_(Json::CharReaderBuilder{}.newCharReader())
{
@@ -497,7 +484,7 @@ DhtProxyClient::buildRequest(const std::string& target)
request->set_certificate_authority(serverCertificate_);
if (clientIdentity_.first and clientIdentity_.second)
request->set_identity(clientIdentity_);
request->set_header_field(restinio::http_field_t::user_agent, userAgent_);
request->set_header_field(restinio::http_field_t::user_agent, "RESTinio client");
return request;
}
@@ -813,8 +800,8 @@ SockAddr
DhtProxyClient::parsePublicAddress(const Json::Value& val)
{
auto public_ip = val.asString();
auto [host, service] = splitPort(public_ip);
auto sa = SockAddr::resolve(host);
auto hostAndService = splitPort(public_ip);
auto sa = SockAddr::resolve(hostAndService.first);
if (sa.empty()) return {};
return sa.front().getMappedIPv4();
}
@@ -1394,24 +1381,4 @@ DhtProxyClient::fillBody(bool resubscribe)
}
#endif // OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyClient::setPushNotificationToken([[maybe_unused]] const std::string& token) {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
std::unique_lock<std::mutex> l(lockCurrentProxyInfos_);
if (deviceKey_ != token) {
deviceKey_ = token;
if (statusIpv4_ == NodeStatus::Connected || statusIpv6_ == NodeStatus::Connected) {
if (logger_)
logger_->d("[proxy:client] [push] token changed, resubscribing");
for (auto& search : searches_) {
for (auto& listener : search.second.listeners) {
resubscribe(search.first, listener.first, listener.second);
}
}
}
}
#endif
}
} // namespace dht
+4 -34
View File
@@ -223,7 +223,6 @@ DhtProxyServer::DhtProxyServer(const std::shared_ptr<DhtRunner>& dht,
: ioContext_(std::make_shared<asio::io_context>()),
dht_(dht), persistPath_(config.persistStatePath), logger_(logger),
printStatsTimer_(std::make_unique<asio::steady_timer>(*ioContext_, 3s)),
serverStartTime_(clock::now()),
connListener_(std::make_shared<ConnectionListener>(std::bind(&DhtProxyServer::onConnectionClosed, this, std::placeholders::_1))),
pushServer_(config.pushServer),
bundleId_(config.bundleId)
@@ -543,15 +542,7 @@ DhtProxyServer::updateStats(std::shared_ptr<NodeInfo> info) const
stats.requestRate = count / dt.count();
#ifdef OPENDHT_PUSH_NOTIFICATIONS
stats.pushListenersCount = pushListeners_.size();
{
std::lock_guard lk(pushStatsMutex_);
stats.androidPush = androidPush_;
stats.iosPush = iosPush_;
stats.unifiedPush = unifiedPush_;
}
#endif
stats.serverStartTime = serverStartTime_;
stats.lastUpdated = now;
stats.totalPermanentPuts = 0;
std::for_each(puts_.begin(), puts_.end(), [&stats](const auto& put) {
stats.totalPermanentPuts += put.second.puts.size();
@@ -631,8 +622,6 @@ DhtProxyServer::createRestRouter()
router->http_get("/key/:hash", std::bind(&DhtProxyServer::get, this, _1, _2));
// key.post
router->http_post("/key/:hash", std::bind(&DhtProxyServer::put, this, _1, _2));
router->add_handler(restinio::http_method_options(),
"/key/:hash/listen", std::bind(&DhtProxyServer::options, this, _1, _2));
// key.listen
router->http_get("/key/:hash/listen", std::bind(&DhtProxyServer::listen, this, _1, _2));
#ifdef OPENDHT_PUSH_NOTIFICATIONS
@@ -1118,14 +1107,10 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
notification["tokens"] = std::move(tokens);
notification["platform"] = type == PushType::Android ? 2 : 1;
notification["data"] = std::move(json);
auto priority = highPriority ? "high" : "normal";
if (type == PushType::Android) {
Json::Value androidConfig(Json::objectValue);
androidConfig["priority"] = priority;
androidConfig["ttl"] = "86400s"; // time to live = 24 hours
notification["android"] = std::move(androidConfig);
} else {
notification["priority"] = priority;
notification["priority"] = highPriority ? "high" : "normal";
if (type == PushType::Android)
notification["time_to_live"] = 3600 * 24; // 24 hours
else {
const auto expiration = std::chrono::system_clock::now() + std::chrono::hours(24);
uint32_t exp = std::chrono::duration_cast<std::chrono::seconds>(expiration.time_since_epoch()).count();
notification["expiration"] = exp;
@@ -1166,21 +1151,6 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso
requests_[reqid] = request;
}
request->send();
// For monitoring purposes
std::lock_guard lk(pushStatsMutex_);
switch (type) {
case PushType::Android:
androidPush_.increment(highPriority);
break;
case PushType::iOS:
iosPush_.increment(highPriority);
break;
case PushType::UnifiedPush:
unifiedPush_.increment(highPriority);
break;
default:
break;
}
}
catch (const std::exception &e){
if (logger_)
+12 -24
View File
@@ -180,9 +180,9 @@ DhtRunner::run(const Config& config, Context&& context)
throw;
}
statusCbs.clear();
if (context.statusChangedCallback)
statusCbs.emplace_back(std::move(context.statusChangedCallback));
if (context.statusChangedCallback) {
statusCb = std::move(context.statusChangedCallback);
}
if (context.certificateStore) {
dht_->setLocalCertificateStore(std::move(context.certificateStore));
}
@@ -264,17 +264,6 @@ DhtRunner::run(const Config& config, Context&& context)
}
}
}
if (peerDiscovery_) {
statusCbs.emplace_back([this](NodeStatus status4, NodeStatus status6) {
if (status4 == NodeStatus::Disconnected && status6 == NodeStatus::Disconnected) {
peerDiscovery_->connectivityChanged();
}
else if (status4 != NodeStatus::Connected || status6 != NodeStatus::Connected) {
peerDiscovery_->stopConnectivityChanged();
}
});
}
#endif
}
}
@@ -701,9 +690,8 @@ DhtRunner::loop_()
if (nstatus4 != status4 || nstatus6 != status6) {
status4 = nstatus4;
status6 = nstatus6;
for (auto& cb : statusCbs){
cb(status4, status6);
}
if (statusCb)
statusCb(status4, status6);
}
return wakeup;
@@ -1120,13 +1108,13 @@ DhtRunner::enableProxy(bool proxify)
cv.notify_all();
}
},
config_.proxy_server,
config_.proxy_user_agent,
config_.push_node_id,
config_.push_token,
config_.push_topic,
config_.push_platform,
logger_);
config_.proxy_server, config_.push_node_id, logger_);
if (not config_.push_token.empty())
dht_via_proxy->setPushNotificationToken(config_.push_token);
if (not config_.push_topic.empty())
dht_via_proxy->setPushNotificationTopic(config_.push_topic);
if (not config_.push_platform.empty())
dht_via_proxy->setPushNotificationPlatform(config_.push_platform);
dht_ = std::make_unique<SecureDht>(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_);
// and use it
use_proxy = proxify;
+6 -5
View File
@@ -54,7 +54,7 @@ constexpr const char HTTPS_PROTOCOL[] = "https://";
constexpr const char ORIGIN_PROTOCOL[] = "//";
constexpr unsigned MAX_REDIRECTS {5};
Url::Url(std::string_view url): url(url)
Url::Url(const std::string& url): url(url)
{
size_t addr_begin = 0;
// protocol
@@ -69,9 +69,10 @@ Url::Url(std::string_view url): url(url)
size_t addr_size = url.substr(addr_begin).find("/");
if (addr_size == std::string::npos)
addr_size = url.size() - addr_begin;
auto [h, s] = splitPort(url.substr(addr_begin, addr_size));
host = std::move(h);
service = std::move(s);
auto host_service = splitPort(url.substr(addr_begin, addr_size));
host = host_service.first;
if (!host_service.second.empty())
service = host_service.second;
// target, query and fragment
size_t query_begin = url.find("?");
auto addr_end = addr_begin + addr_size;
@@ -460,7 +461,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
bool verified = verifier(preverified, ctx);
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
logger->error("[http::connection:{:d}] ssl verification error={:d} {}", id, verify_ec, verified);
logger->error("[http::connection:{:d}] ssl verification error={:d} %d", id, verify_ec, verified);
if (verified and checkOcsp) {
std::unique_ptr<stack_st_X509, void(*)(stack_st_X509*)> chain(
X509_STORE_CTX_get1_chain(ctx.native_handle()),
+23 -82
View File
@@ -143,7 +143,7 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -166,9 +166,6 @@ NetworkEngine::tellListenerRefreshed(const Sp<Node>& n, Tid socket_id, const Inf
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -197,7 +194,7 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (version >= 1 ? 1 : 0) + (config.network?1:0));
pk.pack(version >= 1 ? KEY_A : KEY_U);
pk.pack_map(1 + (version >= 1 ? 1 : 0) + (not values.empty()?1:0) + (not token.empty()?1:0));
@@ -220,9 +217,6 @@ NetworkEngine::tellListenerExpired(const Sp<Node>& n, Tid socket_id, const InfoH
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
if (version >= 1) {
Tid tid (n->getNewTid());
@@ -526,13 +520,8 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
throw DhtProtocolException {DhtProtocolException::UNKNOWN_TID, "Can't find socket", msg->id};
node->received(now, {});
onNewNode(node, 2);
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
}
else if (msg->type == MessageType::Error or msg->type == MessageType::Reply) {
auto rsocket = node->getSocket(msg->tid);
@@ -595,22 +584,13 @@ NetworkEngine::process(std::unique_ptr<ParsedMessage>&& msg, const SockAddr& fro
r.node->authSuccess();
}
r.reply_time = scheduler.time();
try {
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
deserializeNodes(*msg, from);
r.setDone(std::move(*msg));
break;
} else { /* request socket data */
try {
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
} catch (const DhtProtocolException& e) {
if (logger_)
logger_->w("Can't deserialize nodes %s", e.what());
}
deserializeNodes(*msg, from);
rsocket->on_receive(node, std::move(*msg));
}
break;
default:
@@ -724,7 +704,7 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
Tid tid (node->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -736,9 +716,6 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid, node,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -764,7 +741,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)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -776,9 +753,6 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -789,7 +763,7 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -808,9 +782,6 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -837,7 +808,7 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
unsigned sendQuery = (not query.where.empty() or not query.select.empty()) ? 1 : 0;
unsigned sendWant = (want > 0) ? 1 : 0;
@@ -864,10 +835,7 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
[=](const Request& req_status, ParsedMessage&& msg) { /* on done */
@@ -984,13 +952,10 @@ NetworkEngine::sendValueParts(Tid tid, const std::vector<Blob>& svals, const Soc
end = std::min(start + MTU, v.size());
buffer.clear();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(3+(config.network?1:0));
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack(tid);
pk.pack(KEY_V); pk.pack_map(1);
@@ -1011,7 +976,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)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R);
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -1053,9 +1018,6 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
// send response
send(addr, buffer.data(), buffer.size());
@@ -1127,7 +1089,7 @@ NetworkEngine::sendListen(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
auto has_query = not query.where.empty() or not query.select.empty();
pk.pack(KEY_A); pk.pack_map(5 + has_query);
@@ -1147,9 +1109,6 @@ NetworkEngine::sendListen(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1171,7 +1130,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)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1183,9 +1142,6 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1202,7 +1158,7 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
bool add_created = created < scheduler.time();
pk.pack(KEY_A); pk.pack_map(add_created ? 5 : 4);
@@ -1222,9 +1178,6 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1291,7 +1244,7 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 7 : 6));
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1312,9 +1265,6 @@ NetworkEngine::sendUpdateValues(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::UpdateValue, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1339,7 +1289,7 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
Tid tid (n->getNewTid());
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(config.network?1:0)+(config.is_client?1:0));
pk.pack_map(5+(config.network?1:0));
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1354,9 +1304,6 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid, n,
Blob(buffer.data(), buffer.data() + buffer.size()),
@@ -1388,7 +1335,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)+(config.is_client?1:0));
pk.pack_map(4+(config.network?1:0));
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
@@ -1401,9 +1348,6 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
@@ -1417,7 +1361,7 @@ NetworkEngine::sendError(const SockAddr& addr,
{
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0)+(config.is_client?1:0));
pk.pack_map(4 + (include_id?1:0) + (config.network?1:0));
pk.pack(KEY_E); pk.pack_array(2);
pk.pack(code);
@@ -1434,9 +1378,6 @@ NetworkEngine::sendError(const SockAddr& addr,
if (config.network) {
pk.pack(KEY_NETID); pk.pack(config.network);
}
if (config.is_client) {
pk.pack(KEY_ISCLIENT); pk.pack(config.is_client);
}
send(addr, buffer.data(), buffer.size());
}
+3 -61
View File
@@ -22,10 +22,6 @@
#include "network_utils.h"
#include "utils.h"
#ifdef __ANDROID__
#include "compat/getif_workaround_android.h"
#endif
#include <asio.hpp>
using namespace std::literals;
@@ -52,7 +48,6 @@ public:
void connectivityChanged();
void stopConnectivityChanged();
private:
Sp<Logger> logger_;
//dmtx_ for callbackmap_ and drunning_ (write)
@@ -60,14 +55,6 @@ private:
//mtx_ for messages_ and lrunning (listen)
std::mutex mtx_;
std::shared_ptr<asio::io_context> ioContext_;
static constexpr dht::duration PeerDiscovery_PERIOD_MAX{
std::chrono::minutes(1)};
static constexpr std::chrono::seconds PeerDiscovery_PERIOD{10};
asio::steady_timer peerDiscoveryTimer;
std::chrono::steady_clock::duration peerDiscovery_period{
PeerDiscovery_PERIOD};
asio::ip::udp::socket sockFd_;
asio::ip::udp::endpoint sockAddrSend_;
@@ -95,7 +82,6 @@ private:
PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
: logger_(logger)
, ioContext_(ioContext)
, peerDiscoveryTimer(*ioContext_)
, sockFd_(*ioContext_, domain)
, sockAddrSend_(asio::ip::address::from_string(domain.family() == AF_INET ? MULTICAST_ADDRESS_IPV4
: MULTICAST_ADDRESS_IPV6), port)
@@ -105,23 +91,8 @@ PeerDiscovery::DomainPeerDiscovery::DomainPeerDiscovery(asio::ip::udp domain, in
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
sockFd_.bind({domain, port});
} catch (const std::exception& e) {
#ifdef __ANDROID__
if(domain.family() == AF_INET && strcmp(e.what(), "set_option: No such device") == 0) {
try{
sockFd_.set_option(asio::ip::udp::socket::reuse_address(true));
auto mc_interface = workaround::get_interface();
sockFd_.set_option(asio::ip::multicast::outbound_interface(mc_interface));
sockFd_.set_option(asio::ip::multicast::join_group(sockAddrSend_.address().to_v4(), mc_interface));
sockFd_.bind({domain, port});
} catch(const std::exception& e){
if (logger_)
logger_->error("Can't start peer discovery using android workaround: {}", e.what());
}
}
else
#endif
if (logger_)
logger_->error("Can't start peer discovery for {}: {}",
logger_->e("Can't start peer discovery for %s: %s",
domain.family() == AF_INET ? "IPv4" : "IPv6", e.what());
}
}
@@ -327,30 +298,8 @@ PeerDiscovery::DomainPeerDiscovery::reDiscover()
void
PeerDiscovery::DomainPeerDiscovery::connectivityChanged()
{
ioContext_->post([this] () {
reDiscover();
publish(sockAddrSend_);
});
if (logger_)
logger_->d("PeerDiscovery: connectivity changed");
if (peerDiscovery_period == PeerDiscovery_PERIOD_MAX ){
peerDiscovery_period = PeerDiscovery_PERIOD;
}
else{
peerDiscoveryTimer.expires_after(peerDiscovery_period);
peerDiscoveryTimer.async_wait([this](const asio::error_code& ec) {
if (ec == asio::error::operation_aborted)
return;
connectivityChanged();
});
peerDiscovery_period = std::min(peerDiscovery_period * 2, PeerDiscovery_PERIOD_MAX);
}
}
void PeerDiscovery::DomainPeerDiscovery::stopConnectivityChanged() {
peerDiscoveryTimer.cancel();
peerDiscovery_period = PeerDiscovery_PERIOD;
reDiscover();
publish(sockAddrSend_);
}
PeerDiscovery::PeerDiscovery(in_port_t port, Sp<asio::io_context> ioContext, Sp<Logger> logger)
@@ -463,11 +412,4 @@ PeerDiscovery::connectivityChanged()
peerDiscovery6_->connectivityChanged();
}
void PeerDiscovery::stopConnectivityChanged() {
if (peerDiscovery4_)
peerDiscovery4_->stopConnectivityChanged();
if (peerDiscovery6_)
peerDiscovery6_->stopConnectivityChanged();
}
} /* namespace dht */
+19 -26
View File
@@ -45,7 +45,7 @@ struct Dht::Announce {
bool permanent;
Sp<Value> value;
time_point created;
std::vector<DoneCallback> callbacks;
DoneCallback callback;
};
struct Dht::SearchNode {
@@ -442,9 +442,8 @@ struct Dht::Search {
g.second.done_cb = {};
}
for (auto& a : announce) {
for (auto& cb : a.callbacks)
cb(false, {});
a.callbacks.clear();
a.callback(false, {});
a.callback = {};
}
}
@@ -628,9 +627,7 @@ struct Dht::Search {
return a.value->id == value->id;
});
if (a_sr == announce.end()) {
auto& a = announce.emplace_back(Announce {permanent, value, created, {}} );
if (callback)
a.callbacks.emplace_back(std::move(callback));
announce.emplace_back(Announce {permanent, value, created, callback});
for (auto& n : nodes) {
n->probe_query.reset();
n->acked[value->id].req.reset();
@@ -638,26 +635,24 @@ struct Dht::Search {
} else {
a_sr->permanent = permanent;
a_sr->created = created;
if (a_sr->value != value && *a_sr->value != *value) {
// Value is updated, previous ops are failed
if (a_sr->value != value) {
a_sr->value = value;
for (auto& n : nodes) {
n->acked[value->id].req.reset();
n->probe_query.reset();
}
for (auto& cb: a_sr->callbacks)
cb(false, {});
a_sr->callbacks.clear();
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
} else if (isAnnounced(value->id)) {
// Same value, already announced
}
if (isAnnounced(value->id)) {
if (a_sr->callback)
a_sr->callback(true, {});
a_sr->callback = {};
if (callback)
callback(true, {});
return;
} else {
// Same value, not announced yet
if (callback)
a_sr->callbacks.emplace_back(std::move(callback));
if (a_sr->callback)
a_sr->callback(false, {});
a_sr->callback = callback;
}
}
}
@@ -727,8 +722,8 @@ struct Dht::Search {
std::vector<DoneCallback> a_cbs;
a_cbs.reserve(announce.size());
for (auto ait = announce.begin() ; ait != announce.end(); ) {
a_cbs.insert(a_cbs.end(), std::make_move_iterator(ait->callbacks.begin()), std::make_move_iterator(ait->callbacks.end()));
ait->callbacks.clear();
if (ait->callback)
a_cbs.emplace_back(std::move(ait->callback));
if (not ait->permanent)
ait = announce.erase(ait);
else
@@ -752,11 +747,9 @@ struct Dht::Search {
if (vid != Value::INVALID_ID and (!a.value || a.value->id != vid))
return true;
if (isAnnounced(a.value->id)) {
if (!a.callbacks.empty()) {
const auto& nodes = getNodes();
for (auto& cb : a.callbacks)
cb(true, nodes);
a.callbacks.clear();
if (a.callback) {
a.callback(true, getNodes());
a.callback = nullptr;
}
if (not a.permanent)
return false;
+9 -9
View File
@@ -44,23 +44,23 @@ const HexMap hex_map = {};
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
std::pair<std::string, std::string>
splitPort(std::string_view s) {
splitPort(const std::string& s) {
if (s.empty())
return {};
if (s[0] == '[') {
std::size_t closure = s.find_first_of(']');
std::size_t found = s.find_last_of(':');
if (closure == std::string_view::npos)
return {std::string(s), ""};
if (found == std::string_view::npos or found < closure)
return {std::string(s.substr(1,closure-1)), ""};
return {std::string(s.substr(1,closure-1)), std::string(s.substr(found+1))};
if (closure == std::string::npos)
return {s, ""};
if (found == std::string::npos or found < closure)
return {s.substr(1,closure-1), ""};
return {s.substr(1,closure-1), s.substr(found+1)};
}
std::size_t found = s.find_last_of(':');
std::size_t first = s.find_first_of(':');
if (found == std::string_view::npos or found != first)
return {std::string(s), ""};
return {std::string(s.substr(0,found)), std::string(s.substr(found+1))};
if (found == std::string::npos or found != first)
return {s, ""};
return {s.substr(0,found), s.substr(found+1)};
}
std::vector<SockAddr>
-1
View File
@@ -271,7 +271,6 @@ Value::encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to)
setRecipient(to.getId());
sign(from);
Value nv {id};
nv.priority = priority;
nv.setCypher(to.encrypt(getToEncrypt()));
return nv;
}
-21
View File
@@ -239,27 +239,6 @@ void CryptoTester::testAesEncryption() {
CPPUNIT_ASSERT(data2 == decrypted2);
}
void CryptoTester::testAesEncryptionWithMultipleKeySizes() {
auto data = std::vector<uint8_t>(rand(), rand());
// Valid key sizes
for (auto key_length : {16, 24, 32}) {
auto key = std::vector<uint8_t>(key_length, rand());
auto encrypted_data = dht::crypto::aesEncrypt(data, key);
auto decrypted_data = dht::crypto::aesDecrypt(encrypted_data, key);
CPPUNIT_ASSERT(data == decrypted_data);
}
// Invalid key sizes
for (auto key_length : {12, 28, 36}) {
auto key = std::vector<uint8_t>(key_length, rand());
CPPUNIT_ASSERT_THROW(dht::crypto::aesEncrypt(data, key), dht::crypto::DecryptError);
}
}
void
CryptoTester::tearDown() {
-2
View File
@@ -34,7 +34,6 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testCertificateSerialNumber);
CPPUNIT_TEST(testOcsp);
CPPUNIT_TEST(testAesEncryption);
CPPUNIT_TEST(testAesEncryptionWithMultipleKeySizes);
CPPUNIT_TEST_SUITE_END();
public:
@@ -70,7 +69,6 @@ class CryptoTester : public CppUnit::TestFixture {
* Test key streching and aes encryption/decryption
*/
void testAesEncryption();
void testAesEncryptionWithMultipleKeySizes();
};
} // namespace test
+1 -54
View File
@@ -90,59 +90,6 @@ DhtRunnerTester::testGetPut() {
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutDuplicate() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("hey");
val->id = 42;
auto val_data = val->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testPutOverride() {
auto key = dht::InfoHash::get("123");
auto val = std::make_shared<dht::Value>("meh");
val->id = 42;
auto val2 = std::make_shared<dht::Value>("hey");
val2->id = 42;
CPPUNIT_ASSERT_EQUAL(val->id, val2->id);
auto val_data = val2->data;
std::promise<bool> p1;
std::promise<bool> p2;
node2.put(key, val, [&](bool ok){
p1.set_value(ok);
});
node2.put(key, val2, [&](bool ok){
p2.set_value(ok);
});
auto p1ret = p1.get_future().get();
auto p2ret = p2.get_future().get();
CPPUNIT_ASSERT(!p1ret);
CPPUNIT_ASSERT(p2ret);
auto vals = node1.get(key).get();
CPPUNIT_ASSERT(not vals.empty());
CPPUNIT_ASSERT(vals.size() == 1);
CPPUNIT_ASSERT(vals.front()->data == val_data);
}
void
DhtRunnerTester::testListen() {
std::mutex mutex;
@@ -342,7 +289,7 @@ DhtRunnerTester::testIdOps() {
valueCountEdit++;
cv.notify_all();
});
node2.listen(key2, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool /*expired*/){
node2.listen(key2, [&](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired){
for (const auto& v : values) {
if (v->seq == 0)
CPPUNIT_ASSERT_EQUAL("v1"s, dht::unpackMsg<std::string>(v->data));
-10
View File
@@ -31,8 +31,6 @@ class DhtRunnerTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DhtRunnerTester);
CPPUNIT_TEST(testConstructors);
CPPUNIT_TEST(testGetPut);
CPPUNIT_TEST(testPutDuplicate);
CPPUNIT_TEST(testPutOverride);
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testListenLotOfBytes);
CPPUNIT_TEST(testIdOps);
@@ -57,14 +55,6 @@ class DhtRunnerTester : public CppUnit::TestFixture {
* Test get and put methods
*/
void testGetPut();
/**
* Test get and multiple put
*/
void testPutDuplicate();
/**
* Test get and multiple put with changing value
*/
void testPutOverride();
/**
* Test listen method
*/
+2 -2
View File
@@ -107,8 +107,8 @@ main(int argc, char **argv)
token = dht.listen<dht::ImMessage>(room, [&](dht::ImMessage&& msg) {
if (msg.from != myid)
std::cout << msg.from.toString() << " at " << printTime(msg.date)
<< " (took " << print_duration(std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t(msg.date))
<< ") " << (msg.to == myid ? "ENCRYPTED ":"") << ": " << msg.id << " - " << msg.msg << std::endl;
<< " (took " << print_dt(std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t(msg.date))
<< "s) " << (msg.to == myid ? "ENCRYPTED ":"") << ": " << msg.id << " - " << msg.msg << std::endl;
return true;
});
connected = true;
+5 -14
View File
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <inttypes.h>
#include <getopt.h>
#include <readline/readline.h>
@@ -39,10 +38,6 @@ struct listen_context {
dht_op_token* token;
size_t count;
};
struct put_context {
dht_runner* runner;
dht_value* value;
};
bool dht_value_callback(const dht_value* value, bool expired, void* user_data)
{
@@ -72,10 +67,8 @@ void dht_get_done_callback(bool ok, void* user_data)
void dht_put_done_callback(bool ok, void* user_data)
{
struct put_context* ctx = (struct put_context*)user_data;
printf("Put completed (id: %" PRIx64 "): %s\n", dht_value_get_id(ctx->value), ok ? "success !" : "failure :-(");
dht_value_unref(ctx->value);
free(ctx);
dht_runner* runner = (dht_runner*)user_data;
printf("Put completed: %s\n", ok ? "success !" : "failure :-(");
}
void dht_shutdown_callback(void* user_data)
@@ -268,13 +261,11 @@ int main(int argc, char **argv)
else if (!strcmp(cmd, "p")) {
key = parse_key(arg);
dht_value* val = dht_value_new_from_string(value);
struct put_context* ctx = malloc(sizeof(struct put_context));
ctx->runner = runner;
ctx->value = val;
dht_runner_put(runner, &key, val, dht_put_done_callback, ctx, true);
dht_runner_put(runner, &key, val, dht_put_done_callback, runner, true);
dht_value_unref(val);
}
else {
printf("Unknown command: %s\n", cmd);
printf("Unkown command: %s\n", cmd);
}
}
+168 -236
View File
@@ -1,78 +1,190 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>OpenDHT web node</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap.min.css" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>OpenDHT tester</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">"use strict";
let onGet;
let onPut;
let setServer;
const valueGetElement = function(o) {
const d = window.atob(o.data);
return d;
};
$(function() {
let request = undefined;
let server;
const getTools = $("#getTools");
const getBtn = $("#getBtn");
const getDropdown = $("#getDropdown");
const listenBtn = $("#listenBtn").click(function(){onGet('LISTEN');});
const setGetRequest = function() {
getBtn.button('loading');
getStopBtn.appendTo(getTools);
getDropdown.hide();
}
const clearGetRequest = function() {
if (request === undefined)
return;
request.abort();
request = undefined;
getStopBtn.detach();
getDropdown.show();
getBtn.button('reset');
}
const getStopBtn = $("#getStopBtn").detach().click(clearGetRequest);
const putBtn = $("#putBtn");
const result = $("#dhtResult");
const group = $('<ul class="list-group"/>').appendTo(result);
onGet = function (method) {
if (request !== undefined)
return false;
const input = $("#getKey").val();
group.empty();
let lastAppended = 0;
let start = new Date().getTime();
request = new XMLHttpRequest();
request.onreadystatechange = function(event) {
if (this.readyState >= XMLHttpRequest.LOADING) {
if (this.readyState == XMLHttpRequest.DONE) {
clearGetRequest();
}
if (this.status === 200) {
const elements = this.responseText.split("\n");
const elementsLength = elements.length;
const now = new Date().getTime();
for (let i = lastAppended; i < elementsLength; i++) {
const element = elements[i];
if (!element || element.length == 0)
return;
const o = JSON.parse(element);
if (o.expired) {
$('#value'+o.id).slideUp(100, (e) => $(e.target).remove());
} else {
const d = window.atob(o.data);
const delay = Math.max(0, start-now);
$('<li class="list-group-item" id="value'+o.id+'"/>').append(valueGetElement(o)).appendTo(group).hide().delay(delay).slideDown(100);
lastAppended = i+1;
start = Math.max(start, now)+25;
}
}
} else if (this.status !== 0) {
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text("Error loading content: " + this.statusText));
}
}
};
request.onerror = function(event) {
clearGetRequest();
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text("Error loading content."));
};
request.open(method, server + input, true);
request.send(null);
setGetRequest();
return false;
};
onPut = function( ) {
const key = $("#getKey").val();
const value = $("#putValue").val();
$.ajax({
url: server + key,
type: 'POST',
data: JSON.stringify({
data:window.btoa(value)
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function( result ) {
putBtn.button('reset');
//$('<li class="list-group-item list-group-item-success"/>').append(valueGetElement(result)).appendTo(group.empty());
},
error: function(result) {
putBtn.button('reset');
group.empty().append($('<li class="list-group-item list-group-item-danger"/>').text(result.statusText));
}
});
putBtn.button('loading');
return false;
};
const serverValue = $("#serverValue");
const serverStatus = $("#serverStatus");
const serverBtn = $("#serverBtn");
setServer = function(event) {
server = serverValue.val() + '/';
serverStatus.empty();
serverBtn.button('loading');
$.getJSON(server, function(data){
$('<span><b>Node</b> '+data.node_id+'</span>').appendTo(serverStatus).hide().fadeIn();
}).fail(function(error) {
var message = " Cant' access node."
if (serverValue.val().indexOf("https") != -1){
message += "</br></br>Self-signed certificate must be allowed in browser."
}
serverStatus.html("<div class='alert alert-danger' style='margin-bottom: 0px;'>" +
"<span class='glyphicon glyphicon-remove' aria-hidden='true'></span>" +
message + "</div>");
}).always(function(error) {
serverBtn.button('reset');
});
return false;
};
setServer();
});
</script>
</head>
<body>
<div class="container" style="max-width: 880px;">
<header class="m-3 p-3">
<div class="container" style="max-width: 730px;">
<header class="page-header">
<div class="row">
<div class="col-sm-5 d-flex align-items-center">
<h2>OpenDHT web node</h2>
<div class="col-sm-5">
<h1>OpenDHT tester</h1>
</div>
<div class="col-sm-7">
<div class="card card-body bg-light" style="margin-top:10px; margin-bottom:0px;">
<form id="serverForm" class="form-inline" onsubmit="return setServer();"
style="margin-bottom:4px;">
<div class="well well-sm" style="margin-top:10px; margin-bottom:0px;">
<form id="serverForm" class="form-inline" onsubmit="return setServer();" style="margin-bottom:4px;">
<div class="input-group">
<input type="text" class="form-control" id="serverValue" placeholder="Proxy server" value="http://127.0.0.1:8080" />
<button id="serverBtn" type="submit" class="btn btn-outline-secondary">
<div class='spinner-border spinner-border-sm' role='status'
style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-icon"><i class="bi bi-arrow-clockwise"></i></span>
</button>
<input type="text" class="form-control" id="serverValue" placeholder="Proxy server" value="http://127.0.0.1:8080"/>
<span class="input-group-btn">
<button id="serverBtn" type="submit" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i>"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
</span>
</div>
</form>
<div id="serverStatus">
<div class='spinner-border spinner-border-sm' role='status'><span
class='visually-hidden'>Loading...</span></div>
</div>
<div id="serverStatus"><i class='fa fa-circle-o-notch fa-spin'></i></div>
</div>
</div>
</div>
</header>
<div class="list-group" id="dhtResult">
<div class="list-group-item list-group-item-light">
<div class="row">
<div class="col-sm-6">
<form class="form-inline" onsubmit="return onGet('');">
<div class="input-group" id="getTools">
<div class="panel panel-default" id="dhtResult">
<div class="panel-heading">
<div class="row">
<div class="col-xs-6">
<form class="form-inline" onsubmit="return onGet('GET');">
<div class="input-group">
<input type="text" class="form-control" id="getKey" placeholder="Key" aria-label="Key" />
<button id="getBtn" class="btn btn-outline-secondary" type="submit">
<div class='spinner-border spinner-border-sm' role='status' style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-text">Get</span>
</button>
<button id="menuBtn" type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" id="listenBtn" href="#">Listen</a></li>
</ul>
<button id="getStopBtn" class="btn btn-outline-secondary">Stop</button>
<span class="input-group-btn" id="getTools">
<button id="getBtn" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i>" type="submit">Get</button>
<button id="getDropdown"type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button>
<ul class="dropdown-menu">
<li><a id="listenBtn" href="#">Listen</a></li>
</ul>
<button id="getStopBtn" class="btn btn-default" type="submit"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
</span>
</div>
</form>
</div>
<div class="col-sm-6">
<div class="col-xs-6">
<form class="form-inline" onsubmit="return onPut();">
<div class="input-group">
<input type="text" class="form-control input-group-input" id="putValue"
placeholder="Value" />
<button id="putBtn" type="submit" class="btn btn-outline-secondary">
<div class='spinner-border spinner-border-sm' role='status' style="display: none;">
<span class='visually-hidden'>Loading...</span>
</div>
<span class="btn-text">Put</span>
</button>
<input type="text" class="form-control input-group-input" id="putValue" placeholder="Value" />
<span class="input-group-btn">
<button id="putBtn" type="submit" class="btn btn-default" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i> Loading">Put</button>
</span>
</div>
</form>
</div>
@@ -80,185 +192,5 @@
</div>
</div>
</div>
<script type="text/javascript">"use strict";
const valueGetElement = (o) => window.atob(o.data);
const getTools = document.getElementById("getTools");
const getBtn = document.getElementById("getBtn");
const menuBtn = document.getElementById("menuBtn");
const getStopBtn = document.getElementById("getStopBtn");
const listenBtn = document.getElementById("listenBtn");
const putBtn = document.getElementById("putBtn");
const group = document.getElementById("dhtResult");
const serverValue = document.getElementById("serverValue");
const serverStatus = document.getElementById("serverStatus");
const serverBtn = document.getElementById("serverBtn");
var request = undefined;
const setGetRequest = () => {
getBtn.disabled = true;
getBtn.querySelector('.spinner-border').style.display = 'inline-block';
getBtn.querySelector('.btn-text').style.display = 'none';
menuBtn.style.display = 'none';
getTools.appendChild(getStopBtn);
};
const clearGetRequest = () => {
if (request === undefined)
return;
request.abort();
request = undefined;
if (getStopBtn.parentNode) {
getStopBtn.parentNode.removeChild(getStopBtn);
}
menuBtn.style.display = '';
getBtn.disabled = false;
getBtn.querySelector('.spinner-border').style.display = 'none';
getBtn.querySelector('.btn-text').style.display = 'inline';
};
const clearResults = () => {
while (group.children.length > 1) {
group.removeChild(group.lastChild);
}
};
var server;
const setServer = (event) => {
server = serverValue.value + '/';
serverStatus.innerHTML = '';
serverBtn.disabled = true;
serverBtn.querySelector('.spinner-border').style.display = 'inline-block';
serverBtn.querySelector('.btn-icon').style.display = 'none';
var xhr = new XMLHttpRequest();
xhr.open('GET', server, true);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
serverBtn.disabled = false;
serverBtn.querySelector('.spinner-border').style.display = 'none';
serverBtn.querySelector('.btn-icon').style.display = 'inline';
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
const span = document.createElement('span');
span.innerHTML = '<b>Node</b> ' + data.node_id;
serverStatus.appendChild(span);
} else {
const message = " Can't access node.";
if (serverValue.value.indexOf("https") != -1) {
message += "</br></br>Self-signed certificate must be allowed in browser.";
}
serverStatus.innerHTML = "<div class='alert alert-danger' style='margin-bottom: 0px;'>" +
"<span class='glyphicon glyphicon-remove' aria-hidden='true'></span>" +
message + "</div>";
}
}
};
xhr.send();
return false;
};
setServer();
const onGet = (path) => {
if (request !== undefined)
return false;
const input = document.getElementById("getKey").value;
clearResults()
let lastAppended = 0;
let start = new Date().getTime();
request = new XMLHttpRequest();
request.onreadystatechange = (event) => {
if (request.readyState >= 2) { // LOADING
if (request.status === 200) {
const elements = request.responseText.split("\n");
const elementsLength = elements.length;
const now = new Date().getTime();
for (let i = lastAppended; i < elementsLength; i++) {
const element = elements[i];
if (!element || element.length == 0)
break;
const o = JSON.parse(element);
if (o.expired) {
const expiredElement = document.getElementById('value' + o.id);
if (expiredElement) {
expiredElement.style.display = 'none';
if (expiredElement.parentNode) {
expiredElement.parentNode.removeChild(expiredElement);
}
}
} else {
const d = window.atob(o.data);
const delay = Math.max(0, start - now);
const li = document.createElement('li');
li.className = 'list-group-item';
li.id = 'value' + o.id;
li.innerHTML = valueGetElement(o);
li.style.opacity = 0;
li.style.transition = 'opacity 0.1s ease-in';
group.appendChild(li);
setTimeout(() => {
li.style.opacity = 1;
}, delay);
lastAppended = i + 1;
start = Math.max(start, now) + 25;
}
}
} else if (request.status !== 0) {
clearResults()
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = "Error loading content: " + request.statusText;
group.appendChild(li);
}
}
if (request.readyState == 4) { // DONE
clearGetRequest();
}
};
request.onerror = (event) => {
clearGetRequest();
clearResults()
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = "Error loading content.";
group.appendChild(li);
};
request.open('GET', server + 'key/' + input + path, true);
request.send(null);
setGetRequest();
return false;
};
const onPut = () => {
const key = document.getElementById("getKey").value;
const value = document.getElementById("putValue").value;
putBtn.disabled = true;
putBtn.querySelector('.spinner-border').style.display = 'inline-block';
putBtn.querySelector('.btn-text').style.display = 'none';
fetch(server + key, {
method: 'POST',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: JSON.stringify({ data: window.btoa(value) })
})
.then(response => {
if (!response.ok)
throw new Error(response.statusText);
})
.catch(error => {
group.innerHTML = '';
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-danger';
li.textContent = error.message;
group.appendChild(li);
})
.finally(() => {
putBtn.disabled = false;
putBtn.querySelector('.spinner-border').style.display = 'none';
putBtn.querySelector('.btn-text').style.display = 'inline';
});
return false;
};
listenBtn.addEventListener('click', () => { onGet('/listen'); });
getStopBtn.parentNode.removeChild(getStopBtn);
getStopBtn.addEventListener('click', clearGetRequest);
</script>
</body>
</html>
</html>