Compare commits

...
Author SHA1 Message Date
Adrien Béraud d80aab9399 pingpong: cleanup 2019-03-29 13:13:29 -04:00
Adrien Béraud 9b881d4e95 crypto: add initial certificate request support 2019-03-29 13:13:29 -04:00
Adrien Béraud b4c3c2cba0 update to version 1.8.2 2019-03-18 13:47:41 -04:00
Sébastien Blin 4519a23996 Merge pull request #386 from savoirfairelinux/parse_perf
Network: improve parsing performance
2019-03-18 13:13:57 -04:00
Adrien Béraud 1ac4e08f45 build: add clang-tidy configuration 2019-03-17 19:23:26 -04:00
Adrien Béraud 5e92777702 fix clang-tidy warnings 2019-03-17 19:22:28 -04:00
Adrien Béraud 4401e47002 cleanup, fix clang-tidy warnings 2019-03-17 17:43:52 -04:00
Adrien Béraud 215b44ca3b search: don't store filter in search
Filter is not supported anymore at the search listen stage.
Filters are now stored and called by the op cache.
2019-03-17 17:30:30 -04:00
Adrien Béraud 379fdae212 cmake: don't explicitly disable stack protector 2019-03-17 16:07:20 -04:00
Adrien Béraud 1e10e28fd7 network: improve message parsing performance 2019-03-17 16:07:20 -04:00
Adrien Béraud dccdb84836 tests: add Value tester 2019-03-16 14:27:46 -04:00
Adrien Béraud 71599da8ea value: add "not" method 2019-03-16 14:27:23 -04:00
Adrien Béraud f418b3651f update copyright date 2019-03-16 12:37:23 -04:00
Adrien Béraud 313f54c840 dht: disable some verbose logs 2019-03-10 17:27:37 -04:00
Adrien Béraud cdb721ade4 dht: move store logic to storage 2019-03-10 17:04:26 -04:00
Adrien Béraud 57ea09808e value: fix chain null check 2019-03-10 16:39:31 -04:00
Adrien Béraud fec5a6ede7 make move operators noexcept 2019-03-10 16:39:16 -04:00
Adrien Béraud 5f8e9d9480 storage: make non-movable 2019-03-10 16:39:16 -04:00
Adrien Béraud 311a8981fc thread pool: add computation, io pools 2019-03-10 16:39:16 -04:00
Adrien Béraud 04850e1701 dht: add configuration to persist state 2019-03-10 16:39:16 -04:00
Adrien Béraud a30f1b8032 dht: make exportNodes const 2019-03-10 16:39:16 -04:00
Sébastien Blin 41f8b06743 Merge pull request #376 from savoirfairelinux/server_thread_pool
Server thread pool
2019-02-19 19:57:13 -05:00
Adrien Béraud 1c74c2207f proxy server: cache json StreamBuilder 2019-02-19 18:43:14 -05:00
Adrien Béraud 9319bec7b8 proxy client: close previous request on resubscribe 2019-02-19 18:43:14 -05:00
Adrien Béraud e5f2a6eef5 proxy: send expired to sync values 2019-02-19 18:43:14 -05:00
Adrien Béraud 55f6c847b8 build: use define flags for proxy 2019-02-19 18:43:14 -05:00
Adrien Béraud 00cc4ebe28 proxy server: send push notification on thread pool 2019-02-19 18:43:14 -05:00
Adrien Béraud aa93db4fa6 proxy server: move json to sendPushNotification 2019-02-19 18:43:14 -05:00
Adrien Béraud 683570a3da add ThreadPool 2019-02-19 18:43:14 -05:00
Sébastien Blin 43559577f6 Merge pull request #377 from savoirfairelinux/proxy_sync_expired
Proxy: sync expired state
2019-02-19 18:42:32 -05:00
90 changed files with 1537 additions and 831 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
Checks: '-*,clang-diagnostic-*,performance-*,bugprone-*,llvm-*,clang-analyzer-*,misc-*,-llvm-namespace-comment,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-llvm-header-guard,-llvm-include-order,-bugprone-suspicious-string-compare'
+9 -15
View File
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.1)
project (opendht)
set (opendht_VERSION_MAJOR 1)
set (opendht_VERSION_MINOR 8.1)
set (opendht_VERSION_MINOR 8.2)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -70,8 +70,6 @@ set (CMAKE_CXX_STANDARD_REQUIRED on)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -pedantic-errors -fvisibility=hidden")
if (OPENDHT_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fstack-protector-strong")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector")
endif ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT")
if (NOT CMAKE_BUILD_TYPE)
@@ -184,40 +182,34 @@ if (OPENDHT_INDEX)
endif()
if (OPENDHT_PROXY_SERVER)
add_definitions(-DOPENDHT_PROXY_SERVER=true)
add_definitions(-DOPENDHT_PROXY_SERVER)
if (OPENDHT_PROXY_SERVER_IDENTITY)
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=true)
else ()
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY=false)
add_definitions(-DOPENDHT_PROXY_SERVER_IDENTITY)
endif()
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_server.h
)
list (APPEND opendht_SOURCES
src/thread_pool.h
src/thread_pool.cpp
src/dht_proxy_server.cpp
)
else ()
add_definitions(-DENABLE_PROXY_SERVER=false)
endif ()
if (OPENDHT_PROXY_CLIENT)
add_definitions(-DOPENDHT_PROXY_CLIENT=true)
add_definitions(-DOPENDHT_PROXY_CLIENT)
list (APPEND opendht_HEADERS
include/opendht/dht_proxy_client.h
)
list (APPEND opendht_SOURCES
src/dht_proxy_client.cpp
)
else ()
add_definitions(-DOPENDHT_PROXY_CLIENT=false)
endif ()
if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT)
if (OPENDHT_PUSH_NOTIFICATIONS)
message("Using push notification")
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=true)
else ()
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS=false)
add_definitions(-DOPENDHT_PUSH_NOTIFICATIONS)
endif ()
list (APPEND opendht_HEADERS
include/opendht/proxy.h
@@ -312,6 +304,8 @@ if (OPENDHT_TESTS)
list (APPEND test_FILES
tests/infohashtester.h
tests/infohashtester.cpp
tests/valuetester.h
tests/valuetester.cpp
tests/cryptotester.h
tests/cryptotester.cpp
tests/dhtrunnertester.h
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
+1 -1
View File
@@ -106,7 +106,7 @@ for r in results:
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
## License
Copyright (C) 2014-2018 Savoir-faire Linux Inc.
Copyright (C) 2014-2019 Savoir-faire Linux Inc.
OpenDHT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
+5 -16
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 1)
m4_define([opendht_minor_version], 8)
m4_define([opendht_patch_version], 1)
m4_define([opendht_patch_version], 2)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -177,21 +177,10 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AM_COND_IF(ENABLE_PROXY_SERVER,
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=true"],
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER=false"])
AM_COND_IF(ENABLE_PROXY_CLIENT,
[CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=true"],
[CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT=false"])
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS,
[CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=true"],
[CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS=false"])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY,
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=true"],
[CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY=false"])
AM_COND_IF(ENABLE_PROXY_SERVER, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER"], [])
AM_COND_IF(ENABLE_PROXY_CLIENT, [CPPFLAGS+=" -DOPENDHT_PROXY_CLIENT"], [])
AM_COND_IF(ENABLE_PUSH_NOTIFICATIONS, [CPPFLAGS+=" -DOPENDHT_PUSH_NOTIFICATIONS"], [])
AM_COND_IF(ENABLE_PROXY_SERVER_IDENTITY, [CPPFLAGS+=" -DOPENDHT_PROXY_SERVER_IDENTITY"], [])
AM_COND_IF([HAVE_DOXYGEN], [
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#pragma once
#include "opendht/dhtrunner.h"
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
#include "opendht/dht_proxy_server.h"
#endif
#include "opendht/log.h"
+10 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -103,6 +103,9 @@ struct OPENDHT_PUBLIC Config {
/** Makes the DHT responsible to maintain its stored values. Consumes more ressources. */
bool maintain_storage;
/** If set, the dht will load its state from this file on start and save its state in this file on shutdown */
std::string persist_path;
};
/**
@@ -128,8 +131,8 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
using DoneCallback = std::function<void(bool success, const std::vector<std::shared_ptr<Node>>& nodes)>;
typedef void (*DoneCallbackRaw)(bool, std::vector<std::shared_ptr<Node>>*, void *user_data);
@@ -139,10 +142,10 @@ typedef bool (*FilterRaw)(const Value&, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
}
+54 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -66,7 +66,7 @@ using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certific
*/
struct OPENDHT_PUBLIC PublicKey
{
PublicKey() {}
PublicKey();
/**
* Takes ownership of an existing gnutls_pubkey.
@@ -115,7 +115,9 @@ struct OPENDHT_PUBLIC PublicKey
void msgpack_unpack(msgpack::object o);
gnutls_pubkey_t pk {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_pubkey_t pk {nullptr};
private:
PublicKey(const PublicKey&) = delete;
PublicKey& operator=(const PublicKey&) = delete;
@@ -186,7 +188,7 @@ class OPENDHT_PUBLIC RevocationList
public:
RevocationList();
RevocationList(const Blob& b);
RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
RevocationList(RevocationList&& o) noexcept : crl(o.crl) { o.crl = nullptr; }
~RevocationList();
RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
@@ -254,14 +256,48 @@ private:
RevocationList& operator=(const RevocationList&) = delete;
};
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
class OPENDHT_PUBLIC CertificateRequest {
public:
CertificateRequest();
CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
o.request = nullptr;
}
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
~CertificateRequest();
void setName(const std::string& name);
void setUID(const std::string& name);
void setAltName(NameType type, const std::string& name);
std::string getName() const;
std::string getUID() const;
void sign(const PrivateKey& key, const std::string& password = {});
bool verify() const;
Blob pack() const;
gnutls_x509_crq_t get() const { return request; }
private:
CertificateRequest(const CertificateRequest& o) = delete;
CertificateRequest& operator=(const CertificateRequest& o) = delete;
gnutls_x509_crq_t request {nullptr};
};
struct OPENDHT_PUBLIC Certificate {
Certificate() {}
Certificate() noexcept {}
/**
* Take ownership of existing gnutls structure
*/
Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
@@ -392,8 +428,6 @@ struct OPENDHT_PUBLIC Certificate {
/** Read certificate issuer User ID (UID) */
std::string getIssuerUID() const;
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
/** Read certificate alternative names */
std::vector<std::pair<NameType, std::string>> getAltNames() const;
@@ -431,7 +465,8 @@ struct OPENDHT_PUBLIC Certificate {
void addRevocationList(RevocationList&&);
void addRevocationList(std::shared_ptr<RevocationList>);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
static Certificate generate(const CertificateRequest& request, const Identity& ca);
gnutls_x509_crt_t getCopy() const {
if (not cert)
@@ -472,7 +507,9 @@ struct OPENDHT_PUBLIC Certificate {
return {crts, crls};
}
gnutls_x509_crt_t cert {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
private:
Certificate(const Certificate&) = delete;
@@ -500,10 +537,10 @@ struct OPENDHT_PUBLIC TrustList
};
TrustList();
TrustList(TrustList&& o) : trust(std::move(o.trust)) {
TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
o.trust = nullptr;
}
TrustList& operator=(TrustList&& o);
TrustList& operator=(TrustList&& o) noexcept;
~TrustList();
void add(const Certificate& crt);
void add(const RevocationList& crl);
@@ -513,7 +550,7 @@ struct OPENDHT_PUBLIC TrustList
private:
TrustList(const TrustList& o) = delete;
TrustList& operator=(const TrustList& o) = delete;
gnutls_x509_trust_list_t trust;
gnutls_x509_trust_list_t trust {nullptr};
};
template <class T>
@@ -611,11 +648,11 @@ using SecureBlob = secure_vector<uint8_t>;
* If not set, the generated certificate will be a self-signed CA.
* @param key_length stength of the generated private key (bits).
*/
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca);
OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", const Identity& ca = {}, unsigned key_length = 4096);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
/**
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ class OPENDHT_PUBLIC DhtMessage : public Value::Serializable<DhtMessage>
public:
static const ValueType TYPE;
DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
DhtMessage(const std::string& s = {}, const Blob& msg = {}) : service(s), data(msg) {}
std::string getService() const {
return service;
@@ -48,7 +48,7 @@ public:
static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr&);
static Value::Filter ServiceFilter(std::string s);
static Value::Filter ServiceFilter(const std::string& s);
/** print value for debugging */
friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
+16 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -68,7 +68,7 @@ public:
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
*/
Dht(const int& s, const int& s6, Config config);
Dht(const int& s, const int& s6, const Config& config);
virtual ~Dht();
/**
@@ -261,11 +261,14 @@ public:
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
std::vector<NodeExport> exportNodes();
std::vector<NodeExport> exportNodes() const;
std::vector<ValuesExport> exportValues() const;
void importValues(const std::vector<ValuesExport>&);
void saveState(const std::string& path) const;
void loadState(const std::string& path);
NodeStats getNodesStats(sa_family_t af) const;
std::string getStorageLog() const;
@@ -359,13 +362,6 @@ private:
// registred types
TypeStore types;
// are we a bootstrap node ?
// note: Any running node can be used as a bootstrap node.
// Only nodes running only as bootstrap nodes should
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
// the stuff
RoutingTable buckets4 {};
RoutingTable buckets6 {};
@@ -400,6 +396,15 @@ private:
std::mt19937_64 rd {crypto::getSeededRandomEngine<std::mt19937_64>()};
std::string persistPath;
// are we a bootstrap node ?
// note: Any running node can be used as a bootstrap node.
// Only nodes running only as bootstrap nodes should
// be put in bootstrap mode.
const bool is_bootstrap {false};
const bool maintain_storage {false};
void rotateSecrets();
Blob makeToken(const SockAddr&, bool old) const;
@@ -425,7 +430,7 @@ private:
* nodes.
*/
void dataPersistence(InfoHash id);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, DoneCallback donecb=nullptr);
size_t maintainStorage(decltype(store)::value_type&, bool force=false, const DoneCallback& donecb={});
// Buckets
RoutingTable& buckets(sa_family_t af) { return af == AF_INET ? buckets4 : buckets6; }
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -181,7 +181,7 @@ public:
* Get the list of good nodes for local storage saving purposes
* The list is ordered to minimize the back-to-work delay.
*/
virtual std::vector<NodeExport> exportNodes() = 0;
virtual std::vector<NodeExport> exportNodes() const = 0;
virtual std::vector<ValuesExport> exportValues() const = 0;
virtual void importValues(const std::vector<ValuesExport>&) = 0;
+4 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -17,8 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_CLIENT
#pragma once
#include <functional>
@@ -49,7 +47,7 @@ public:
explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "");
virtual void setPushNotificationToken(const std::string& token) {
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
deviceKey_ = token;
#endif
}
@@ -237,7 +235,7 @@ public:
void insertNode(const InfoHash&, const sockaddr*, socklen_t) { }
void insertNode(const NodeExport&) { }
std::pair<size_t, size_t> getStoreSize() const { return {}; }
std::vector<NodeExport> exportNodes() { return {}; }
std::vector<NodeExport> exportNodes() const { return {}; }
std::vector<ValuesExport> exportValues() const { return {}; }
void importValues(const std::vector<ValuesExport>&) {}
std::string getStorageLog() const { return {}; }
@@ -376,7 +374,7 @@ private:
const std::function<void()> loopSignal_;
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
void fillBody(std::shared_ptr<restbed::Request> request, bool resubscribe);
void getPushRequest(Json::Value&) const;
#endif // OPENDHT_PUSH_NOTIFICATIONS
@@ -385,5 +383,3 @@ private:
};
}
#endif // OPENDHT_PROXY_CLIENT
+8 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -17,8 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_SERVER
#pragma once
#include "callbacks.h"
@@ -45,6 +43,7 @@ namespace Json {
namespace dht {
class DhtRunner;
class ThreadPool;
/**
* Describes the REST API
@@ -178,7 +177,7 @@ private:
void cancelPut(const InfoHash& key, Value::Id vid);
#if OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
/**
* Put a value to sign by the proxy on the DHT
* Method: SIGN "/{InfoHash: .*}"
@@ -229,7 +228,7 @@ private:
*/
void removeClosedListeners(bool testSession = true);
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
/**
* Subscribe to push notifications for an iOS or Android device.
* Method: SUBSCRIBE "/{InfoHash: .*}"
@@ -253,7 +252,7 @@ private:
* @param key of the device
* @param json, the content to send
*/
void sendPushNotification(const std::string& key, const Json::Value& json, bool isAndroid) const;
void sendPushNotification(const std::string& key, Json::Value&& json, bool isAndroid) const;
/**
* Remove a push listener between a client and a hash
@@ -272,11 +271,13 @@ private:
std::thread server_thread {};
std::unique_ptr<restbed::Service> service_;
std::shared_ptr<DhtRunner> dht_;
Json::StreamWriterBuilder jsonBuilder_;
std::mutex schedulerLock_;
std::condition_variable schedulerCv_;
Scheduler scheduler_;
std::thread schedulerThread_;
std::unique_ptr<ThreadPool> threadPool_;
Sp<Scheduler::Job> printStatsJob_;
mutable std::mutex statsMutex_;
@@ -305,7 +306,7 @@ private:
mutable ServerStats stats_;
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct Listener;
struct PushListener;
std::mutex lockPushListeners_;
@@ -315,5 +316,3 @@ private:
};
}
#endif //OPENDHT_PROXY_SERVER
+6 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -354,7 +354,8 @@ public:
/*.node_id = */{},
/*.network = */network,
/*.is_bootstrap = */false,
/*.maintain_storage*/false
/*.maintain_storage = */false,
/*.persist_path = */{}
},
/*.id = */identity
},
@@ -363,7 +364,7 @@ public:
/*.push_node_id = */""
});
}
void run(in_port_t port, Config config);
void run(in_port_t port, const Config& config);
/**
* @param local4: Local IPv4 address and port to bind. Can be null.
@@ -373,12 +374,12 @@ public:
* @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(const SockAddr& local4, const SockAddr& local6, Config config);
void run(const SockAddr& local4, const SockAddr& local6, const Config& config);
/**
* Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
*/
void run(const char* ip4, const char* ip6, const char* service, Config config);
void run(const char* ip4, const char* ip6, const char* service, const Config& config);
void setOnStatusChanged(StatusCallback&& cb) {
statusCb = std::move(cb);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+10 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -206,15 +206,15 @@ public:
NetworkEngine(Logger& log, Scheduler& scheduler, const int& s = -1, const int& s6 = -1);
NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
decltype(NetworkEngine::onPing) onPing,
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce,
decltype(NetworkEngine::onRefresh) onRefresh);
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
decltype(NetworkEngine::onPing)&& onPing,
decltype(NetworkEngine::onFindNode)&& onFindNode,
decltype(NetworkEngine::onGetValues)&& onGetValues,
decltype(NetworkEngine::onListen)&& onListen,
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
decltype(NetworkEngine::onRefresh)&& onRefresh);
virtual ~NetworkEngine();
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -43,8 +43,8 @@ public:
* result_type is unsigned int so this is currently safe.
*/
static_assert(
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 2 ||
sizeof(result_type) == 4 ||
sizeof(result_type) == 8,
"result_type must be 16, 32 or 64 bits");
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+8 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -37,9 +37,9 @@ public:
using Config = SecureDhtConfig;
static dht::Config& getConfig(SecureDht::Config& conf)
static dht::Config getConfig(const SecureDht::Config& conf)
{
auto& c = conf.node_config;
auto c = conf.node_config;
if (not c.node_id and conf.id.second)
c.node_id = InfoHash::get("node:"+conf.id.second->getId().toString());
return c;
@@ -127,8 +127,8 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb);
void findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb);
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
@@ -168,7 +168,7 @@ public:
void setStorageLimit(size_t limit = DEFAULT_STORAGE_LIMIT) override {
dht_->setStorageLimit(limit);
}
std::vector<NodeExport> exportNodes() override {
std::vector<NodeExport> exportNodes() const override {
return dht_->exportNodes();
}
std::vector<ValuesExport> exportValues() const override {
@@ -332,8 +332,8 @@ private:
SecureDht& operator=(const SecureDht&) = delete;
Sp<Value> checkValue(const Sp<Value>& v);
ValueCallback getCallbackFilter(ValueCallback, Value::Filter&&);
GetCallback getCallbackFilter(GetCallback, Value::Filter&&);
ValueCallback getCallbackFilter(const ValueCallback&, Value::Filter&&);
GetCallback getCallbackFilter(const GetCallback&, Value::Filter&&);
Sp<crypto::PrivateKey> key_ {};
Sp<crypto::Certificate> certificate_ {};
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@ public:
SockAddr(const SockAddr& o) {
set(o.get(), o.getLength());
}
SockAddr(SockAddr&& o) : len(o.len), addr(std::move(o.addr)) {
SockAddr(SockAddr&& o) noexcept : len(o.len), addr(std::move(o.addr)) {
o.len = 0;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+17 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -79,7 +79,7 @@ static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
struct OPENDHT_PUBLIC ValueType {
typedef uint16_t Id;
static bool DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&);
static bool DEFAULT_EDIT_POLICY(InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&) {
return false;
}
@@ -165,8 +165,15 @@ struct OPENDHT_PUBLIC Value
return chainOr(std::move(f1), std::move(f2));
}
static Filter chain(Filter&& f1, Filter&& f2) {
if (not f1) return std::move(f1);
if (not f2) return std::move(f2);
if (not f1) return std::move(f2);
if (not f2) return std::move(f1);
return [f1,f2](const Value& v) {
return f1(v) and f2(v);
};
}
static Filter chain(const Filter& f1, const Filter& f2) {
if (not f1) return f2;
if (not f2) return f1;
return [f1,f2](const Value& v) {
return f1(v) and f2(v);
};
@@ -189,6 +196,10 @@ struct OPENDHT_PUBLIC Value
return f1(v) or f2(v);
};
}
static Filter notFilter(Filter&& f) {
if (not f) return [](const Value&) { return false; };
return [f](const Value& v) { return not f(v); };
}
std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values) {
if (not (*this))
return values;
@@ -874,7 +885,7 @@ struct OPENDHT_PUBLIC Query
{
static const std::string QUERY_PARSE_ERROR;
Query(Select s = {}, Where w = {}, bool none = false) : select(s), where(w), none(none) { };
Query(Select s = {}, Where w = {}, bool none = false) : select(std::move(s)), where(std::move(w)), none(none) { };
/**
* Initializes a query based on a SQL-ish formatted string. The abstract
@@ -936,7 +947,7 @@ struct OPENDHT_PUBLIC Query
*/
struct OPENDHT_PUBLIC FieldValueIndex {
FieldValueIndex() {}
FieldValueIndex(const Value& v, Select s = {});
FieldValueIndex(const Value& v, const Select& s = {});
/**
* Tells if all the fields of this are contained in the other
* FieldValueIndex with the same value.
+1 -1
View File
@@ -5,7 +5,7 @@
# distutils: libraries = opendht gnutls
# cython: language_level=3
#
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2016 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
#
+1 -1
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015 Savoir-Faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-Faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
# Simon Désaulniers <sim.desaulniers@gmail.com>
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2017 Savoir-faire Linux Inc.
# Copyright (C) 2015-2019 Savoir-faire Linux Inc.
# Author(s): Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2016 Savoir-faire Linux Inc.
# Copyright (c) 2016-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+3 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2017 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@ ping_node.run()
pong_node = dht.DhtRunner()
pong_node.run()
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound());
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
@@ -42,7 +42,7 @@ def done(h, ok):
def ping(node, h):
global i
time.sleep(0.0075)
time.sleep(0.0075)
i += 1
if i < MAX:
node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok))
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 Savoir-faire Linux Inc.
# Copyright (c) 2015-2019 Savoir-faire Linux Inc.
# Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
#
# This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -56,7 +56,7 @@ nobase_include_HEADERS = \
../include/opendht/rng.h
if ENABLE_PROXY_SERVER
libopendht_la_SOURCES += dht_proxy_server.cpp
libopendht_la_SOURCES += dht_proxy_server.cpp thread_pool.h thread_pool.cpp
nobase_include_HEADERS += ../include/opendht/dht_proxy_server.h
endif
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@
#include "base64.h"
#include <stdint.h>
#include <stdlib.h>
#include <cstdint>
#include <cstdlib>
/* Mainly based on the following stackoverflow question:
* http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2017 Savoir-faire Linux Inc.
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+5 -5
View File
@@ -4,7 +4,7 @@ namespace dht {
GetCallbackSimple
bindGetCb(GetCallbackRaw raw_cb, void* user_data)
bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](const std::shared_ptr<Value>& value) {
@@ -13,7 +13,7 @@ bindGetCb(GetCallbackRaw raw_cb, void* user_data)
}
GetCallback
bindGetCb(GetCallbackSimple cb)
bindGetCb(const GetCallbackSimple& cb)
{
if (not cb) return {};
return [=](const std::vector<std::shared_ptr<Value>>& values) {
@@ -25,7 +25,7 @@ bindGetCb(GetCallbackSimple cb)
}
ShutdownCallback
bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data)
bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data)
{
return [=]() { shutdown_cb_raw(user_data); };
}
@@ -39,7 +39,7 @@ bindDoneCb(DoneCallbackSimple donecb)
}
DoneCallback
bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](bool success, const std::vector<std::shared_ptr<Node>>& nodes) {
@@ -48,7 +48,7 @@ bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
}
DoneCallbackSimple
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](bool success) {
raw_cb(success, user_data);
+265 -106
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -40,31 +40,6 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey)
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt)
{
gnutls_pubkey_t pubkey;
gnutls_pubkey_init(&pubkey);
int result = gnutls_pubkey_import_x509(pubkey, crt, 0);
if (result < 0) {
gnutls_pubkey_deinit(pubkey);
return GNUTLS_DIG_UNKNOWN;
}
gnutls_digest_algorithm_t dig = get_dig_for_pub(pubkey);
gnutls_pubkey_deinit(pubkey);
return dig;
}
// support for GnuTLS < 3.4.
#if GNUTLS_VERSION_NUMBER < 0x030400
#define GNUTLS_PKCS_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES
@@ -377,15 +352,19 @@ PrivateKey::serialize(const std::string& password) const
PublicKey
PrivateKey::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret {pk};
if (gnutls_pubkey_import_privkey(pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0) != GNUTLS_E_SUCCESS)
return {};
return pk_ret;
PublicKey pk;
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
return pk;
}
PublicKey::PublicKey(const Blob& dat) : pk(nullptr)
PublicKey::PublicKey()
{
if (auto err = gnutls_pubkey_init(&pk))
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const Blob& dat) : PublicKey()
{
unpack(dat.data(), dat.size());
}
@@ -415,8 +394,7 @@ PublicKey::pack(Blob& b) const
throw CryptoException(std::string("Could not export public key: null key"));
std::vector<uint8_t> tmp(2048);
size_t sz = tmp.size();
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
tmp.resize(sz);
b.insert(b.end(), tmp.begin(), tmp.end());
@@ -425,9 +403,6 @@ PublicKey::pack(Blob& b) const
void
PublicKey::unpack(const uint8_t* data, size_t data_size)
{
if (pk)
gnutls_pubkey_deinit(pk);
gnutls_pubkey_init(&pk);
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)data_size};
int err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
@@ -446,10 +421,9 @@ PublicKey::toString() const
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
ret.resize(sz);
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
} else if (err != GNUTLS_E_SUCCESS)
err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
}
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
return ret;
}
@@ -572,7 +546,180 @@ PublicKey::getLongId() const
#endif
}
Certificate::Certificate(const Blob& certData) : cert(nullptr)
gnutls_digest_algorithm_t
PublicKey::getPreferredDigest() const
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pk, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
// Certificate Request
static NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return NameType::RFC822;
case GNUTLS_SAN_URI:
return NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return NameType::IP;
default:
return NameType::UNKNOWN;
}
}
static gnutls_x509_subject_alt_name_t
GnuTLSFromType(NameType type)
{
switch(type) {
case NameType::DNS:
return GNUTLS_SAN_DNSNAME;
case NameType::RFC822:
return GNUTLS_SAN_RFC822NAME;
case NameType::URI:
return GNUTLS_SAN_URI;
case NameType::IP:
return GNUTLS_SAN_IPADDRESS;
default:
return (gnutls_x509_subject_alt_name_t)0;
}
}
static std::string
getDN(gnutls_x509_crq_t request, const char* oid)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = gnutls_x509_crq_get_dn_by_oid(request, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
CertificateRequest::CertificateRequest()
{
if (auto err = gnutls_x509_crq_init(&request))
throw CryptoException(std::string("Can't initialize certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::CertificateRequest(const uint8_t* data, size_t size) : CertificateRequest()
{
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)size};
if (auto err = gnutls_x509_crq_import(request, &dat, GNUTLS_X509_FMT_PEM))
throw CryptoException(std::string("Can't import certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::~CertificateRequest()
{
if (request) {
gnutls_x509_crq_deinit(request);
request = nullptr;
}
}
CertificateRequest&
CertificateRequest::operator=(CertificateRequest&& o) noexcept
{
if (request)
gnutls_x509_crq_deinit(request);
request = o.request;
o.request = nullptr;
return *this;
}
void
CertificateRequest::setAltName(NameType type, const std::string& name)
{
gnutls_x509_crq_set_subject_alt_name(request, GnuTLSFromType(type), name.data(), name.size(), 0);
}
void
CertificateRequest::setName(const std::string& name)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
}
std::string
CertificateRequest::getName() const
{
return getDN(request, GNUTLS_OID_X520_COMMON_NAME);
}
std::string
CertificateRequest::getUID() const
{
return getDN(request, GNUTLS_OID_LDAP_UID);
}
void
CertificateRequest::setUID(const std::string& uid)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_LDAP_UID, 0, uid.data(), uid.length());
}
void
CertificateRequest::sign(const PrivateKey& key, const std::string& password)
{
gnutls_x509_crq_set_version(request, 1);
if (not password.empty())
gnutls_x509_crq_set_challenge_password(request, password.c_str());
if (auto err = gnutls_x509_crq_set_key(request, key.x509_key))
throw CryptoException(std::string("Can't set certificate request key: ") + gnutls_strerror(err));
#if GNUTLS_VERSION_NUMBER < 0x030601
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, key.getPublicKey().getPreferredDigest(), 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#else
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, GNUTLS_DIG_UNKNOWN, 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#endif
}
bool
CertificateRequest::verify() const
{
return gnutls_x509_crq_verify(request, 0) >= 0;
}
Blob
CertificateRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
Blob ret(dat.data, dat.data + dat.size);
gnutls_free(dat.data);
return ret;
}
// Certificate
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
Certificate::Certificate(const Blob& certData)
{
unpack(certData.data(), certData.size());
}
@@ -656,11 +803,9 @@ Certificate::~Certificate()
PublicKey
Certificate::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret(pk);
if (gnutls_pubkey_import_x509(pk, cert, 0) != GNUTLS_E_SUCCESS)
return {};
PublicKey pk_ret;
if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
return pk_ret;
}
@@ -696,21 +841,6 @@ Certificate::getLongId() const
#endif
}
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
std::string
Certificate::getName() const
{
@@ -735,24 +865,7 @@ Certificate::getIssuerUID() const
return getDN(cert, GNUTLS_OID_LDAP_UID, true);
}
static Certificate::NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return Certificate::NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return Certificate::NameType::RFC822;
case GNUTLS_SAN_URI:
return Certificate::NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return Certificate::NameType::IP;
default:
return Certificate::NameType::UNKNOWN;
}
}
std::vector<std::pair<Certificate::NameType, std::string>>
std::vector<std::pair<NameType, std::string>>
Certificate::getAltNames() const
{
std::vector<std::pair<NameType, std::string>> names;
@@ -867,6 +980,14 @@ Certificate::getExpiration() const
return std::chrono::system_clock::from_time_t(t);
}
gnutls_digest_algorithm_t
Certificate::getPreferredDigest() const
{
return getPublicKey().getPreferredDigest();
}
// PrivateKey
PrivateKey
PrivateKey::generate(unsigned key_length)
{
@@ -896,7 +1017,7 @@ PrivateKey::generateEC()
}
Identity
generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_length, bool is_ca)
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length, bool is_ca)
{
auto key = std::make_shared<PrivateKey>(PrivateKey::generate(key_length));
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -905,12 +1026,12 @@ generateIdentity(const std::string& name, crypto::Identity ca, unsigned key_leng
Identity
generateIdentity(const std::string& name, Identity ca, unsigned key_length) {
generateIdentity(const std::string& name, const Identity& ca, unsigned key_length) {
return generateIdentity(name, ca, key_length, !ca.first || !ca.second);
}
Identity
generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca)
{
auto key = std::make_shared<PrivateKey>(PrivateKey::generateEC());
auto cert = std::make_shared<Certificate>(Certificate::generate(*key, name, ca, is_ca));
@@ -918,25 +1039,40 @@ generateEcIdentity(const std::string& name, crypto::Identity ca, bool is_ca)
}
Identity
generateEcIdentity(const std::string& name, Identity ca) {
generateEcIdentity(const std::string& name, const Identity& ca) {
return generateEcIdentity(name, ca, !ca.first || !ca.second);
}
void
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
{
int64_t now = time(nullptr);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + validity));
}
void
setRandomSerial(gnutls_x509_crt_t cert)
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
Certificate
Certificate::generate(const PrivateKey& key, const std::string& name, Identity ca, bool is_ca)
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
{
gnutls_x509_crt_t cert;
if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
return {};
Certificate ret {cert};
int64_t now = time(NULL);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + (10 * 365 * 24 * 60 * 60)));
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate key" << std::endl;
return {};
@@ -947,19 +1083,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
}
// TODO: compute the subject key using the recommended RFC method
auto pk_id = key.getPublicKey().getId();
auto pk = key.getPublicKey();
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
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());
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
@@ -975,15 +1107,13 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
// Signing certificate must be CA.
return {};
}
//if (gnutls_x509_crt_sign2(cert, ca.second->cert, ca.first->x509_key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
ret.issuer = ca.second;
} else {
//if (gnutls_x509_crt_sign2(cert, cert, key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
@@ -992,6 +1122,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, Identity c
return ret.getPacked();
}
Certificate
Certificate::generate(const CertificateRequest& request, const Identity& ca)
{
gnutls_x509_crt_t cert;
if (auto err = gnutls_x509_crt_init(&cert))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
Certificate ret {cert};
if (auto err = gnutls_x509_crt_set_crq(cert, request.get()))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crt_set_version(cert, 3)) {
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
}
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
setRandomSerial(cert);
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
throw CryptoException(std::string("Can't sign certificate: ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
return ret.getPacked();
}
std::vector<std::shared_ptr<RevocationList>>
Certificate::getRevocationLists() const
{
@@ -1002,6 +1157,8 @@ Certificate::getRevocationLists() const
return ret;
}
// RevocationList
RevocationList::RevocationList()
{
gnutls_x509_crl_init(&crl);
@@ -1219,6 +1376,8 @@ RevocationList::toString() const
return ret;
}
// TrustList
TrustList::TrustList() {
gnutls_x509_trust_list_init(&trust, 0);
}
@@ -1228,11 +1387,11 @@ TrustList::~TrustList() {
}
TrustList&
TrustList::operator=(TrustList&& o)
TrustList::operator=(TrustList&& o) noexcept
{
if (trust)
gnutls_x509_trust_list_deinit(trust, true);
trust = std::move(o.trust);
trust = o.trust;
o.trust = nullptr;
return *this;
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ DhtMessage::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const InfoHash& f
}
Value::Filter
DhtMessage::ServiceFilter(std::string s)
DhtMessage::ServiceFilter(const std::string& s)
{
return Value::Filter::chain(
Value::TypeFilter(TYPE),
+92 -48
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -29,6 +29,7 @@
#include <algorithm>
#include <random>
#include <sstream>
#include <fstream>
namespace dht {
@@ -54,6 +55,9 @@ Dht::getStatus(sa_family_t af) const
void
Dht::shutdown(ShutdownCallback cb)
{
if (not persistPath.empty())
saveState(persistPath);
if (not maintain_storage) {
if (cb) cb();
return;
@@ -533,7 +537,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
if (auto sr = ws.lock()) {
auto l = sr->listeners.find(list_token);
if (l != sr->listeners.end()) {
l->second.get_cb(l->second.filter.filter(values), expired);
l->second.get_cb(values, expired);
}
}
}, [ws,list_token] (ListenSyncStatus status) {
@@ -832,41 +836,28 @@ Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
{
scheduler.syncTime();
Query q {{}, where};
auto vals = std::make_shared<std::map<Value::Id, Sp<Value>>>();
auto token = ++listener_token;
auto gcb = OpValueCache::cacheCallback(std::move(cb), [this, id, token]{
cancelListen(id, token);
});
auto query = std::make_shared<Query>(q);
auto filter = f.chain(q.where.getFilter());
size_t tokenlocal = 0;
auto query = std::make_shared<Query>(Select{}, std::move(where));
auto filter = f.chain(query->where.getFilter());
auto st = store.find(id);
if (st == store.end() && store.size() < MAX_HASHES)
st = store.emplace(id, scheduler.time() + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME).first;
size_t tokenlocal = 0;
if (st != store.end()) {
if (not st->second.empty()) {
std::vector<Sp<Value>> newvals = st->second.get(filter);
if (not newvals.empty()) {
if (!gcb(newvals, false))
return 0;
for (const auto& v : newvals) {
auto it = vals->emplace(v->id, v);
if (not it.second)
it.first->second = v;
}
}
}
tokenlocal = ++st->second.listener_token;
st->second.local_listeners.emplace(tokenlocal, LocalListener{query, filter, gcb});
tokenlocal = st->second.listen(gcb, filter, query);
if (tokenlocal == 0)
return 0;
}
auto token4 = Dht::listenTo(id, AF_INET, gcb, filter, query);
auto token6 = token4 == 0 ? 0 : Dht::listenTo(id, AF_INET6, gcb, filter, query);
if (token6 == 0 && st != store.end()) {
st->second.local_listeners.erase(tokenlocal);
st->second.cancelListen(tokenlocal);
return 0;
}
@@ -885,15 +876,17 @@ Dht::cancelListen(const InfoHash& id, size_t token)
return false;
}
DHT_LOG.d(id, "cancelListen %s with token %d", id.toString().c_str(), token);
auto st = store.find(id);
auto tokenlocal = std::get<0>(it->second);
if (st != store.end() && tokenlocal)
st->second.local_listeners.erase(tokenlocal);
if (auto tokenlocal = std::get<0>(it->second)) {
auto st = store.find(id);
if (st != store.end())
st->second.cancelListen(tokenlocal);
}
auto searches_cancel_listen = [this,&id](std::map<InfoHash, Sp<Search>>& srs, size_t token) {
auto srp = srs.find(id);
if (srp != srs.end() and token)
srp->second->cancelListen(token, scheduler);
if (token) {
auto srp = srs.find(id);
if (srp != srs.end())
srp->second->cancelListen(token, scheduler);
}
};
searches_cancel_listen(searches4, std::get<1>(it->second));
searches_cancel_listen(searches6, std::get<2>(it->second));
@@ -1272,16 +1265,16 @@ Dht::storageAddListener(const InfoHash& id, const Sp<Node>& node, size_t socket_
return;
st = store.emplace(id, now).first;
}
auto node_listeners = st->second.listeners.emplace(node, std::map<size_t, Listener> {}).first;
auto l = node_listeners->second.find(socket_id);
if (l == node_listeners->second.end()) {
auto& node_listeners = st->second.listeners[node];
auto l = node_listeners.find(socket_id);
if (l == node_listeners.end()) {
auto vals = st->second.get(query.where.getFilter());
if (not vals.empty()) {
network_engine.tellListener(node, socket_id, id, WANT4 | WANT6, makeToken(node->getAddr(), false),
buckets4.findClosestNodes(id, now, TARGET_NODES), buckets6.findClosestNodes(id, now, TARGET_NODES),
std::move(vals), query);
}
node_listeners->second.emplace(socket_id, Listener {now, std::forward<Query>(query)});
node_listeners.emplace(socket_id, Listener {now, std::forward<Query>(query)});
}
else
l->second.refresh(now, std::forward<Query>(query));
@@ -1721,10 +1714,8 @@ Dht::~Dht()
Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {}
Dht::Dht(const int& s, const int& s6, Config config)
: myid(config.node_id ? config.node_id : InfoHash::getRandom()),
is_bootstrap(config.is_bootstrap),
maintain_storage(config.maintain_storage), store(), store_quota(),
Dht::Dht(const int& s, const int& s6, const Config& config)
: myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
network_engine(myid, config.network, s, s6, DHT_LOG, scheduler,
std::bind(&Dht::onError, this, _1, _2),
std::bind(&Dht::onNewNode, this, _1, _2),
@@ -1734,7 +1725,10 @@ Dht::Dht(const int& s, const int& s6, Config config)
std::bind(&Dht::onGetValues, this, _1, _2, _3, _4),
std::bind(&Dht::onListen, this, _1, _2, _3, _4, _5),
std::bind(&Dht::onAnnounce, this, _1, _2, _3, _4, _5),
std::bind(&Dht::onRefresh, this, _1, _2, _3, _4))
std::bind(&Dht::onRefresh, this, _1, _2, _3, _4)),
persistPath(config.persist_path),
is_bootstrap(config.is_bootstrap),
maintain_storage(config.maintain_storage)
{
scheduler.syncTime();
if (s < 0 && s6 < 0)
@@ -1765,8 +1759,10 @@ Dht::Dht(const int& s, const int& s6, Config config)
expire();
DHT_LOG.d("DHT initialised with node ID %s", myid.toString().c_str());
}
if (not persistPath.empty())
loadState(persistPath);
}
bool
Dht::neighbourhoodMaintenance(RoutingTable& list)
@@ -1850,12 +1846,12 @@ Dht::bucketMaintenance(RoutingTable& list)
}
DHT_LOG.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,start,n](const net::Request&, bool over) {
//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;
DHT_LOG.d(n->id, "[node %s] bucket maintenance op expired after %llu ms", n->toString().c_str(), duration_cast<milliseconds>(end-start).count());
// using namespace std::chrono;
// DHT_LOG.d(n->id, "[node %s] bucket maintenance op expired after %llu ms", n->toString().c_str(), duration_cast<milliseconds>(end-start).count());
scheduler.edit(nextNodesConfirmation, end + Node::MAX_RESPONSE_TIME);
}
});
@@ -1881,7 +1877,7 @@ Dht::dataPersistence(InfoHash id)
}
size_t
Dht::maintainStorage(decltype(store)::value_type& storage, bool force, DoneCallback donecb)
Dht::maintainStorage(decltype(store)::value_type& storage, bool force, const DoneCallback& donecb)
{
const auto& now = scheduler.time();
size_t announce_per_af = 0;
@@ -2056,7 +2052,7 @@ Dht::importValues(const std::vector<ValuesExport>& import)
std::vector<NodeExport>
Dht::exportNodes()
Dht::exportNodes() const
{
const auto& now = scheduler.time();
std::vector<NodeExport> nodes;
@@ -2283,7 +2279,7 @@ Dht::onListen(Sp<Node> node, const InfoHash& hash, const Blob& token, size_t soc
}
void
Dht::onListenDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>& sr)
Dht::onListenDone(const Sp<Node>& /* node */, net::RequestAnswer& /* answer */, Sp<Search>& sr)
{
// DHT_LOG.d(sr->id, node->id, "[search %s] [node %s] got listen confirmation",
// sr->id.toString().c_str(), node->toString().c_str(), answer.values.size());
@@ -2424,4 +2420,52 @@ Dht::onAnnounceDone(const Sp<Node>& node, net::RequestAnswer& answer, Sp<Search>
sr->checkAnnounced(answer.vid);
}
void
Dht::saveState(const std::string& path) const
{
std::ofstream file(path);
msgpack::pack(file, exportNodes());
msgpack::pack(file, exportValues());
}
void
Dht::loadState(const std::string& path)
{
DHT_LOG.d("Importing state from %s", path.c_str());
try {
// Import nodes from binary file
msgpack::unpacker pac;
{
// Read whole file
std::ifstream file(path, std::ios::binary|std::ios::ate);
if (!file.is_open()) {
return;
}
auto size = file.tellg();
file.seekg (0, std::ios::beg);
pac.reserve_buffer(size);
file.read (pac.buffer(), size);
pac.buffer_consumed(size);
}
// Import nodes
msgpack::object_handle oh;
if (pac.next(oh)) {
{
auto imported_nodes = oh.get().as<std::vector<NodeExport>>();
DHT_LOG.d("Importing %zu nodes", imported_nodes.size());
for (const auto& node : imported_nodes)
insertNode(node);
}
if (pac.next(oh)) {
auto imported_values = oh.get().as<std::vector<ValuesExport>>();
DHT_LOG.d("Importing %zu values", imported_values.size());
importValues(imported_values);
}
}
} catch (const std::exception& e) {
DHT_LOG.w("Error importing state from %s: %s", path.c_str(), e.what());
}
}
}
+97 -101
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2018 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -17,8 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#include "dhtrunner.h"
@@ -45,8 +43,7 @@ struct DhtProxyClient::ListenState {
struct DhtProxyClient::Listener
{
ValueCache cache;
Sp<Scheduler::Job> cacheExpirationJob {};
OpValueCache cache;
ValueCallback cb;
Value::Filter filter;
Sp<restbed::Request> req;
@@ -54,23 +51,21 @@ struct DhtProxyClient::Listener
unsigned callbackId;
Sp<ListenState> state;
Sp<Scheduler::Job> refreshJob;
Listener(ValueCache&& c, Sp<Scheduler::Job>&& j, const Sp<restbed::Request>& r, Value::Filter&& f)
: cache(std::move(c)),
cacheExpirationJob(std::move(j)),
filter(std::move(f)),
req(r)
{}
Listener(OpValueCache&& c, const Sp<restbed::Request>& r, Value::Filter&& f)
: cache(std::move(c)), filter(std::move(f)),req(r) {}
};
struct PermanentPut {
Sp<Value> value;
Sp<Scheduler::Job> refreshJob;
Sp<std::atomic_bool> ok;
PermanentPut(const Sp<Value>& v, Sp<Scheduler::Job>&& j, const Sp<std::atomic_bool>& o)
: value(v), refreshJob(std::move(j)), ok(o) {}
};
struct DhtProxyClient::ProxySearch {
SearchCache ops {};
Sp<Scheduler::Job> opExpirationJob;
Sp<Scheduler::Job> opExpirationJob {};
std::map<size_t, Listener> listeners {};
std::map<Value::Id, PermanentPut> puts {};
};
@@ -338,24 +333,26 @@ DhtProxyClient::put(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_po
if (permanent) {
std::lock_guard<std::mutex> lock(searchLock_);
auto id = val->id;
auto search = searches_.emplace(key, ProxySearch{}).first;
auto& search = searches_[key];
auto nextRefresh = scheduler.time() + proxy::OP_TIMEOUT - proxy::OP_MARGIN;
auto ok = std::make_shared<std::atomic_bool>(false);
search->second.puts.erase(id);
search->second.puts.emplace(id, PermanentPut {val, scheduler.add(nextRefresh, [this, key, id, ok]{
std::lock_guard<std::mutex> lock(searchLock_);
auto s = searches_.find(key);
if (s != searches_.end()) {
auto p = s->second.puts.find(id);
if (p != s->second.puts.end()) {
doPut(key, p->second.value,
[ok](bool result, const std::vector<std::shared_ptr<dht::Node> >&){
*ok = result;
}, time_point::max(), true);
scheduler.edit(p->second.refreshJob, scheduler.time() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
search.puts.erase(id);
search.puts.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(val, scheduler.add(nextRefresh, [this, key, id, ok]{
std::lock_guard<std::mutex> lock(searchLock_);
auto s = searches_.find(key);
if (s != searches_.end()) {
auto p = s->second.puts.find(id);
if (p != s->second.puts.end()) {
doPut(key, p->second.value,
[ok](bool result, const std::vector<std::shared_ptr<dht::Node> >&){
*ok = result;
}, time_point::max(), true);
scheduler.edit(p->second.refreshJob, scheduler.time() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
}
}
}
}), ok});
}), ok));
}
doPut(key, val, std::move(cb), created, permanent);
}
@@ -373,7 +370,7 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_
if (deviceKey_.empty()) {
json["permanent"] = true;
} else {
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
Json::Value refresh;
getPushRequest(refresh);
json["permanent"] = refresh;
@@ -663,12 +660,9 @@ DhtProxyClient::getPublicAddress(sa_family_t family)
size_t
DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filter, Where where) {
DHT_LOG.d(key, "[search %s]: listen", key.to_c_str());
auto it = searches_.find(key);
if (it == searches_.end()) {
it = searches_.emplace(key, ProxySearch{}).first;
}
auto& search = searches_[key];
auto query = std::make_shared<Query>(Select{}, where);
auto token = it->second.ops.listen(cb, query, filter, [this, key, filter](Sp<Query> /*q*/, ValueCallback cb, SyncCallback scb) -> size_t {
auto token = search.ops.listen(cb, query, filter, [this, key, filter](Sp<Query> /*q*/, ValueCallback cb, SyncCallback /*scb*/) -> size_t {
scheduler.syncTime();
restbed::Uri uri(serverHost_ + "/" + key.toString());
std::lock_guard<std::mutex> lock(searchLock_);
@@ -684,21 +678,9 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
auto l = search->second.listeners.find(token);
if (l == search->second.listeners.end()) {
auto f = filter;
l = search->second.listeners.emplace(token, Listener {
ValueCache(cb, std::move(scb)), scheduler.add(time_point::max(), [this, key, token]{
std::lock_guard<std::mutex> lock(searchLock_);
auto s = searches_.find(key);
if (s == searches_.end()) {
return;
}
auto l = s->second.listeners.find(token);
if (l == s->second.listeners.end()) {
return;
}
auto next = l->second.cache.expireValues(scheduler.time());
scheduler.edit(l->second.cacheExpirationJob, next);
}), req, std::move(f)
}).first;
l = search->second.listeners.emplace(std::piecewise_construct,
std::forward_as_tuple(token),
std::forward_as_tuple(std::move(cb), req, std::move(f))).first;
} else {
if (l->second.state)
l->second.state->cancel = true;
@@ -718,17 +700,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
if (l == s->second.listeners.end()) {
return false;
}
const std::vector<Sp<Value>> new_values_empty;
std::vector<Value::Id> expired_ids;
if (expired) {
expired_ids.reserve(values.size());
for (const auto& v : values)
expired_ids.emplace_back(v->id);
}
auto next = l->second.cache.onValues(expired ? new_values_empty : values, std::vector<Value::Id>{}, expired_ids, types, scheduler.time());
scheduler.edit(l->second.cacheExpirationJob, next);
loopSignal_();
return true;
return l->second.cache.onValue(values, expired);
};
auto vcb = l->second.cb;
@@ -751,8 +723,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
}
l->second.thread = std::thread([this, req, vcb, filter, state]() {
sendListen(req, vcb, filter, state,
deviceKey_.empty() ? ListenMethod::LISTEN
: ListenMethod::SUBSCRIBE);
deviceKey_.empty() ? ListenMethod::LISTEN : ListenMethod::SUBSCRIBE);
});
return token;
});
@@ -791,23 +762,23 @@ void DhtProxyClient::sendListen(const std::shared_ptr<restbed::Request> &req,
const Value::Filter &filter,
const Sp<ListenState> &state,
ListenMethod method) {
auto settings = std::make_shared<restbed::Settings>();
if (method != ListenMethod::LISTEN) {
req->set_method("SUBSCRIBE");
} else {
std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(
timeout); // Avoid the client to close the socket after 5 seconds.
req->set_method("LISTEN");
}
try {
#if OPENDHT_PUSH_NOTIFICATIONS
if (method != ListenMethod::LISTEN)
fillBody(req, method == ListenMethod::RESUBSCRIBE);
#endif
auto settings = std::make_shared<restbed::Settings>();
if (method != ListenMethod::LISTEN) {
req->set_method("SUBSCRIBE");
} else {
std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(timeout); // Avoid the client to close the socket after 5 seconds.
req->set_method("LISTEN");
}
try {
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (method != ListenMethod::LISTEN)
fillBody(req, method == ListenMethod::RESUBSCRIBE);
#endif
restbed::Http::async(req,
[this, filter, cb, state](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply) {
[this, filter, cb, state](const std::shared_ptr<restbed::Request>& req,
const std::shared_ptr<restbed::Response>& reply)
{
auto code = reply->get_status_code();
if (code == 200) {
try {
@@ -994,7 +965,7 @@ DhtProxyClient::restartListeners()
void
DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string>& notification)
{
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
scheduler.syncTime();
{
// If a push notification is received, the proxy is up and running
@@ -1021,20 +992,45 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
resubscribe(key, list.second);
}
} else {
auto keyidx = notification.find("key");
InfoHash key(keyidx->second);
for (auto& search: searches_) {
for (auto& list : search.second.listeners) {
if (search.first != key || list.second.state->cancel)
continue;
DHT_LOG.d(search.first, "[search %s] handling push notification", search.first.to_c_str());
auto key = InfoHash(notification.at("key"));
auto& search = searches_.at(key);
for (auto& list : search.listeners) {
if (list.second.state->cancel)
continue;
DHT_LOG.d(key, "[search %s] handling push notification", key.to_c_str());
auto expired = notification.find("exp");
auto token = list.first;
auto state = list.second.state;
if (expired == notification.end()) {
auto cb = list.second.cb;
auto filter = list.second.filter;
get(search.first, [cb](const std::vector<Sp<Value>>& vals) {
cb(vals, false);
return true;
}, DoneCallbackSimple{}, std::move(filter));
auto oldValues = list.second.cache.getValues();
get(key, [cb](const std::vector<Sp<Value>>& vals) {
return cb(vals, false);
}, [cb, oldValues](bool /*ok*/) {
// Decrement old values refcount to expire values not present in the new list
cb(oldValues, true);
}, std::move(filter));
} else {
std::stringstream ss(expired->second);
std::vector<Value::Id> ids;
while(ss.good()){
std::string substr;
getline(ss, substr, ',');
ids.emplace_back(std::stoull(substr));
}
std::lock_guard<std::mutex> lock(lockCallbacks);
callbacks_.emplace_back([this, key, token, state, ids]() {
if (state->cancel) return;
std::lock_guard<std::mutex> lock(searchLock_);
auto s = searches_.find(key);
if (s == searches_.end()) return;
auto l = s->second.listeners.find(token);
if (l == s->second.listeners.end()) return;
if (not state->cancel and not l->second.cache.onValuesExpired(ids))
state->cancel = true;
});
loopSignal_();
}
}
}
@@ -1047,20 +1043,22 @@ DhtProxyClient::pushNotificationReceived(const std::map<std::string, std::string
void
DhtProxyClient::resubscribe(const InfoHash& key, Listener& listener)
{
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (deviceKey_.empty()) return;
scheduler.syncTime();
DHT_LOG.d(key, "[search %s] resubscribe push listener", key.to_c_str());
// Subscribe
restbed::Uri uri(serverHost_ + "/" + key.toString());
auto req = std::make_shared<restbed::Request>(uri);
req->set_method("SUBSCRIBE");
auto state = listener.state;
if (listener.thread.joinable())
if (listener.thread.joinable()) {
state->cancel = true;
if (listener.req)
restbed::Http::close(listener.req);
listener.thread.join();
}
state->cancel = false;
state->ok = true;
auto req = std::make_shared<restbed::Request>(restbed::Uri {serverHost_ + "/" + key.toString()});
req->set_method("SUBSCRIBE");
listener.req = req;
scheduler.edit(listener.refreshJob, scheduler.time() + proxy::OP_TIMEOUT - proxy::OP_MARGIN);
auto vcb = listener.cb;
@@ -1071,7 +1069,7 @@ DhtProxyClient::resubscribe(const InfoHash& key, Listener& listener)
#endif
}
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
void
DhtProxyClient::getPushRequest(Json::Value& body) const
{
@@ -1094,9 +1092,9 @@ DhtProxyClient::fillBody(std::shared_ptr<restbed::Request> req, bool resubscribe
// }
Json::Value body;
getPushRequest(body);
if (!resubscribe) {
if (resubscribe) {
// This is the first listen, we want to retrieve previous values.
body["previous_values"] = true;
body["refresh"] = true;
}
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
@@ -1109,5 +1107,3 @@ DhtProxyClient::fillBody(std::shared_ptr<restbed::Request> req, bool resubscribe
#endif // OPENDHT_PUSH_NOTIFICATIONS
} // namespace dht
#endif // OPENDHT_PROXY_CLIENT
+49 -52
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -17,9 +17,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if OPENDHT_PROXY_SERVER
#include "dht_proxy_server.h"
#include "thread_pool.h"
#include "default_types.h"
#include "dhtrunner.h"
@@ -47,9 +47,11 @@ struct DhtProxyServer::SearchPuts {
};
constexpr const std::chrono::minutes PRINT_STATS_PERIOD {2};
constexpr const size_t IO_THREADS_MAX {64};
DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port , const std::string& pushServer)
: dht_(dht) , pushServer_(pushServer)
: dht_(dht), threadPool_(new ThreadPool(IO_THREADS_MAX)), pushServer_(pushServer)
{
if (not dht_)
throw std::invalid_argument("A DHT instance must be provided");
@@ -58,13 +60,16 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port ,
std::cout << "Running DHT proxy server on port " << port << std::endl;
if (not pushServer.empty()) {
#if !OPENDHT_PUSH_NOTIFICATIONS
std::cerr << "Push server defined but built OpenDHT built without push notification support" << std::endl;
#else
#ifdef OPENDHT_PUSH_NOTIFICATIONS
std::cout << "Using push notification server: " << pushServer << std::endl;
#else
std::cerr << "Push server defined but built OpenDHT built without push notification support" << std::endl;
#endif
}
jsonBuilder_["commentStyle"] = "None";
jsonBuilder_["indentation"] = "";
server_thread = std::thread([this, port]() {
// Create endpoints
auto resource = std::make_shared<restbed::Resource>();
@@ -76,12 +81,12 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port ,
resource->set_path("/{hash: .*}");
resource->set_method_handler("GET", std::bind(&DhtProxyServer::get, this, _1));
resource->set_method_handler("LISTEN", [this](const Sp<restbed::Session>& session) mutable { listen(session); } );
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
resource->set_method_handler("SUBSCRIBE", [this](const Sp<restbed::Session>& session) mutable { subscribe(session); } );
resource->set_method_handler("UNSUBSCRIBE", [this](const Sp<restbed::Session>& session) mutable { unsubscribe(session); } );
#endif //OPENDHT_PUSH_NOTIFICATIONS
resource->set_method_handler("POST", [this](const Sp<restbed::Session>& session) mutable { put(session); });
#if OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
resource->set_method_handler("SIGN", std::bind(&DhtProxyServer::putSigned, this, _1));
resource->set_method_handler("ENCRYPT", std::bind(&DhtProxyServer::putEncrypted, this, _1));
#endif // OPENDHT_PROXY_SERVER_IDENTITY
@@ -177,6 +182,7 @@ DhtProxyServer::stop()
schedulerThread_.join();
if (server_thread.joinable())
server_thread.join();
threadPool_->stop();
}
void
@@ -187,7 +193,7 @@ DhtProxyServer::updateStats() const
auto count = requestNum_.exchange(0);
auto dt = std::chrono::duration<double>(now - last);
stats_.requestRate = count / dt.count();
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
stats_.pushListenersCount = pushListeners_.size();
#endif
stats_.putCount = puts_.size();
@@ -219,10 +225,7 @@ DhtProxyServer::getNodeInfo(const Sp<restbed::Session>& session) const
result = nodeInfo_.toJson();
}
result["public_ip"] = s->get_origin(); // [ipv6:ipv4]:port or ipv4:port
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, result) + "\n";
auto output = Json::writeString(jsonBuilder_, result) + "\n";
s->close(restbed::OK, output);
}
else
@@ -246,10 +249,7 @@ DhtProxyServer::getStats(const Sp<restbed::Session>& session) const
try {
if (dht_) {
#ifdef OPENDHT_JSONCPP
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, stats_.toJson()) + "\n";
auto output = Json::writeString(jsonBuilder_, stats_.toJson()) + "\n";
s->close(restbed::OK, output);
#else
s->close(restbed::NotFound, "{\"err\":\"JSON not enabled on this instance\"}");
@@ -281,13 +281,10 @@ DhtProxyServer::get(const Sp<restbed::Session>& session) const
infoHash = InfoHash::get(hash);
}
s->yield(restbed::OK, "", [=](const Sp<restbed::Session>&) {});
dht_->get(infoHash, [s](const Sp<Value>& value) {
dht_->get(infoHash, [this,s](const Sp<Value>& value) {
if (s->is_closed()) return false;
// Send values as soon as we get them
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(wbuilder, value->toJson()) + "\n";
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
s->yield(output, [](const Sp<restbed::Session>& /*session*/){ });
return true;
}, [s](bool /*ok* */) {
@@ -335,19 +332,16 @@ DhtProxyServer::listen(const Sp<restbed::Session>& session)
// cache the session to avoid an incrementation of the shared_ptr's counter
// else, the session->close() will not close the socket.
auto cacheSession = std::weak_ptr<restbed::Session>(s);
listener.token = dht_->listen(infoHash, [cacheSession](const std::vector<Sp<Value>>& values, bool expired) {
listener.token = dht_->listen(infoHash, [this,cacheSession](const std::vector<Sp<Value>>& values, bool expired) {
auto s = cacheSession.lock();
if (!s) return false;
// Send values as soon as we get them
if (!s->is_closed()) {
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
for (const auto& value : values) {
auto val = value->toJson();
if (expired)
val["expired"] = true;
auto output = Json::writeString(wbuilder, val) + "\n";
auto output = Json::writeString(jsonBuilder_, val) + "\n";
s->yield(output, [](const Sp<restbed::Session>&){ });
}
}
@@ -367,7 +361,7 @@ DhtProxyServer::listen(const Sp<restbed::Session>& session)
);
}
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
struct DhtProxyServer::Listener {
std::string clientId;
@@ -430,20 +424,14 @@ DhtProxyServer::subscribe(const std::shared_ptr<restbed::Session>& session)
scheduler_.edit(listener.expireNotifyJob, timeout - proxy::OP_MARGIN);
s->yield(restbed::OK);
if (root.isMember("previous_values") &&
root["previous_values"].asBool()) {
if (!root.isMember("refresh") or !root["refresh"].asBool()) {
dht_->get(
infoHash,
[this, s](const Sp<Value> &value) {
if (s->is_closed())
return false;
// Send values as soon as we get them
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
wbuilder["indentation"] = "";
auto output = Json::writeString(
wbuilder, value->toJson()) +
"\n";
auto output = Json::writeString(jsonBuilder_, value->toJson()) + "\n";
s->yield(output, [](const Sp<restbed::Session>
& /*session*/) {});
return true;
@@ -473,12 +461,22 @@ DhtProxyServer::subscribe(const std::shared_ptr<restbed::Session>& session)
// The listener is not found, so add it.
listener.internalToken = dht_->listen(infoHash,
[this, infoHash, pushToken, isAndroid, clientId](std::vector<std::shared_ptr<Value>> /*value*/) {
// Build message content.
Json::Value json;
json["key"] = infoHash.toString();
json["to"] = clientId;
sendPushNotification(pushToken, json, isAndroid);
[this, infoHash, pushToken, isAndroid, clientId](const std::vector<std::shared_ptr<Value>>& values, bool expired) {
threadPool_->run([this, infoHash, pushToken, isAndroid, clientId, values, expired]() {
// Build message content
Json::Value json;
json["key"] = infoHash.toString();
json["to"] = clientId;
if (expired and values.size() < 3) {
std::stringstream ss;
for(size_t i = 0; i < values.size(); ++i) {
if(i != 0) ss << ",";
ss << values[i]->id;
}
json["exp"] = ss.str();
}
sendPushNotification(pushToken, std::move(json), isAndroid);
});
return true;
}
);
@@ -493,7 +491,7 @@ DhtProxyServer::subscribe(const std::shared_ptr<restbed::Session>& session)
Json::Value json;
json["timeout"] = infoHash.toString();
json["to"] = clientId;
sendPushNotification(pushToken, json, isAndroid);
sendPushNotification(pushToken, std::move(json), isAndroid);
}
);
}
@@ -571,7 +569,7 @@ DhtProxyServer::cancelPushListen(const std::string& pushToken, const dht::InfoHa
}
void
DhtProxyServer::sendPushNotification(const std::string& token, const Json::Value& json, bool isAndroid) const
DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& json, bool isAndroid) const
{
if (pushServer_.empty())
return;
@@ -583,9 +581,9 @@ DhtProxyServer::sendPushNotification(const std::string& token, const Json::Value
Json::Value notification(Json::objectValue);
Json::Value tokens(Json::arrayValue);
tokens[0] = token;
notification["tokens"] = tokens;
notification["tokens"] = std::move(tokens);
notification["platform"] = isAndroid ? 2 : 1;
notification["data"] = json;
notification["data"] = std::move(json);
notification["priority"] = "high";
notification["time_to_live"] = 600;
@@ -593,7 +591,7 @@ DhtProxyServer::sendPushNotification(const std::string& token, const Json::Value
notifications[0] = notification;
Json::Value content;
content["notifications"] = notifications;
content["notifications"] = std::move(notifications);
Json::StreamWriterBuilder wbuilder;
wbuilder["commentStyle"] = "None";
@@ -684,7 +682,7 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session)
std::cout << "Permanent put expired: " << infoHash << " " << vid << std::endl;
cancelPut(infoHash, vid);
});
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not pushToken.empty()) {
pput.expireNotifyJob = scheduler_.add(timeout - proxy::OP_MARGIN,
[this, infoHash, vid, pushToken, clientId, isAndroid]
@@ -694,7 +692,7 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session)
json["timeout"] = infoHash.toString();
json["to"] = clientId;
json["vid"] = std::to_string(vid);
sendPushNotification(pushToken, json, isAndroid);
sendPushNotification(pushToken, std::move(json), isAndroid);
});
}
#endif
@@ -734,7 +732,7 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session)
);
}
#if OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
void
DhtProxyServer::putSigned(const std::shared_ptr<restbed::Session>& session) const
{
@@ -840,7 +838,7 @@ void
DhtProxyServer::handleOptionsMethod(const std::shared_ptr<restbed::Session>& session) const
{
requestNum_++;
#if OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
const auto allowed = "OPTIONS, GET, POST, LISTEN, SIGN, ENCRYPT";
#else
const auto allowed = "OPTIONS, GET, POST, LISTEN";
@@ -910,4 +908,3 @@ DhtProxyServer::removeClosedListeners(bool testSession)
}
}
#endif //OPENDHT_PROXY_SERVER
+33 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -21,7 +21,7 @@
#include "dhtrunner.h"
#include "securedht.h"
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
#include "dht_proxy_client.h"
#endif
@@ -55,7 +55,7 @@ struct DhtRunner::Listener {
};
DhtRunner::DhtRunner() : dht_()
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
, dht_via_proxy_()
#endif //OPENDHT_PROXY_CLIENT
{
@@ -75,7 +75,7 @@ DhtRunner::~DhtRunner()
}
void
DhtRunner::run(in_port_t port, DhtRunner::Config config)
DhtRunner::run(in_port_t port, const DhtRunner::Config& config)
{
SockAddr sin4;
sin4.setFamily(AF_INET);
@@ -87,7 +87,7 @@ DhtRunner::run(in_port_t port, DhtRunner::Config config)
}
void
DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner::Config config)
DhtRunner::run(const char* ip4, const char* ip6, const char* service, const DhtRunner::Config& config)
{
auto res4 = SockAddr::resolve(ip4, service);
auto res6 = SockAddr::resolve(ip6, service);
@@ -96,7 +96,7 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner:
}
void
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config config)
DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const DhtRunner::Config& config)
{
if (running)
return;
@@ -105,7 +105,7 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config)));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
config_ = config;
#endif
enableProxy(not config.proxy_server.empty());
@@ -151,7 +151,7 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config
void
DhtRunner::shutdown(ShutdownCallback cb) {
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(cb);
#endif
@@ -250,7 +250,7 @@ DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
std::lock_guard<std::mutex> lck(dht_mtx);
if (dht_)
dht_->setLoggers(error, warn, debug);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLoggers(error, warn, debug);
#endif
@@ -262,7 +262,7 @@ DhtRunner::setLogFilter(const InfoHash& f) {
activeDht()->setLogFilter(f);
if (dht_)
dht_->setLogFilter(f);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLogFilter(f);
#endif
@@ -376,7 +376,7 @@ DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
void
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method) {
std::lock_guard<std::mutex> lck(dht_mtx);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->setLocalCertificateStore(std::forward<CertificateStoreQuery>(query_method));
#endif
@@ -629,7 +629,7 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, vcb, dcb, std::move(f), std::move(w));
dht.get(hash, std::move(vcb), std::move(dcb), std::move(f), std::move(w));
});
}
cv.notify_all();
@@ -638,14 +638,14 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
void
DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb, Value::Filter f, Where w)
{
get(InfoHash::get(key), vcb, dcb, f, w);
get(InfoHash::get(key), std::move(vcb), std::move(dcb), std::move(f), std::move(w));
}
void
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, cb, done_cb, std::move(q));
dht.query(hash, std::move(cb), std::move(done_cb), std::move(q));
});
}
cv.notify_all();
@@ -658,7 +658,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
Listener listener {};
listener.hash = hash;
@@ -678,7 +678,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
listeners_.emplace(tokenbGlobal, std::move(listener));
ret_token->set_value(tokenbGlobal);
#else
ret_token->set_value(dht.listen(hash, vcb, f, w));
ret_token->set_value(dht.listen(hash, std::move(vcb), std::move(f), std::move(w)));
#endif
});
}
@@ -689,7 +689,7 @@ DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
std::future<size_t>
DhtRunner::listen(const std::string& key, GetCallback vcb, Value::Filter f, Where w)
{
return listen(InfoHash::get(key), vcb, f, w);
return listen(InfoHash::get(key), std::move(vcb), std::move(f), std::move(w));
}
void
@@ -697,7 +697,7 @@ DhtRunner::cancelListen(InfoHash h, size_t token)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(token);
if (it == listeners_.end()) return;
@@ -721,7 +721,7 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
{
{
std::lock_guard<std::mutex> lck(storage_mtx);
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
pending_ops.emplace([=](SecureDht&) {
auto it = listeners_.find(ftoken.get());
if (it == listeners_.end()) return;
@@ -768,7 +768,7 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
void
DhtRunner::put(const std::string& key, Value&& value, DoneCallbackSimple cb, time_point created, bool permanent)
{
put(InfoHash::get(key), std::forward<Value>(value), cb, created, permanent);
put(InfoHash::get(key), std::forward<Value>(value), std::move(cb), created, permanent);
}
void
@@ -798,13 +798,13 @@ DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback c
void
DhtRunner::putSigned(InfoHash hash, Value&& value, DoneCallback cb)
{
putSigned(hash, std::make_shared<Value>(std::move(value)), cb);
putSigned(hash, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple cb)
{
putSigned(InfoHash::get(key), std::forward<Value>(value), cb);
putSigned(InfoHash::get(key), std::forward<Value>(value), std::move(cb));
}
void
@@ -822,13 +822,13 @@ DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), cb);
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb));
}
void
DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb)
{
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb));
}
void
@@ -973,7 +973,7 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const std::shared_p
void
DhtRunner::resetDht()
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
listeners_.clear();
dht_via_proxy_.reset();
#endif // OPENDHT_PROXY_CLIENT
@@ -983,7 +983,7 @@ DhtRunner::resetDht()
SecureDht*
DhtRunner::activeDht() const
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
return use_proxy? dht_via_proxy_.get() : dht_.get();
#else
return dht_.get();
@@ -993,7 +993,7 @@ DhtRunner::activeDht() const
void
DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeId)
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (config_.proxy_server == proxy and config_.push_node_id == pushNodeId)
return;
config_.proxy_server = proxy;
@@ -1008,7 +1008,7 @@ DhtRunner::setProxyServer(const std::string& proxy, const std::string& pushNodeI
void
DhtRunner::enableProxy(bool proxify)
{
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_) {
dht_via_proxy_->shutdown({});
}
@@ -1026,7 +1026,7 @@ DhtRunner::enableProxy(bool proxify)
}, config_.proxy_server, config_.push_node_id)
);
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
if (not pushToken_.empty())
dht_via_proxy_->setPushNotificationToken(pushToken_);
#endif
@@ -1059,8 +1059,8 @@ DhtRunner::enableProxy(bool proxify)
void
DhtRunner::forwardAllMessages(bool forward)
{
#if OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->forwardAllMessages(forward);
#endif // OPENDHT_PROXY_CLIENT
@@ -1074,7 +1074,7 @@ DhtRunner::forwardAllMessages(bool forward)
*/
void
DhtRunner::setPushNotificationToken(const std::string& token) {
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
pushToken_ = token;
if (dht_via_proxy_)
dht_via_proxy_->setPushNotificationToken(token);
@@ -1084,7 +1084,7 @@ DhtRunner::setPushNotificationToken(const std::string& token) {
void
DhtRunner::pushNotificationReceived(const std::map<std::string, std::string>& data)
{
#if OPENDHT_PROXY_CLIENT && OPENDHT_PUSH_NOTIFICATIONS
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
{
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht&) {
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Nicolas Reynaud <nicolas.reynaud@savoirfairelinux.com>
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+139 -131
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -142,19 +142,27 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, const int& s, const int& s6)
: myid(zeroes), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, const int& s, const int& s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
decltype(NetworkEngine::onPing) onPing,
decltype(NetworkEngine::onFindNode) onFindNode,
decltype(NetworkEngine::onGetValues) onGetValues,
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce,
decltype(NetworkEngine::onRefresh) onRefresh) :
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), onRefresh(onRefresh), myid(myid),
network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
decltype(NetworkEngine::onError)&& onError,
decltype(NetworkEngine::onNewNode)&& onNewNode,
decltype(NetworkEngine::onReportedAddr)&& onReportedAddr,
decltype(NetworkEngine::onPing)&& onPing,
decltype(NetworkEngine::onFindNode)&& onFindNode,
decltype(NetworkEngine::onGetValues)&& onGetValues,
decltype(NetworkEngine::onListen)&& onListen,
decltype(NetworkEngine::onAnnounce)&& onAnnounce,
decltype(NetworkEngine::onRefresh)&& onRefresh) :
onError(std::move(onError)),
onNewNode(std::move(onNewNode)),
onReportedAddr(std::move(onReportedAddr)),
onPing(std::move(onPing)),
onFindNode(std::move(onFindNode)),
onGetValues(std::move(onGetValues)),
onListen(std::move(onListen)),
onAnnounce(std::move(onAnnounce)),
onRefresh(std::move(onRefresh)),
myid(myid), network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{
if (dht_socket >= 0) {
if (!set_nonblocking(dht_socket, 1))
@@ -191,23 +199,23 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("u"));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
if (not values.empty()) {
pk.pack(std::string("re"));
pk.pack(KEY_REQ_REFRESHED);
pk.pack(values);
DHT_LOG.d(n->id, "[node %s] sending %zu refreshed values", n->toString().c_str(), values.size());
}
pk.pack(std::string("t")); pk.pack(socket_id);
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -221,23 +229,23 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("u"));
pk.pack(KEY_U);
pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
if (not values.empty()) {
pk.pack(std::string("exp"));
pk.pack(KEY_REQ_EXPIRED);
pk.pack(values);
DHT_LOG.d(n->id, "[node %s] sending %zu expired values", n->toString().c_str(), values.size());
}
pk.pack(std::string("t")); pk.pack(socket_id);
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_TID); pk.pack(socket_id);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -687,16 +695,16 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(1);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_A); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(std::string("q")); pk.pack(std::string("ping"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_PING);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node,
@@ -724,17 +732,17 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) {
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
@@ -748,23 +756,23 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("target")); pk.pack(target);
pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0));
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_TARGET); pk.pack(target);
if (want > 0) {
pk.pack(std::string("w"));
pk.pack(KEY_REQ_WANT);
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
if (want & WANT4) pk.pack(AF_INET);
if (want & WANT6) pk.pack(AF_INET6);
}
pk.pack(std::string("q")); pk.pack(std::string("find"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_FIND);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n,
@@ -794,26 +802,26 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query&
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(2 +
pk.pack(KEY_A); pk.pack_map(2 +
(query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) +
(want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(info_hash);
pk.pack(std::string("q")); pk.pack(query);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(info_hash);
pk.pack(KEY_Q); pk.pack(query);
if (want > 0) {
pk.pack(std::string("w"));
pk.pack(KEY_REQ_WANT);
pk.pack_array(((want & WANT4)?1:0) + ((want & WANT6)?1:0));
if (want & WANT4) pk.pack(AF_INET);
if (want & WANT6) pk.pack(AF_INET6);
}
pk.pack(std::string("q")); pk.pack(std::string("get"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_GET);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n,
@@ -901,13 +909,13 @@ NetworkEngine::packValueHeader(msgpack::sbuffer& buffer, const std::vector<Sp<Va
total_size += v.size();
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack(std::string("values"));
pk.pack(KEY_REQ_VALUES);
pk.pack_array(svals.size());
// try to put everything in a single UDP packet
if (svals.size() < 50 && total_size < MAX_PACKET_VALUE_SIZE) {
for (const auto& b : svals)
buffer.write((const char*)b.data(), b.size());
DHT_LOG.d("sending %lu bytes of values", total_size);
// DHT_LOG.d("sending %lu bytes of values", total_size);
svals.clear();
} else {
for (const auto& b : svals)
@@ -929,12 +937,12 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(3+(network?1:0));
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
pk.pack(std::string("y")); pk.pack(std::string("v"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Y); pk.pack(KEY_V);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("p")); pk.pack_map(1);
pk.pack(KEY_V); pk.pack_map(1);
pk.pack(i); pk.pack_map(2);
pk.pack(std::string("o")); pk.pack(start);
pk.pack(std::string("d")); pk.pack_bin(end-start);
@@ -954,22 +962,22 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r"));
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));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
if (nodes.size() > 0) {
pk.pack(std::string("n4"));
pk.pack(KEY_REQ_NODES4);
pk.pack_bin(nodes.size());
pk.pack_bin_body((const char*)nodes.data(), nodes.size());
}
if (nodes6.size() > 0) {
pk.pack(std::string("n6"));
pk.pack(KEY_REQ_NODES6);
pk.pack_bin(nodes6.size());
pk.pack_bin_body((const char*)nodes6.data(), nodes6.size());
}
if (not token.empty()) {
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
}
std::vector<Blob> svals {};
if (not st.empty()) { /* pack complete values */
@@ -977,7 +985,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
if (fields.empty()) {
svals = packValueHeader(buffer, st);
} else { /* pack fields */
pk.pack(std::string("fields"));
pk.pack(KEY_REQ_FIELDS);
pk.pack_map(2);
pk.pack(std::string("f")); pk.pack(fields);
pk.pack(std::string("v")); pk.pack_array(st.size()*fields.size());
@@ -989,12 +997,12 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes,
}
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
// send response
@@ -1086,23 +1094,23 @@ NetworkEngine::sendListen(Sp<Node> n,
pk.pack_map(5+(network?1:0));
auto has_query = query.where.getFilter() or not query.select.getSelection().empty();
pk.pack(std::string("a")); pk.pack_map(4 + has_query);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(hash);
pk.pack(std::string("token")); packToken(pk, token);
pk.pack(std::string("sid")); pk.pack_bin(sid.size());
pk.pack_bin_body((const char*)sid.data(), sid.size());
pk.pack(KEY_A); pk.pack_map(4 + has_query);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(hash);
pk.pack(KEY_REQ_TOKEN); packToken(pk, token);
pk.pack(KEY_REQ_SID); pk.pack_bin(sid.size());
pk.pack_bin_body((const char*)sid.data(), sid.size());
if (has_query) {
pk.pack(std::string("q")); pk.pack(query);
pk.pack(KEY_REQ_QUERY); pk.pack(query);
}
pk.pack(std::string("q")); pk.pack(std::string("listen"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_LISTEN);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n,
@@ -1128,17 +1136,17 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) {
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(2);
pk.pack(KEY_REQ_ID); pk.pack(myid);
insertAddr(pk, addr);
TransId t (tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
@@ -1158,23 +1166,23 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(infohash);
pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(infohash);
auto v = packValueHeader(buffer, {value});
if (created < scheduler.time()) {
pk.pack(std::string("c"));
pk.pack(KEY_REQ_CREATION);
pk.pack(to_time_t(created));
}
pk.pack(std::string("token")); pk.pack(token);
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
pk.pack(std::string("q")); pk.pack(std::string("put"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Q); pk.pack(QUERY_PUT);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n,
@@ -1216,19 +1224,19 @@ NetworkEngine::sendRefreshValue(Sp<Node> n,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack(std::string("a")); pk.pack_map(4);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("h")); pk.pack(infohash);
pk.pack(std::string("vid")); pk.pack(vid);
pk.pack(std::string("token")); pk.pack(token);
pk.pack(KEY_A); pk.pack_map(4);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_H); pk.pack(infohash);
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
pk.pack(KEY_REQ_TOKEN); pk.pack(token);
pk.pack(std::string("q")); pk.pack(std::string("refresh"));
pk.pack(std::string("t")); pk.pack_bin(tid.size());
pk.pack(KEY_Q); pk.pack(QUERY_REFRESH);
pk.pack(KEY_TID); pk.pack_bin(tid.size());
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_Q);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n,
@@ -1261,18 +1269,18 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid)
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack(std::string("r")); pk.pack_map(3);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(std::string("vid")); pk.pack(vid);
pk.pack(KEY_R); pk.pack_map(3);
pk.pack(KEY_REQ_ID); pk.pack(myid);
pk.pack(KEY_REQ_VALUE_ID); pk.pack(vid);
insertAddr(pk, addr);
TransId t(tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_R);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
@@ -1289,22 +1297,22 @@ NetworkEngine::sendError(const SockAddr& addr,
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4 + (include_id?1:0));
pk.pack(std::string("e")); pk.pack_array(2);
pk.pack(KEY_E); pk.pack_array(2);
pk.pack(code);
pk.pack(message);
if (include_id) {
pk.pack(std::string("r")); pk.pack_map(1);
pk.pack(std::string("id")); pk.pack(myid);
pk.pack(KEY_R); pk.pack_map(1);
pk.pack(KEY_REQ_ID); pk.pack(myid);
}
TransId t(tid);
pk.pack(std::string("t")); pk.pack_bin(t.size());
pk.pack(KEY_TID); pk.pack_bin(t.size());
pk.pack_bin_body((const char*)t.data(), t.size());
pk.pack(std::string("y")); pk.pack(std::string("e"));
pk.pack(std::string("v")); pk.pack(my_v);
pk.pack(KEY_Y); pk.pack(KEY_E);
pk.pack(KEY_UA); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
pk.pack(KEY_NETID); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, addr);
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -49,7 +49,7 @@ Node::isGood(time_point now) const
bool
Node::isPendingMessage() const
{
for (auto r : requests_) {
for (const auto& r : requests_) {
if (r.second->pending())
return true;
}
@@ -60,7 +60,7 @@ size_t
Node::getPendingMessageCount() const
{
size_t count {0};
for (auto r : requests_) {
for (const auto& r : requests_) {
if (r.second->pending())
count++;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+23 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -34,6 +34,7 @@ OpValueCache::onValuesAdded(const std::vector<Sp<Value>>& vals) {
}
return newValues.empty() ? true : callback(newValues, false);
}
bool
OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
std::vector<Sp<Value>> expiredValues;
@@ -49,6 +50,24 @@ OpValueCache::onValuesExpired(const std::vector<Sp<Value>>& vals) {
}
return expiredValues.empty() ? true : callback(expiredValues, true);
}
bool
OpValueCache::onValuesExpired(const std::vector<Value::Id>& vids)
{
std::vector<Sp<Value>> expiredValues;
for (const auto& vid : vids) {
auto vit = values.find(vid);
if (vit != values.end()) {
vit->second.refCount--;
if (not vit->second.refCount) {
expiredValues.emplace_back(std::move(vit->second.data));
values.erase(vit);
}
}
}
return expiredValues.empty() ? true : callback(expiredValues, true);
}
std::vector<Sp<Value>>
OpValueCache::get(const Value::Filter& filter) const {
std::vector<Sp<Value>> ret;
@@ -141,7 +160,7 @@ SearchCache::getOp(const Sp<Query>& q) const
}
size_t
SearchCache::listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, OnListen onListen)
SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
{
// find exact match
auto op = getOp(q);
@@ -173,7 +192,7 @@ SearchCache::cancelListen(size_t gtoken, const time_point& now) {
}
void
SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
SearchCache::cancelAll(const std::function<void(size_t)>& onCancel) {
for (auto& op : ops) {
auto cache = std::move(op.second);
cache->removeAll();
@@ -183,7 +202,7 @@ SearchCache::cancelAll(std::function<void(size_t)> onCancel) {
}
time_point
SearchCache::expire(const time_point& now, std::function<void(size_t)> onCancel) {
SearchCache::expire(const time_point& now, const std::function<void(size_t)>& onCancel) {
nextExpiration_ = time_point::max();
auto ret = nextExpiration_;
for (auto it = ops.begin(); it != ops.end();) {
+8 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -32,8 +32,8 @@ struct OpCacheValueStorage
class OpValueCache {
public:
OpValueCache(ValueCallback&& cb) : callback(std::forward<ValueCallback>(cb)) {}
OpValueCache(OpValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)) {
OpValueCache(ValueCallback&& cb) noexcept : callback(std::forward<ValueCallback>(cb)) {}
OpValueCache(OpValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)) {
o.callback = {};
}
@@ -56,6 +56,7 @@ public:
bool onValuesAdded(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Sp<Value>>& vals);
bool onValuesExpired(const std::vector<Value::Id>& vals);
void onNodeChanged(ListenSyncStatus status) {
switch (status) {
@@ -103,7 +104,7 @@ public:
void onValuesAdded(const std::vector<Sp<Value>>& vals);
void onValuesExpired(const std::vector<Sp<Value>>& vals);
bool addListener(size_t token, ValueCallback cb, Sp<Query> q, Value::Filter filter) {
bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
listeners.emplace(token, LocalListener{q, filter, cb});
auto cached = cache.get(filter);
if (not cached.empty()) {
@@ -162,12 +163,12 @@ public:
SearchCache(SearchCache&&) = default;
using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
size_t listen(ValueCallback get_cb, Sp<Query> q, Value::Filter filter, OnListen onListen);
size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
bool cancelListen(size_t gtoken, const time_point& now);
void cancelAll(std::function<void(size_t)> onCancel);
void cancelAll(const std::function<void(size_t)>& onCancel);
time_point expire(const time_point& now, std::function<void(size_t)> onCancel);
time_point expire(const time_point& now, const std::function<void(size_t)>& onCancel);
time_point getExpiration() const {
return nextExpiration_;
}
+156 -93
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,42 @@
namespace dht {
namespace net {
static const std::string KEY_Y {"y"};
static const std::string KEY_R {"r"};
static const std::string KEY_U {"u"};
static const std::string KEY_E {"e"};
static const std::string KEY_V {"p"};
static const std::string KEY_TID {"t"};
static const std::string KEY_UA {"v"};
static const std::string KEY_NETID {"n"};
static const std::string KEY_ISCLIENT {"s"};
static const std::string KEY_Q {"q"};
static const std::string KEY_A {"a"};
static const std::string KEY_REQ_SID {"sid"};
static const std::string KEY_REQ_ID {"id"};
static const std::string KEY_REQ_H {"h"};
static const std::string KEY_REQ_TARGET {"target"};
static const std::string KEY_REQ_QUERY {"q"};
static const std::string KEY_REQ_TOKEN {"token"};
static const std::string KEY_REQ_VALUE_ID {"vid"};
static const std::string KEY_REQ_NODES4 {"n4"};
static const std::string KEY_REQ_NODES6 {"n6"};
static const std::string KEY_REQ_CREATION {"c"};
static const std::string KEY_REQ_ADDRESS {"sa"};
static const std::string KEY_REQ_VALUES {"values"};
static const std::string KEY_REQ_EXPIRED {"exp"};
static const std::string KEY_REQ_REFRESHED {"re"};
static const std::string KEY_REQ_FIELDS {"fileds"};
static const std::string KEY_REQ_WANT {"w"};
static const std::string QUERY_PING {"ping"};
static const std::string QUERY_FIND {"find"};
static const std::string QUERY_GET {"get"};
static const std::string QUERY_PUT {"put"};
static const std::string QUERY_LISTEN {"listen"};
static const std::string QUERY_REFRESH {"refresh"};
Tid unpackTid(const msgpack::object& o) {
switch (o.type) {
case msgpack::type::POSITIVE_INTEGER:
@@ -78,7 +114,7 @@ struct ParsedMessage {
/* reported address by the distant node */
std::string ua;
SockAddr addr;
void msgpack_unpack(msgpack::object o);
void msgpack_unpack(const msgpack::object& o);
bool append(const ParsedMessage& block);
bool complete();
@@ -123,63 +159,79 @@ ParsedMessage::complete()
}
void
ParsedMessage::msgpack_unpack(msgpack::object msg)
ParsedMessage::msgpack_unpack(const msgpack::object& msg)
{
auto y = findMapValue(msg, "y");
auto r = findMapValue(msg, "r");
auto u = findMapValue(msg, "u");
auto e = findMapValue(msg, "e");
auto v = findMapValue(msg, "p");
if (msg.type != msgpack::type::MAP) throw msgpack::type_error();
if (auto t = findMapValue(msg, "t"))
tid = unpackTid(*t);
struct ParsedMsg {
msgpack::object* y;
msgpack::object* r;
msgpack::object* u;
msgpack::object* e;
msgpack::object* v;
msgpack::object* a;
std::string q;
} parsed {};
if (auto rv = findMapValue(msg, "v"))
ua = rv->as<std::string>();
if (auto netid = findMapValue(msg, "n"))
network = netid->as<NetId>();
if (auto is_client_v = findMapValue(msg, "s"))
is_client = is_client_v->as<bool>();
std::string q;
if (auto rq = findMapValue(msg, "q")) {
if (rq->type != msgpack::type::STR)
throw msgpack::type_error();
q = rq->as<std::string>();
for (unsigned i = 0; i < msg.via.map.size; i++) {
auto& o = msg.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
continue;
auto key = o.key.as<std::string>();
if (key == KEY_Y)
parsed.y = &o.val;
else if (key == KEY_R)
parsed.r = &o.val;
else if (key == KEY_U)
parsed.u = &o.val;
else if (key == KEY_E)
parsed.e = &o.val;
else if (key == KEY_V)
parsed.v = &o.val;
else if (key == KEY_TID)
tid = unpackTid(o.val);
else if (key == KEY_UA)
ua = o.val.as<std::string>();
else if (key == KEY_NETID)
network = o.val.as<NetId>();
else if (key == KEY_ISCLIENT)
is_client = o.val.as<bool>();
else if (key == KEY_Q)
parsed.q = o.val.as<std::string>();
else if (key == KEY_A)
parsed.a = &o.val;
}
if (e)
if (parsed.e)
type = MessageType::Error;
else if (r)
else if (parsed.r)
type = MessageType::Reply;
else if (v)
else if (parsed.v)
type = MessageType::ValueData;
else if (u)
else if (parsed.u)
type = MessageType::ValueUpdate;
else if (y and y->as<std::string>() != "q")
else if (parsed.y and parsed.y->as<std::string>() != "q")
throw msgpack::type_error();
else if (q == "ping")
else if (parsed.q == QUERY_PING)
type = MessageType::Ping;
else if (q == "find")
else if (parsed.q == QUERY_FIND)
type = MessageType::FindNode;
else if (q == "get")
else if (parsed.q == QUERY_GET)
type = MessageType::GetValues;
else if (q == "listen")
else if (parsed.q == QUERY_LISTEN)
type = MessageType::Listen;
else if (q == "put")
else if (parsed.q == QUERY_PUT)
type = MessageType::AnnounceValue;
else if (q == "refresh")
else if (parsed.q == QUERY_REFRESH)
type = MessageType::Refresh;
else
throw msgpack::type_error();
if (type == MessageType::ValueData) {
if (v->type != msgpack::type::MAP)
if (parsed.v->type != msgpack::type::MAP)
throw msgpack::type_error();
for (size_t i = 0; i < v->via.map.size; ++i) {
auto& vdat = v->via.map.ptr[i];
for (size_t i = 0; i < parsed.v->via.map.size; ++i) {
auto& vdat = parsed.v->via.map.ptr[i];
auto o = findMapValue(vdat.val, "o");
auto d = findMapValue(vdat.val, "d");
if (not o or not d)
@@ -189,70 +241,85 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
return;
}
auto a = findMapValue(msg, "a");
if (!a && !r && !e && !u)
if (!parsed.a && !parsed.r && !parsed.e && !parsed.u)
throw msgpack::type_error();
auto& req = a ? *a : (r ? *r : (u ? *u : *e));
auto& req = parsed.a ? *parsed.a : (parsed.r ? *parsed.r : (parsed.u ? *parsed.u : *parsed.e));
if (e) {
if (e->type != msgpack::type::ARRAY)
if (parsed.e) {
if (parsed.e->type != msgpack::type::ARRAY)
throw msgpack::type_error();
error_code = e->via.array.ptr[0].as<uint16_t>();
error_code = parsed.e->via.array.ptr[0].as<uint16_t>();
}
if (auto t = findMapValue(req, "sid"))
socket_id = unpackTid(*t);
struct ParsedReq {
msgpack::object* values;
msgpack::object* fields;
msgpack::object* sa;
msgpack::object* want;
} parsedReq {};
if (auto rid = findMapValue(req, "id"))
id = {*rid};
for (unsigned i = 0; i < req.via.map.size; i++) {
auto& o = req.via.map.ptr[i];
if (o.key.type != msgpack::type::STR)
continue;
auto key = o.key.as<std::string>();
if (key == KEY_REQ_SID)
socket_id = unpackTid(o.val);
else if (key == KEY_REQ_ID)
id = {o.val};
else if (key == KEY_REQ_H)
info_hash = {o.val};
else if (key == KEY_REQ_TARGET)
target = {o.val};
else if (key == KEY_REQ_QUERY)
query.msgpack_unpack(o.val);
else if (key == KEY_REQ_TOKEN)
token = unpackBlob(o.val);
else if (key == KEY_REQ_VALUE_ID)
value_id = o.val.as<Value::Id>();
else if (key == KEY_REQ_NODES4)
nodes4_raw = unpackBlob(o.val);
else if (key == KEY_REQ_NODES6)
nodes6_raw = unpackBlob(o.val);
else if (key == KEY_REQ_ADDRESS)
parsedReq.sa = &o.val;
else if (key == KEY_REQ_CREATION)
created = from_time_t(o.val.as<std::time_t>());
else if (key == KEY_REQ_VALUES)
parsedReq.values = &o.val;
else if (key == KEY_REQ_EXPIRED)
expired_values = o.val.as<decltype(expired_values)>();
else if (key == KEY_REQ_REFRESHED)
refreshed_values = o.val.as<decltype(refreshed_values)>();
else if (key == KEY_REQ_FIELDS)
parsedReq.fields = &o.val;
else if (key == KEY_REQ_WANT)
parsedReq.want = &o.val;
}
if (auto rh = findMapValue(req, "h"))
info_hash = {*rh};
if (auto rtarget = findMapValue(req, "target"))
target = {*rtarget};
if (auto rquery = findMapValue(req, "q"))
query.msgpack_unpack(*rquery);
if (auto otoken = findMapValue(req, "token"))
token = unpackBlob(*otoken);
if (auto vid = findMapValue(req, "vid"))
value_id = vid->as<Value::Id>();
if (auto rnodes4 = findMapValue(req, "n4"))
nodes4_raw = unpackBlob(*rnodes4);
if (auto rnodes6 = findMapValue(req, "n6"))
nodes6_raw = unpackBlob(*rnodes6);
if (auto sa = findMapValue(req, "sa")) {
if (sa->type != msgpack::type::BIN)
if (parsedReq.sa) {
if (parsedReq.sa->type != msgpack::type::BIN)
throw msgpack::type_error();
auto l = sa->via.bin.size;
auto l = parsedReq.sa->via.bin.size;
if (l == sizeof(in_addr)) {
addr.setFamily(AF_INET);
auto& a = addr.getIPv4();
a.sin_port = 0;
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin_addr);
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin_addr);
} else if (l == sizeof(in6_addr)) {
addr.setFamily(AF_INET6);
auto& a = addr.getIPv6();
a.sin6_port = 0;
std::copy_n(sa->via.bin.ptr, l, (char*)&a.sin6_addr);
std::copy_n(parsedReq.sa->via.bin.ptr, l, (char*)&a.sin6_addr);
}
} else
addr = {};
if (auto rcreated = findMapValue(req, "c"))
created = from_time_t(rcreated->as<std::time_t>());
if (auto rvalues = findMapValue(req, "values")) {
if (rvalues->type != msgpack::type::ARRAY)
if (parsedReq.values) {
if (parsedReq.values->type != msgpack::type::ARRAY)
throw msgpack::type_error();
for (size_t i = 0; i < rvalues->via.array.size; i++) {
auto& packed_v = rvalues->via.array.ptr[i];
for (size_t i = 0; i < parsedReq.values->via.array.size; i++) {
auto& packed_v = parsedReq.values->via.array.ptr[i];
if (packed_v.type == msgpack::type::POSITIVE_INTEGER) {
// Skip oversize values with a small margin for header overhead
if (packed_v.via.u64 > MAX_VALUE_SIZE + 32)
@@ -260,16 +327,16 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
value_parts.emplace(i, std::make_pair(packed_v.via.u64, Blob{}));
} else {
try {
values.emplace_back(std::make_shared<Value>(rvalues->via.array.ptr[i]));
values.emplace_back(std::make_shared<Value>(parsedReq.values->via.array.ptr[i]));
} catch (const std::exception& e) {
//DHT_LOG_WARN("Error reading value: %s", e.what());
}
}
}
} else if (auto raw_fields = findMapValue(req, "fields")) {
if (auto rfields = findMapValue(*raw_fields, "f")) {
} else if (parsedReq.fields) {
if (auto rfields = findMapValue(*parsedReq.fields, "f")) {
auto vfields = rfields->as<std::set<Value::Field>>();
if (auto rvalues = findMapValue(*raw_fields, "v")) {
if (auto rvalues = findMapValue(*parsedReq.fields, "v")) {
if (rvalues->type != msgpack::type::ARRAY)
throw msgpack::type_error();
size_t val_num = rvalues->via.array.size / vfields.size();
@@ -284,18 +351,14 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
} else {
throw msgpack::type_error();
}
} else if (auto raw_fields = findMapValue(req, "exp")) {
expired_values = raw_fields->as<decltype(expired_values)>();
} else if (auto raw_fields = findMapValue(req, "re")) {
refreshed_values = raw_fields->as<decltype(refreshed_values)>();
}
if (auto w = findMapValue(req, "w")) {
if (w->type != msgpack::type::ARRAY)
if (parsedReq.want) {
if (parsedReq.want->type != msgpack::type::ARRAY)
throw msgpack::type_error();
want = 0;
for (unsigned i=0; i<w->via.array.size; i++) {
auto& val = w->via.array.ptr[i];
for (unsigned i=0; i<parsedReq.want->via.array.size; i++) {
auto& val = parsedReq.want->via.array.ptr[i];
try {
auto w = val.as<sa_family_t>();
if (w == AF_INET)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -92,7 +92,7 @@ RoutingTable::middle(const RoutingTable::const_iterator& it) const
throw std::out_of_range("End of table");
InfoHash id = it->first;
id.setBit(bit, 1);
id.setBit(bit, true);
return id;
}
+4 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2018 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -387,7 +387,6 @@ struct Dht::Search {
/* listeners */
struct SearchListener {
Sp<Query> query;
Value::Filter filter;
ValueCallback get_cb;
SyncCallback sync_cb;
};
@@ -489,7 +488,7 @@ struct Dht::Search {
bool isAnnounced(Value::Id id) const;
bool isListening(time_point now) const;
void get(Value::Filter f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
void get(const Value::Filter& f, const Sp<Query>& q, const QueryCallback& qcb, const GetCallback& gcb, const DoneCallback& dcb, Scheduler& scheduler) {
if (gcb or qcb) {
if (not cache.get(f, q, gcb, dcb)) {
const auto& now = scheduler.time();
@@ -499,12 +498,12 @@ struct Dht::Search {
}
}
size_t listen(ValueCallback cb, Value::Filter f, const Sp<Query>& q, Scheduler& scheduler) {
size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
//DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
done = false;
auto token = ++listener_token;
listeners.emplace(token, SearchListener{q, f, vcb, scb});
listeners.emplace(token, SearchListener{q, vcb, scb});
scheduler.edit(nextSearchStep, scheduler.time());
return token;
});
+7 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
* Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -61,8 +61,7 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
}
}
SecureDht::~SecureDht()
{}
SecureDht::~SecureDht() = default;
ValueType
SecureDht::secureType(ValueType&& type)
@@ -166,7 +165,7 @@ SecureDht::registerCertificate(Sp<crypto::Certificate>& cert)
}
void
SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<crypto::Certificate>)> cb)
SecureDht::findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb)
{
Sp<crypto::Certificate> b = getCertificate(node);
if (b && *b) {
@@ -207,7 +206,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const Sp<cry
}
void
SecureDht::findPublicKey(const InfoHash& node, std::function<void(const Sp<const crypto::PublicKey>)> cb)
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
@@ -235,7 +234,7 @@ SecureDht::checkValue(const Sp<Value>& v)
// Decrypt encrypted values
if (v->isEncrypted()) {
if (not key_) {
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
if (forward_all_) // We are currently a proxy, send messages to clients.
return v;
#endif
@@ -280,7 +279,7 @@ SecureDht::checkValue(const Sp<Value>& v)
}
ValueCallback
SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
SecureDht::getCallbackFilter(const ValueCallback& cb, Value::Filter&& filter)
{
return [=](const std::vector<Sp<Value>>& values, bool expired) {
std::vector<Sp<Value>> tmpvals {};
@@ -299,7 +298,7 @@ SecureDht::getCallbackFilter(ValueCallback cb, Value::Filter&& filter)
GetCallback
SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
SecureDht::getCallbackFilter(const GetCallback& cb, Value::Filter&& filter)
{
return [=](const std::vector<Sp<Value>>& values) {
std::vector<Sp<Value>> tmpvals {};
+23 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -90,20 +90,7 @@ struct Storage {
Storage() {}
Storage(time_point t) : maintenance_time(t) {}
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 || defined(_WIN32)
// GCC-bug: remove me when support of GCC < 4.9.2 is abandoned
Storage(Storage&& o) noexcept
: maintenance_time(std::move(o.maintenance_time))
, listeners(std::move(o.listeners))
, local_listeners(std::move(o.local_listeners))
, listener_token(std::move(o.listener_token))
, values(std::move(o.values))
, total_size(std::move(o.total_size)) {}
#else
Storage(Storage&& o) noexcept = default;
#endif
Storage& operator=(Storage&& o) = default;
bool empty() const {
@@ -166,6 +153,12 @@ struct Storage {
return time_point::max();
}
size_t listen(ValueCallback& cb, Value::Filter& f, const Sp<Query>& q);
void cancelListen(size_t token) {
local_listeners.erase(token);
}
StoreDiff remove(const InfoHash& id, Value::Id);
std::pair<ssize_t, std::vector<Sp<Value>>> expire(const InfoHash& id, time_point now);
@@ -179,6 +172,22 @@ private:
};
size_t
Storage::listen(ValueCallback& gcb, Value::Filter& filter, const Sp<Query>& query)
{
if (not empty()) {
std::vector<Sp<Value>> newvals = get(filter);
if (not newvals.empty()) {
if (!gcb(newvals, false))
return 0;
}
}
auto tokenlocal = ++listener_token;
local_listeners.emplace(tokenlocal, LocalListener{query, filter, gcb});
return tokenlocal;
}
std::pair<ValueStorage*, Storage::StoreDiff>
Storage::store(const InfoHash& id, const Sp<Value>& value, time_point created, time_point expiration, StorageBucket* sb)
{
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "thread_pool.h"
#include <atomic>
#include <thread>
#include <ciso646> // fix windows compiler bug
namespace dht {
constexpr const size_t IO_THREADS_MAX {64};
struct ThreadPool::ThreadState
{
std::thread thread {};
std::atomic_bool run {true};
};
ThreadPool&
ThreadPool::computation()
{
static ThreadPool pool;
return pool;
}
ThreadPool&
ThreadPool::io()
{
static ThreadPool pool(IO_THREADS_MAX);
return pool;
}
ThreadPool::ThreadPool(size_t maxThreads) : maxThreads_(maxThreads)
{
threads_.reserve(maxThreads_);
}
ThreadPool::ThreadPool()
: ThreadPool(std::max<size_t>(std::thread::hardware_concurrency(), 4))
{}
ThreadPool::~ThreadPool()
{
join();
}
void
ThreadPool::run(std::function<void()>&& cb)
{
std::unique_lock<std::mutex> l(lock_);
if (not running_) return;
// launch new thread if necessary
if (not readyThreads_ && threads_.size() < maxThreads_) {
threads_.emplace_back(new ThreadState());
auto& t = *threads_.back();
t.thread = std::thread([&]() {
while (t.run) {
std::function<void()> task;
// pick task from queue
{
std::unique_lock<std::mutex> l(lock_);
readyThreads_++;
cv_.wait(l, [&](){
return not t.run or not tasks_.empty();
});
readyThreads_--;
if (not t.run)
break;
task = std::move(tasks_.front());
tasks_.pop();
}
// run task
try {
if (task)
task();
} catch (const std::exception& e) {
// LOG_ERR("Exception running task: %s", e.what());
}
}
});
}
// push task to queue
tasks_.emplace(std::move(cb));
// notify thread
l.unlock();
cv_.notify_one();
}
void
ThreadPool::stop()
{
{
std::lock_guard<std::mutex> l(lock_);
running_ = false;
}
for (auto& t : threads_)
t->run = false;
cv_.notify_all();
}
void
ThreadPool::join()
{
stop();
for (auto& t : threads_)
t->thread.join();
threads_.clear();
}
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2016-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <condition_variable>
#include <vector>
#include <queue>
#include <future>
#include <functional>
namespace dht {
class ThreadPool {
public:
static ThreadPool& computation();
static ThreadPool& io();
ThreadPool();
ThreadPool(size_t maxThreads);
~ThreadPool();
void run(std::function<void()>&& cb);
template<class T>
std::future<T> get(std::function<T()>&& cb) {
auto ret = std::make_shared<std::promise<T>>();
run(std::bind([=](std::function<T()>& mcb) mutable {
ret->set_value(mcb());
}, std::move(cb)));
return ret->get_future();
}
template<class T>
std::shared_ptr<std::future<T>> getShared(std::function<T()>&& cb) {
return std::make_shared<std::future<T>>(get(std::move(cb)));
}
void stop();
void join();
private:
struct ThreadState;
std::queue<std::function<void()>> tasks_ {};
std::vector<std::unique_ptr<ThreadState>> threads_;
unsigned readyThreads_ {0};
std::mutex lock_ {};
std::condition_variable cv_ {};
const unsigned maxThreads_;
bool running_ {true};
};
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
+7 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
*
@@ -65,8 +65,8 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
} else {
s << "Data (type: " << v.type << " ): ";
s << std::hex;
for (size_t i=0; i<v.data.size(); i++)
s << std::setfill('0') << std::setw(2) << (unsigned)v.data[i];
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
}
}
@@ -78,7 +78,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
const ValueType ValueType::USER_DATA = {0, "User Data"};
bool
ValueType::DEFAULT_STORE_POLICY(InfoHash, std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr<Value>& v, const InfoHash&, const SockAddr&)
{
return v->size() <= MAX_VALUE_SIZE;
}
@@ -292,7 +292,7 @@ FieldValue::getLocalFilter() const
}
}
FieldValueIndex::FieldValueIndex(const Value& v, Select s)
FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
{
auto selection = s.getSelection();
if (not selection.empty()) {
@@ -399,8 +399,8 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
}
void trim_str(std::string& str) {
auto first = std::min(str.size(), str.find_first_not_of(" "));
auto last = std::min(str.size(), str.find_last_not_of(" "));
auto first = std::min(str.size(), str.find_first_not_of(' '));
auto last = std::min(str.size(), str.find_last_not_of(' '));
str = str.substr(first, last - first + 1);
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
* Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@ public:
if (syncCallback)
syncCallback(ListenSyncStatus::ADDED);
}
ValueCache(ValueCache&& o) : values(std::move(o.values)), callback(std::move(o.callback)), syncCallback(std::move(o.syncCallback)) {
ValueCache(ValueCache&& o) noexcept : values(std::move(o.values)), callback(std::move(o.callback)), syncCallback(std::move(o.syncCallback)) {
o.callback = {};
o.syncCallback = {};
}
+2 -2
View File
@@ -3,7 +3,7 @@ bin_PROGRAMS = opendht_unit_tests
AM_CPPFLAGS = -I../include
nobase_include_HEADERS = infohashtester.h cryptotester.h dhtrunnertester.h dhtproxytester.h
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp dhtrunnertester.cpp dhtproxytester.cpp
nobase_include_HEADERS = infohashtester.h valuetester.h cryptotester.h dhtrunnertester.h dhtproxytester.h
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp valuetester.cpp dhtrunnertester.cpp dhtproxytester.cpp
opendht_unit_tests_LDFLAGS = -lopendht -lcppunit -L@top_builddir@/src/.libs @GnuTLS_LIBS@
endif
+30 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -54,7 +54,6 @@ CryptoTester::testCertificateRevocation()
auto device11 = dht::crypto::generateIdentity("dev11", account1);
auto device12 = dht::crypto::generateIdentity("dev12", account1);
dht::crypto::TrustList list;
list.add(*ca1.second);
auto v = list.verify(*account1.second);
@@ -72,7 +71,7 @@ CryptoTester::testCertificateRevocation()
v = list.verify(*device2.second);
CPPUNIT_ASSERT_MESSAGE(v.toString(), !v);
account1.second->revoke(*account1.first, *device11.second);
dht::crypto::TrustList list2;
list2.add(*account1.second);
@@ -83,6 +82,34 @@ CryptoTester::testCertificateRevocation()
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::testCertificateRequest()
{
// Generate CA
auto ca = dht::crypto::generateIdentity("Test CA");
// Generate signed request
auto deviceKey = dht::crypto::PrivateKey::generate();
auto request = dht::crypto::CertificateRequest();
request.setName("Test Device");
request.sign(deviceKey);
// Export/import request
auto importedRequest = dht::crypto::CertificateRequest(request.pack());
CPPUNIT_ASSERT(importedRequest.verify());
// Generate/sign certificate from request
auto signedCert = dht::crypto::Certificate::generate(request, ca);
CPPUNIT_ASSERT_EQUAL(ca.second->getName(), signedCert.getIssuerName());
CPPUNIT_ASSERT_EQUAL(request.getName(), signedCert.getName());
// Check generated certificate
dht::crypto::TrustList list;
list.add(*ca.second);
auto v = list.verify(signedCert);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::tearDown() {
+6 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -29,6 +29,7 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CryptoTester);
CPPUNIT_TEST(testSignatureEncryption);
CPPUNIT_TEST(testCertificateRevocation);
CPPUNIT_TEST(testCertificateRequest);
CPPUNIT_TEST_SUITE_END();
public:
@@ -48,6 +49,10 @@ class CryptoTester : public CppUnit::TestFixture {
* Test certificate generation, validation and revocation
*/
void testCertificateRevocation();
/**
* Test certificate requests
*/
void testCertificateRequest();
};
} // namespace test
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+5 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
@@ -38,14 +38,13 @@ void
InfoHashTester::testConstructors() {
// Default constructor creates a null infohash
auto nullHash = dht::InfoHash();
CPPUNIT_ASSERT(nullHash.size() == 20);
CPPUNIT_ASSERT_EQUAL((size_t)20u, nullHash.size());
CPPUNIT_ASSERT(!nullHash);
// Build from a uint8_t. if length to short, should get a null infohash
uint8_t to_short[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
auto infohash = dht::InfoHash(to_short, 8);
CPPUNIT_ASSERT(infohash.size() == 20);
CPPUNIT_ASSERT_EQUAL(infohash.toString(),
std::string("0000000000000000000000000000000000000000"));
CPPUNIT_ASSERT_EQUAL((size_t)20u, infohash.size());
CPPUNIT_ASSERT_EQUAL(std::string("0000000000000000000000000000000000000000"), infohash.toString());
// Build from a uint8_t. if length is enough, data should contains the uint8_t
uint8_t enough[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa};
@@ -66,7 +65,7 @@ InfoHashTester::testConstructors() {
}
// Build from string
auto infohashFromStr = dht::InfoHash("0102030405060708090A0102030405060708090A");
CPPUNIT_ASSERT(infohashFromStr.size() == 20);
CPPUNIT_ASSERT_EQUAL((size_t)20u, infohashFromStr.size());
const auto* dataStr = infohashFromStr.data();
for (auto i = 0; i < 20; ++i) {
CPPUNIT_ASSERT_EQUAL((int)dataStr[i], (int)data[i]);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2018 Savoir-faire Linux Inc.
* Copyright (C) 2017-2019 Savoir-faire Linux Inc.
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include <cppunit/CompilerOutputter.h>
#include <iostream>
int main(int argc, char** argv) {
int main(int /*argc*/, char** /*argv*/) {
CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
CppUnit::Test *suite = registry.makeTest();
if (suite->countTestCases() == 0) {
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "valuetester.h"
#include <iostream>
#include <string>
// opendht
#include "opendht/value.h"
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(ValueTester);
void
ValueTester::setUp() {
}
void
ValueTester::testConstructors() {
std::string the_data {"42 cats"};
dht::Value the_dht_value {(const uint8_t*)the_data.data(), the_data.size()};
std::string from_value {the_dht_value.data.begin(), the_dht_value.data.end()};
CPPUNIT_ASSERT_EQUAL(the_data, from_value);
}
void
ValueTester::testFilter()
{
dht::Value::Filter defaultFiler {};
auto isPairSize = dht::Value::Filter([](const dht::Value& v) {
return v.data.size() % 2 == 0;
});
auto isUserTypeTest = dht::Value::Filter([](const dht::Value& v) {
return v.user_type == "test";
});
std::string data1 {"42 cats"};
dht::Value value1 {(const uint8_t*)data1.data(), data1.size()};
value1.user_type = "test";
std::string data2 {"420 cats"};
dht::Value value2 {(const uint8_t*)data2.data(), data2.size()};
dht::Value value3 {(const uint8_t*)data2.data(), data2.size()};
value3.user_type = "test";
CPPUNIT_ASSERT(!isPairSize(value1));
CPPUNIT_ASSERT(isUserTypeTest(value1));
auto isBoth = dht::Value::Filter::chain(isPairSize, isUserTypeTest);
auto isUserTypeTest2 = dht::Value::Filter::chain(defaultFiler, isUserTypeTest);
CPPUNIT_ASSERT(isUserTypeTest2(value1));
CPPUNIT_ASSERT(!isUserTypeTest2(value2));
CPPUNIT_ASSERT(!isBoth(value1));
CPPUNIT_ASSERT(!isBoth(value2));
CPPUNIT_ASSERT(isBoth(value3));
}
void
ValueTester::tearDown() {
}
} // namespace test
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
// cppunit
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
namespace test {
class ValueTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ValueTester);
CPPUNIT_TEST(testConstructors);
CPPUNIT_TEST(testFilter);
CPPUNIT_TEST_SUITE_END();
public:
/**
* Method automatically called before each test by CppUnit
*/
void setUp();
/**
* Method automatically called after each test CppUnit
*/
void tearDown();
/**
* Test the differents behaviors of constructors
*/
void testConstructors();
/**
* Test compare operators
*/
void testFilter();
};
} // namespace test
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
@@ -76,7 +76,7 @@ main(int argc, char **argv)
if (not params.bootstrap.first.empty())
dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
if (!params.proxyclient.empty()) {
dht.setProxyServer(params.proxyclient);
dht.enableProxy(true);
+20 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Authors: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Simon Désaulniers <simon.desaulniers@savoirfairelinux.com>
@@ -58,9 +58,9 @@ void print_help() {
<< " ld [key] Print basic information about currenty stored values on this node (or key)." << std::endl
<< " lr Print the full current routing table of this node." << std::endl;
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
std::cout << std::endl << "Operations with the proxy:" << std::endl
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
<< " pst [port] <pushServer> Start the proxy interface on port." << std::endl
#else
<< " pst [port] Start the proxy interface on port." << std::endl
@@ -68,9 +68,9 @@ void print_help() {
<< " psp [port] Stop the proxy interface on port." << std::endl;
#endif //OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
std::cout << std::endl << "Operations with the proxy:" << std::endl
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
<< " stt [server_address] <device_key> Start the proxy client." << std::endl
<< " rs [token] Resubscribe to opendht." << std::endl
<< " rp [token] Inject a push notification in Opendht." << std::endl
@@ -102,7 +102,7 @@ void print_help() {
}
void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
, std::map<in_port_t, std::unique_ptr<DhtProxyServer>>& proxies
#endif
)
@@ -141,7 +141,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
std::cout << dht->getNodesStats(AF_INET).toString() << std::endl;
std::cout << "IPv6 stats:" << std::endl;
std::cout << dht->getNodesStats(AF_INET6).toString() << std::endl;
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
for (const auto& proxy : proxies) {
std::cout << "Stats for proxy on port " << proxy.first << std::endl;
std::cout << " " << proxy.second->stats().toString() << std::endl;
@@ -201,16 +201,16 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
dht->connectivityChanged();
continue;
}
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
else if (op == "pst") {
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
iss >> idstr >> pushServer;
#else
iss >> idstr;
#endif // OPENDHT_PUSH_NOTIFICATIONS
try {
unsigned int port = std::stoi(idstr);
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
proxies.emplace(port, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, port, pushServer)));
#else
proxies.emplace(port, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, port)));
@@ -227,7 +227,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
continue;
}
#endif //OPENDHT_PROXY_SERVER
#if OPENDHT_PROXY_CLIENT
#ifdef OPENDHT_PROXY_CLIENT
else if (op == "stt") {
dht->enableProxy(true);
continue;
@@ -235,7 +235,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
dht->enableProxy(false);
continue;
}
#if OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PUSH_NOTIFICATIONS
else if (op == "rp") {
iss >> value;
dht->pushNotificationReceived({{"to", "dhtnode"}, {"token", value}});
@@ -307,7 +307,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
}, [start](bool ok) {
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Get: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
}, {}, dht::Where {std::move(rem)});
}, {}, dht::Where {rem});
}
else if (op == "q") {
std::string rem;
@@ -322,7 +322,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
}, [start](bool ok) {
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Query: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
}, dht::Query {std::move(rem)});
}, dht::Query {rem});
}
else if (op == "l") {
std::string rem;
@@ -332,7 +332,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
for (const auto& value : values)
std::cout << "\t" << *value << std::endl;
return true;
}, {}, dht::Where {std::move(rem)});
}, {}, dht::Where {rem});
auto t = token.get();
std::cout << "Listening, token: " << t << std::endl;
}
@@ -431,7 +431,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& dht, dht_params& params
<< p.toString() << std::endl
<< " hash: " << p.hash() << std::endl;
std::cout << " entries:" << std::endl;
for (auto v : vals)
for (const auto& v : vals)
std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl;
},
[start](bool ok) {
@@ -500,6 +500,7 @@ main(int argc, char **argv)
dht::DhtRunner::Config config {};
config.dht_config.node_config.network = params.network;
config.dht_config.node_config.maintain_storage = false;
config.dht_config.node_config.persist_path = params.persist_path;
config.dht_config.id = crt;
config.threaded = true;
config.proxy_server = params.proxyclient;
@@ -523,11 +524,11 @@ main(int argc, char **argv)
dht->bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
}
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
std::map<in_port_t, std::unique_ptr<DhtProxyServer>> proxies;
#endif
if (params.proxyserver != 0) {
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
proxies.emplace(params.proxyserver, std::unique_ptr<DhtProxyServer>(new DhtProxyServer(dht, params.proxyserver, params.pushserver)));
#else
std::cerr << "DHT proxy server requested but OpenDHT built without proxy server support." << std::endl;
@@ -539,7 +540,7 @@ main(int argc, char **argv)
while (runner.wait());
else
cmd_loop(dht, params
#if OPENDHT_PROXY_SERVER
#ifdef OPENDHT_PROXY_SERVER
, proxies
#endif
);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
+7 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2017 Savoir-faire Linux Inc.
* Copyright (C) 2014-2019 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
@@ -103,6 +103,7 @@ struct dht_params {
std::string proxyclient {};
std::string pushserver {};
std::string devicekey {};
std::string persist_path {};
};
static const constexpr struct option long_options[] = {
@@ -114,6 +115,7 @@ static const constexpr struct option long_options[] = {
{"verbose", no_argument , nullptr, 'v'},
{"daemonize", no_argument , nullptr, 'd'},
{"service", no_argument , nullptr, 's'},
{"persist", required_argument, nullptr, 'f'},
{"logfile", required_argument, nullptr, 'l'},
{"syslog", no_argument , nullptr, 'L'},
{"proxyserver",required_argument, nullptr, 'S'},
@@ -127,7 +129,7 @@ dht_params
parseArgs(int argc, char **argv) {
dht_params params;
int opt;
while ((opt = getopt_long(argc, argv, "hidsvp:n:b:l:", long_options, nullptr)) != -1) {
while ((opt = getopt_long(argc, argv, "hidsvp:n:b:f:l:", long_options, nullptr)) != -1) {
switch (opt) {
case 'p': {
int port_arg = atoi(optarg);
@@ -154,6 +156,9 @@ parseArgs(int argc, char **argv) {
case 'D':
params.devicekey = optarg;
break;
case 'f':
params.persist_path = optarg;
break;
case 'n':
params.network = strtoul(optarg, nullptr, 0);
break;