mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-09 12:57:03 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c60c6b8af2 | ||
|
|
9f7e4aaa96 | ||
|
|
0bfd3cd9fc | ||
|
|
442e5501d8 | ||
|
|
0203bd8318 | ||
|
|
cd07d68bef | ||
|
|
88f3870f20 | ||
|
|
d9d2c44e0f | ||
|
|
f427f36d9c | ||
|
|
a1c881d914 | ||
|
|
fbc489863f | ||
|
|
504a3638d9 | ||
|
|
a85abccd62 | ||
|
|
afce0fb0b4 | ||
|
|
99f0334229 | ||
|
|
55ac11bf5c |
No files matched your search
+1
-1
@@ -10,7 +10,7 @@ if(POLICY CMP0167)
|
||||
endif()
|
||||
|
||||
set (opendht_VERSION_MAJOR 3)
|
||||
set (opendht_VERSION_MINOR 6.0)
|
||||
set (opendht_VERSION_MINOR 6.2)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
dnl define macros
|
||||
m4_define([opendht_major_version], 3)
|
||||
m4_define([opendht_minor_version], 6)
|
||||
m4_define([opendht_patch_version], 0)
|
||||
m4_define([opendht_patch_version], 2)
|
||||
m4_define([opendht_version],
|
||||
[opendht_major_version.opendht_minor_version.opendht_patch_version])
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ RUN cd opendht && mkdir build && cd build \
|
||||
-DOPENDHT_SYSTEMD=On \
|
||||
&& make -j8 && make install
|
||||
|
||||
FROM alpine:3.22 AS install
|
||||
FROM alpine:3.23 AS install
|
||||
COPY --from=build /install /
|
||||
RUN apk add --no-cache \
|
||||
libstdc++ \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.23
|
||||
LABEL maintainer="Adrien Béraud <adrien.beraud@savoirfairelinux.com>"
|
||||
LABEL org.opencontainers.image.source=https://github.com/savoirfairelinux/opendht
|
||||
|
||||
|
||||
+190
-89
@@ -1,7 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2025 Savoir-faire Linux Inc.
|
||||
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
|
||||
* Vsevolod Ivanov <vsevolod.ivanov@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
|
||||
@@ -47,10 +45,13 @@ namespace dht {
|
||||
*/
|
||||
namespace crypto {
|
||||
|
||||
class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
|
||||
class OPENDHT_PUBLIC CryptoException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit CryptoException(const std::string& str) : std::runtime_error(str) {};
|
||||
explicit CryptoException(const char* str) : std::runtime_error(str) {};
|
||||
explicit CryptoException(const std::string& str)
|
||||
: std::runtime_error(str) {};
|
||||
explicit CryptoException(const char* str)
|
||||
: std::runtime_error(str) {};
|
||||
CryptoException(const CryptoException& e) noexcept = default;
|
||||
CryptoException& operator=(const CryptoException&) noexcept = default;
|
||||
};
|
||||
@@ -58,10 +59,13 @@ public:
|
||||
/**
|
||||
* Exception thrown when a decryption error happened.
|
||||
*/
|
||||
class OPENDHT_PUBLIC DecryptError : public CryptoException {
|
||||
class OPENDHT_PUBLIC DecryptError : public CryptoException
|
||||
{
|
||||
public:
|
||||
explicit DecryptError(const std::string& str) : CryptoException(str) {};
|
||||
explicit DecryptError(const char* str) : CryptoException(str) {};
|
||||
explicit DecryptError(const std::string& str)
|
||||
: CryptoException(str) {};
|
||||
explicit DecryptError(const char* str)
|
||||
: CryptoException(str) {};
|
||||
DecryptError(const DecryptError& e) noexcept = default;
|
||||
DecryptError& operator=(const DecryptError&) noexcept = default;
|
||||
};
|
||||
@@ -82,29 +86,35 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
/**
|
||||
* Takes ownership of an existing gnutls_pubkey.
|
||||
*/
|
||||
PublicKey(gnutls_pubkey_t k) : pk(k) {}
|
||||
PublicKey(gnutls_pubkey_t k)
|
||||
: pk(k)
|
||||
{}
|
||||
|
||||
/** Import public key from serialized data */
|
||||
PublicKey(const uint8_t* dat, size_t dat_size);
|
||||
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
|
||||
PublicKey(std::string_view pk) : PublicKey((const uint8_t*)pk.data(), pk.size()) {}
|
||||
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; }
|
||||
PublicKey(const Blob& pk)
|
||||
: PublicKey(pk.data(), pk.size())
|
||||
{}
|
||||
PublicKey(std::string_view pk)
|
||||
: PublicKey((const uint8_t*) pk.data(), pk.size())
|
||||
{}
|
||||
PublicKey(PublicKey&& o) noexcept
|
||||
: pk(o.pk)
|
||||
{
|
||||
o.pk = nullptr;
|
||||
}
|
||||
|
||||
~PublicKey();
|
||||
explicit operator bool() const { return pk; }
|
||||
bool operator ==(const PublicKey& o) const {
|
||||
return pk == o.pk || getLongId() == o.getLongId();
|
||||
}
|
||||
bool operator !=(const PublicKey& o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
bool operator==(const PublicKey& o) const { return pk == o.pk || getLongId() == o.getLongId(); }
|
||||
bool operator!=(const PublicKey& o) const { return !(*this == o); }
|
||||
|
||||
PublicKey& operator=(PublicKey&& o) noexcept;
|
||||
|
||||
/**
|
||||
* Get public key fingerprint
|
||||
*/
|
||||
const InfoHash& getId() const;
|
||||
const InfoHash& getId() const;
|
||||
|
||||
/**
|
||||
* Get public key long fingerprint
|
||||
@@ -112,30 +122,27 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
const PkId& getLongId() const;
|
||||
|
||||
bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const;
|
||||
inline bool checkSignature(const Blob& data, const Blob& signature) const {
|
||||
inline bool checkSignature(const Blob& data, const Blob& signature) const
|
||||
{
|
||||
return checkSignature(data.data(), data.size(), signature.data(), signature.size());
|
||||
}
|
||||
|
||||
Blob encrypt(const uint8_t* data, size_t data_len) const;
|
||||
inline Blob encrypt(const Blob& data) const {
|
||||
return encrypt(data.data(), data.size());
|
||||
}
|
||||
inline Blob encrypt(std::string_view data) const {
|
||||
return encrypt((const uint8_t*)data.data(), data.size());
|
||||
}
|
||||
inline Blob encrypt(const Blob& data) const { return encrypt(data.data(), data.size()); }
|
||||
inline Blob encrypt(std::string_view data) const { return encrypt((const uint8_t*) data.data(), data.size()); }
|
||||
void pack(Blob& b) const;
|
||||
int pack(uint8_t* out, size_t* out_len) const;
|
||||
void unpack(const uint8_t* dat, size_t dat_size);
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
template <typename Packer>
|
||||
template<typename Packer>
|
||||
void msgpack_pack(Packer& p) const
|
||||
{
|
||||
Blob b;
|
||||
pack(b);
|
||||
p.pack_bin(b.size());
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
p.pack_bin_body((const char*) b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
@@ -143,6 +150,7 @@ struct OPENDHT_PUBLIC PublicKey
|
||||
gnutls_digest_algorithm_t getPreferredDigest() const;
|
||||
|
||||
gnutls_pubkey_t pk {nullptr};
|
||||
|
||||
private:
|
||||
mutable InfoHash cachedId_ {};
|
||||
mutable PkId cachedLongId_ {};
|
||||
@@ -160,7 +168,7 @@ private:
|
||||
struct OPENDHT_PUBLIC PrivateKey
|
||||
{
|
||||
PrivateKey();
|
||||
//PrivateKey(gnutls_privkey_t k) : key(k) {}
|
||||
// PrivateKey(gnutls_privkey_t k) : key(k) {}
|
||||
|
||||
/**
|
||||
* Takes ownership of an existing gnutls_x509_privkey.
|
||||
@@ -171,8 +179,12 @@ struct OPENDHT_PUBLIC PrivateKey
|
||||
PrivateKey& operator=(PrivateKey&& o) noexcept;
|
||||
|
||||
PrivateKey(const uint8_t* src, size_t src_size, const char* password = nullptr);
|
||||
PrivateKey(const Blob& src, const std::string& password = {}) : PrivateKey(src.data(), src.size(), password.c_str()) {}
|
||||
PrivateKey(std::string_view src, const std::string& password = {}) : PrivateKey((const uint8_t*)src.data(), src.size(), password.c_str()) {}
|
||||
PrivateKey(const Blob& src, const std::string& password = {})
|
||||
: PrivateKey(src.data(), src.size(), password.c_str())
|
||||
{}
|
||||
PrivateKey(std::string_view src, const std::string& password = {})
|
||||
: PrivateKey((const uint8_t*) src.data(), src.size(), password.c_str())
|
||||
{}
|
||||
|
||||
~PrivateKey();
|
||||
explicit operator bool() const { return key; }
|
||||
@@ -188,7 +200,7 @@ struct OPENDHT_PUBLIC PrivateKey
|
||||
* @returns the signature data.
|
||||
*/
|
||||
Blob sign(const uint8_t* data, size_t data_len) const;
|
||||
inline Blob sign(std::string_view dat) const { return sign((const uint8_t*)dat.data(), dat.size()); }
|
||||
inline Blob sign(std::string_view dat) const { return sign((const uint8_t*) dat.data(), dat.size()); }
|
||||
inline Blob sign(const Blob& dat) const { return sign(dat.data(), dat.size()); }
|
||||
|
||||
/**
|
||||
@@ -211,6 +223,7 @@ struct OPENDHT_PUBLIC PrivateKey
|
||||
|
||||
gnutls_privkey_t key {};
|
||||
gnutls_x509_privkey_t x509_key {};
|
||||
|
||||
private:
|
||||
PrivateKey(const PrivateKey&) = delete;
|
||||
PrivateKey& operator=(const PrivateKey&) = delete;
|
||||
@@ -225,28 +238,39 @@ class OPENDHT_PUBLIC RevocationList
|
||||
using clock = std::chrono::system_clock;
|
||||
using time_point = clock::time_point;
|
||||
using duration = clock::duration;
|
||||
|
||||
public:
|
||||
RevocationList();
|
||||
RevocationList(const Blob& b);
|
||||
RevocationList(RevocationList&& o) noexcept : 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; }
|
||||
RevocationList& operator=(RevocationList&& o)
|
||||
{
|
||||
crl = o.crl;
|
||||
o.crl = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pack(Blob& b) const;
|
||||
void unpack(const uint8_t* dat, size_t dat_size);
|
||||
Blob getPacked() const {
|
||||
Blob getPacked() const
|
||||
{
|
||||
Blob b;
|
||||
pack(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
template<typename Packer>
|
||||
void msgpack_pack(Packer& p) const
|
||||
{
|
||||
Blob b = getPacked();
|
||||
p.pack_bin(b.size());
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
p.pack_bin_body((const char*) b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
@@ -281,7 +305,8 @@ public:
|
||||
time_point getNextUpdateTime() const;
|
||||
|
||||
gnutls_x509_crl_t get() { return crl; }
|
||||
gnutls_x509_crl_t getCopy() const {
|
||||
gnutls_x509_crl_t getCopy() const
|
||||
{
|
||||
if (not crl)
|
||||
return nullptr;
|
||||
auto copy = RevocationList(getPacked());
|
||||
@@ -298,14 +323,21 @@ private:
|
||||
|
||||
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
|
||||
|
||||
class OPENDHT_PUBLIC CertificateRequest {
|
||||
class OPENDHT_PUBLIC CertificateRequest
|
||||
{
|
||||
public:
|
||||
CertificateRequest();
|
||||
CertificateRequest(const uint8_t* data, size_t size);
|
||||
CertificateRequest(std::string_view src) : CertificateRequest((const uint8_t*)src.data(), src.size()) {}
|
||||
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
|
||||
CertificateRequest(std::string_view src)
|
||||
: CertificateRequest((const uint8_t*) src.data(), src.size())
|
||||
{}
|
||||
CertificateRequest(const Blob& data)
|
||||
: CertificateRequest(data.data(), data.size())
|
||||
{}
|
||||
|
||||
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
|
||||
CertificateRequest(CertificateRequest&& o) noexcept
|
||||
: request(std::move(o.request))
|
||||
{
|
||||
o.request = nullptr;
|
||||
}
|
||||
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
|
||||
@@ -327,6 +359,7 @@ public:
|
||||
std::string toString() const;
|
||||
|
||||
gnutls_x509_crq_t get() const { return request; }
|
||||
|
||||
private:
|
||||
CertificateRequest(const CertificateRequest& o) = delete;
|
||||
CertificateRequest& operator=(const CertificateRequest& o) = delete;
|
||||
@@ -336,9 +369,13 @@ private:
|
||||
class OPENDHT_PUBLIC OcspRequest
|
||||
{
|
||||
public:
|
||||
OcspRequest(gnutls_ocsp_req_t r) : request(r) {}
|
||||
OcspRequest(gnutls_ocsp_req_t r)
|
||||
: request(r)
|
||||
{}
|
||||
OcspRequest(const uint8_t* dat_ptr, size_t dat_size);
|
||||
OcspRequest(std::string_view dat): OcspRequest((const uint8_t*)dat.data(), dat.size()) {}
|
||||
OcspRequest(std::string_view dat)
|
||||
: OcspRequest((const uint8_t*) dat.data(), dat.size())
|
||||
{}
|
||||
~OcspRequest();
|
||||
|
||||
/*
|
||||
@@ -348,6 +385,7 @@ public:
|
||||
|
||||
Blob pack() const;
|
||||
Blob getNonce() const;
|
||||
|
||||
private:
|
||||
gnutls_ocsp_req_t request;
|
||||
};
|
||||
@@ -356,7 +394,9 @@ class OPENDHT_PUBLIC OcspResponse
|
||||
{
|
||||
public:
|
||||
OcspResponse(const uint8_t* dat_ptr, size_t dat_size);
|
||||
OcspResponse(std::string_view response) : OcspResponse((const uint8_t*)response.data(), response.size()) {}
|
||||
OcspResponse(std::string_view response)
|
||||
: OcspResponse((const uint8_t*) response.data(), response.size())
|
||||
{}
|
||||
~OcspResponse();
|
||||
|
||||
Blob pack() const;
|
||||
@@ -383,36 +423,46 @@ private:
|
||||
gnutls_ocsp_resp_t response;
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC Certificate {
|
||||
struct OPENDHT_PUBLIC Certificate
|
||||
{
|
||||
Certificate() noexcept {}
|
||||
|
||||
/**
|
||||
* Take ownership of existing gnutls structure
|
||||
*/
|
||||
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
|
||||
Certificate(gnutls_x509_crt_t crt) noexcept
|
||||
: cert(crt)
|
||||
{}
|
||||
|
||||
Certificate(Certificate&& o) noexcept
|
||||
: cert(o.cert)
|
||||
, issuer(std::move(o.issuer))
|
||||
, publicKey_(std::move(o.publicKey_))
|
||||
{ o.cert = nullptr; };
|
||||
{
|
||||
o.cert = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Import certificate (PEM or DER) or certificate chain (PEM),
|
||||
* ordered from subject to issuer
|
||||
*/
|
||||
Certificate(const Blob& crt);
|
||||
Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
|
||||
Certificate(const uint8_t* dat, size_t dat_size)
|
||||
: cert(nullptr)
|
||||
{
|
||||
unpack(dat, dat_size);
|
||||
}
|
||||
Certificate(std::string_view pem) : Certificate((const uint8_t*)pem.data(), pem.size()) {}
|
||||
Certificate(std::string_view pem)
|
||||
: Certificate((const uint8_t*) pem.data(), pem.size())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Import certificate chain (PEM or DER),
|
||||
* ordered from subject to issuer
|
||||
*/
|
||||
template<typename Iterator>
|
||||
Certificate(const Iterator& begin, const Iterator& end) {
|
||||
Certificate(const Iterator& begin, const Iterator& end)
|
||||
{
|
||||
unpack(begin, end);
|
||||
}
|
||||
|
||||
@@ -421,7 +471,8 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
* ordered from subject to issuer
|
||||
*/
|
||||
template<typename Iterator>
|
||||
Certificate(const std::vector<std::pair<Iterator, Iterator>>& certs) {
|
||||
Certificate(const std::vector<std::pair<Iterator, Iterator>>& certs)
|
||||
{
|
||||
unpack(certs);
|
||||
}
|
||||
|
||||
@@ -430,7 +481,8 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
|
||||
void pack(Blob& b) const;
|
||||
void unpack(const uint8_t* dat, size_t dat_size);
|
||||
Blob getPacked() const {
|
||||
Blob getPacked() const
|
||||
{
|
||||
Blob b;
|
||||
pack(b);
|
||||
return b;
|
||||
@@ -479,7 +531,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
for (auto li = certs.rbegin(); li != certs.rend(); ++li) {
|
||||
Certificate tmp_crt;
|
||||
gnutls_x509_crt_init(&tmp_crt.cert);
|
||||
const gnutls_datum_t crt_dt {(uint8_t*)&(*li->first), (unsigned)(li->second-li->first)};
|
||||
const gnutls_datum_t crt_dt {(uint8_t*) &(*li->first), (unsigned) (li->second - li->first)};
|
||||
int err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_PEM);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_DER);
|
||||
@@ -491,13 +543,13 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
*this = tmp_issuer ? std::move(*tmp_issuer) : Certificate();
|
||||
}
|
||||
|
||||
template <typename Packer>
|
||||
template<typename Packer>
|
||||
void msgpack_pack(Packer& p) const
|
||||
{
|
||||
Blob b;
|
||||
pack(b);
|
||||
p.pack_bin(b.size());
|
||||
p.pack_bin_body((const char*)b.data(), b.size());
|
||||
p.pack_bin_body((const char*) b.data(), b.size());
|
||||
}
|
||||
|
||||
void msgpack_unpack(const msgpack::object& o);
|
||||
@@ -513,7 +565,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
|
||||
Blob getSerialNumber() const;
|
||||
|
||||
/** Read certificate full DN as described in RFC4514 */
|
||||
/** Read certificate full DN as described in RFC4514 */
|
||||
std::string getDN() const;
|
||||
|
||||
/** Read certificate Common Name (CN) */
|
||||
@@ -568,10 +620,15 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
void addRevocationList(RevocationList&&);
|
||||
void addRevocationList(std::shared_ptr<RevocationList>);
|
||||
|
||||
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false, int64_t validity = 0);
|
||||
static Certificate generate(const PrivateKey& key,
|
||||
const std::string& name = "dhtnode",
|
||||
const Identity& ca = {},
|
||||
bool is_ca = false,
|
||||
int64_t validity = 0);
|
||||
static Certificate generate(const CertificateRequest& request, const Identity& ca, int64_t validity = 0);
|
||||
|
||||
gnutls_x509_crt_t getCopy() const {
|
||||
gnutls_x509_crt_t getCopy() const
|
||||
{
|
||||
if (not cert)
|
||||
return nullptr;
|
||||
auto copy = Certificate(getPacked());
|
||||
@@ -580,8 +637,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<gnutls_x509_crt_t>
|
||||
getChain(bool copy = false) const
|
||||
std::vector<gnutls_x509_crt_t> getChain(bool copy = false) const
|
||||
{
|
||||
if (not cert)
|
||||
return {};
|
||||
@@ -591,11 +647,8 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
return crts;
|
||||
}
|
||||
|
||||
std::pair<
|
||||
std::vector<gnutls_x509_crt_t>,
|
||||
std::vector<gnutls_x509_crl_t>
|
||||
>
|
||||
getChainWithRevocations(bool copy = false) const
|
||||
std::pair<std::vector<gnutls_x509_crt_t>, std::vector<gnutls_x509_crl_t>> getChainWithRevocations(
|
||||
bool copy = false) const
|
||||
{
|
||||
if (not cert)
|
||||
return {};
|
||||
@@ -628,6 +681,7 @@ struct OPENDHT_PUBLIC Certificate {
|
||||
gnutls_x509_crt_t cert {nullptr};
|
||||
std::shared_ptr<Certificate> issuer {};
|
||||
std::shared_ptr<OcspResponse> ocspResponse;
|
||||
|
||||
private:
|
||||
Certificate(const Certificate&) = delete;
|
||||
Certificate& operator=(const Certificate&) = delete;
|
||||
@@ -636,8 +690,10 @@ private:
|
||||
mutable std::atomic_bool idCached_ {false};
|
||||
mutable std::atomic_bool longIdCached_ {false};
|
||||
|
||||
struct crlNumberCmp {
|
||||
bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
|
||||
struct crlNumberCmp
|
||||
{
|
||||
bool operator()(const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const
|
||||
{
|
||||
return lhs->getNumber() < rhs->getNumber();
|
||||
}
|
||||
};
|
||||
@@ -650,18 +706,21 @@ private:
|
||||
|
||||
struct OPENDHT_PUBLIC TrustList
|
||||
{
|
||||
struct VerifyResult {
|
||||
struct VerifyResult
|
||||
{
|
||||
int ret;
|
||||
unsigned result;
|
||||
bool hasError() const { return ret < 0; }
|
||||
bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); }
|
||||
explicit operator bool() const { return isValid(); }
|
||||
OPENDHT_PUBLIC std::string toString() const;
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h);
|
||||
OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const VerifyResult& h);
|
||||
};
|
||||
|
||||
TrustList();
|
||||
TrustList(TrustList&& o) noexcept : trust(std::move(o.trust)) {
|
||||
TrustList(TrustList&& o) noexcept
|
||||
: trust(std::move(o.trust))
|
||||
{
|
||||
o.trust = nullptr;
|
||||
}
|
||||
TrustList& operator=(TrustList&& o) noexcept;
|
||||
@@ -685,13 +744,15 @@ private:
|
||||
* @param key_length stength of the generated private key (bits).
|
||||
*/
|
||||
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 generateIdentity(const std::string& name = "dhtnode",
|
||||
const Identity& ca = {},
|
||||
unsigned key_length = 4096);
|
||||
|
||||
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 = {});
|
||||
|
||||
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
|
||||
OPENDHT_PUBLIC Identity loadIdentity(const std::string &path,const std::string &privkey_password = {});
|
||||
OPENDHT_PUBLIC Identity loadIdentity(const std::string& path, const std::string& privkey_password = {});
|
||||
|
||||
/**
|
||||
* Performs SHA512, SHA256 or SHA1, depending on hash_length.
|
||||
@@ -701,7 +762,7 @@ OPENDHT_PUBLIC Identity loadIdentity(const std::string &path,const std::string &
|
||||
* will use SHA256 for hash_length up to 32 bytes,
|
||||
* will use SHA512 for hash_length of 33 bytes and more.
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
|
||||
OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512 / 8);
|
||||
|
||||
OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
|
||||
|
||||
@@ -712,20 +773,23 @@ OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash,
|
||||
* that can be transmitted in clear, and will be generated if
|
||||
* not provided (32 bytes).
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob stretchKey(std::string_view password, Blob& salt, size_t key_length = 512/8);
|
||||
OPENDHT_PUBLIC Blob stretchKey(std::string_view password, Blob& salt, size_t key_length = 512 / 8);
|
||||
|
||||
/**
|
||||
* AES-GCM encryption. Key must be 128, 192 or 256 bits long (16, 24 or 32 bytes).
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob aesEncrypt(const uint8_t* data, size_t data_length, const Blob& key);
|
||||
OPENDHT_PUBLIC inline Blob aesEncrypt(const Blob& data, const Blob& key) {
|
||||
OPENDHT_PUBLIC inline Blob
|
||||
aesEncrypt(const Blob& data, const Blob& key)
|
||||
{
|
||||
return aesEncrypt(data.data(), data.size(), key);
|
||||
}
|
||||
/**
|
||||
* AES-GCM encryption with argon2 key derivation.
|
||||
* This function uses `stretchKey` to generate an AES key from the password and a random salt.
|
||||
* The result is a bundle including the salt that can be decrypted with `aesDecrypt(data, password)`.
|
||||
* If needed, the salt or encrypted data can be individually extracted from the bundle with `aesGetSalt` and `aesGetEncrypted`.
|
||||
* If needed, the salt or encrypted data can be individually extracted from the bundle with `aesGetSalt` and
|
||||
* `aesGetEncrypted`.
|
||||
* @param data: data to encrypt
|
||||
* @param password: password to encrypt the data with
|
||||
* @param salt: optional salt to use for key derivation. If not provided, a random salt will be generated.
|
||||
@@ -736,28 +800,47 @@ OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, std::string_view password, cons
|
||||
* AES-GCM decryption.
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key);
|
||||
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, const Blob& key) { return aesDecrypt(data.data(), data.size(), key); }
|
||||
OPENDHT_PUBLIC inline Blob aesDecrypt(std::string_view data, const Blob& key) { return aesDecrypt((uint8_t*)data.data(), data.size(), key); }
|
||||
OPENDHT_PUBLIC inline Blob
|
||||
aesDecrypt(const Blob& data, const Blob& key)
|
||||
{
|
||||
return aesDecrypt(data.data(), data.size(), key);
|
||||
}
|
||||
OPENDHT_PUBLIC inline Blob
|
||||
aesDecrypt(std::string_view data, const Blob& key)
|
||||
{
|
||||
return aesDecrypt((uint8_t*) data.data(), data.size(), key);
|
||||
}
|
||||
|
||||
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, std::string_view password);
|
||||
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, std::string_view password) { return aesDecrypt(data.data(), data.size(), password); }
|
||||
OPENDHT_PUBLIC inline Blob aesDecrypt(std::string_view data, std::string_view password) { return aesDecrypt((uint8_t*)data.data(), data.size(), password); }
|
||||
OPENDHT_PUBLIC inline Blob
|
||||
aesDecrypt(const Blob& data, std::string_view password)
|
||||
{
|
||||
return aesDecrypt(data.data(), data.size(), password);
|
||||
}
|
||||
OPENDHT_PUBLIC inline Blob
|
||||
aesDecrypt(std::string_view data, std::string_view password)
|
||||
{
|
||||
return aesDecrypt((uint8_t*) data.data(), data.size(), password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw AES key from password and salt stored with the encrypted data.
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob aesGetKey(const uint8_t* data, size_t data_length, std::string_view password);
|
||||
OPENDHT_PUBLIC Blob inline aesGetKey(const Blob& data, std::string_view password) {
|
||||
OPENDHT_PUBLIC Blob inline aesGetKey(const Blob& data, std::string_view password)
|
||||
{
|
||||
return aesGetKey(data.data(), data.size(), password);
|
||||
}
|
||||
/** Get the salt part of data password-encrypted with `aesEncrypt(data, password)` */
|
||||
OPENDHT_PUBLIC Blob aesGetSalt(const uint8_t* data, size_t data_length);
|
||||
OPENDHT_PUBLIC Blob inline aesGetSalt(const Blob& data) {
|
||||
OPENDHT_PUBLIC Blob inline aesGetSalt(const Blob& data)
|
||||
{
|
||||
return aesGetSalt(data.data(), data.size());
|
||||
}
|
||||
/** Get the encrypted data (ciphertext) part of data password-encrypted with `aesEncrypt(data, password)` */
|
||||
OPENDHT_PUBLIC std::string_view aesGetEncrypted(const uint8_t* data, size_t data_length);
|
||||
OPENDHT_PUBLIC std::string_view inline aesGetEncrypted(const Blob& data) {
|
||||
OPENDHT_PUBLIC std::string_view inline aesGetEncrypted(const Blob& data)
|
||||
{
|
||||
return aesGetEncrypted(data.data(), data.size());
|
||||
}
|
||||
|
||||
@@ -767,12 +850,30 @@ OPENDHT_PUBLIC std::string_view inline aesGetEncrypted(const Blob& data) {
|
||||
* Can be obtained from an existing bundle with `aesGetSalt`.
|
||||
**/
|
||||
OPENDHT_PUBLIC Blob aesBuildEncrypted(const uint8_t* encryptedData, size_t data_length, const Blob& salt);
|
||||
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(const Blob& encryptedData, const Blob& salt) {
|
||||
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(const Blob& encryptedData, const Blob& salt)
|
||||
{
|
||||
return aesBuildEncrypted(encryptedData.data(), encryptedData.size(), salt);
|
||||
}
|
||||
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(std::string_view encryptedData, const Blob& salt) {
|
||||
return aesBuildEncrypted((const uint8_t*)encryptedData.data(), encryptedData.size(), salt);
|
||||
OPENDHT_PUBLIC Blob inline aesBuildEncrypted(std::string_view encryptedData, const Blob& salt)
|
||||
{
|
||||
return aesBuildEncrypted((const uint8_t*) encryptedData.data(), encryptedData.size(), salt);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encrypts a payload for WebPush (RFC 8291).
|
||||
* @param p256dh: The user's P-256 public key (uncompressed, 65 bytes).
|
||||
* @param auth: The user's authentication secret (16 bytes).
|
||||
* @param payload: The data to encrypt.
|
||||
* @param privKey: (Optional) The sender's private key (for testing).
|
||||
* @param salt: (Optional) The salt to use (for testing).
|
||||
* @return The encrypted body (including salt, record size, keyid).
|
||||
*/
|
||||
OPENDHT_PUBLIC Blob webPushEncrypt(const Blob& p256dh,
|
||||
const Blob& auth,
|
||||
const uint8_t* payload,
|
||||
size_t payload_length,
|
||||
const PrivateKey& privKey = {},
|
||||
const Blob& salt = {});
|
||||
|
||||
} // namespace crypto
|
||||
} // namespace dht
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
if (v.owner) {
|
||||
owner = v.owner;
|
||||
from = v.owner->getId();
|
||||
} else {
|
||||
throw std::runtime_error("Value has no owner");
|
||||
}
|
||||
BaseClass::unpackValue(v);
|
||||
}
|
||||
@@ -89,6 +91,9 @@ public:
|
||||
|
||||
public:
|
||||
virtual void unpackValue(const Value& v) override {
|
||||
if (!v.recipient) {
|
||||
throw std::runtime_error("Value has no recipient");
|
||||
}
|
||||
to = v.recipient;
|
||||
BaseClass::unpackValue(v);
|
||||
}
|
||||
@@ -103,9 +108,6 @@ public:
|
||||
dht::InfoHash to;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage>
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -366,6 +366,7 @@ public:
|
||||
void setLogFilter(const InfoHash& f = {});
|
||||
|
||||
void registerType(const ValueType& type);
|
||||
void registerInsecureType(const ValueType& type);
|
||||
|
||||
void importValues(const std::vector<ValuesExport>& values);
|
||||
|
||||
|
||||
+64
-58
@@ -25,8 +25,8 @@
|
||||
// some libraries may try to redefine snprintf
|
||||
// but restinio will use it in std namespace
|
||||
#ifdef _MSC_VER
|
||||
# undef snprintf
|
||||
# define snprintf snprintf
|
||||
#undef snprintf
|
||||
#define snprintf snprintf
|
||||
#endif
|
||||
|
||||
#include <asio/ip/tcp.hpp>
|
||||
@@ -47,7 +47,7 @@ namespace restinio {
|
||||
namespace impl {
|
||||
class tls_socket_t;
|
||||
}
|
||||
}
|
||||
} // namespace restinio
|
||||
|
||||
namespace dht {
|
||||
namespace log {
|
||||
@@ -62,8 +62,7 @@ namespace http {
|
||||
|
||||
using HandlerCb = std::function<void(const asio::error_code& ec)>;
|
||||
using BytesHandlerCb = std::function<void(const asio::error_code& ec, size_t bytes)>;
|
||||
using ConnectHandlerCb = std::function<void(const asio::error_code& ec,
|
||||
const asio::ip::tcp::endpoint& endpoint)>;
|
||||
using ConnectHandlerCb = std::function<void(const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint)>;
|
||||
|
||||
using ssl_socket_t = restinio::impl::tls_socket_t;
|
||||
using socket_t = asio::ip::tcp::socket;
|
||||
@@ -75,11 +74,13 @@ public:
|
||||
Url(std::string_view url);
|
||||
std::string url;
|
||||
std::string protocol {"http"};
|
||||
std::string host;
|
||||
std::string service;
|
||||
std::string_view user;
|
||||
std::string_view password;
|
||||
std::string_view host;
|
||||
std::string_view service;
|
||||
std::string target;
|
||||
std::string query;
|
||||
std::string fragment;
|
||||
std::string_view query;
|
||||
std::string_view fragment;
|
||||
|
||||
std::string toString() const;
|
||||
};
|
||||
@@ -88,11 +89,13 @@ class OPENDHT_PUBLIC Connection : public std::enable_shared_from_this<Connection
|
||||
{
|
||||
public:
|
||||
Connection(asio::io_context& ctx, const bool ssl = true, std::shared_ptr<log::Logger> l = {});
|
||||
Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certificate> server_ca,
|
||||
const dht::crypto::Identity& identity, std::shared_ptr<log::Logger> l = {});
|
||||
Connection(asio::io_context& ctx,
|
||||
std::shared_ptr<dht::crypto::Certificate> server_ca,
|
||||
const dht::crypto::Identity& identity,
|
||||
std::shared_ptr<log::Logger> l = {});
|
||||
~Connection();
|
||||
|
||||
inline unsigned int id() const { return id_; };
|
||||
inline unsigned int id() const { return id_; };
|
||||
bool is_open() const;
|
||||
bool is_ssl() const;
|
||||
void checkOcsp(bool check = true) { checkOcsp_ = check; }
|
||||
@@ -122,10 +125,10 @@ public:
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
T wrapCallback(T cb) const {
|
||||
return [t=shared_from_this(),cb=std::move(cb)](auto ...params) {
|
||||
T wrapCallback(T cb) const
|
||||
{
|
||||
return [t = shared_from_this(), cb = std::move(cb)](auto... params) {
|
||||
cb(params...);
|
||||
};
|
||||
}
|
||||
@@ -159,35 +162,38 @@ private:
|
||||
class OPENDHT_PUBLIC Resolver
|
||||
{
|
||||
public:
|
||||
using ResolverCb = std::function<void(const asio::error_code& ec,
|
||||
const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
|
||||
using ResolverCb
|
||||
= std::function<void(const asio::error_code& ec, const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
|
||||
|
||||
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx, const std::string& host, const std::string& service,
|
||||
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx,
|
||||
std::string_view host,
|
||||
std::string_view service,
|
||||
const bool ssl = false,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
|
||||
// use already resolved endpoints with classes using this resolver
|
||||
Resolver(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint> endpoints,
|
||||
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx, const std::string& url, std::vector<asio::ip::tcp::endpoint> endpoints,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx,
|
||||
std::vector<asio::ip::tcp::endpoint> endpoints,
|
||||
const bool ssl = false,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx,
|
||||
const std::string& url,
|
||||
std::vector<asio::ip::tcp::endpoint> endpoints,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
|
||||
~Resolver();
|
||||
|
||||
inline const Url& get_url() const {
|
||||
return url_;
|
||||
}
|
||||
inline const Url& get_url() const { return url_; }
|
||||
|
||||
void add_callback(ResolverCb cb, sa_family_t family = AF_UNSPEC);
|
||||
|
||||
std::shared_ptr<log::Logger> getLogger() const {
|
||||
return logger_;
|
||||
}
|
||||
std::shared_ptr<log::Logger> getLogger() const { return logger_; }
|
||||
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
void resolve(const std::string& host, const std::string& service);
|
||||
void resolve(std::string_view host, std::string_view service);
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
@@ -217,13 +223,7 @@ struct Response
|
||||
class OPENDHT_PUBLIC Request : public std::enable_shared_from_this<Request>
|
||||
{
|
||||
public:
|
||||
enum class State {
|
||||
CREATED,
|
||||
SENDING,
|
||||
HEADER_RECEIVED,
|
||||
RECEIVING,
|
||||
DONE
|
||||
};
|
||||
enum class State { CREATED, SENDING, HEADER_RECEIVED, RECEIVING, DONE };
|
||||
using OnStatusCb = std::function<void(unsigned status_code)>;
|
||||
using OnDataCb = std::function<void(const char* at, size_t length)>;
|
||||
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
|
||||
@@ -231,46 +231,51 @@ public:
|
||||
using OnDoneCb = std::function<void(const Response& response)>;
|
||||
|
||||
// resolves implicitly
|
||||
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb,
|
||||
Request(asio::io_context& ctx,
|
||||
const std::string& url,
|
||||
const Json::Value& json,
|
||||
OnJsonCb jsoncb,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb, std::shared_ptr<log::Logger> logger = {});
|
||||
|
||||
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
|
||||
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx,
|
||||
std::string_view host,
|
||||
std::string_view service,
|
||||
const bool ssl = false,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<log::Logger> logger = {});
|
||||
|
||||
// user defined resolver
|
||||
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, sa_family_t family = AF_UNSPEC);
|
||||
Request(asio::io_context& ctx, std::shared_ptr<Resolver> resolver, const std::string& target, sa_family_t family = AF_UNSPEC);
|
||||
Request(asio::io_context& ctx,
|
||||
std::shared_ptr<Resolver> resolver,
|
||||
const std::string& target,
|
||||
sa_family_t family = AF_UNSPEC);
|
||||
|
||||
// user defined resolved endpoints
|
||||
Request(asio::io_context& ctx, std::vector<asio::ip::tcp::endpoint>&& endpoints,
|
||||
const bool ssl = false, std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx,
|
||||
std::vector<asio::ip::tcp::endpoint>&& endpoints,
|
||||
const bool ssl = false,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
|
||||
~Request();
|
||||
|
||||
inline unsigned int id() const { return id_; };
|
||||
inline unsigned int id() const { return id_; };
|
||||
void set_connection(std::shared_ptr<Connection> connection);
|
||||
std::shared_ptr<Connection> get_connection() const;
|
||||
inline const Url& get_url() const {
|
||||
return resolver_->get_url();
|
||||
};
|
||||
inline const Url& get_url() const { return resolver_->get_url(); };
|
||||
|
||||
void timeout(const std::chrono::seconds& timeout, HandlerCb cb = {}) {
|
||||
void timeout(const std::chrono::seconds& timeout, HandlerCb cb = {})
|
||||
{
|
||||
timeout_ = timeout;
|
||||
timeoutCb_ = cb;
|
||||
}
|
||||
|
||||
/** The previous request in case of redirect following */
|
||||
std::shared_ptr<Request> getPrevious() const {
|
||||
return prev_.lock();
|
||||
}
|
||||
std::shared_ptr<Request> getPrevious() const { return prev_.lock(); }
|
||||
|
||||
inline std::string& to_string() {
|
||||
return request_;
|
||||
}
|
||||
inline std::string& to_string() { return request_; }
|
||||
|
||||
void set_certificate_authority(std::shared_ptr<dht::crypto::Certificate> certificate);
|
||||
void set_identity(const dht::crypto::Identity& identity);
|
||||
@@ -285,6 +290,7 @@ public:
|
||||
void set_header_field(restinio::http_field_t field, std::string value);
|
||||
void set_connection_type(restinio::http_connection_header_t connection);
|
||||
void set_body(std::string body);
|
||||
void set_body(const uint8_t* data, size_t length);
|
||||
void set_auth(const std::string& username, const std::string& password);
|
||||
|
||||
void add_on_status_callback(OnStatusCb cb);
|
||||
@@ -306,7 +312,8 @@ public:
|
||||
private:
|
||||
using OnCompleteCb = std::function<void()>;
|
||||
|
||||
struct Callbacks {
|
||||
struct Callbacks
|
||||
{
|
||||
OnStatusCb on_status;
|
||||
OnDataCb on_header_field;
|
||||
OnDataCb on_header_value;
|
||||
@@ -381,4 +388,3 @@ private:
|
||||
|
||||
} // namespace http
|
||||
} // namespace dht
|
||||
|
||||
@@ -52,14 +52,16 @@ bool setNonblocking(int fd, bool nonblocking = true);
|
||||
#ifdef _WIN32
|
||||
void udpPipe(int fds[2]);
|
||||
#endif
|
||||
struct ReceivedPacket {
|
||||
struct ReceivedPacket
|
||||
{
|
||||
Blob data;
|
||||
SockAddr from;
|
||||
time_point received;
|
||||
};
|
||||
using PacketList = std::list<ReceivedPacket>;
|
||||
|
||||
class OPENDHT_PUBLIC DatagramSocket {
|
||||
class OPENDHT_PUBLIC DatagramSocket
|
||||
{
|
||||
public:
|
||||
/** A function that takes a list of new received packets and
|
||||
* optionally returns consumed packets for recycling.
|
||||
@@ -69,7 +71,8 @@ public:
|
||||
|
||||
virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0;
|
||||
|
||||
inline void setOnReceive(OnReceive&& cb) {
|
||||
inline void setOnReceive(OnReceive&& cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
rx_callback = std::move(cb);
|
||||
}
|
||||
@@ -77,11 +80,13 @@ public:
|
||||
virtual bool hasIPv4() const = 0;
|
||||
virtual bool hasIPv6() const = 0;
|
||||
|
||||
SockAddr getBound(sa_family_t family = AF_UNSPEC) const {
|
||||
SockAddr getBound(sa_family_t family = AF_UNSPEC) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
return getBoundRef(family);
|
||||
}
|
||||
in_port_t getPort(sa_family_t family = AF_UNSPEC) const {
|
||||
in_port_t getPort(sa_family_t family = AF_UNSPEC) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
return getBoundRef(family).getPort();
|
||||
}
|
||||
@@ -89,14 +94,16 @@ public:
|
||||
virtual const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const = 0;
|
||||
|
||||
/** Virtual resolver mothod allows to implement custom resolver */
|
||||
virtual std::vector<SockAddr> resolve(const std::string& host, const std::string& service = {}) {
|
||||
virtual std::vector<SockAddr> resolve(const std::string& host, const std::string& service = {})
|
||||
{
|
||||
return SockAddr::resolve(host, service);
|
||||
}
|
||||
|
||||
virtual void stop() = 0;
|
||||
protected:
|
||||
|
||||
PacketList getNewPacket() {
|
||||
protected:
|
||||
PacketList getNewPacket()
|
||||
{
|
||||
PacketList pkts;
|
||||
if (toRecycle_.empty()) {
|
||||
pkts.emplace_back();
|
||||
@@ -108,7 +115,8 @@ protected:
|
||||
return pkts;
|
||||
}
|
||||
|
||||
inline void onReceived(PacketList&& packets) {
|
||||
inline void onReceived(PacketList&& packets)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
if (rx_callback) {
|
||||
auto r = rx_callback(std::move(packets));
|
||||
@@ -116,14 +124,17 @@ protected:
|
||||
toRecycle_.splice(toRecycle_.end(), std::move(r));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable std::mutex lock;
|
||||
|
||||
private:
|
||||
OnReceive rx_callback;
|
||||
PacketList toRecycle_;
|
||||
};
|
||||
|
||||
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket {
|
||||
class OPENDHT_PUBLIC UdpSocket : public DatagramSocket
|
||||
{
|
||||
public:
|
||||
UdpSocket(in_port_t port, const std::shared_ptr<Logger>& l = {});
|
||||
UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const std::shared_ptr<Logger>& l = {});
|
||||
@@ -131,20 +142,24 @@ public:
|
||||
|
||||
int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override;
|
||||
|
||||
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override {
|
||||
const SockAddr& getBoundRef(sa_family_t family = AF_UNSPEC) const override
|
||||
{
|
||||
return (family == AF_INET6) ? bound6 : bound4;
|
||||
}
|
||||
|
||||
bool hasIPv4() const override {
|
||||
bool hasIPv4() const override
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
return s4 != -1;
|
||||
}
|
||||
bool hasIPv6() const override {
|
||||
bool hasIPv6() const override
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(lock);
|
||||
return s6 != -1;
|
||||
}
|
||||
|
||||
void stop() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Logger> logger;
|
||||
int s4 {-1};
|
||||
@@ -157,5 +172,5 @@ private:
|
||||
void openSockets(const SockAddr& bind4, const SockAddr& bind6);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace net
|
||||
} // namespace dht
|
||||
+12
-1
@@ -62,10 +62,21 @@ erase_if(std::map<Key, Item>& map, const Condition& condition)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string
|
||||
concat(Args&&... args)
|
||||
{
|
||||
static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
|
||||
std::string s;
|
||||
s.reserve((std::string_view {args}.size() + ...));
|
||||
(s.append(std::forward<Args>(args)), ...);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split "[host]:port" or "host:port" to pair<"host", "port">.
|
||||
*/
|
||||
OPENDHT_PUBLIC std::pair<std::string, std::string> splitPort(std::string_view s);
|
||||
OPENDHT_PUBLIC std::pair<std::string_view, std::string_view> splitPort(std::string_view s);
|
||||
|
||||
class OPENDHT_PUBLIC DhtException : public std::runtime_error
|
||||
{
|
||||
|
||||
+6
-3
@@ -3,7 +3,7 @@ project(
|
||||
'c',
|
||||
'cpp',
|
||||
'cython',
|
||||
version: '3.6.0',
|
||||
version: '3.6.2',
|
||||
meson_version: '>=1.1.0',
|
||||
default_options: ['cpp_std=c++17', 'warning_level=3'],
|
||||
)
|
||||
@@ -29,8 +29,11 @@ deps = [
|
||||
jsoncpp,
|
||||
simdutf,
|
||||
llhttp,
|
||||
io_uring,
|
||||
]
|
||||
|
||||
if host_machine.system() == 'linux' and io_uring.found()
|
||||
deps += io_uring
|
||||
endif
|
||||
conf_data = configuration_data()
|
||||
|
||||
add_project_arguments('-DMSGPACK_NO_BOOST', '-DASIO_STANDALONE', language: 'cpp')
|
||||
@@ -245,7 +248,7 @@ if get_option('tests').enabled()
|
||||
'tests/tests_runner.cpp',
|
||||
include_directories: opendht_interface_inc,
|
||||
link_with: opendht,
|
||||
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack],
|
||||
dependencies: [cppunit, jsoncpp, fmt, openssl, msgpack, gnutls],
|
||||
)
|
||||
test('Crypto', test_crypto)
|
||||
|
||||
|
||||
+14
-7
@@ -16,31 +16,38 @@
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <simdutf.h>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace dht {
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
std::string
|
||||
base64_encode(const std::vector<unsigned char>& str)
|
||||
{
|
||||
std::string buffer(simdutf::base64_length_from_binary(str.size()), '\0');
|
||||
simdutf::binary_to_base64((const char*)str.data(), str.size(), buffer.data());
|
||||
simdutf::binary_to_base64((const char*) str.data(), str.size(), buffer.data());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::vector<unsigned char>
|
||||
base64_decode(const std::string& str)
|
||||
base64_decode(std::string_view str)
|
||||
{
|
||||
std::vector<unsigned char> buffer(simdutf::maximal_binary_length_from_base64(str.data(), str.size()));
|
||||
simdutf::result r = simdutf::base64_to_binary(str.data(), str.size(), (char *)buffer.data());
|
||||
if(r.error) {
|
||||
// Decoding error, return an empty vector
|
||||
return std::vector<unsigned char>();
|
||||
simdutf::result r = simdutf::base64_to_binary(str.data(), str.size(), (char*) buffer.data());
|
||||
if (r.error) {
|
||||
throw std::invalid_argument(concat("Invalid base64 input: "sv, simdutf::error_to_string(r.error)));
|
||||
} else {
|
||||
buffer.resize(r.count); // resize the buffer according to actual number of bytes
|
||||
buffer.resize(r.count);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace dht
|
||||
+5
-1
@@ -20,6 +20,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dht {
|
||||
|
||||
/**
|
||||
* Encode a buffer in base64.
|
||||
*
|
||||
@@ -33,4 +35,6 @@ std::string base64_encode(const std::vector<unsigned char>& str);
|
||||
* @param str the input buffer
|
||||
* @return a base64-decoded buffer
|
||||
*/
|
||||
std::vector<unsigned char> base64_decode(const std::string& str);
|
||||
std::vector<unsigned char> base64_decode(std::string_view str);
|
||||
|
||||
} // namespace dht
|
||||
+450
-185
File diff suppressed because it is too large.
Load diff
+293
-256
File diff suppressed because it is too large.
Load diff
+417
-285
File diff suppressed because it is too large.
Load diff
+184
-143
@@ -40,18 +40,20 @@ using namespace std::literals;
|
||||
|
||||
constexpr auto PEER_DISCOVERY_DHT_SERVICE = "dht"sv;
|
||||
|
||||
struct NodeInsertionPack {
|
||||
struct NodeInsertionPack
|
||||
{
|
||||
dht::InfoHash nodeId;
|
||||
in_port_t port;
|
||||
dht::NetId net;
|
||||
MSGPACK_DEFINE(nodeId, port, net)
|
||||
};
|
||||
|
||||
DhtRunner::DhtRunner() : dht_()
|
||||
DhtRunner::DhtRunner()
|
||||
: dht_()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsd;
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
|
||||
throw DhtException("Can't initialize Winsock2");
|
||||
#endif
|
||||
}
|
||||
@@ -95,7 +97,8 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
auto expected = State::Idle;
|
||||
if (not running.compare_exchange_strong(expected, State::Running)) {
|
||||
if (context.logger)
|
||||
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.", fmt::ptr(this));
|
||||
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.",
|
||||
fmt::ptr(this));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,7 +107,9 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
auto local6 = config.bind6;
|
||||
if (not local4 and not local6) {
|
||||
if (context.logger)
|
||||
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses", fmt::ptr(this));
|
||||
context.logger
|
||||
->w("[runner %p] No address to bind specified in the configuration, using default addresses",
|
||||
fmt::ptr(this));
|
||||
local4.setFamily(AF_INET);
|
||||
local6.setFamily(AF_INET6);
|
||||
}
|
||||
@@ -118,14 +123,18 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
if (inConfig >> port) {
|
||||
if (local4.getPort() == 0) {
|
||||
if (context.logger)
|
||||
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", fmt::ptr(this), port);
|
||||
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration",
|
||||
fmt::ptr(this),
|
||||
port);
|
||||
local4.setPort(port);
|
||||
}
|
||||
}
|
||||
if (inConfig >> port) {
|
||||
if (local6.getPort() == 0) {
|
||||
if (context.logger)
|
||||
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", fmt::ptr(this), port);
|
||||
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration",
|
||||
fmt::ptr(this),
|
||||
port);
|
||||
local6.setPort(port);
|
||||
}
|
||||
}
|
||||
@@ -146,7 +155,7 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
if (not context.sock) {
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
|
||||
}
|
||||
context.sock->setOnReceive([&] (net::PacketList&& pkts) {
|
||||
context.sock->setOnReceive([&](net::PacketList&& pkts) {
|
||||
net::PacketList ret;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(sock_mtx);
|
||||
@@ -169,12 +178,18 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
|
||||
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
|
||||
}
|
||||
auto dht = std::make_unique<Dht>(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger, std::move(context.rng));
|
||||
dht_ = std::make_unique<SecureDht>(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger);
|
||||
auto dht = std::make_unique<Dht>(std::move(context.sock),
|
||||
SecureDht::getConfig(config.dht_config),
|
||||
context.logger,
|
||||
std::move(context.rng));
|
||||
dht_ = std::make_unique<SecureDht>(std::move(dht),
|
||||
config.dht_config,
|
||||
std::move(context.identityAnnouncedCb),
|
||||
context.logger);
|
||||
} else {
|
||||
enableProxy(true);
|
||||
}
|
||||
} catch(const std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
config_ = {};
|
||||
identityAnnouncedCb_ = {};
|
||||
dht_.reset();
|
||||
@@ -215,7 +230,8 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
if (not pending_ops_prio.empty())
|
||||
return true;
|
||||
auto s = getStatus();
|
||||
if (not pending_ops.empty() and (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping))
|
||||
if (not pending_ops.empty()
|
||||
and (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -230,9 +246,8 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
if (config.proxy_server.empty()) {
|
||||
if (config.peer_discovery or config.peer_publish) {
|
||||
#ifdef OPENDHT_PEER_DISCOVERY
|
||||
peerDiscovery_ = context.peerDiscovery ?
|
||||
std::move(context.peerDiscovery) :
|
||||
std::make_shared<PeerDiscovery>();
|
||||
peerDiscovery_ = context.peerDiscovery ? std::move(context.peerDiscovery)
|
||||
: std::make_shared<PeerDiscovery>();
|
||||
#else
|
||||
std::cerr << "Peer discovery requested but OpenDHT built without peer discovery support." << std::endl;
|
||||
#endif
|
||||
@@ -241,12 +256,13 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
#ifdef OPENDHT_PEER_DISCOVERY
|
||||
auto netId = config.dht_config.node_config.network;
|
||||
if (config.peer_discovery) {
|
||||
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE, [this, netId](NodeInsertionPack&& v, SockAddr&& addr){
|
||||
addr.setPort(v.port);
|
||||
if (v.nodeId != dht_->getNodeId() && netId == v.net){
|
||||
bootstrap(v.nodeId, addr);
|
||||
}
|
||||
});
|
||||
peerDiscovery_->startDiscovery<NodeInsertionPack>(PEER_DISCOVERY_DHT_SERVICE,
|
||||
[this, netId](NodeInsertionPack&& v, SockAddr&& addr) {
|
||||
addr.setPort(v.port);
|
||||
if (v.nodeId != dht_->getNodeId() && netId == v.net) {
|
||||
bootstrap(v.nodeId, addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (config.peer_publish) {
|
||||
msgpack::sbuffer sbuf_node;
|
||||
@@ -273,11 +289,9 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
statusCbs.emplace_back([this](NodeStatus status4, NodeStatus status6) {
|
||||
if (status4 == NodeStatus::Disconnected && status6 == NodeStatus::Disconnected) {
|
||||
peerDiscovery_->connectivityChanged();
|
||||
}
|
||||
else if (status4 != NodeStatus::Connected || status6 != NodeStatus::Connected) {
|
||||
} else if (status4 != NodeStatus::Connected || status6 != NodeStatus::Connected) {
|
||||
peerDiscovery_->stopConnectivityChanged();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
#endif
|
||||
@@ -285,15 +299,15 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
|
||||
DhtRunner::shutdown(ShutdownCallback cb, bool stop)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
auto expected = State::Running;
|
||||
if (not running.compare_exchange_strong(expected, State::Stopping)) {
|
||||
if (expected == State::Stopping and ongoing_ops) {
|
||||
if (cb)
|
||||
shutdownCallbacks_.emplace_back(std::move(cb));
|
||||
}
|
||||
else if (cb) {
|
||||
} else if (cb) {
|
||||
lck.unlock();
|
||||
cb();
|
||||
}
|
||||
@@ -304,7 +318,9 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
|
||||
ongoing_ops++;
|
||||
shutdownCallbacks_.emplace_back(std::move(cb));
|
||||
pending_ops.emplace([=](SecureDht&) mutable {
|
||||
auto onShutdown = [this]{ opEnded(); };
|
||||
auto onShutdown = [this] {
|
||||
opEnded();
|
||||
};
|
||||
if (dht_)
|
||||
dht_->shutdown(onShutdown, stop);
|
||||
else
|
||||
@@ -314,29 +330,35 @@ DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::opEnded() {
|
||||
DhtRunner::opEnded()
|
||||
{
|
||||
if (--ongoing_ops == 0)
|
||||
checkShutdown();
|
||||
}
|
||||
|
||||
DoneCallback
|
||||
DhtRunner::bindOpDoneCallback(DoneCallback&& cb) {
|
||||
return [this, cb = std::move(cb)](bool ok, const std::vector<std::shared_ptr<Node>>& nodes){
|
||||
if (cb) cb(ok, nodes);
|
||||
DhtRunner::bindOpDoneCallback(DoneCallback&& cb)
|
||||
{
|
||||
return [this, cb = std::move(cb)](bool ok, const std::vector<std::shared_ptr<Node>>& nodes) {
|
||||
if (cb)
|
||||
cb(ok, nodes);
|
||||
opEnded();
|
||||
};
|
||||
}
|
||||
|
||||
DoneCallbackSimple
|
||||
DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) {
|
||||
return [this, cb = std::move(cb)](bool ok){
|
||||
if (cb) cb(ok);
|
||||
DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb)
|
||||
{
|
||||
return [this, cb = std::move(cb)](bool ok) {
|
||||
if (cb)
|
||||
cb(ok);
|
||||
opEnded();
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
DhtRunner::checkShutdown() {
|
||||
DhtRunner::checkShutdown()
|
||||
{
|
||||
decltype(shutdownCallbacks_) cbs;
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
@@ -345,7 +367,8 @@ DhtRunner::checkShutdown() {
|
||||
cbs = std::move(shutdownCallbacks_);
|
||||
}
|
||||
for (auto& cb : cbs)
|
||||
if (cb) cb();
|
||||
if (cb)
|
||||
cb();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -390,16 +413,18 @@ DhtRunner::join()
|
||||
}
|
||||
|
||||
SockAddr
|
||||
DhtRunner::getBound(sa_family_t af) const {
|
||||
DhtRunner::getBound(sa_family_t af) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
if (auto sock = dht_->getSocket())
|
||||
return sock->getBound(af);
|
||||
return SockAddr{};
|
||||
return SockAddr {};
|
||||
}
|
||||
|
||||
in_port_t
|
||||
DhtRunner::getBoundPort(sa_family_t af) const {
|
||||
DhtRunner::getBoundPort(sa_family_t af) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
if (auto sock = dht_->getSocket())
|
||||
@@ -417,24 +442,24 @@ DhtRunner::dumpTables() const
|
||||
InfoHash
|
||||
DhtRunner::getId() const
|
||||
{
|
||||
return dht_ ? dht_->getId() : InfoHash{};
|
||||
return dht_ ? dht_->getId() : InfoHash {};
|
||||
}
|
||||
|
||||
std::shared_ptr<crypto::PublicKey>
|
||||
DhtRunner::getPublicKey() const
|
||||
{
|
||||
return dht_ ? dht_->getPublicKey() : std::shared_ptr<crypto::PublicKey>{};
|
||||
return dht_ ? dht_->getPublicKey() : std::shared_ptr<crypto::PublicKey> {};
|
||||
}
|
||||
|
||||
InfoHash
|
||||
DhtRunner::getNodeId() const
|
||||
{
|
||||
return dht_ ? dht_->getNodeId() : InfoHash{};
|
||||
return dht_ ? dht_->getNodeId() : InfoHash {};
|
||||
}
|
||||
|
||||
|
||||
std::pair<size_t, size_t>
|
||||
DhtRunner::getStoreSize() const {
|
||||
DhtRunner::getStoreSize() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (!dht_)
|
||||
return {};
|
||||
@@ -442,7 +467,8 @@ DhtRunner::getStoreSize() const {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setStorageLimit(size_t limit) {
|
||||
DhtRunner::setStorageLimit(size_t limit)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (!dht_)
|
||||
throw std::runtime_error("dht is not running");
|
||||
@@ -450,7 +476,8 @@ DhtRunner::setStorageLimit(size_t limit) {
|
||||
}
|
||||
|
||||
std::vector<NodeExport>
|
||||
DhtRunner::exportNodes() const {
|
||||
DhtRunner::exportNodes() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (!dht_)
|
||||
return {};
|
||||
@@ -458,7 +485,8 @@ DhtRunner::exportNodes() const {
|
||||
}
|
||||
|
||||
std::vector<ValuesExport>
|
||||
DhtRunner::exportValues() const {
|
||||
DhtRunner::exportValues() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (!dht_)
|
||||
return {};
|
||||
@@ -466,7 +494,8 @@ DhtRunner::exportValues() const {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLogger(const Sp<Logger>& logger) {
|
||||
DhtRunner::setLogger(const Sp<Logger>& logger)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
logger_ = logger;
|
||||
if (dht_)
|
||||
@@ -474,26 +503,40 @@ DhtRunner::setLogger(const Sp<Logger>& logger) {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLogFilter(const InfoHash& f) {
|
||||
DhtRunner::setLogFilter(const InfoHash& f)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
dht_->setLogFilter(f);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::registerType(const ValueType& type) {
|
||||
DhtRunner::registerType(const ValueType& type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->registerType(type);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::importValues(const std::vector<ValuesExport>& values) {
|
||||
DhtRunner::registerInsecureType(const ValueType& type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->registerInsecureType(type);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::importValues(const std::vector<ValuesExport>& values)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->importValues(values);
|
||||
}
|
||||
|
||||
unsigned
|
||||
DhtRunner::getNodesStats(sa_family_t af, unsigned *good_return, unsigned *dubious_return, unsigned *cached_return, unsigned *incoming_return) const
|
||||
DhtRunner::getNodesStats(sa_family_t af,
|
||||
unsigned* good_return,
|
||||
unsigned* dubious_return,
|
||||
unsigned* cached_return,
|
||||
unsigned* incoming_return) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
const auto stats = dht_->getNodesStats(af);
|
||||
@@ -516,7 +559,8 @@ DhtRunner::getNodesStats(sa_family_t af) const
|
||||
}
|
||||
|
||||
NodeInfo
|
||||
DhtRunner::getNodeInfo() const {
|
||||
DhtRunner::getNodeInfo() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
NodeInfo info {};
|
||||
if (dht_) {
|
||||
@@ -538,7 +582,7 @@ DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ongoing_ops++;
|
||||
pending_ops_prio.emplace([cb = std::move(cb), this](SecureDht& dht){
|
||||
pending_ops_prio.emplace([cb = std::move(cb), this](SecureDht& dht) {
|
||||
auto sinfo = std::make_shared<NodeInfo>();
|
||||
auto& info = *sinfo;
|
||||
info.id = dht.getId();
|
||||
@@ -616,7 +660,7 @@ DhtRunner::getPublicAddress(std::function<void(std::vector<SockAddr>&&)> cb, sa_
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ongoing_ops++;
|
||||
pending_ops_prio.emplace([cb = std::move(cb), this, af](SecureDht& dht){
|
||||
pending_ops_prio.emplace([cb = std::move(cb), this, af](SecureDht& dht) {
|
||||
cb(dht.getPublicAddress(af));
|
||||
opEnded();
|
||||
});
|
||||
@@ -624,19 +668,22 @@ DhtRunner::getPublicAddress(std::function<void(std::vector<SockAddr>&&)> cb, sa_
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::registerCertificate(const std::shared_ptr<crypto::Certificate>& cert) {
|
||||
DhtRunner::registerCertificate(const std::shared_ptr<crypto::Certificate>& cert)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
dht_->registerCertificate(cert);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setLocalCertificateStore(CertificateStoreQueryLegacy&& query_method) {
|
||||
DhtRunner::setLocalCertificateStore(CertificateStoreQueryLegacy&& query_method)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
dht_->setLocalCertificateStore(std::forward<CertificateStoreQueryLegacy>(query_method));
|
||||
}
|
||||
|
||||
void DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method)
|
||||
void
|
||||
DhtRunner::setLocalCertificateStore(CertificateStoreQuery&& query_method)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
if (dht_)
|
||||
@@ -653,8 +700,10 @@ DhtRunner::loop_()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
auto s = getStatus();
|
||||
ops = (pending_ops_prio.empty() && (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping)) ?
|
||||
std::move(pending_ops) : std::move(pending_ops_prio);
|
||||
ops = (pending_ops_prio.empty()
|
||||
&& (s == NodeStatus::Connected or s == NodeStatus::Disconnected or running == State::Stopping))
|
||||
? std::move(pending_ops)
|
||||
: std::move(pending_ops_prio);
|
||||
}
|
||||
while (not ops.empty()) {
|
||||
ops.front()(*dht_);
|
||||
@@ -713,7 +762,7 @@ DhtRunner::loop_()
|
||||
if (nstatus4 != status4 || nstatus6 != status6) {
|
||||
status4 = nstatus4;
|
||||
status6 = nstatus6;
|
||||
for (auto& cb : statusCbs){
|
||||
for (auto& cb : statusCbs) {
|
||||
cb(status4, status6);
|
||||
}
|
||||
}
|
||||
@@ -727,7 +776,8 @@ DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (dcb) dcb(false, {});
|
||||
if (dcb)
|
||||
dcb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
@@ -743,11 +793,13 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
|
||||
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) {
|
||||
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (done_cb) done_cb(false, {});
|
||||
if (done_cb)
|
||||
done_cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
@@ -814,14 +866,12 @@ DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([=,
|
||||
cb = std::move(cb),
|
||||
sv = std::make_shared<Value>(std::move(value))
|
||||
] (SecureDht& dht) mutable {
|
||||
pending_ops.emplace([=, cb = std::move(cb), sv = std::make_shared<Value>(std::move(value))](SecureDht& dht) mutable {
|
||||
dht.put(hash, sv, bindOpDoneCallback(std::move(cb)), created, permanent);
|
||||
});
|
||||
cv.notify_all();
|
||||
@@ -833,7 +883,8 @@ DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, tim
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
@@ -853,9 +904,7 @@ void
|
||||
DhtRunner::cancelPut(const InfoHash& h, Value::Id id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelPut(h, id);
|
||||
});
|
||||
pending_ops.emplace([=](SecureDht& dht) { dht.cancelPut(h, id); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -863,9 +912,7 @@ void
|
||||
DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops.emplace([=](SecureDht& dht) {
|
||||
dht.cancelPut(h, value->id);
|
||||
});
|
||||
pending_ops.emplace([=](SecureDht& dht) { dht.cancelPut(h, value->id); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -875,14 +922,12 @@ DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback c
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([=,
|
||||
cb = std::move(cb),
|
||||
value = std::move(value)
|
||||
](SecureDht& dht) mutable {
|
||||
pending_ops.emplace([=, cb = std::move(cb), value = std::move(value)](SecureDht& dht) mutable {
|
||||
dht.putSigned(hash, value, bindOpDoneCallback(std::move(cb)), permanent);
|
||||
});
|
||||
cv.notify_all();
|
||||
@@ -906,14 +951,12 @@ DhtRunner::putEncrypted(InfoHash hash, const PkId& to, std::shared_ptr<Value> va
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([=,
|
||||
cb = std::move(cb),
|
||||
value = std::move(value)
|
||||
] (SecureDht& dht) mutable {
|
||||
pending_ops.emplace([=, cb = std::move(cb), value = std::move(value)](SecureDht& dht) mutable {
|
||||
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
|
||||
});
|
||||
cv.notify_all();
|
||||
@@ -925,14 +968,12 @@ DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([=,
|
||||
cb = std::move(cb),
|
||||
value = std::move(value)
|
||||
] (SecureDht& dht) mutable {
|
||||
pending_ops.emplace([=, cb = std::move(cb), value = std::move(value)](SecureDht& dht) mutable {
|
||||
dht.putEncrypted(hash, to, value, bindOpDoneCallback(std::move(cb)), permanent);
|
||||
});
|
||||
cv.notify_all();
|
||||
@@ -951,26 +992,29 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
|
||||
DhtRunner::putEncrypted(InfoHash hash,
|
||||
const std::shared_ptr<crypto::PublicKey>& to,
|
||||
std::shared_ptr<Value> value,
|
||||
DoneCallback cb,
|
||||
bool permanent)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false, {});
|
||||
if (cb)
|
||||
cb(false, {});
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([=,
|
||||
cb = std::move(cb),
|
||||
value = std::move(value)
|
||||
] (SecureDht& dht) mutable {
|
||||
pending_ops.emplace([=, cb = std::move(cb), value = std::move(value)](SecureDht& dht) mutable {
|
||||
dht.putEncrypted(hash, *to, value, bindOpDoneCallback(std::move(cb)), permanent);
|
||||
});
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb, bool permanent)
|
||||
DhtRunner::putEncrypted(
|
||||
InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb, bool permanent)
|
||||
{
|
||||
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
|
||||
}
|
||||
@@ -979,9 +1023,7 @@ void
|
||||
DhtRunner::bootstrap(const std::string& host, const std::string& service)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([host, service] (SecureDht& dht) mutable {
|
||||
dht.addBootstrap(host, service);
|
||||
});
|
||||
pending_ops_prio.emplace([host, service](SecureDht& dht) mutable { dht.addBootstrap(host, service); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -989,9 +1031,9 @@ void
|
||||
DhtRunner::bootstrap(const std::string& hostService)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([host_service = splitPort(hostService)] (SecureDht& dht) mutable {
|
||||
dht.addBootstrap(host_service.first, host_service.second);
|
||||
});
|
||||
auto [h, s] = splitPort(hostService);
|
||||
pending_ops_prio.emplace(
|
||||
[host = std::string(h), service = std::string(s)](SecureDht& dht) { dht.addBootstrap(host, service); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -999,9 +1041,7 @@ void
|
||||
DhtRunner::clearBootstrap()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([] (SecureDht& dht) mutable {
|
||||
dht.clearBootstrap();
|
||||
});
|
||||
pending_ops_prio.emplace([](SecureDht& dht) mutable { dht.clearBootstrap(); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -1014,15 +1054,12 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple cb)
|
||||
}
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
ongoing_ops++;
|
||||
pending_ops_prio.emplace([
|
||||
cb = bindOpDoneCallback(std::move(cb)),
|
||||
nodes = std::move(nodes)
|
||||
] (SecureDht& dht) mutable {
|
||||
pending_ops_prio.emplace([cb = bindOpDoneCallback(std::move(cb)), nodes = std::move(nodes)](SecureDht& dht) mutable {
|
||||
auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
|
||||
for (auto& node : nodes) {
|
||||
if (node.getPort() == 0)
|
||||
node.setPort(net::DHT_DEFAULT_PORT);
|
||||
dht.pingNode(std::move(node), [rem,cb](bool ok) {
|
||||
dht.pingNode(std::move(node), [rem, cb](bool ok) {
|
||||
auto& r = *rem;
|
||||
r.first--;
|
||||
r.second |= ok;
|
||||
@@ -1041,7 +1078,8 @@ DhtRunner::bootstrap(SockAddr addr, DoneCallbackSimple cb)
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
if (cb) cb(false);
|
||||
if (cb)
|
||||
cb(false);
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
@@ -1057,9 +1095,7 @@ DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running)
|
||||
return;
|
||||
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
|
||||
dht.insertNode(id, address);
|
||||
});
|
||||
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable { dht.insertNode(id, address); });
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -1091,7 +1127,8 @@ DhtRunner::connectivityChanged()
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb) {
|
||||
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
lck.unlock();
|
||||
@@ -1099,8 +1136,8 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Ce
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
|
||||
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
|
||||
pending_ops.emplace([this, hash, cb = std::move(cb)](SecureDht& dht) {
|
||||
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt) {
|
||||
cb(crt);
|
||||
opEnded();
|
||||
});
|
||||
@@ -1108,7 +1145,8 @@ DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Ce
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void DhtRunner::findCertificate(PkId hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)> cb)
|
||||
void
|
||||
DhtRunner::findCertificate(PkId hash, std::function<void(const std::shared_ptr<crypto::Certificate>&)> cb)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(storage_mtx);
|
||||
if (running != State::Running) {
|
||||
@@ -1116,8 +1154,8 @@ void DhtRunner::findCertificate(PkId hash, std::function<void(const std::shared_
|
||||
return;
|
||||
}
|
||||
ongoing_ops++;
|
||||
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
|
||||
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
|
||||
pending_ops.emplace([this, hash, cb = std::move(cb)](SecureDht& dht) {
|
||||
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt) {
|
||||
cb(crt);
|
||||
opEnded();
|
||||
});
|
||||
@@ -1159,22 +1197,22 @@ DhtRunner::enableProxy(bool proxify)
|
||||
if (proxify) {
|
||||
// Init the proxy client
|
||||
auto dht_via_proxy = std::make_unique<DhtProxyClient>(
|
||||
config_.server_ca,
|
||||
config_.client_identity,
|
||||
[this]{
|
||||
if (config_.threaded) {
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht&) mutable {});
|
||||
cv.notify_all();
|
||||
}
|
||||
},
|
||||
config_.proxy_server,
|
||||
config_.proxy_user_agent,
|
||||
config_.push_node_id,
|
||||
config_.push_token,
|
||||
config_.push_topic,
|
||||
config_.push_platform,
|
||||
logger_);
|
||||
config_.server_ca,
|
||||
config_.client_identity,
|
||||
[this] {
|
||||
if (config_.threaded) {
|
||||
std::lock_guard<std::mutex> lck(storage_mtx);
|
||||
pending_ops_prio.emplace([=](SecureDht&) mutable {});
|
||||
cv.notify_all();
|
||||
}
|
||||
},
|
||||
config_.proxy_server,
|
||||
config_.proxy_user_agent,
|
||||
config_.push_node_id,
|
||||
config_.push_token,
|
||||
config_.push_topic,
|
||||
config_.push_platform,
|
||||
logger_);
|
||||
dht_ = std::make_unique<SecureDht>(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_);
|
||||
// and use it
|
||||
use_proxy = proxify;
|
||||
@@ -1199,7 +1237,8 @@ DhtRunner::forwardAllMessages(bool forward)
|
||||
* Updates the push notification device token
|
||||
*/
|
||||
void
|
||||
DhtRunner::setPushNotificationToken(const std::string& token) {
|
||||
DhtRunner::setPushNotificationToken(const std::string& token)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
|
||||
config_.push_token = token;
|
||||
@@ -1211,7 +1250,8 @@ DhtRunner::setPushNotificationToken(const std::string& token) {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setPushNotificationTopic(const std::string& topic) {
|
||||
DhtRunner::setPushNotificationTopic(const std::string& topic)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
|
||||
config_.push_topic = topic;
|
||||
@@ -1223,7 +1263,8 @@ DhtRunner::setPushNotificationTopic(const std::string& topic) {
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunner::setPushNotificationPlatform(const std::string& platform) {
|
||||
DhtRunner::setPushNotificationPlatform(const std::string& platform)
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(dht_mtx);
|
||||
#if defined(OPENDHT_PROXY_CLIENT) && defined(OPENDHT_PUSH_NOTIFICATIONS)
|
||||
config_.push_platform = platform;
|
||||
@@ -1256,4 +1297,4 @@ DhtRunner::pushNotificationReceived([[maybe_unused]] const std::map<std::string,
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace dht
|
||||
+509
-336
File diff suppressed because it is too large.
Load diff
+9
-31
@@ -294,7 +294,8 @@ NetworkEngine::requestStep(Sp<Request> sreq)
|
||||
requests.erase(req.tid);
|
||||
return;
|
||||
} else if (req.attempt_count == 1) {
|
||||
req.on_expired(req, false);
|
||||
if (req.on_expired)
|
||||
req.on_expired(req, false);
|
||||
}
|
||||
|
||||
auto err = send(node.getAddr(), (char*)req.msg.data(), req.msg.size(), node.getReplyTime() < now - UDP_REPLY_TIME);
|
||||
@@ -749,11 +750,7 @@ NetworkEngine::sendPing(const Sp<Node>& node, RequestCb&& on_done, RequestExpire
|
||||
on_done(req_status, {});
|
||||
}
|
||||
},
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
}
|
||||
std::move(on_expired)
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.ping;
|
||||
@@ -819,11 +816,7 @@ NetworkEngine::sendFindNode(const Sp<Node>& n, const InfoHash& target, want_t wa
|
||||
on_done(req_status, {std::forward<ParsedMessage>(msg)});
|
||||
}
|
||||
},
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
}
|
||||
std::move(on_expired)
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.find;
|
||||
@@ -875,11 +868,7 @@ NetworkEngine::sendGetValues(const Sp<Node>& n, const InfoHash& info_hash, const
|
||||
on_done(req_status, {std::forward<ParsedMessage>(msg)});
|
||||
}
|
||||
},
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
}
|
||||
std::move(on_expired)
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.get;
|
||||
@@ -1157,10 +1146,7 @@ NetworkEngine::sendListen(const Sp<Node>& n,
|
||||
if (on_done)
|
||||
on_done(req_status, {std::forward<ParsedMessage>(msg)});
|
||||
},
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired)
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
std::move(on_expired)
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.listen;
|
||||
@@ -1240,11 +1226,7 @@ NetworkEngine::sendAnnounceValue(const Sp<Node>& n,
|
||||
}
|
||||
}
|
||||
},
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
}
|
||||
std::move(on_expired)
|
||||
);
|
||||
req->parts = std::move(v);
|
||||
sendRequest(req);
|
||||
@@ -1372,12 +1354,8 @@ NetworkEngine::sendRefreshValue(const Sp<Node>& n,
|
||||
}
|
||||
}
|
||||
},
|
||||
on_error,
|
||||
[=](const Request& req_status, bool done) { /* on expired */
|
||||
if (on_expired) {
|
||||
on_expired(req_status, done);
|
||||
}
|
||||
}
|
||||
std::move(on_error),
|
||||
std::move(on_expired)
|
||||
);
|
||||
sendRequest(req);
|
||||
++out_stats.refresh;
|
||||
|
||||
+2
-1
@@ -89,7 +89,8 @@ struct Request {
|
||||
void setExpired() {
|
||||
if (pending()) {
|
||||
state_ = Request::State::EXPIRED;
|
||||
on_expired(*this, true);
|
||||
if (on_expired)
|
||||
on_expired(*this, true);
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
+47
-31
@@ -20,7 +20,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && (_WIN32_WINNT < 0x0502) && (NTDDI_VERSION >= NTDDI_VISTA)
|
||||
#if defined(_WIN32) && (_WIN32_WINNT < 0x0502) && (NTDDI_VERSION >= NTDDI_VISTA)
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WIN10
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -42,30 +42,35 @@
|
||||
|
||||
namespace dht {
|
||||
|
||||
const char* version() {
|
||||
const char*
|
||||
version()
|
||||
{
|
||||
return PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
|
||||
};
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
splitPort(std::string_view s) {
|
||||
std::pair<std::string_view, std::string_view>
|
||||
splitPort(std::string_view s)
|
||||
{
|
||||
if (s.empty())
|
||||
return {};
|
||||
if (s[0] == '[') {
|
||||
std::size_t closure = s.find_first_of(']');
|
||||
std::size_t found = s.find_last_of(':');
|
||||
if (closure == std::string_view::npos)
|
||||
return {std::string(s), ""};
|
||||
return {s, ""};
|
||||
if (found == std::string_view::npos or found < closure)
|
||||
return {std::string(s.substr(1,closure-1)), ""};
|
||||
return {std::string(s.substr(1,closure-1)), std::string(s.substr(found+1))};
|
||||
return {s.substr(1, closure - 1), ""};
|
||||
return {s.substr(1, closure - 1), s.substr(found + 1)};
|
||||
}
|
||||
std::size_t found = s.find_last_of(':');
|
||||
std::size_t first = s.find_first_of(':');
|
||||
if (found == std::string_view::npos or found != first)
|
||||
return {std::string(s), ""};
|
||||
return {std::string(s.substr(0,found)), std::string(s.substr(found+1))};
|
||||
return {s, ""};
|
||||
return {s.substr(0, found), s.substr(found + 1)};
|
||||
}
|
||||
|
||||
std::vector<SockAddr>
|
||||
@@ -80,7 +85,7 @@ SockAddr::resolve(const std::string& host, const std::string& service)
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
addrinfo* info = nullptr;
|
||||
int rc = getaddrinfo(host.c_str(), service.empty() ? nullptr : service.c_str(), &hints, &info);
|
||||
if(rc != 0)
|
||||
if (rc != 0)
|
||||
throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
|
||||
|
||||
for (addrinfo* infop = info; infop; infop = infop->ai_next)
|
||||
@@ -108,11 +113,13 @@ SockAddr::setAddress(const char* address)
|
||||
throw std::runtime_error(std::string("Can't parse IP address: ") + strerror(errno));
|
||||
}
|
||||
|
||||
void print_addr(std::ostream& out, const sockaddr* sa, socklen_t slen)
|
||||
void
|
||||
print_addr(std::ostream& out, const sockaddr* sa, socklen_t slen)
|
||||
{
|
||||
char hbuf[NI_MAXHOST];
|
||||
char sbuf[NI_MAXSERV];
|
||||
if (sa and slen and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
||||
if (sa and slen
|
||||
and !getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
||||
if (sa->sa_family == AF_INET6)
|
||||
out << '[' << hbuf << ']';
|
||||
else
|
||||
@@ -134,7 +141,7 @@ print_addr(const sockaddr* sa, socklen_t slen)
|
||||
std::string
|
||||
print_addr(const sockaddr_storage& ss, socklen_t sslen)
|
||||
{
|
||||
return print_addr((const sockaddr*)&ss, sslen);
|
||||
return print_addr((const sockaddr*) &ss, sslen);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -156,7 +163,7 @@ SockAddr::isLoopback() const
|
||||
switch (getFamily()) {
|
||||
case AF_INET: {
|
||||
auto addr_host = ntohl(getIPv4().sin_addr.s_addr);
|
||||
uint8_t b1 = (uint8_t)(addr_host >> 24);
|
||||
uint8_t b1 = (uint8_t) (addr_host >> 24);
|
||||
return b1 == 127;
|
||||
}
|
||||
case AF_INET6:
|
||||
@@ -176,8 +183,8 @@ SockAddr::isPrivate() const
|
||||
case AF_INET: {
|
||||
auto addr_host = ntohl(getIPv4().sin_addr.s_addr);
|
||||
uint8_t b1, b2;
|
||||
b1 = (uint8_t)(addr_host >> 24);
|
||||
b2 = (uint8_t)((addr_host >> 16) & 0x0ff);
|
||||
b1 = (uint8_t) (addr_host >> 24);
|
||||
b2 = (uint8_t) ((addr_host >> 16) & 0x0ff);
|
||||
// 10.x.y.z
|
||||
if (b1 == 10)
|
||||
return true;
|
||||
@@ -240,11 +247,15 @@ SockAddr::getMappedIPv6()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool operator==(const SockAddr& a, const SockAddr& b) {
|
||||
bool
|
||||
operator==(const SockAddr& a, const SockAddr& b)
|
||||
{
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
time_point from_time_t(std::time_t t) {
|
||||
time_point
|
||||
from_time_t(std::time_t t)
|
||||
{
|
||||
auto dt = system_clock::from_time_t(t) - system_clock::now();
|
||||
auto now = clock::now();
|
||||
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
|
||||
@@ -254,7 +265,9 @@ time_point from_time_t(std::time_t t) {
|
||||
return now + dt;
|
||||
}
|
||||
|
||||
std::time_t to_time_t(time_point t) {
|
||||
std::time_t
|
||||
to_time_t(time_point t)
|
||||
{
|
||||
auto dt = t - clock::now();
|
||||
auto now = system_clock::now();
|
||||
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
|
||||
@@ -265,15 +278,16 @@ std::time_t to_time_t(time_point t) {
|
||||
}
|
||||
|
||||
Blob
|
||||
unpackBlob(const msgpack::object& o) {
|
||||
unpackBlob(const msgpack::object& o)
|
||||
{
|
||||
switch (o.type) {
|
||||
case msgpack::type::BIN:
|
||||
return {o.via.bin.ptr, o.via.bin.ptr+o.via.bin.size};
|
||||
return {o.via.bin.ptr, o.via.bin.ptr + o.via.bin.size};
|
||||
case msgpack::type::STR:
|
||||
return {o.via.str.ptr, o.via.str.ptr+o.via.str.size};
|
||||
return {o.via.str.ptr, o.via.str.ptr + o.via.str.size};
|
||||
case msgpack::type::ARRAY: {
|
||||
Blob ret(o.via.array.size);
|
||||
std::transform(o.via.array.ptr, o.via.array.ptr+o.via.array.size, ret.begin(), [](const msgpack::object& b) {
|
||||
std::transform(o.via.array.ptr, o.via.array.ptr + o.via.array.size, ret.begin(), [](const msgpack::object& b) {
|
||||
return b.as<uint8_t>();
|
||||
});
|
||||
return ret;
|
||||
@@ -284,21 +298,23 @@ unpackBlob(const msgpack::object& o) {
|
||||
}
|
||||
|
||||
msgpack::unpacked
|
||||
unpackMsg(Blob b) {
|
||||
return msgpack::unpack((const char*)b.data(), b.size());
|
||||
unpackMsg(Blob b)
|
||||
{
|
||||
return msgpack::unpack((const char*) b.data(), b.size());
|
||||
}
|
||||
|
||||
msgpack::object*
|
||||
findMapValue(const msgpack::object& map, const char* key, size_t key_length) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
findMapValue(const msgpack::object& map, const char* key, size_t key_length)
|
||||
{
|
||||
if (map.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if (o.key.type == msgpack::type::STR
|
||||
&& key_length == o.key.via.str.size
|
||||
if (o.key.type == msgpack::type::STR && key_length == o.key.via.str.size
|
||||
&& std::strncmp(o.key.via.str.ptr, key, o.key.via.str.size) == 0)
|
||||
return &o.val;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace dht
|
||||
+71
-49
@@ -30,19 +30,22 @@
|
||||
#include "base64.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace dht {
|
||||
|
||||
const std::string Query::QUERY_PARSE_ERROR {"Error parsing query."};
|
||||
|
||||
Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data) {
|
||||
if (not raw_filter) return {};
|
||||
Value::Filter
|
||||
bindFilterRaw(FilterRaw raw_filter, void* user_data)
|
||||
{
|
||||
if (not raw_filter)
|
||||
return {};
|
||||
return [=](const Value& value) {
|
||||
return raw_filter(value, user_data);
|
||||
};
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& s, const Value& v)
|
||||
std::ostream&
|
||||
operator<<(std::ostream& s, const Value& v)
|
||||
{
|
||||
auto flags(s.flags());
|
||||
s << "Value[id:" << std::hex << v.id << std::dec << ' ';
|
||||
@@ -240,7 +243,8 @@ Value::toJson() const
|
||||
}
|
||||
|
||||
uint64_t
|
||||
unpackId(const Json::Value& json, const std::string& key) {
|
||||
unpackId(const Json::Value& json, const std::string& key)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
try {
|
||||
const auto& t = json[key];
|
||||
@@ -249,7 +253,8 @@ unpackId(const Json::Value& json, const std::string& key) {
|
||||
} else {
|
||||
ret = t.asLargestUInt();
|
||||
}
|
||||
} catch (...) {}
|
||||
} catch (...) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -297,7 +302,7 @@ Value::decrypt(const crypto::PrivateKey& key)
|
||||
decrypted = true;
|
||||
if (isEncrypted()) {
|
||||
auto decryptedBlob = key.decrypt(cypher);
|
||||
auto msg = msgpack::unpack((const char*)decryptedBlob.data(), decryptedBlob.size());
|
||||
auto msg = msgpack::unpack((const char*) decryptedBlob.data(), decryptedBlob.size());
|
||||
auto v = std::make_unique<Value>(id);
|
||||
v->msgpack_unpack_body(msg.get());
|
||||
if (v->recipient != key.getPublicKey().getId())
|
||||
@@ -355,13 +360,13 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
{
|
||||
if (not s.empty()) {
|
||||
auto selection = s.getSelection();
|
||||
std::transform(selection.begin(), selection.end(), std::inserter(index, index.end()),
|
||||
[](const std::set<Value::Field>::value_type& f) {
|
||||
return std::make_pair(f, FieldValue {});
|
||||
});
|
||||
std::transform(selection.begin(),
|
||||
selection.end(),
|
||||
std::inserter(index, index.end()),
|
||||
[](const std::set<Value::Field>::value_type& f) { return std::make_pair(f, FieldValue {}); });
|
||||
} else {
|
||||
index.clear();
|
||||
for (size_t f = 1 ; f < static_cast<int>(Value::Field::COUNT) ; ++f)
|
||||
for (size_t f = 1; f < static_cast<int>(Value::Field::COUNT); ++f)
|
||||
index[static_cast<Value::Field>(f)] = {};
|
||||
}
|
||||
for (const auto& fvp : index) {
|
||||
@@ -374,13 +379,15 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
index[f] = {f, v.type};
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash()};
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
index[f] = {f, v.seq};
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
|
||||
index[f] = {
|
||||
f, Blob {v.user_type.begin(), v.user_type.end()}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -388,7 +395,9 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
}
|
||||
}
|
||||
|
||||
bool FieldValueIndex::containedIn(const FieldValueIndex& other) const {
|
||||
bool
|
||||
FieldValueIndex::containedIn(const FieldValueIndex& other) const
|
||||
{
|
||||
if (index.size() > other.index.size())
|
||||
return false;
|
||||
for (const auto& field : index) {
|
||||
@@ -399,7 +408,9 @@ bool FieldValueIndex::containedIn(const FieldValueIndex& other) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi) {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FieldValueIndex& fvi)
|
||||
{
|
||||
os << "Index[";
|
||||
for (auto v = fvi.index.begin(); v != fvi.index.end(); ++v) {
|
||||
switch (v->first) {
|
||||
@@ -438,7 +449,7 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
|
||||
|
||||
unsigned j = 0;
|
||||
for (const auto& field : fields) {
|
||||
auto& field_value = o.via.array.ptr[offset+(j++)];
|
||||
auto& field_value = o.via.array.ptr[offset + (j++)];
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
@@ -457,13 +468,16 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
|
||||
}
|
||||
}
|
||||
|
||||
void trim_str(std::string& str) {
|
||||
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(' '));
|
||||
str = str.substr(first, last - first + 1);
|
||||
}
|
||||
|
||||
Select::Select(std::string_view q_str) {
|
||||
Select::Select(std::string_view q_str)
|
||||
{
|
||||
std::istringstream q_iss {std::string(q_str)};
|
||||
std::string token {};
|
||||
q_iss >> token;
|
||||
@@ -488,7 +502,8 @@ Select::Select(std::string_view q_str) {
|
||||
}
|
||||
}
|
||||
|
||||
Where::Where(std::string_view q_str) {
|
||||
Where::Where(std::string_view q_str)
|
||||
{
|
||||
std::istringstream q_iss {std::string(q_str)};
|
||||
std::string token {};
|
||||
q_iss >> token;
|
||||
@@ -509,11 +524,9 @@ Where::Where(std::string_view q_str) {
|
||||
std::string s {};
|
||||
std::istringstream convert {value_str};
|
||||
convert >> v;
|
||||
if (not convert
|
||||
and value_str.size() > 1
|
||||
and value_str[0] == '"'
|
||||
and value_str[value_str.size()-1] == '"')
|
||||
s = value_str.substr(1, value_str.size()-2);
|
||||
if (not convert and value_str.size() > 1 and value_str[0] == '"'
|
||||
and value_str[value_str.size() - 1] == '"')
|
||||
s = value_str.substr(1, value_str.size() - 2);
|
||||
else
|
||||
s = value_str;
|
||||
if (field_str == VALUE_KEY_ID)
|
||||
@@ -527,7 +540,8 @@ Where::Where(std::string_view q_str) {
|
||||
else if (field_str == "user_type")
|
||||
userType(s);
|
||||
else
|
||||
throw std::invalid_argument(Query::QUERY_PARSE_ERROR + " (WHERE) incorrect token near: " + field_str);
|
||||
throw std::invalid_argument(Query::QUERY_PARSE_ERROR
|
||||
+ " (WHERE) incorrect token near: " + field_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -536,24 +550,25 @@ Where::Where(std::string_view q_str) {
|
||||
void
|
||||
Query::msgpack_unpack(const msgpack::object& o)
|
||||
{
|
||||
if (o.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
if (o.type != msgpack::type::MAP)
|
||||
throw msgpack::type_error();
|
||||
|
||||
auto rfilters = findMapValue(o, "w"sv); /* unpacking filters */
|
||||
if (rfilters)
|
||||
auto rfilters = findMapValue(o, "w"sv); /* unpacking filters */
|
||||
if (rfilters)
|
||||
where.msgpack_unpack(*rfilters);
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
|
||||
auto rfield_selector = findMapValue(o, "s"sv); /* unpacking field selectors */
|
||||
if (rfield_selector)
|
||||
auto rfield_selector = findMapValue(o, "s"sv); /* unpacking field selectors */
|
||||
if (rfield_selector)
|
||||
select.msgpack_unpack(*rfield_selector);
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
else
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool subset(const std::vector<T>& fds, const std::vector<T>& qfds)
|
||||
template<typename T>
|
||||
bool
|
||||
subset(const std::vector<T>& fds, const std::vector<T>& qfds)
|
||||
{
|
||||
for (const auto& fd : fds) {
|
||||
if (std::find_if(qfds.begin(), qfds.end(), [&fd](const T& _vfd) { return fd == _vfd; }) == qfds.end())
|
||||
@@ -562,22 +577,28 @@ bool subset(const std::vector<T>& fds, const std::vector<T>& qfds)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Select::isSatisfiedBy(const Select& os) const {
|
||||
bool
|
||||
Select::isSatisfiedBy(const Select& os) const
|
||||
{
|
||||
/* empty, means all values are selected. */
|
||||
return fieldSelection_.empty() ?
|
||||
os.fieldSelection_.empty() :
|
||||
subset(fieldSelection_, os.fieldSelection_);
|
||||
return fieldSelection_.empty() ? os.fieldSelection_.empty() : subset(fieldSelection_, os.fieldSelection_);
|
||||
}
|
||||
|
||||
bool Where::isSatisfiedBy(const Where& ow) const {
|
||||
bool
|
||||
Where::isSatisfiedBy(const Where& ow) const
|
||||
{
|
||||
return subset(ow.filters_, filters_);
|
||||
}
|
||||
|
||||
bool Query::isSatisfiedBy(const Query& q) const {
|
||||
bool
|
||||
Query::isSatisfiedBy(const Query& q) const
|
||||
{
|
||||
return none or (where.isSatisfiedBy(q.where) and select.isSatisfiedBy(q.select));
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& s, const dht::Select& select)
|
||||
{
|
||||
s << "SELECT ";
|
||||
if (select.fieldSelection_.empty())
|
||||
s << '*';
|
||||
@@ -608,10 +629,12 @@ std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& s, const dht::Where& where)
|
||||
{
|
||||
if (not where.filters_.empty()) {
|
||||
s << "WHERE ";
|
||||
for (auto f = where.filters_.begin() ; f != where.filters_.end() ; ++f) {
|
||||
for (auto f = where.filters_.begin(); f != where.filters_.end(); ++f) {
|
||||
switch (f->getField()) {
|
||||
case Value::Field::Id:
|
||||
s << VALUE_KEY_ID << '=' << f->getInt();
|
||||
@@ -639,5 +662,4 @@ std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // namespace dht
|
||||
+193
-29
@@ -26,12 +26,12 @@ namespace test {
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTester);
|
||||
|
||||
void
|
||||
CryptoTester::setUp() {
|
||||
|
||||
}
|
||||
CryptoTester::setUp()
|
||||
{}
|
||||
|
||||
void
|
||||
CryptoTester::testSignatureEncryption() {
|
||||
CryptoTester::testSignatureEncryption()
|
||||
{
|
||||
auto key = dht::crypto::PrivateKey::generate();
|
||||
const auto& public_key = key.getPublicKey();
|
||||
|
||||
@@ -140,40 +140,47 @@ CryptoTester::testCertificateRequest()
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
|
||||
}
|
||||
|
||||
void CryptoTester::testCertificateSerialNumber()
|
||||
void
|
||||
CryptoTester::testCertificateSerialNumber()
|
||||
{
|
||||
static const std::string cert_pem = "-----BEGIN CERTIFICATE-----"
|
||||
"MIICDjCCAZSgAwIBAgIIS90uAKp+u/swCgYIKoZIzj0EAwMwTDEQMA4GA1UEAxMH"
|
||||
"ZGh0bm9kZTE4MDYGCgmSJomT8ixkAQETKDBlNDQxZTA4YWJmYTQzYTc3ZTVjZDBm"
|
||||
"Y2QzMzAzMTc4MjYxMTk0MzIwHhcNMTkxMTA3MDA0MTMwWhcNMjkxMTA0MDA0MTMw"
|
||||
"WjBMMRAwDgYDVQQDEwdkaHRub2RlMTgwNgYKCZImiZPyLGQBARMoMGU0NDFlMDhh"
|
||||
"YmZhNDNhNzdlNWNkMGZjZDMzMDMxNzgyNjExOTQzMjB2MBAGByqGSM49AgEGBSuB"
|
||||
"BAAiA2IABCZ7sBp0Pu+b5yIifoNXchU9crv9won0in++COWynvM4GCLF2Gk6QGhh"
|
||||
"YLDxNGsyQjGR7z5AGibvYhNLU0JA4RbmxYWHw4g3wBrPA1jm9hGZ8y5Y8R97d0Hl"
|
||||
"VpyreEMjRKNDMEEwHQYDVR0OBBYEFA5EHgir+kOnflzQ/NMwMXgmEZQyMA8GA1Ud"
|
||||
"EwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAKBggqhkjOPQQDAwNoADBlAjEA"
|
||||
"kKF/6WReNytwSrJ8JSTToc7xWS5SvAa23Fnla4mywZUxUFS4VSxCMQTjQCknO3iZ"
|
||||
"AjBgxXyXYqn0d7vz7S6oAY5TdaD5YFT5MD2c1MAAp8pxQSwdPa9k0ZSoGIEn31Z0"
|
||||
"GxU="
|
||||
"-----END CERTIFICATE-----";
|
||||
"MIICDjCCAZSgAwIBAgIIS90uAKp+u/swCgYIKoZIzj0EAwMwTDEQMA4GA1UEAxMH"
|
||||
"ZGh0bm9kZTE4MDYGCgmSJomT8ixkAQETKDBlNDQxZTA4YWJmYTQzYTc3ZTVjZDBm"
|
||||
"Y2QzMzAzMTc4MjYxMTk0MzIwHhcNMTkxMTA3MDA0MTMwWhcNMjkxMTA0MDA0MTMw"
|
||||
"WjBMMRAwDgYDVQQDEwdkaHRub2RlMTgwNgYKCZImiZPyLGQBARMoMGU0NDFlMDhh"
|
||||
"YmZhNDNhNzdlNWNkMGZjZDMzMDMxNzgyNjExOTQzMjB2MBAGByqGSM49AgEGBSuB"
|
||||
"BAAiA2IABCZ7sBp0Pu+b5yIifoNXchU9crv9won0in++COWynvM4GCLF2Gk6QGhh"
|
||||
"YLDxNGsyQjGR7z5AGibvYhNLU0JA4RbmxYWHw4g3wBrPA1jm9hGZ8y5Y8R97d0Hl"
|
||||
"VpyreEMjRKNDMEEwHQYDVR0OBBYEFA5EHgir+kOnflzQ/NMwMXgmEZQyMA8GA1Ud"
|
||||
"EwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAKBggqhkjOPQQDAwNoADBlAjEA"
|
||||
"kKF/6WReNytwSrJ8JSTToc7xWS5SvAa23Fnla4mywZUxUFS4VSxCMQTjQCknO3iZ"
|
||||
"AjBgxXyXYqn0d7vz7S6oAY5TdaD5YFT5MD2c1MAAp8pxQSwdPa9k0ZSoGIEn31Z0"
|
||||
"GxU="
|
||||
"-----END CERTIFICATE-----";
|
||||
/*
|
||||
* $ openssl x509 -in cert.pem -noout -serial
|
||||
* serial=4BDD2E00AA7EBBFB
|
||||
*/
|
||||
static constexpr std::array<uint8_t, 8> SERIAL {{0x4b,0xdd,0x2e,0x00,0xaa,0x7e,0xbb,0xfb}};
|
||||
static constexpr std::array<uint8_t, 8> SERIAL {
|
||||
{0x4b, 0xdd, 0x2e, 0x00, 0xaa, 0x7e, 0xbb, 0xfb}
|
||||
};
|
||||
auto serial = dht::crypto::Certificate(cert_pem).getSerialNumber();
|
||||
CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end()));
|
||||
}
|
||||
|
||||
void CryptoTester::testOcsp() {
|
||||
void
|
||||
CryptoTester::testOcsp()
|
||||
{
|
||||
auto ca = dht::crypto::generateIdentity("Test CA");
|
||||
auto device = dht::crypto::generateIdentity("Test Device", ca);
|
||||
auto ocspRequest = device.second->generateOcspRequest(ca.second->cert);
|
||||
auto req = dht::crypto::OcspRequest((const uint8_t*)ocspRequest.first.data(), ocspRequest.first.size());
|
||||
auto req = dht::crypto::OcspRequest((const uint8_t*) ocspRequest.first.data(), ocspRequest.first.size());
|
||||
CPPUNIT_ASSERT(ocspRequest.second == req.getNonce());
|
||||
}
|
||||
|
||||
void CryptoTester::testAesEncryption() {
|
||||
void
|
||||
CryptoTester::testAesEncryption()
|
||||
{
|
||||
auto password = "this is a password 123414!@#%@#$?" + std::to_string(rand());
|
||||
|
||||
std::vector<uint8_t> data1 {5, 10};
|
||||
@@ -214,8 +221,8 @@ void CryptoTester::testAesEncryption() {
|
||||
CPPUNIT_ASSERT(encrypted11 == encrypted1);
|
||||
CPPUNIT_ASSERT(encrypted22 == encrypted2);
|
||||
|
||||
auto key12 = dht::crypto::stretchKey(password, salt1, 256/8);
|
||||
auto key22 = dht::crypto::stretchKey(password, salt2, 256/8);
|
||||
auto key12 = dht::crypto::stretchKey(password, salt1, 256 / 8);
|
||||
auto key22 = dht::crypto::stretchKey(password, salt2, 256 / 8);
|
||||
|
||||
CPPUNIT_ASSERT(key1 == key12);
|
||||
CPPUNIT_ASSERT(key2 == key22);
|
||||
@@ -239,7 +246,9 @@ void CryptoTester::testAesEncryption() {
|
||||
CPPUNIT_ASSERT(data2 == decrypted2);
|
||||
}
|
||||
|
||||
void CryptoTester::testAesEncryptionWithMultipleKeySizes() {
|
||||
void
|
||||
CryptoTester::testAesEncryptionWithMultipleKeySizes()
|
||||
{
|
||||
auto data = std::vector<uint8_t>(rand(), rand());
|
||||
|
||||
// Valid key sizes
|
||||
@@ -260,7 +269,9 @@ void CryptoTester::testAesEncryptionWithMultipleKeySizes() {
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoTester::testOaep() {
|
||||
void
|
||||
CryptoTester::testOaep()
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030804 && !defined(_WIN32)
|
||||
auto data = std::vector<uint8_t>(446, 10);
|
||||
auto ca = dht::crypto::generateIdentity("n1");
|
||||
@@ -275,7 +286,7 @@ void CryptoTester::testOaep() {
|
||||
|
||||
auto crt = dht::crypto::Certificate::generate(key, "dhtnode", ca);
|
||||
auto pk2 = crt.getSharedPublicKey();
|
||||
|
||||
|
||||
auto encrypted2 = pk2->encrypt(data);
|
||||
auto decrypted2 = key.decrypt(encrypted2);
|
||||
CPPUNIT_ASSERT(data == decrypted2);
|
||||
@@ -303,7 +314,160 @@ void CryptoTester::testOaep() {
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::tearDown() {
|
||||
CryptoTester::testWebPushEncryption()
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030802
|
||||
// 1. Generate Receiver P-256 Key Pair
|
||||
gnutls_privkey_t receiver_key;
|
||||
CPPUNIT_ASSERT_EQUAL(GNUTLS_E_SUCCESS, gnutls_privkey_init(&receiver_key));
|
||||
CPPUNIT_ASSERT_EQUAL(GNUTLS_E_SUCCESS,
|
||||
gnutls_privkey_generate(receiver_key,
|
||||
GNUTLS_PK_ECC,
|
||||
GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1),
|
||||
0));
|
||||
|
||||
gnutls_datum_t x, y, k;
|
||||
CPPUNIT_ASSERT_EQUAL(GNUTLS_E_SUCCESS, gnutls_privkey_export_ecc_raw(receiver_key, NULL, &x, &y, &k));
|
||||
|
||||
// Construct receiver public key (uncompressed)
|
||||
std::vector<uint8_t> p256dh(65);
|
||||
p256dh[0] = 0x04;
|
||||
|
||||
auto copy_coord = [](uint8_t* dest, const gnutls_datum_t& src) {
|
||||
if (src.size > 32 && (src.size != 33 || src.data[0] != 0))
|
||||
throw std::runtime_error("Invalid key coordinate size: " + std::to_string(src.size));
|
||||
size_t offset = src.size > 32 ? 1 : 0;
|
||||
size_t len = src.size - offset;
|
||||
std::memset(dest, 0, 32 - len);
|
||||
std::memcpy(dest + (32 - len), src.data + offset, len);
|
||||
};
|
||||
|
||||
copy_coord(p256dh.data() + 1, x);
|
||||
copy_coord(p256dh.data() + 33, y);
|
||||
|
||||
gnutls_free(x.data);
|
||||
gnutls_free(y.data);
|
||||
gnutls_free(k.data);
|
||||
gnutls_privkey_deinit(receiver_key);
|
||||
|
||||
// 2. Generate Auth Secret
|
||||
std::vector<uint8_t> auth(16, 'a'); // Dummy auth
|
||||
|
||||
// 3. Payload
|
||||
std::string payloadStr = "{\"test\":\"data\"}";
|
||||
std::vector<uint8_t> payload(payloadStr.begin(), payloadStr.end());
|
||||
|
||||
std::vector<uint8_t> longPayload(3 * 4096 + 17, 'b');
|
||||
|
||||
// 4. Encrypt
|
||||
auto encrypted = dht::crypto::webPushEncrypt(p256dh, auth, payload.data(), payload.size());
|
||||
auto encryptedLong = dht::crypto::webPushEncrypt(p256dh, auth, longPayload.data(), longPayload.size());
|
||||
|
||||
// 5. Verify Structure
|
||||
// Salt (16) + RS (4) + IDLEN (1) + Key (65) + Ciphertext (payload + 1 + 16)
|
||||
size_t expectedSize = 16 + 4 + 1 + 65 + payload.size() + 1 + 16;
|
||||
CPPUNIT_ASSERT_EQUAL(expectedSize, encrypted.size());
|
||||
|
||||
expectedSize = 16 + 4 + 1 + 65 + longPayload.size() + 1 + 16;
|
||||
CPPUNIT_ASSERT_EQUAL(expectedSize, encryptedLong.size());
|
||||
|
||||
// Check IDLEN
|
||||
CPPUNIT_ASSERT_EQUAL((uint8_t) 65, encrypted[20]);
|
||||
CPPUNIT_ASSERT_EQUAL((uint8_t) 65, encryptedLong[20]);
|
||||
|
||||
// Check Key Header
|
||||
CPPUNIT_ASSERT_EQUAL((uint8_t) 0x04, encrypted[21]);
|
||||
CPPUNIT_ASSERT_EQUAL((uint8_t) 0x04, encryptedLong[21]);
|
||||
#else
|
||||
std::cerr << "Skipping Web Push Encryption test, not supported by the current GnuTLS version" << std::endl;
|
||||
#endif
|
||||
}
|
||||
} // namespace test
|
||||
|
||||
void
|
||||
CryptoTester::testWebPushRFC8291()
|
||||
{
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030802
|
||||
// RFC 8291 Example
|
||||
// https://www.rfc-editor.org/rfc/rfc8291.html#section-5
|
||||
|
||||
// Plaintext
|
||||
std::string plaintextStr = "When I grow up, I want to be a watermelon";
|
||||
dht::Blob payload(plaintextStr.begin(), plaintextStr.end());
|
||||
|
||||
// Receiver (UA) Public Key (P-256 uncompressed)
|
||||
// Base64URL: BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4
|
||||
dht::Blob uaPub = {0x04, 0x25, 0x71, 0xb2, 0xbe, 0xcd, 0xfd, 0xe3, 0x60, 0x55, 0x1a, 0xaf, 0x1e,
|
||||
0xd0, 0xf4, 0xcd, 0x36, 0x6c, 0x11, 0xce, 0xbe, 0x55, 0x5f, 0x89, 0xbc, 0xb7,
|
||||
0xb1, 0x86, 0xa5, 0x33, 0x39, 0x17, 0x31, 0x68, 0xec, 0xe2, 0xeb, 0xe0, 0x18,
|
||||
0x59, 0x7b, 0xd3, 0x04, 0x79, 0xb8, 0x6e, 0x3c, 0x8f, 0x8e, 0xce, 0xd5, 0x77,
|
||||
0xca, 0x59, 0x18, 0x7e, 0x92, 0x46, 0x99, 0x0d, 0xb6, 0x82, 0x00, 0x8b, 0x0e};
|
||||
|
||||
// Auth Secret
|
||||
// BTBZMqHH6r4Tts7J_aSIgg
|
||||
dht::Blob auth = {0x05, 0x30, 0x59, 0x32, 0xa1, 0xc7, 0xea, 0xbe, 0x13, 0xb6, 0xce, 0xc9, 0xfd, 0xa4, 0x88, 0x82};
|
||||
|
||||
// Salt
|
||||
// DGv6ra1nlYgDCS1FRnbzlw
|
||||
dht::Blob salt = {0x0c, 0x6b, 0xfa, 0xad, 0xad, 0x67, 0x95, 0x88, 0x03, 0x09, 0x2d, 0x45, 0x46, 0x76, 0xf3, 0x97};
|
||||
|
||||
// AS Private Key (Sender)
|
||||
// yfWPiYE-n46HLnH0KqZOF1fJJU3MYrct3AELtAQ-oRw
|
||||
dht::Blob asPrivRaw = {0xc9, 0xf5, 0x8f, 0x89, 0x81, 0x3e, 0x9f, 0x8e, 0x87, 0x2e, 0x71,
|
||||
0xf4, 0x2a, 0xa6, 0x4e, 0x17, 0x57, 0xc9, 0x25, 0x4d, 0xcc, 0x62,
|
||||
0xb7, 0x2d, 0xdc, 0x01, 0x0b, 0xb4, 0x04, 0x3e, 0xa1, 0x1c};
|
||||
|
||||
// AS Public Key (Sender) - for verification
|
||||
// BP4z9KsN6nGRTbVYI_c7VJSPQTBtkgcy27mlmlMoZIIgDll6e3vCYLocInmYWAmS6TlzAC8wEqKK6PBru3jl7A8
|
||||
dht::Blob asPubRaw = {0x04, 0xfe, 0x33, 0xf4, 0xab, 0x0d, 0xea, 0x71, 0x91, 0x4d, 0xb5, 0x58, 0x23,
|
||||
0xf7, 0x3b, 0x54, 0x94, 0x8f, 0x41, 0x30, 0x6d, 0x92, 0x07, 0x32, 0xdb, 0xb9,
|
||||
0xa5, 0x9a, 0x53, 0x28, 0x64, 0x82, 0x20, 0x0e, 0x59, 0x7a, 0x7b, 0x7b, 0xc2,
|
||||
0x60, 0xba, 0x1c, 0x22, 0x79, 0x98, 0x58, 0x09, 0x92, 0xe9, 0x39, 0x73, 0x00,
|
||||
0x2f, 0x30, 0x12, 0xa2, 0x8a, 0xe8, 0xf0, 0x6b, 0xbb, 0x78, 0xe5, 0xec, 0x0f};
|
||||
|
||||
gnutls_privkey_t asPrivKeyGnutls;
|
||||
gnutls_privkey_init(&asPrivKeyGnutls);
|
||||
gnutls_datum_t k = {(unsigned char*) asPrivRaw.data(), (unsigned int) asPrivRaw.size()};
|
||||
gnutls_datum_t x = {(unsigned char*) asPubRaw.data() + 1, 32};
|
||||
gnutls_datum_t y = {(unsigned char*) asPubRaw.data() + 33, 32};
|
||||
|
||||
int ret = gnutls_privkey_import_ecc_raw(asPrivKeyGnutls, GNUTLS_ECC_CURVE_SECP256R1, &x, &y, &k);
|
||||
CPPUNIT_ASSERT_EQUAL(0, ret);
|
||||
|
||||
dht::crypto::PrivateKey asPrivKey;
|
||||
asPrivKey.key = asPrivKeyGnutls;
|
||||
|
||||
// Expected Ciphertext (from RFC)
|
||||
// 8pfeW0KbunFT06SuDKoJH9Ql87S1QUrdirN6GcG7sFz1y1sqLgVi1VhjVkHsUoEsbI_0LpXMuGvnzQ
|
||||
dht::Blob expectedCiphertext = {0xf2, 0x97, 0xde, 0x5b, 0x42, 0x9b, 0xba, 0x71, 0x53, 0xd3, 0xa4, 0xae,
|
||||
0x0c, 0xaa, 0x09, 0x1f, 0xd4, 0x25, 0xf3, 0xb4, 0xb5, 0x41, 0x4a, 0xdd,
|
||||
0x8a, 0xb3, 0x7a, 0x19, 0xc1, 0xbb, 0xb0, 0x5c, 0xf5, 0xcb, 0x5b, 0x2a,
|
||||
0x2e, 0x05, 0x62, 0xd5, 0x58, 0x63, 0x56, 0x41, 0xec, 0x52, 0x81, 0x2c,
|
||||
0x6c, 0x8f, 0xf4, 0x2e, 0x95, 0xcc, 0xb8, 0x6b, 0xe7, 0xcd};
|
||||
|
||||
// Perform Encryption
|
||||
auto output = dht::crypto::webPushEncrypt(uaPub, auth, payload.data(), payload.size(), asPrivKey, salt);
|
||||
|
||||
// Verify Output
|
||||
size_t headerSize = 16 + 4 + 1 + 65;
|
||||
CPPUNIT_ASSERT(output.size() == headerSize + expectedCiphertext.size());
|
||||
|
||||
// Check Salt
|
||||
dht::Blob outSalt(output.begin(), output.begin() + 16);
|
||||
CPPUNIT_ASSERT(outSalt == salt);
|
||||
|
||||
// Check Ciphertext
|
||||
dht::Blob outCiphertext(output.begin() + headerSize, output.end());
|
||||
CPPUNIT_ASSERT(outCiphertext == expectedCiphertext);
|
||||
|
||||
// Check AS Public Key in header
|
||||
dht::Blob outASPub(output.begin() + 16 + 4 + 1, output.begin() + 16 + 4 + 1 + 65);
|
||||
CPPUNIT_ASSERT(outASPub == asPubRaw);
|
||||
#else
|
||||
std::cerr << "Skipping Web Push RFC8291 test, not supported by the current GnuTLS version" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::tearDown()
|
||||
{}
|
||||
} // namespace test
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
namespace test {
|
||||
|
||||
class CryptoTester : public CppUnit::TestFixture {
|
||||
class CryptoTester : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(CryptoTester);
|
||||
CPPUNIT_TEST(testSignatureEncryption);
|
||||
CPPUNIT_TEST(testCertificateRevocation);
|
||||
@@ -36,9 +37,11 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST(testAesEncryption);
|
||||
CPPUNIT_TEST(testAesEncryptionWithMultipleKeySizes);
|
||||
CPPUNIT_TEST(testOaep);
|
||||
CPPUNIT_TEST(testWebPushEncryption);
|
||||
CPPUNIT_TEST(testWebPushRFC8291);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Method automatically called before each test by CppUnit
|
||||
*/
|
||||
@@ -74,6 +77,8 @@ class CryptoTester : public CppUnit::TestFixture {
|
||||
void testAesEncryptionWithMultipleKeySizes();
|
||||
|
||||
void testOaep();
|
||||
void testWebPushEncryption();
|
||||
void testWebPushRFC8291();
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace test
|
||||
+171
-39
@@ -31,12 +31,13 @@ namespace test {
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(HttpTester);
|
||||
|
||||
void
|
||||
HttpTester::setUp() {
|
||||
HttpTester::setUp()
|
||||
{
|
||||
nodePeer = std::make_shared<dht::DhtRunner>();
|
||||
nodePeer->run(0);
|
||||
|
||||
auto nodeProxy = std::make_shared<dht::DhtRunner>();
|
||||
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
|
||||
nodeProxy->run(0, /*identity*/ {}, /*threaded*/ true);
|
||||
auto bound = nodePeer->getBound();
|
||||
if (bound.isUnspecified())
|
||||
bound.setLoopback();
|
||||
@@ -52,17 +53,19 @@ HttpTester::setUp() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::tearDown() {
|
||||
HttpTester::tearDown()
|
||||
{
|
||||
serverProxy.reset();
|
||||
nodePeer->join();
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url() {
|
||||
HttpTester::test_parse_url()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://google.com/";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -71,11 +74,12 @@ HttpTester::test_parse_url() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_https_url_no_service() {
|
||||
HttpTester::test_parse_https_url_no_service()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "https://jami.net/";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "https");
|
||||
@@ -84,11 +88,12 @@ HttpTester::test_parse_https_url_no_service() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_no_prefix_no_target() {
|
||||
HttpTester::test_parse_url_no_prefix_no_target()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "google.com";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -97,11 +102,12 @@ HttpTester::test_parse_url_no_prefix_no_target() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_target() {
|
||||
HttpTester::test_parse_url_target()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "https://www.google.com:666/going/under";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "https");
|
||||
@@ -111,11 +117,12 @@ HttpTester::test_parse_url_target() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_query() {
|
||||
HttpTester::test_parse_url_query()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://google.com/?key=1";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -125,11 +132,12 @@ HttpTester::test_parse_url_query() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_fragment() {
|
||||
HttpTester::test_parse_url_fragment()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://google.com/?key=1#some-important-id";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -140,11 +148,12 @@ HttpTester::test_parse_url_fragment() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_ipv4() {
|
||||
HttpTester::test_parse_url_ipv4()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://172.217.13.132/";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -153,11 +162,12 @@ HttpTester::test_parse_url_ipv4() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_no_prefix_no_target_ipv4() {
|
||||
HttpTester::test_parse_url_no_prefix_no_target_ipv4()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "172.217.13.132";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -165,11 +175,12 @@ HttpTester::test_parse_url_no_prefix_no_target_ipv4() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_target_ipv4() {
|
||||
HttpTester::test_parse_url_target_ipv4()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "https://172.217.13.132:666/going/under";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "https");
|
||||
@@ -179,11 +190,12 @@ HttpTester::test_parse_url_target_ipv4() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_ipv6() {
|
||||
HttpTester::test_parse_url_ipv6()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://[2607:f8b0:4006:804::2004]/";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -192,11 +204,12 @@ HttpTester::test_parse_url_ipv6() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_no_prefix_no_target_ipv6() {
|
||||
HttpTester::test_parse_url_no_prefix_no_target_ipv6()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "2607:f8b0:4006:804::2004";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "http");
|
||||
@@ -204,11 +217,12 @@ HttpTester::test_parse_url_no_prefix_no_target_ipv6() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_target_ipv6() {
|
||||
HttpTester::test_parse_url_target_ipv6()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "https://[2607:f8b0:4006:804::2004]:666/going/under";
|
||||
// Act
|
||||
dht::http::Url parsed (url);
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url == url);
|
||||
CPPUNIT_ASSERT(parsed.protocol == "https");
|
||||
@@ -218,7 +232,125 @@ HttpTester::test_parse_url_target_ipv6() {
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_send_json() {
|
||||
HttpTester::test_parse_url_user_pass()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://user:pass@example.com/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(url, parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("user"), parsed.user);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("pass"), parsed.password);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("example.com"), parsed.host);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_user_only()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://user@example.com/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(url, parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("user"), parsed.user);
|
||||
CPPUNIT_ASSERT(parsed.password.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("example.com"), parsed.host);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_ipv6_brackets()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://[2001:db8::1]/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(url, parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("2001:db8::1"), parsed.host);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_ipv6_brackets_port()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "http://[2001:db8::1]:8080/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(url, parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("2001:db8::1"), parsed.host);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("8080"), parsed.service);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_mixed_case_protocol()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "HtTp://example.com/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http://example.com/"), parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("example.com"), parsed.host);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_complex_path_query_fragment()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "https://example.com/path/to/resource?query=param&q2=v2#fragment";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(url, parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("https"), parsed.protocol);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("example.com"), parsed.host);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/path/to/resource?query=param&q2=v2"), parsed.target);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("query=param&q2=v2"), parsed.query);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string_view("#fragment"), parsed.fragment);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_empty()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(parsed.url.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol); // Default
|
||||
CPPUNIT_ASSERT(parsed.host.empty());
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_parse_url_just_slash()
|
||||
{
|
||||
// Arrange
|
||||
std::string url = "/";
|
||||
// Act
|
||||
dht::http::Url parsed(url);
|
||||
// Assert
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http:///"), parsed.toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("http"), parsed.protocol);
|
||||
CPPUNIT_ASSERT(parsed.host.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_send_json()
|
||||
{
|
||||
// Arrange
|
||||
std::condition_variable cv;
|
||||
std::mutex cv_m;
|
||||
@@ -231,19 +363,19 @@ HttpTester::test_send_json() {
|
||||
|
||||
// Act
|
||||
auto request = std::make_shared<dht::http::Request>(serverProxy->io_context(),
|
||||
"http://127.0.0.1:8080/key/key",
|
||||
json,
|
||||
[&](Json::Value value, const dht::http::Response& response) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
resp_val = std::move(value);
|
||||
status = response.status_code;
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
"http://127.0.0.1:8080/key/key",
|
||||
json,
|
||||
[&](Json::Value value, const dht::http::Response& response) {
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
resp_val = std::move(value);
|
||||
status = response.status_code;
|
||||
done = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
request->send();
|
||||
|
||||
// Assert
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
|
||||
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&] { return done; }));
|
||||
CPPUNIT_ASSERT_EQUAL(200u, status);
|
||||
CPPUNIT_ASSERT_EQUAL(json["data"].asString(), resp_val["data"].asString());
|
||||
done = false;
|
||||
@@ -292,4 +424,4 @@ HttpTester::test_send_json() {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace test
|
||||
@@ -47,6 +47,14 @@ class HttpTester : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST(test_parse_url_ipv6);
|
||||
CPPUNIT_TEST(test_parse_url_no_prefix_no_target_ipv6);
|
||||
CPPUNIT_TEST(test_parse_url_target_ipv6);
|
||||
CPPUNIT_TEST(test_parse_url_user_pass);
|
||||
CPPUNIT_TEST(test_parse_url_user_only);
|
||||
CPPUNIT_TEST(test_parse_url_ipv6_brackets);
|
||||
CPPUNIT_TEST(test_parse_url_ipv6_brackets_port);
|
||||
CPPUNIT_TEST(test_parse_url_mixed_case_protocol);
|
||||
CPPUNIT_TEST(test_parse_url_complex_path_query_fragment);
|
||||
CPPUNIT_TEST(test_parse_url_empty);
|
||||
CPPUNIT_TEST(test_parse_url_just_slash);
|
||||
// send
|
||||
CPPUNIT_TEST(test_send_json);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
@@ -82,6 +90,14 @@ class HttpTester : public CppUnit::TestFixture {
|
||||
void test_parse_url_ipv6();
|
||||
void test_parse_url_no_prefix_no_target_ipv6();
|
||||
void test_parse_url_target_ipv6();
|
||||
void test_parse_url_user_pass();
|
||||
void test_parse_url_user_only();
|
||||
void test_parse_url_ipv6_brackets();
|
||||
void test_parse_url_ipv6_brackets_port();
|
||||
void test_parse_url_mixed_case_protocol();
|
||||
void test_parse_url_complex_path_query_fragment();
|
||||
void test_parse_url_empty();
|
||||
void test_parse_url_just_slash();
|
||||
/**
|
||||
* Test send(json)
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "opendht",
|
||||
"version-string": "3.6.0",
|
||||
"version-string": "3.6.2",
|
||||
"port-version": 1,
|
||||
"description": "OpenDHT: A lightweight C++17 Distributed Hash Table library.",
|
||||
"homepage": "https://opendht.net",
|
||||
|
||||
Reference in new issue
Block a user