mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 12:28:42 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
370f619ac4 |
No files matched your search
@@ -16,7 +16,7 @@ jobs:
|
||||
name: Ubuntu/GCC Meson build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
matrix:
|
||||
cxx_standard: [17, 20, 23]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Minimal Dependencies
|
||||
run: |
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
matrix:
|
||||
cxx_standard: [17, 20, 23]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Homebrew Dependencies
|
||||
run: brew install msgpack-cxx asio gnutls nettle readline fmt jsoncpp argon2 openssl cppunit
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
name: Clang Static Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: deps
|
||||
run: |
|
||||
sudo apt update && \
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
|
||||
@@ -16,14 +16,14 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm, macos-15]
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
# Run locally with: pipx run cibuildwheel --platform linux python
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v4.1.1
|
||||
uses: pypa/cibuildwheel@v3.4.1
|
||||
with:
|
||||
package-dir: python
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
name: Build wheels on Windows
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VCPKG_VERSION: "2026.06.01"
|
||||
VCPKG_VERSION: "2025.07.25"
|
||||
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
|
||||
VCPKG_DISABLE_METRICS: "1"
|
||||
VCPKG_DEFAULT_TRIPLET: x64-windows-release
|
||||
@@ -44,11 +44,11 @@ jobs:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_binary_cache
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Cache vcpkg installed packages
|
||||
id: cache-vcpkg
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -148,7 +148,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -231,7 +231,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -273,7 +273,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
name: Build Windows MSI Installer
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VCPKG_VERSION: "2026.06.01"
|
||||
VCPKG_VERSION: "2025.07.25"
|
||||
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
|
||||
VCPKG_DISABLE_METRICS: "1"
|
||||
VCPKG_DEFAULT_TRIPLET: x64-windows
|
||||
@@ -319,7 +319,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -334,7 +334,7 @@ jobs:
|
||||
|
||||
- name: Cache vcpkg installed packages
|
||||
id: cache-vcpkg
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -413,7 +413,7 @@ jobs:
|
||||
name: Build Windows dhtnode
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VCPKG_VERSION: "2026.06.01"
|
||||
VCPKG_VERSION: "2025.07.25"
|
||||
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
|
||||
VCPKG_DISABLE_METRICS: "1"
|
||||
VCPKG_DEFAULT_TRIPLET: x64-windows-static-release
|
||||
@@ -423,7 +423,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -432,7 +432,7 @@ jobs:
|
||||
|
||||
- name: Cache vcpkg static installed packages
|
||||
id: cache-vcpkg-static
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -499,7 +499,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download Windows MSI artifact
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
branches: [ main, master ]
|
||||
|
||||
env:
|
||||
VCPKG_VERSION: "2026.06.01"
|
||||
VCPKG_VERSION: "2026.01.16"
|
||||
VCPKG_INSTALLATION_ROOT: "C:\\vcpkg"
|
||||
VCPKG_DISABLE_METRICS: "1"
|
||||
VCPKG_INSTALLED_DIR: ${{ github.workspace }}\vcpkg_installed
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up MSVC
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
|
||||
- name: Cache vcpkg installed packages
|
||||
id: cache-vcpkg
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up MSVC
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
|
||||
- name: Cache vcpkg static installed packages
|
||||
id: cache-vcpkg-static
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -125,14 +125,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up MSVC
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Restore vcpkg installed packages
|
||||
id: cache-vcpkg-restore
|
||||
uses: actions/cache/restore@v6
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -202,14 +202,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up MSVC
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Restore vcpkg static installed packages
|
||||
id: cache-vcpkg-static-restore
|
||||
uses: actions/cache/restore@v6
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_INSTALLED_DIR }}
|
||||
@@ -275,7 +275,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup MinGW
|
||||
uses: msys2/setup-msys2@v2
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required (VERSION 3.21...4.4)
|
||||
cmake_minimum_required (VERSION 3.21...3.31)
|
||||
if(POLICY CMP0091)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
endif()
|
||||
@@ -10,7 +10,7 @@ if(POLICY CMP0167)
|
||||
endif()
|
||||
|
||||
set (opendht_VERSION_MAJOR 4)
|
||||
set (opendht_VERSION_MINOR 2.0)
|
||||
set (opendht_VERSION_MINOR 0.0)
|
||||
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
|
||||
set (PACKAGE_VERSION ${opendht_VERSION})
|
||||
set (VERSION "${opendht_VERSION}")
|
||||
|
||||
@@ -267,14 +267,9 @@ public:
|
||||
/**
|
||||
* Sign this revocation list using provided key and certificate.
|
||||
* Validity_period sets the duration until next update (default to no next update).
|
||||
* If `number` is non-zero, it is stored verbatim (big-endian) as the CRL Number
|
||||
* extension. Otherwise the number is initialized randomly on the first signature
|
||||
* and incremented on subsequent ones.
|
||||
*/
|
||||
void sign(const PrivateKey&, const Certificate&, duration validity_period = {}, uint64_t number = 0);
|
||||
void sign(const Identity& id, duration validity_period = {}, uint64_t number = 0) {
|
||||
sign(*id.first, *id.second, validity_period, number);
|
||||
}
|
||||
void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
|
||||
void sign(const Identity& id) { sign(*id.first, *id.second); }
|
||||
|
||||
bool isSignedBy(const Certificate& issuer) const;
|
||||
|
||||
|
||||
@@ -159,13 +159,7 @@ public:
|
||||
{}
|
||||
|
||||
static Value::Filter getFilter() { return EncryptedValue::getFilter(); }
|
||||
virtual void unpackValue(const dht::Value& v) override
|
||||
{
|
||||
BaseClass::unpackValue(v);
|
||||
id = v.id;
|
||||
}
|
||||
|
||||
dht::Value::Id id {0}; /// Value ID of the trust request, used for deserialization only.
|
||||
std::string service;
|
||||
std::string conversationId;
|
||||
Blob payload;
|
||||
|
||||
+14
-8
@@ -51,11 +51,11 @@ using ConnectHandlerCb = std::function<void(const asio::error_code& ec, const as
|
||||
using ssl_socket_t = restinio::impl::tls_socket_t;
|
||||
using socket_t = asio::ip::tcp::socket;
|
||||
|
||||
struct OPENDHT_PUBLIC Url
|
||||
class OPENDHT_PUBLIC Url
|
||||
{
|
||||
public:
|
||||
Url() = default;
|
||||
Url(std::string url);
|
||||
|
||||
Url(std::string_view url);
|
||||
std::string url;
|
||||
std::string protocol {"http"};
|
||||
std::string_view user;
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
using ResolverCb
|
||||
= std::function<void(const asio::error_code& ec, const std::vector<asio::ip::tcp::endpoint>& endpoints)>;
|
||||
|
||||
Resolver(asio::io_context& ctx, std::string url, std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<log::Logger> logger = {});
|
||||
Resolver(asio::io_context& ctx,
|
||||
std::string_view host,
|
||||
std::string_view service,
|
||||
@@ -161,6 +161,10 @@ public:
|
||||
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();
|
||||
|
||||
@@ -212,19 +216,19 @@ public:
|
||||
|
||||
// resolves implicitly
|
||||
Request(asio::io_context& ctx,
|
||||
std::string url,
|
||||
const std::string& url,
|
||||
const Json::Value& json,
|
||||
OnJsonCb jsoncb,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, std::string url, 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, std::string url, 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,
|
||||
std::string_view host,
|
||||
std::string_view service,
|
||||
const bool ssl = false,
|
||||
std::shared_ptr<log::Logger> logger = {});
|
||||
Request(asio::io_context& ctx, std::string url, OnDoneCb onDone, 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);
|
||||
@@ -340,6 +344,8 @@ private:
|
||||
|
||||
dht::crypto::Identity client_identity_;
|
||||
std::shared_ptr<dht::crypto::Certificate> server_ca_;
|
||||
std::string service_;
|
||||
std::string host_;
|
||||
|
||||
unsigned int id_;
|
||||
static std::atomic_uint ids_;
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
#include <future>
|
||||
#include <functional>
|
||||
|
||||
#if __cplusplus < 202002L
|
||||
#include <ciso646>
|
||||
#endif
|
||||
#include <ciso646> // fix windows compiler bug
|
||||
|
||||
namespace dht {
|
||||
|
||||
|
||||
@@ -85,14 +85,6 @@ using system_clock = std::chrono::system_clock;
|
||||
using time_point = clock::time_point;
|
||||
using duration = clock::duration;
|
||||
|
||||
OPENDHT_PUBLIC time_point from_system_time(system_clock::time_point t,
|
||||
time_point steady_now,
|
||||
system_clock::time_point system_now);
|
||||
OPENDHT_PUBLIC time_point from_system_time(system_clock::time_point t);
|
||||
OPENDHT_PUBLIC system_clock::time_point to_system_time(time_point t,
|
||||
time_point steady_now,
|
||||
system_clock::time_point system_now);
|
||||
OPENDHT_PUBLIC system_clock::time_point to_system_time(time_point t);
|
||||
OPENDHT_PUBLIC time_point from_time_t(std::time_t t);
|
||||
OPENDHT_PUBLIC std::time_t to_time_t(time_point t);
|
||||
|
||||
|
||||
+6
-23
@@ -5,7 +5,7 @@ project(
|
||||
'cython',
|
||||
license: 'MIT',
|
||||
license_files: 'LICENSE',
|
||||
version: '4.2.0',
|
||||
version: '4.0.0',
|
||||
meson_version: '>=1.1.0',
|
||||
default_options: ['cpp_std=c++20', 'warning_level=3'],
|
||||
)
|
||||
@@ -15,23 +15,10 @@ nettle = dependency('nettle')
|
||||
msgpack = dependency('msgpack-cxx', required: false)
|
||||
argon2 = dependency('libargon2')
|
||||
fmt = dependency('fmt')
|
||||
|
||||
proxy_enabled = get_option('proxy_client').enabled() or get_option('proxy_server').enabled()
|
||||
|
||||
openssl = dependency('openssl', required: proxy_enabled)
|
||||
jsoncpp = dependency('jsoncpp', required: proxy_enabled)
|
||||
llhttp = dependency('llhttp', 'libllhttp', required: proxy_enabled)
|
||||
simdutf = dependency('simdutf', required: proxy_enabled)
|
||||
|
||||
# restinio is a header-only library that may not ship a pkg-config file
|
||||
restinio_dep = dependency('restinio', required: false)
|
||||
if not restinio_dep.found()
|
||||
cpp = meson.get_compiler('cpp')
|
||||
if cpp.has_header('restinio/all.hpp', required: proxy_enabled)
|
||||
restinio_dep = declare_dependency()
|
||||
endif
|
||||
endif
|
||||
|
||||
openssl = dependency('openssl', required: get_option('proxy_client'))
|
||||
jsoncpp = dependency('jsoncpp', required: get_option('proxy_client'))
|
||||
llhttp = dependency('llhttp', 'libllhttp', required: get_option('proxy_client'))
|
||||
simdutf = dependency('simdutf', required: get_option('proxy_client'))
|
||||
io_uring = host_machine.system() == 'linux' ? dependency('liburing', required: false) : disabler()
|
||||
|
||||
deps = [
|
||||
@@ -46,10 +33,6 @@ deps = [
|
||||
llhttp,
|
||||
]
|
||||
|
||||
if restinio_dep.found()
|
||||
deps += restinio_dep
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'linux' and io_uring.found()
|
||||
deps += io_uring
|
||||
endif
|
||||
@@ -96,7 +79,7 @@ if get_option('indexation').enabled()
|
||||
opendht_src += 'src/indexation/pht.cpp'
|
||||
add_project_arguments('-DOPENDHT_INDEXATION', language: 'cpp')
|
||||
endif
|
||||
if jsoncpp.found() and simdutf.found()
|
||||
if jsoncpp.found()
|
||||
opendht_src += ['src/base64.cpp']
|
||||
add_project_arguments('-DOPENDHT_JSONCPP', language: 'cpp')
|
||||
conf_data.set('jsoncpp_lib', ', jsoncpp')
|
||||
|
||||
+11
-1
@@ -28,8 +28,18 @@ install(CODE [[
|
||||
if(NOT _pip_check EQUAL 0)
|
||||
message(WARNING "Skipping Python package install: pip not available for ${Python3_EXECUTABLE}.")
|
||||
else()
|
||||
set(_pip_install_args
|
||||
install
|
||||
--no-deps
|
||||
--no-build-isolation
|
||||
--break-system-packages
|
||||
--prefix ${CMAKE_INSTALL_PREFIX})
|
||||
if(DEFINED ENV{DESTDIR} AND NOT "$ENV{DESTDIR}" STREQUAL "")
|
||||
list(APPEND _pip_install_args --root "$ENV{DESTDIR}")
|
||||
endif()
|
||||
list(APPEND _pip_install_args .)
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE} -m pip install --no-deps --break-system-packages .
|
||||
COMMAND ${Python3_EXECUTABLE} -m pip ${_pip_install_args}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/python
|
||||
OUTPUT_VARIABLE _pip_output
|
||||
ERROR_VARIABLE _pip_error
|
||||
|
||||
@@ -36,19 +36,4 @@ base64_decode(std::string_view str)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::vector<unsigned char>
|
||||
base64_default_or_url_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(),
|
||||
simdutf::base64_options::base64_default_or_url);
|
||||
if (r.error) {
|
||||
throw std::invalid_argument(concat("Invalid base64 input: "sv, simdutf::error_to_string(r.error)));
|
||||
} else {
|
||||
buffer.resize(r.count);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
} // namespace dht
|
||||
+1
-8
@@ -21,12 +21,5 @@ std::string base64_encode(const std::vector<unsigned char>& str);
|
||||
* @return a base64-decoded buffer
|
||||
*/
|
||||
std::vector<unsigned char> base64_decode(std::string_view str);
|
||||
/**
|
||||
* Decode a buffer in base64 or url style base64 (including '-' '_' ).
|
||||
*
|
||||
* @param str the input buffer
|
||||
* @return a base64-decoded buffer
|
||||
*/
|
||||
std::vector<unsigned char> base64_default_or_url_decode(std::string_view str);
|
||||
|
||||
} // namespace dht
|
||||
} // namespace dht
|
||||
+41
-33
@@ -571,12 +571,6 @@ PublicKey::toString() const
|
||||
}
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
|
||||
// GnuTLS reports the PEM size including the terminating null byte, which
|
||||
// does not belong to the text and would end up embedded in whatever the
|
||||
// string is copied into, such as the "owner" field of a serialized value.
|
||||
ret.resize(sz);
|
||||
if (not ret.empty() and ret.back() == '\0')
|
||||
ret.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1402,11 +1396,8 @@ setRandomSerial(gnutls_x509_crt_t cert)
|
||||
{
|
||||
std::random_device rdev;
|
||||
std::uniform_int_distribution<int64_t> dist {1};
|
||||
const auto cert_serial = dist(rdev);
|
||||
std::array<uint8_t, sizeof(cert_serial)> packed_serial;
|
||||
for (size_t i = 0; i < packed_serial.size(); i++)
|
||||
packed_serial[i] = cert_serial >> (8 * (packed_serial.size() - 1 - i));
|
||||
gnutls_x509_crt_set_serial(cert, packed_serial.data(), packed_serial.size());
|
||||
int64_t cert_serial = dist(rdev);
|
||||
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
|
||||
}
|
||||
|
||||
Certificate
|
||||
@@ -1882,8 +1873,34 @@ RevocationList::getUpdateTime() const
|
||||
return std::chrono::system_clock::from_time_t(t);
|
||||
}
|
||||
|
||||
enum class Endian : uint32_t { LITTLE = 0, BIG = 1 };
|
||||
|
||||
template<typename T>
|
||||
T
|
||||
endian(T w, Endian endian = Endian::BIG)
|
||||
{
|
||||
// this gets optimized out into if (endian == host_endian) return w;
|
||||
union {
|
||||
uint64_t quad;
|
||||
uint32_t islittle;
|
||||
} t;
|
||||
t.quad = 1;
|
||||
if (t.islittle ^ (uint32_t) endian)
|
||||
return w;
|
||||
T r = 0;
|
||||
|
||||
// decent compilers will unroll this (gcc)
|
||||
// or even convert straight into single bswap (clang)
|
||||
for (size_t i = 0; i < sizeof(r); i++) {
|
||||
r <<= 8;
|
||||
r |= w & 0xff;
|
||||
w >>= 8;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration validity, uint64_t crlNumber)
|
||||
RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration validity)
|
||||
{
|
||||
if (auto err = gnutls_x509_crl_set_version(crl, 2))
|
||||
throw CryptoException(std::string("Unable to set CRL version: ") + gnutls_strerror(err));
|
||||
@@ -1893,28 +1910,19 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca, duration vali
|
||||
throw CryptoException(std::string("Unable to set CRL update time: ") + gnutls_strerror(err));
|
||||
if (auto err = gnutls_x509_crl_set_next_update(crl, std::chrono::system_clock::to_time_t(next_update)))
|
||||
throw CryptoException(std::string("Unable to set CRL next update time: ") + gnutls_strerror(err));
|
||||
uint64_t number {crlNumber};
|
||||
uint64_t number {0};
|
||||
size_t number_sz {sizeof(number)};
|
||||
unsigned critical {0};
|
||||
gnutls_x509_crl_get_number(crl, &number, &number_sz, &critical);
|
||||
if (number == 0) {
|
||||
// The CRL Number extension holds a DER integer of variable length, so it must be
|
||||
// read as a big-endian byte string rather than straight into an uint64_t.
|
||||
auto current = getNumber();
|
||||
for (uint8_t byte : current)
|
||||
number = (number << 8) | byte;
|
||||
if (number == 0) {
|
||||
// Initialize to a random number.
|
||||
std::random_device rdev;
|
||||
do {
|
||||
std::generate_n((uint8_t*) &number, sizeof(number), std::bind(rand_byte, std::ref(rdev)));
|
||||
} while (number == 0);
|
||||
} else
|
||||
number++;
|
||||
}
|
||||
// Store the number in network byte order.
|
||||
uint8_t packedNumber[sizeof(number)];
|
||||
for (size_t i = 0; i < sizeof(packedNumber); i++)
|
||||
packedNumber[i] = (uint8_t) ((number >> (8 * (sizeof(packedNumber) - 1 - i))) & 0xff);
|
||||
if (auto err = gnutls_x509_crl_set_number(crl, packedNumber, sizeof(packedNumber)))
|
||||
throw CryptoException(std::string("Unable to set CRL number: ") + gnutls_strerror(err));
|
||||
// initialize to a random number
|
||||
number_sz = sizeof(number);
|
||||
std::random_device rdev;
|
||||
std::generate_n((uint8_t*) &number, sizeof(number), std::bind(rand_byte, std::ref(rdev)));
|
||||
} else
|
||||
number = endian(endian(number) + 1);
|
||||
if (auto err = gnutls_x509_crl_set_number(crl, &number, sizeof(number)))
|
||||
throw CryptoException(std::string("Unable to set CRL update time: ") + gnutls_strerror(err));
|
||||
if (auto err = gnutls_x509_crl_sign2(crl, ca.cert, key.x509_key, GNUTLS_DIG_SHA512, 0))
|
||||
throw CryptoException(std::string("Unable to sign certificate revocation list: ") + gnutls_strerror(err));
|
||||
// to be able to actually use the CRL we need to serialize/deserialize it
|
||||
|
||||
+7
-32
@@ -2270,16 +2270,8 @@ Dht::onDisconnected()
|
||||
void
|
||||
Dht::bootstrap()
|
||||
{
|
||||
if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected) {
|
||||
// The job that led here has already run, and the scheduler does not
|
||||
// clear the handle to a job it has executed. onDisconnected() reads a
|
||||
// set handle as "a bootstrap is already scheduled" and does nothing,
|
||||
// so leaving it set here means the node never tries to rejoin the
|
||||
// network once it has lost it. Clearing it is what says that no
|
||||
// bootstrap is pending any more.
|
||||
bootstrapJob.reset();
|
||||
if (dht4.status != NodeStatus::Disconnected || dht6.status != NodeStatus::Disconnected)
|
||||
return;
|
||||
}
|
||||
if (logger_)
|
||||
logger_->debug("[{}] Bootstraping", myid.to_view());
|
||||
bootstrap_pending = false;
|
||||
@@ -2363,9 +2355,6 @@ Dht::confirmNodes()
|
||||
std::vector<ValuesExport>
|
||||
Dht::exportValues() const
|
||||
{
|
||||
const auto& now = scheduler.time();
|
||||
const auto system_now = system_clock::now();
|
||||
|
||||
std::vector<ValuesExport> e {};
|
||||
e.reserve(store.size());
|
||||
for (const auto& h : store) {
|
||||
@@ -2378,7 +2367,7 @@ Dht::exportValues() const
|
||||
pk.pack_array(vals.size());
|
||||
for (const auto& v : vals) {
|
||||
pk.pack_array(4);
|
||||
pk.pack(to_system_time(v.created, now, system_now));
|
||||
pk.pack(v.created.time_since_epoch().count());
|
||||
v.data->msgpack_pack(pk);
|
||||
if (const auto& store_addr = v.store_bucket ? v.store_bucket->getAddr() : SockAddr {}) {
|
||||
pk.pack_bin(store_addr.getLength());
|
||||
@@ -2386,7 +2375,7 @@ Dht::exportValues() const
|
||||
} else {
|
||||
pk.pack_bin(0);
|
||||
}
|
||||
pk.pack(to_system_time(v.expiration, now, system_now));
|
||||
pk.pack(v.expiration.time_since_epoch().count());
|
||||
}
|
||||
ve.second = {buffer.data(), buffer.data() + buffer.size()};
|
||||
e.push_back(std::move(ve));
|
||||
@@ -2398,7 +2387,6 @@ void
|
||||
Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
{
|
||||
const auto& now = scheduler.time();
|
||||
const auto system_now = system_clock::now();
|
||||
|
||||
unsigned imported = 0, ignored = 0;
|
||||
size_t imported_size = 0;
|
||||
@@ -2423,15 +2411,8 @@ Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
Value tmp_val;
|
||||
SockAddr store_addr;
|
||||
try {
|
||||
const bool uses_system_time = valel.via.array.ptr[0].type == msgpack::type::EXT;
|
||||
if (uses_system_time) {
|
||||
val_time = from_system_time(valel.via.array.ptr[0].as<system_clock::time_point>(),
|
||||
now,
|
||||
system_now);
|
||||
} else {
|
||||
val_time = time_point {
|
||||
time_point::duration {valel.via.array.ptr[0].as<time_point::duration::rep>()}};
|
||||
}
|
||||
val_time = time_point {
|
||||
time_point::duration {valel.via.array.ptr[0].as<time_point::duration::rep>()}};
|
||||
tmp_val.msgpack_unpack(valel.via.array.ptr[1]);
|
||||
if (valel.via.array.size >= 3) {
|
||||
auto addr_blob = valel.via.array.ptr[2].as<Blob>();
|
||||
@@ -2441,14 +2422,8 @@ Dht::importValues(const std::vector<ValuesExport>& import)
|
||||
}
|
||||
}
|
||||
if (valel.via.array.size >= 4) {
|
||||
if (uses_system_time) {
|
||||
expiration = from_system_time(valel.via.array.ptr[3].as<system_clock::time_point>(),
|
||||
now,
|
||||
system_now);
|
||||
} else {
|
||||
expiration = time_point {
|
||||
time_point::duration {valel.via.array.ptr[3].as<time_point::duration::rep>()}};
|
||||
}
|
||||
expiration = time_point {
|
||||
time_point::duration {valel.via.array.ptr[3].as<time_point::duration::rep>()}};
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
if (logger_)
|
||||
|
||||
@@ -1205,7 +1205,14 @@ DhtProxyServer::sendPushNotification(
|
||||
try {
|
||||
std::shared_ptr<http::Request> request;
|
||||
if (type == PushType::UnifiedPush) {
|
||||
request = std::make_shared<http::Request>(io_context(), token, logger_);
|
||||
http::Url tokenUrl(token);
|
||||
request = std::make_shared<http::Request>(io_context(),
|
||||
concat(tokenUrl.protocol, "://"sv, tokenUrl.host),
|
||||
tokenUrl.service,
|
||||
tokenUrl.protocol.find("https") == 0,
|
||||
logger_);
|
||||
request->set_target(tokenUrl.target);
|
||||
request->set_header_field(restinio::http_field_t::host, std::string(tokenUrl.host));
|
||||
} else {
|
||||
request = std::make_shared<http::Request>(io_context(),
|
||||
pushHostPort_.first,
|
||||
@@ -1224,8 +1231,8 @@ DhtProxyServer::sendPushNotification(
|
||||
Blob auth; ///< Auth secret
|
||||
auto delim = topicView.find('|');
|
||||
if (delim != std::string_view::npos) {
|
||||
pubKey = base64_default_or_url_decode(topicView.substr(0, delim));
|
||||
auth = base64_default_or_url_decode(topicView.substr(delim + 1));
|
||||
pubKey = base64_decode(topicView.substr(0, delim));
|
||||
auth = base64_decode(topicView.substr(delim + 1));
|
||||
}
|
||||
|
||||
request->set_header_field(restinio::http_field_t::ttl, "86400");
|
||||
|
||||
+1
-21
@@ -99,11 +99,6 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
auto state_path = config.dht_config.node_config.persist_path;
|
||||
if (not state_path.empty())
|
||||
state_path += "_port.txt";
|
||||
// Ports loaded from the persisted state are a best-effort hint to keep a
|
||||
// stable identity across restarts; remember which ones we set so that we
|
||||
// can fall back to random ports if they are already in use (e.g. a fast
|
||||
// restart while the previous instance still holds them).
|
||||
bool triedSavedPort = false;
|
||||
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
|
||||
std::ifstream inConfig(state_path);
|
||||
if (inConfig.is_open()) {
|
||||
@@ -115,7 +110,6 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
fmt::ptr(this),
|
||||
port);
|
||||
local4.setPort(port);
|
||||
triedSavedPort = true;
|
||||
}
|
||||
}
|
||||
if (inConfig >> port) {
|
||||
@@ -125,7 +119,6 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
fmt::ptr(this),
|
||||
port);
|
||||
local6.setPort(port);
|
||||
triedSavedPort = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,20 +136,7 @@ DhtRunner::run(const Config& config, Context&& context)
|
||||
|
||||
if (config.proxy_server.empty()) {
|
||||
if (not context.sock) {
|
||||
try {
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
|
||||
} catch (const DhtException&) {
|
||||
if (not triedSavedPort)
|
||||
throw;
|
||||
// The saved ports are unavailable (typically still held by a
|
||||
// previous instance): fall back to OS-assigned ports.
|
||||
if (context.logger)
|
||||
context.logger->w("[runner %p] Saved ports unavailable, falling back to random ports",
|
||||
fmt::ptr(this));
|
||||
local4.setPort(0);
|
||||
local6.setPort(0);
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
|
||||
}
|
||||
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
|
||||
}
|
||||
context.sock->setOnReceive([&](net::PacketList&& pkts) {
|
||||
net::PacketList ret;
|
||||
|
||||
+16
-23
@@ -42,8 +42,8 @@ constexpr std::string_view ORIGIN_PROTOCOL {"//"sv};
|
||||
constexpr const char HTTP_HEADER_DELIM[] = "\r\n\r\n";
|
||||
constexpr unsigned MAX_REDIRECTS {5};
|
||||
|
||||
Url::Url(std::string url_str)
|
||||
: url(std::move(url_str))
|
||||
Url::Url(std::string_view url_str)
|
||||
: url(url_str)
|
||||
{
|
||||
std::string_view u = url;
|
||||
if (u.empty())
|
||||
@@ -302,7 +302,7 @@ static X509*
|
||||
issuer_from_chain(STACK_OF(X509) * fullchain)
|
||||
{
|
||||
X509 *cert, *issuer;
|
||||
const X509_NAME* issuer_name;
|
||||
X509_NAME* issuer_name;
|
||||
|
||||
cert = cert_from_chain(fullchain);
|
||||
if ((issuer_name = X509_get_issuer_name(cert)) == nullptr)
|
||||
@@ -830,8 +830,8 @@ Connection::timeout(const std::chrono::seconds& timeout, HandlerCb cb)
|
||||
|
||||
// Resolver
|
||||
|
||||
Resolver::Resolver(asio::io_context& ctx, std::string url, std::shared_ptr<dht::Logger> logger)
|
||||
: url_(std::move(url))
|
||||
Resolver::Resolver(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger)
|
||||
: url_(url)
|
||||
, resolver_(ctx)
|
||||
, destroyed_(std::make_shared<bool>(false))
|
||||
, logger_(logger)
|
||||
@@ -917,16 +917,8 @@ Resolver::add_callback(ResolverCb cb, sa_family_t family)
|
||||
else
|
||||
cb(ec, filter(endpoints, family));
|
||||
});
|
||||
else {
|
||||
// Always dispatch the callback on the io_context thread. Invoking it
|
||||
// synchronously would run the caller's continuation (e.g. the whole
|
||||
// connect chain of Request::send) on the calling thread, mutating asio
|
||||
// objects concurrently with the io thread running the io_context.
|
||||
asio::post(resolver_.get_executor(),
|
||||
[cb = std::move(cb),
|
||||
ec = ec_,
|
||||
endpoints = family == AF_UNSPEC ? endpoints_ : filter(endpoints_, family)] { cb(ec, endpoints); });
|
||||
}
|
||||
else
|
||||
cb(ec_, family == AF_UNSPEC ? endpoints_ : filter(endpoints_, family));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -975,14 +967,14 @@ Resolver::resolve(std::string_view host, std::string_view service)
|
||||
std::atomic_uint Request::ids_ {1};
|
||||
|
||||
Request::Request(asio::io_context& ctx,
|
||||
std::string url,
|
||||
const std::string& url,
|
||||
const Json::Value& json,
|
||||
OnJsonCb jsoncb,
|
||||
std::shared_ptr<dht::Logger> logger)
|
||||
: logger_(std::move(logger))
|
||||
, id_(Request::ids_++)
|
||||
, ctx_(ctx)
|
||||
, resolver_(std::make_shared<Resolver>(ctx, std::move(url), logger))
|
||||
, resolver_(std::make_shared<Resolver>(ctx, url, logger))
|
||||
{
|
||||
init_default_headers();
|
||||
set_header_field(restinio::http_field_t::content_type, std::string(HTTP_HEADER_CONTENT_TYPE_JSON));
|
||||
@@ -1005,11 +997,11 @@ Request::Request(asio::io_context& ctx,
|
||||
});
|
||||
}
|
||||
|
||||
Request::Request(asio::io_context& ctx, std::string url, OnJsonCb jsoncb, std::shared_ptr<dht::Logger> logger)
|
||||
Request::Request(asio::io_context& ctx, const std::string& url, OnJsonCb jsoncb, std::shared_ptr<dht::Logger> logger)
|
||||
: logger_(std::move(logger))
|
||||
, id_(Request::ids_++)
|
||||
, ctx_(ctx)
|
||||
, resolver_(std::make_shared<Resolver>(ctx, std::move(url), logger))
|
||||
, resolver_(std::make_shared<Resolver>(ctx, url, logger))
|
||||
{
|
||||
init_default_headers();
|
||||
set_header_field(restinio::http_field_t::accept, std::string(HTTP_HEADER_CONTENT_TYPE_JSON));
|
||||
@@ -1030,20 +1022,20 @@ Request::Request(asio::io_context& ctx, std::string url, OnJsonCb jsoncb, std::s
|
||||
});
|
||||
}
|
||||
|
||||
Request::Request(asio::io_context& ctx, std::string url, std::shared_ptr<dht::Logger> logger)
|
||||
Request::Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger)
|
||||
: logger_(logger)
|
||||
, id_(Request::ids_++)
|
||||
, ctx_(ctx)
|
||||
, resolver_(std::make_shared<Resolver>(ctx, std::move(url), logger))
|
||||
, resolver_(std::make_shared<Resolver>(ctx, url, logger))
|
||||
{
|
||||
init_default_headers();
|
||||
}
|
||||
|
||||
Request::Request(asio::io_context& ctx, std::string url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger)
|
||||
Request::Request(asio::io_context& ctx, const std::string& url, OnDoneCb onDone, std::shared_ptr<dht::Logger> logger)
|
||||
: logger_(logger)
|
||||
, id_(Request::ids_++)
|
||||
, ctx_(ctx)
|
||||
, resolver_(std::make_shared<Resolver>(ctx, std::move(url), logger))
|
||||
, resolver_(std::make_shared<Resolver>(ctx, url, logger))
|
||||
{
|
||||
init_default_headers();
|
||||
add_on_done_callback(std::move(onDone));
|
||||
@@ -1094,6 +1086,7 @@ Request::Request(asio::io_context& ctx,
|
||||
, family_(family)
|
||||
, resolver_(resolver)
|
||||
{
|
||||
set_header_field(restinio::http_field_t::host, concat(get_url().host, ":", get_url().service));
|
||||
set_target(Url(target).target);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ SearchCache::expire(const time_point& now, const std::function<void(size_t)>& on
|
||||
auto ret = nextExpiration_;
|
||||
for (auto it = ops.begin(); it != ops.end();) {
|
||||
auto expiration = it->second->getExpiration();
|
||||
if (expiration <= now) {
|
||||
if (expiration < now) {
|
||||
auto cache = std::move(it->second);
|
||||
it = ops.erase(it);
|
||||
onCancel(cache->searchToken);
|
||||
|
||||
+2
-4
@@ -6,10 +6,8 @@
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <cmath> // std::pow
|
||||
#if __cplusplus < 202002L
|
||||
#include <ciso646>
|
||||
#endif
|
||||
#include <ciso646> // fix windows compiler bug
|
||||
#include <cmath> // std::pow
|
||||
|
||||
namespace dht {
|
||||
|
||||
|
||||
+14
-44
@@ -238,58 +238,28 @@ operator==(const SockAddr& a, const SockAddr& b)
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
time_point
|
||||
from_system_time(system_clock::time_point t, time_point steady_now, system_clock::time_point system_now)
|
||||
{
|
||||
if (t == system_clock::time_point::min())
|
||||
return time_point::min();
|
||||
if (t == system_clock::time_point::max())
|
||||
return time_point::max();
|
||||
auto dt = t - system_now;
|
||||
if (dt > system_clock::duration(0) and steady_now > time_point::max() - dt)
|
||||
return time_point::max();
|
||||
else if (dt < system_clock::duration(0) and steady_now < time_point::min() - dt)
|
||||
return time_point::min();
|
||||
return steady_now + dt;
|
||||
}
|
||||
|
||||
time_point
|
||||
from_system_time(system_clock::time_point t)
|
||||
{
|
||||
return from_system_time(t, clock::now(), system_clock::now());
|
||||
}
|
||||
|
||||
system_clock::time_point
|
||||
to_system_time(time_point t, time_point steady_now, system_clock::time_point system_now)
|
||||
{
|
||||
if (t == time_point::min())
|
||||
return system_clock::time_point::min();
|
||||
if (t == time_point::max())
|
||||
return system_clock::time_point::max();
|
||||
auto dt = t - steady_now;
|
||||
if (dt > duration(0) and system_now >= system_clock::time_point::max() - dt)
|
||||
return system_clock::time_point::max();
|
||||
else if (dt < duration(0) and system_now <= system_clock::time_point::min() - dt)
|
||||
return system_clock::time_point::min();
|
||||
return system_now + std::chrono::duration_cast<system_clock::duration>(dt);
|
||||
}
|
||||
|
||||
system_clock::time_point
|
||||
to_system_time(time_point t)
|
||||
{
|
||||
return to_system_time(t, clock::now(), system_clock::now());
|
||||
}
|
||||
|
||||
time_point
|
||||
from_time_t(std::time_t t)
|
||||
{
|
||||
return from_system_time(system_clock::from_time_t(t));
|
||||
auto dt = system_clock::from_time_t(t) - system_clock::now();
|
||||
auto now = clock::now();
|
||||
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
|
||||
return time_point::max();
|
||||
else if (dt < system_clock::duration(0) and now < time_point::min() - dt)
|
||||
return time_point::min();
|
||||
return now + dt;
|
||||
}
|
||||
|
||||
std::time_t
|
||||
to_time_t(time_point t)
|
||||
{
|
||||
return system_clock::to_time_t(to_system_time(t));
|
||||
auto dt = t - clock::now();
|
||||
auto now = system_clock::now();
|
||||
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::max());
|
||||
else if (dt < duration(0) and now <= system_clock::time_point::min() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::min());
|
||||
return system_clock::to_time_t(now + std::chrono::duration_cast<system_clock::duration>(dt));
|
||||
}
|
||||
|
||||
Blob
|
||||
|
||||
@@ -202,9 +202,6 @@ Value::Value(const Json::Value& json)
|
||||
const auto& jprio = json["prio"];
|
||||
if (jprio.isIntegral())
|
||||
priority = jprio.asUInt();
|
||||
const auto& jpt = json[VALUE_KEY_PUSHTYPE];
|
||||
if (jpt.isString())
|
||||
pushType = jpt.asString();
|
||||
}
|
||||
|
||||
Json::Value
|
||||
@@ -231,8 +228,6 @@ Value::toJson() const
|
||||
}
|
||||
if (priority)
|
||||
val["prio"] = priority;
|
||||
if (not pushType.empty())
|
||||
val[VALUE_KEY_PUSHTYPE] = pushType;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
+2
-178
@@ -59,24 +59,6 @@ CryptoTester::testSignatureEncryption()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testPublicKeyPemIsPlainText()
|
||||
{
|
||||
auto key = dht::crypto::PrivateKey::generate();
|
||||
auto pem = key.getPublicKey().toString();
|
||||
|
||||
// The exported key is PEM text: it must not carry the terminating null
|
||||
// byte GnuTLS counts in the exported size, which would otherwise be
|
||||
// embedded in anything the string is serialized into.
|
||||
CPPUNIT_ASSERT(not pem.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string::npos, pem.find('\0'));
|
||||
CPPUNIT_ASSERT_EQUAL('\n', pem.back());
|
||||
|
||||
// The exported text still reads back as the same key.
|
||||
dht::crypto::PublicKey reloaded(dht::Blob(pem.begin(), pem.end()));
|
||||
CPPUNIT_ASSERT_EQUAL(key.getPublicKey().getId(), reloaded.getId());
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testCertificateRevocation()
|
||||
{
|
||||
@@ -113,159 +95,10 @@ CryptoTester::testCertificateRevocation()
|
||||
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/** Read a CRL Number extension blob (big-endian, variable length) as an integer. */
|
||||
uint64_t
|
||||
crlNumberValue(const dht::Blob& number)
|
||||
{
|
||||
uint64_t value {0};
|
||||
for (uint8_t byte : number)
|
||||
value = (value << 8) | byte;
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
CryptoTester::testRevocationListNumber()
|
||||
{
|
||||
auto ca = dht::crypto::generateIdentity("ca");
|
||||
auto device = dht::crypto::generateIdentity("dev", ca);
|
||||
|
||||
dht::crypto::RevocationList crl;
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(0), crlNumberValue(crl.getNumber()));
|
||||
|
||||
crl.revoke(*device.second);
|
||||
crl.sign(ca);
|
||||
auto first = crl.getNumber();
|
||||
// An unnumbered list gets a random number on its first signature.
|
||||
CPPUNIT_ASSERT(not first.empty());
|
||||
CPPUNIT_ASSERT(crlNumberValue(first) != 0);
|
||||
|
||||
// Re-signing keeps the same lineage and moves the number forward.
|
||||
crl.sign(ca);
|
||||
auto second = crl.getNumber();
|
||||
CPPUNIT_ASSERT_EQUAL(crlNumberValue(first) + 1, crlNumberValue(second));
|
||||
|
||||
crl.sign(ca);
|
||||
CPPUNIT_ASSERT_EQUAL(crlNumberValue(first) + 2, crlNumberValue(crl.getNumber()));
|
||||
|
||||
// The number is a DER integer, so it is stored with leading zeros stripped.
|
||||
// Incrementing must still work for numbers shorter than 8 bytes.
|
||||
for (uint64_t start : {uint64_t(1), uint64_t(0x7f), uint64_t(0x80), uint64_t(0xffff)}) {
|
||||
dht::crypto::RevocationList small;
|
||||
small.revoke(*device.second);
|
||||
small.sign(ca, {}, start);
|
||||
CPPUNIT_ASSERT_EQUAL(start, crlNumberValue(small.getNumber()));
|
||||
small.sign(ca);
|
||||
CPPUNIT_ASSERT_EQUAL(start + 1, crlNumberValue(small.getNumber()));
|
||||
small.sign(ca);
|
||||
CPPUNIT_ASSERT_EQUAL(start + 2, crlNumberValue(small.getNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testRevocationListExplicitNumber()
|
||||
{
|
||||
auto ca = dht::crypto::generateIdentity("ca");
|
||||
auto device = dht::crypto::generateIdentity("dev", ca);
|
||||
|
||||
// Values chosen to cover leading zero bytes, a full-width number and the largest
|
||||
// value that still encodes as a positive 8-byte DER integer.
|
||||
const std::vector<uint64_t> numbers {1,
|
||||
42,
|
||||
0xff,
|
||||
0x100,
|
||||
0x0000'0001'0000'0000ull,
|
||||
0x0000'02a1'0000'0001ull,
|
||||
0x7fff'ffff'ffff'ffffull};
|
||||
for (auto number : numbers) {
|
||||
dht::crypto::RevocationList crl;
|
||||
crl.revoke(*device.second);
|
||||
crl.sign(ca, {}, number);
|
||||
CPPUNIT_ASSERT_EQUAL(number, crlNumberValue(crl.getNumber()));
|
||||
CPPUNIT_ASSERT(crl.isSignedBy(*ca.second));
|
||||
CPPUNIT_ASSERT(crl.isRevoked(*device.second));
|
||||
|
||||
// The number must survive a pack/unpack round-trip.
|
||||
dht::crypto::RevocationList unpacked(crl.getPacked());
|
||||
CPPUNIT_ASSERT_EQUAL(number, crlNumberValue(unpacked.getNumber()));
|
||||
}
|
||||
|
||||
// An explicit number overrides the increment, in both directions.
|
||||
dht::crypto::RevocationList crl;
|
||||
crl.revoke(*device.second);
|
||||
crl.sign(ca, {}, 1000);
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(1000), crlNumberValue(crl.getNumber()));
|
||||
crl.sign(ca, {}, 5);
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(5), crlNumberValue(crl.getNumber()));
|
||||
|
||||
// Passing 0 falls back to the default behavior: increment the current number.
|
||||
crl.sign(ca, {}, 0);
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(6), crlNumberValue(crl.getNumber()));
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testRevocationListPartitionedNumber()
|
||||
{
|
||||
// Two devices holding the same authority issue revocation lists independently.
|
||||
// RFC 5280 5.2.3 requires CRL numbers to increase monotonically for a given CRL
|
||||
// scope and issuer; partitioning the low bits by device keeps each sequence
|
||||
// monotonic while making collisions between devices impossible.
|
||||
constexpr unsigned TAG_BITS = 24;
|
||||
constexpr uint64_t TAG_A = 0x0a0b0c;
|
||||
constexpr uint64_t TAG_B = 0x0a0b0d;
|
||||
|
||||
auto ca = dht::crypto::generateIdentity("ca");
|
||||
auto account = dht::crypto::generateIdentity("acc", ca, 4096, true);
|
||||
auto deviceA = dht::crypto::generateIdentity("devA", account);
|
||||
auto deviceB = dht::crypto::generateIdentity("devB", account);
|
||||
|
||||
uint64_t previous {0};
|
||||
dht::crypto::RevocationList crlA;
|
||||
for (unsigned i = 1; i <= 4; i++) {
|
||||
crlA.revoke(*deviceA.second);
|
||||
crlA.sign(account, {}, (uint64_t(i) << TAG_BITS) | TAG_A);
|
||||
auto number = crlNumberValue(crlA.getNumber());
|
||||
CPPUNIT_ASSERT_EQUAL(TAG_A, number & ((uint64_t(1) << TAG_BITS) - 1));
|
||||
CPPUNIT_ASSERT(number > previous);
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(0), number >> 63);
|
||||
previous = number;
|
||||
}
|
||||
|
||||
// Both devices branch from the same counter but never mint the same number.
|
||||
dht::crypto::RevocationList branchA;
|
||||
branchA.revoke(*deviceA.second);
|
||||
branchA.sign(account, {}, (uint64_t(9) << TAG_BITS) | TAG_A);
|
||||
dht::crypto::RevocationList branchB;
|
||||
branchB.revoke(*deviceB.second);
|
||||
branchB.sign(account, {}, (uint64_t(9) << TAG_BITS) | TAG_B);
|
||||
CPPUNIT_ASSERT(crlNumberValue(branchA.getNumber()) != crlNumberValue(branchB.getNumber()));
|
||||
|
||||
// Both are valid and revoke only their own target.
|
||||
CPPUNIT_ASSERT(branchA.isSignedBy(*account.second));
|
||||
CPPUNIT_ASSERT(branchB.isSignedBy(*account.second));
|
||||
CPPUNIT_ASSERT(branchA.isRevoked(*deviceA.second));
|
||||
CPPUNIT_ASSERT(not branchA.isRevoked(*deviceB.second));
|
||||
CPPUNIT_ASSERT(branchB.isRevoked(*deviceB.second));
|
||||
CPPUNIT_ASSERT(not branchB.isRevoked(*deviceA.second));
|
||||
|
||||
// A number minted by an older client is fully random, so bit 63 may be set. Masking
|
||||
// it out and taking the counter part still yields a strictly greater number.
|
||||
constexpr uint64_t legacy = 0xdead'beef'0123'4567ull;
|
||||
dht::crypto::RevocationList legacyCrl;
|
||||
legacyCrl.revoke(*deviceA.second);
|
||||
legacyCrl.sign(account, {}, legacy);
|
||||
auto counter = ((crlNumberValue(legacyCrl.getNumber()) & ~(uint64_t(1) << 63)) >> TAG_BITS) + 1;
|
||||
legacyCrl.sign(account, {}, (counter << TAG_BITS) | TAG_A);
|
||||
CPPUNIT_ASSERT(crlNumberValue(legacyCrl.getNumber()) > (legacy & ~(uint64_t(1) << 63)));
|
||||
CPPUNIT_ASSERT_EQUAL(uint64_t(0), crlNumberValue(legacyCrl.getNumber()) >> 63);
|
||||
}
|
||||
|
||||
void
|
||||
CryptoTester::testCertificateRequest()
|
||||
{ // Generate CA
|
||||
{
|
||||
// Generate CA
|
||||
auto ca = dht::crypto::generateIdentity("Test CA");
|
||||
|
||||
// Generate signed request
|
||||
@@ -316,15 +149,6 @@ CryptoTester::testCertificateSerialNumber()
|
||||
};
|
||||
auto serial = dht::crypto::Certificate(cert_pem).getSerialNumber();
|
||||
CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end()));
|
||||
|
||||
auto key = dht::crypto::PrivateKey::generateEC();
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
auto generated = dht::crypto::Certificate::generate(key, "generated", {});
|
||||
auto generatedSerial = generated.getSerialNumber();
|
||||
CPPUNIT_ASSERT(not generatedSerial.empty());
|
||||
CPPUNIT_ASSERT_EQUAL(uint8_t {0}, uint8_t(generatedSerial.front() & 0x80));
|
||||
CPPUNIT_ASSERT(std::any_of(generatedSerial.begin(), generatedSerial.end(), [](uint8_t byte) { return byte != 0; }));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -12,11 +12,7 @@ class CryptoTester : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(CryptoTester);
|
||||
CPPUNIT_TEST(testSignatureEncryption);
|
||||
CPPUNIT_TEST(testPublicKeyPemIsPlainText);
|
||||
CPPUNIT_TEST(testCertificateRevocation);
|
||||
CPPUNIT_TEST(testRevocationListNumber);
|
||||
CPPUNIT_TEST(testRevocationListExplicitNumber);
|
||||
CPPUNIT_TEST(testRevocationListPartitionedNumber);
|
||||
CPPUNIT_TEST(testCertificateRequest);
|
||||
CPPUNIT_TEST(testCertificateSerialNumber);
|
||||
CPPUNIT_TEST(testOcsp);
|
||||
@@ -40,26 +36,10 @@ public:
|
||||
* Test data signature, encryption and decryption
|
||||
*/
|
||||
void testSignatureEncryption();
|
||||
/**
|
||||
* Test that an exported public key is text only, with no embedded null byte
|
||||
*/
|
||||
void testPublicKeyPemIsPlainText();
|
||||
/**
|
||||
* Test certificate generation, validation and revocation
|
||||
*/
|
||||
void testCertificateRevocation();
|
||||
/**
|
||||
* Test the default CRL Number behavior: random on first signature, incremented after
|
||||
*/
|
||||
void testRevocationListNumber();
|
||||
/**
|
||||
* Test signing a revocation list with a caller-provided CRL Number
|
||||
*/
|
||||
void testRevocationListExplicitNumber();
|
||||
/**
|
||||
* Test that issuers sharing an authority can partition the CRL Number space
|
||||
*/
|
||||
void testRevocationListPartitionedNumber();
|
||||
/**
|
||||
* Test certificate requests
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::literals;
|
||||
|
||||
@@ -210,42 +208,6 @@ DhtRunnerTester::testImportValuesPreservesRemoteQuota()
|
||||
restored.join();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunnerTester::testExportValuesUsesSystemTime()
|
||||
{
|
||||
auto key = dht::InfoHash::get("export-system-time");
|
||||
const auto created = dht::clock::now();
|
||||
msgpack::sbuffer importBuffer;
|
||||
msgpack::packer<msgpack::sbuffer> pk(&importBuffer);
|
||||
pk.pack_array(1);
|
||||
pk.pack_array(2);
|
||||
pk.pack(created.time_since_epoch().count());
|
||||
dht::Value {std::string("persisted")}.msgpack_pack(pk);
|
||||
node1.importValues({
|
||||
dht::ValuesExport {key, {importBuffer.data(), importBuffer.data() + importBuffer.size()}}
|
||||
});
|
||||
|
||||
auto exported = node1.exportValues();
|
||||
CPPUNIT_ASSERT_EQUAL(size_t(1), exported.size());
|
||||
|
||||
msgpack::unpacked msg;
|
||||
msgpack::unpack(msg, reinterpret_cast<const char*>(exported.front().second.data()), exported.front().second.size());
|
||||
const auto values = msg.get();
|
||||
CPPUNIT_ASSERT(values.type == msgpack::type::ARRAY);
|
||||
CPPUNIT_ASSERT_EQUAL(uint32_t(1), values.via.array.size);
|
||||
const auto& persistedValue = values.via.array.ptr[0];
|
||||
CPPUNIT_ASSERT_EQUAL(uint32_t(4), persistedValue.via.array.size);
|
||||
CPPUNIT_ASSERT(persistedValue.via.array.ptr[0].type == msgpack::type::EXT);
|
||||
CPPUNIT_ASSERT(persistedValue.via.array.ptr[3].type == msgpack::type::EXT);
|
||||
|
||||
const auto persistedCreated = persistedValue.via.array.ptr[0].as<std::chrono::system_clock::time_point>();
|
||||
const auto persistedExpiration = persistedValue.via.array.ptr[3].as<std::chrono::system_clock::time_point>();
|
||||
const auto delta = std::chrono::system_clock::now() - persistedCreated;
|
||||
CPPUNIT_ASSERT(delta >= std::chrono::system_clock::duration::zero());
|
||||
CPPUNIT_ASSERT(delta < 5s);
|
||||
CPPUNIT_ASSERT(persistedExpiration > persistedCreated);
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunnerTester::testImportValuesPreservesStoredExpiration()
|
||||
{
|
||||
@@ -578,34 +540,6 @@ DhtRunnerTester::testShutdownCompletesWithPendingPut()
|
||||
clientNode.join();
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunnerTester::testSavedPortFallback()
|
||||
{
|
||||
// A saved port that is already taken by another process (e.g. fast
|
||||
// application restart while the old instance still holds it) must not
|
||||
// prevent the node from starting: it should fall back to a random port.
|
||||
dht::DhtRunner::Config config;
|
||||
config.dht_config.node_config.persist_path = "/tmp/opendht_test_port_fallback";
|
||||
std::string portFile = config.dht_config.node_config.persist_path + "_port.txt";
|
||||
|
||||
// node1 (from setUp) holds a port; save it as our persisted port.
|
||||
auto takenPort = node1.getBoundPort();
|
||||
{
|
||||
std::ofstream out(portFile);
|
||||
out << takenPort << std::endl << takenPort << std::endl;
|
||||
}
|
||||
|
||||
dht::DhtRunner testNode;
|
||||
CPPUNIT_ASSERT_NO_THROW(testNode.run(0, config));
|
||||
CPPUNIT_ASSERT(testNode.getBoundPort());
|
||||
CPPUNIT_ASSERT(testNode.getBoundPort() != takenPort);
|
||||
|
||||
testNode.shutdown();
|
||||
testNode.join();
|
||||
std::remove(portFile.c_str());
|
||||
std::remove((config.dht_config.node_config.persist_path + "_port.txt").c_str());
|
||||
}
|
||||
|
||||
void
|
||||
DhtRunnerTester::testListen()
|
||||
{
|
||||
|
||||
@@ -21,14 +21,12 @@ class DhtRunnerTester : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testListenLotOfBytes);
|
||||
CPPUNIT_TEST(testIdOps);
|
||||
CPPUNIT_TEST(testImportValuesPreservesRemoteQuota);
|
||||
CPPUNIT_TEST(testExportValuesUsesSystemTime);
|
||||
CPPUNIT_TEST(testImportValuesPreservesStoredExpiration);
|
||||
CPPUNIT_TEST(testImportPermanentValueExpires);
|
||||
CPPUNIT_TEST(testBootstrapSetsConnectingState);
|
||||
CPPUNIT_TEST(testBootstrapThenPutNoRace);
|
||||
CPPUNIT_TEST(testBootstrapMissingNodeThenPutFails);
|
||||
CPPUNIT_TEST(testShutdownCompletesWithPendingPut);
|
||||
CPPUNIT_TEST(testSavedPortFallback);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
dht::DhtRunner node1 {};
|
||||
@@ -68,14 +66,12 @@ public:
|
||||
*/
|
||||
void testIdOps();
|
||||
void testImportValuesPreservesRemoteQuota();
|
||||
void testExportValuesUsesSystemTime();
|
||||
void testImportValuesPreservesStoredExpiration();
|
||||
void testImportPermanentValueExpires();
|
||||
void testBootstrapSetsConnectingState();
|
||||
void testBootstrapThenPutNoRace();
|
||||
void testBootstrapMissingNodeThenPutFails();
|
||||
void testShutdownCompletesWithPendingPut();
|
||||
void testSavedPortFallback();
|
||||
/**
|
||||
* Test listen method with lot of datas
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
|
||||
@@ -333,36 +332,6 @@ HttpTester::test_parse_url_just_slash()
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), parsed.target);
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_completed_resolver_callback_uses_io_thread()
|
||||
{
|
||||
asio::io_context ioContext;
|
||||
const asio::ip::tcp::endpoint endpoint(asio::ip::address_v4::loopback(), 80);
|
||||
dht::http::Resolver resolver(ioContext, {endpoint});
|
||||
const auto callerThread = std::this_thread::get_id();
|
||||
std::thread::id callbackThread;
|
||||
asio::error_code callbackError;
|
||||
std::vector<asio::ip::tcp::endpoint> resolvedEndpoints;
|
||||
std::atomic_bool callbackCalled {false};
|
||||
|
||||
resolver.add_callback([&](const asio::error_code& ec, const auto& endpoints) {
|
||||
callbackError = ec;
|
||||
callbackThread = std::this_thread::get_id();
|
||||
resolvedEndpoints = endpoints;
|
||||
callbackCalled = true;
|
||||
});
|
||||
|
||||
CPPUNIT_ASSERT(!callbackCalled);
|
||||
std::thread ioThread([&] { ioContext.run(); });
|
||||
ioThread.join();
|
||||
|
||||
CPPUNIT_ASSERT(callbackCalled);
|
||||
CPPUNIT_ASSERT(!callbackError);
|
||||
CPPUNIT_ASSERT(callbackThread != callerThread);
|
||||
CPPUNIT_ASSERT_EQUAL(size_t(1), resolvedEndpoints.size());
|
||||
CPPUNIT_ASSERT_EQUAL(endpoint, resolvedEndpoints.front());
|
||||
}
|
||||
|
||||
void
|
||||
HttpTester::test_send_json()
|
||||
{
|
||||
|
||||
@@ -39,7 +39,6 @@ class HttpTester : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(test_parse_url_complex_path_query_fragment);
|
||||
CPPUNIT_TEST(test_parse_url_empty);
|
||||
CPPUNIT_TEST(test_parse_url_just_slash);
|
||||
CPPUNIT_TEST(test_completed_resolver_callback_uses_io_thread);
|
||||
// send
|
||||
CPPUNIT_TEST(test_send_json);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
@@ -83,7 +82,6 @@ public:
|
||||
void test_parse_url_complex_path_query_fragment();
|
||||
void test_parse_url_empty();
|
||||
void test_parse_url_just_slash();
|
||||
void test_completed_resolver_callback_uses_io_thread();
|
||||
/**
|
||||
* Test send(json)
|
||||
*/
|
||||
|
||||
@@ -137,29 +137,4 @@ ValueTester::testPushTypePreservedAfterEncrypt()
|
||||
CPPUNIT_ASSERT(encrypted.isEncrypted());
|
||||
}
|
||||
|
||||
void
|
||||
ValueTester::testPushTypeJsonRoundTrip()
|
||||
{
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
dht::Value original {(const uint8_t*) "hello", 5};
|
||||
original.id = 42;
|
||||
original.priority = 1;
|
||||
original.pushType = "videoCall";
|
||||
|
||||
dht::Value restored(original.toJson());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(original.id, restored.id);
|
||||
CPPUNIT_ASSERT_EQUAL(original.priority, restored.priority);
|
||||
CPPUNIT_ASSERT_EQUAL(original.pushType, restored.pushType);
|
||||
|
||||
// No pushType: the field must stay absent from the JSON and empty after parse.
|
||||
dht::Value plain {(const uint8_t*) "data", 4};
|
||||
plain.id = 7;
|
||||
auto json = plain.toJson();
|
||||
CPPUNIT_ASSERT(!json.isMember("pt"));
|
||||
dht::Value plainRestored(json);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(), plainRestored.pushType);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -16,7 +16,6 @@ class ValueTester : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testPushTypeMsgpackRoundTrip);
|
||||
CPPUNIT_TEST(testPushTypeAbsentAfterUnpack);
|
||||
CPPUNIT_TEST(testPushTypePreservedAfterEncrypt);
|
||||
CPPUNIT_TEST(testPushTypeJsonRoundTrip);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -39,7 +38,6 @@ public:
|
||||
void testPushTypeMsgpackRoundTrip();
|
||||
void testPushTypeAbsentAfterUnpack();
|
||||
void testPushTypePreservedAfterEncrypt();
|
||||
void testPushTypeJsonRoundTrip();
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"default-registry": {
|
||||
"kind": "git",
|
||||
"baseline": "f3e10653cc27d62a37a3763cd84b38bca07c6075",
|
||||
"baseline": "66c0373dc7fca549e5803087b9487edfe3aca0a1",
|
||||
"repository": "https://github.com/microsoft/vcpkg"
|
||||
},
|
||||
"registries": [
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "opendht",
|
||||
"version-string": "4.2.0",
|
||||
"version-string": "4.0.0",
|
||||
"port-version": 1,
|
||||
"description": "OpenDHT: A lightweight C++17 Distributed Hash Table library.",
|
||||
"homepage": "https://opendht.net",
|
||||
|
||||
Reference in new issue
Block a user