2021-03-09 22:24:35 +00:00
|
|
|
#pragma once
|
2018-06-01 14:08:54 +00:00
|
|
|
|
2021-03-09 22:24:35 +00:00
|
|
|
#include "bencode.h"
|
2023-10-24 13:18:03 +00:00
|
|
|
|
2022-07-16 00:41:14 +00:00
|
|
|
#include <llarp/util/formattable.hpp>
|
2023-10-24 13:18:03 +00:00
|
|
|
#include <llarp/util/logging.hpp>
|
2018-12-12 01:02:36 +00:00
|
|
|
|
2022-02-17 18:44:31 +00:00
|
|
|
#include <oxenc/hex.h>
|
2020-06-29 21:46:25 +00:00
|
|
|
|
2023-10-24 13:18:03 +00:00
|
|
|
#include <algorithm>
|
2018-12-20 14:18:03 +00:00
|
|
|
#include <array>
|
|
|
|
#include <cstddef>
|
2018-06-01 14:24:58 +00:00
|
|
|
#include <iomanip>
|
2018-06-01 14:08:54 +00:00
|
|
|
#include <iostream>
|
2018-12-20 14:18:03 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <numeric>
|
|
|
|
#include <type_traits>
|
2018-06-01 14:08:54 +00:00
|
|
|
|
2018-10-23 12:40:34 +00:00
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
extern void
|
|
|
|
randombytes(unsigned char* const ptr, unsigned long long sz);
|
2019-12-10 18:50:52 +00:00
|
|
|
|
|
|
|
extern int
|
2019-12-11 22:58:56 +00:00
|
|
|
sodium_is_zero(const unsigned char* n, const size_t nlen);
|
2018-10-23 12:40:34 +00:00
|
|
|
}
|
2018-06-01 14:08:54 +00:00
|
|
|
namespace llarp
|
|
|
|
{
|
2018-12-20 14:18:03 +00:00
|
|
|
/// aligned buffer that is sz bytes long and aligns to the nearest Alignment
|
2020-04-07 18:38:56 +00:00
|
|
|
template <size_t sz>
|
2020-06-12 23:00:39 +00:00
|
|
|
// Microsoft C malloc(3C) cannot return pointers aligned wider than 8 ffs
|
|
|
|
#ifdef _WIN32
|
|
|
|
struct alignas(uint64_t) AlignedBuffer
|
|
|
|
#else
|
2020-05-23 21:18:00 +00:00
|
|
|
struct alignas(std::max_align_t) AlignedBuffer
|
2020-06-12 23:00:39 +00:00
|
|
|
#endif
|
2018-06-01 14:08:54 +00:00
|
|
|
{
|
2020-05-23 21:18:00 +00:00
|
|
|
static_assert(alignof(std::max_align_t) <= 16, "insane alignment");
|
2020-04-07 18:38:56 +00:00
|
|
|
static_assert(
|
|
|
|
sz >= 8,
|
|
|
|
"AlignedBuffer cannot be used with buffers smaller than 8 "
|
|
|
|
"bytes");
|
2019-12-19 20:17:02 +00:00
|
|
|
|
2018-12-20 14:18:03 +00:00
|
|
|
static constexpr size_t SIZE = sz;
|
|
|
|
|
2021-03-26 14:33:36 +00:00
|
|
|
virtual ~AlignedBuffer() = default;
|
|
|
|
|
2018-07-26 21:08:56 +00:00
|
|
|
AlignedBuffer()
|
|
|
|
{
|
2018-12-20 14:18:03 +00:00
|
|
|
Zero();
|
2018-06-22 00:25:30 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 01:04:06 +00:00
|
|
|
explicit AlignedBuffer(const byte_t* data)
|
2018-06-01 14:08:54 +00:00
|
|
|
{
|
2019-12-12 16:12:45 +00:00
|
|
|
*this = data;
|
2018-12-20 14:18:03 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
explicit AlignedBuffer(const std::array<byte_t, SIZE>& buf)
|
2018-12-20 14:18:03 +00:00
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
_data = buf;
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AlignedBuffer&
|
2018-06-01 17:47:37 +00:00
|
|
|
operator=(const byte_t* data)
|
2018-06-01 14:08:54 +00:00
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
std::memcpy(_data.data(), data, sz);
|
2018-06-01 14:08:54 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-09-24 14:31:58 +00:00
|
|
|
/// bitwise NOT
|
2020-04-07 18:38:56 +00:00
|
|
|
AlignedBuffer<sz>
|
2018-09-24 14:31:58 +00:00
|
|
|
operator~() const
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
AlignedBuffer<sz> ret;
|
2019-01-02 01:04:04 +00:00
|
|
|
std::transform(begin(), end(), ret.begin(), [](byte_t a) { return ~a; });
|
2018-12-20 14:18:03 +00:00
|
|
|
|
2018-09-24 14:31:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-01 14:08:54 +00:00
|
|
|
bool
|
|
|
|
operator==(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data == other._data;
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator!=(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data != other._data;
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
2018-06-22 12:45:46 +00:00
|
|
|
bool
|
|
|
|
operator<(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data < other._data;
|
2018-06-22 12:45:46 +00:00
|
|
|
}
|
|
|
|
|
2018-08-10 21:34:11 +00:00
|
|
|
bool
|
|
|
|
operator>(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data > other._data;
|
2018-08-10 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator<=(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data <= other._data;
|
2018-08-10 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator>=(const AlignedBuffer& other) const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data >= other._data;
|
2018-08-10 21:34:11 +00:00
|
|
|
}
|
|
|
|
|
2018-07-28 22:20:32 +00:00
|
|
|
AlignedBuffer
|
|
|
|
operator^(const AlignedBuffer& other) const
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
AlignedBuffer<sz> ret;
|
2021-03-02 02:06:20 +00:00
|
|
|
std::transform(begin(), end(), other.begin(), ret.begin(), std::bit_xor<>());
|
2018-07-28 22:20:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignedBuffer&
|
|
|
|
operator^=(const AlignedBuffer& other)
|
|
|
|
{
|
2018-12-20 14:18:03 +00:00
|
|
|
// Mutate in place instead.
|
2020-04-07 18:38:56 +00:00
|
|
|
for (size_t i = 0; i < sz; ++i)
|
2018-12-20 14:18:03 +00:00
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
_data[i] ^= other._data[i];
|
2018-12-20 14:18:03 +00:00
|
|
|
}
|
|
|
|
return *this;
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
2021-03-05 17:31:52 +00:00
|
|
|
byte_t&
|
|
|
|
operator[](size_t idx)
|
2019-01-02 01:03:53 +00:00
|
|
|
{
|
|
|
|
assert(idx < SIZE);
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data[idx];
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2021-03-05 17:31:52 +00:00
|
|
|
const byte_t&
|
|
|
|
operator[](size_t idx) const
|
2019-01-02 01:03:53 +00:00
|
|
|
{
|
|
|
|
assert(idx < SIZE);
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data[idx];
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2018-12-20 14:18:03 +00:00
|
|
|
static constexpr size_t
|
2018-06-12 11:57:14 +00:00
|
|
|
size()
|
|
|
|
{
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
2018-06-14 14:04:42 +00:00
|
|
|
void
|
|
|
|
Fill(byte_t f)
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
_data.fill(f);
|
2018-06-14 14:04:42 +00:00
|
|
|
}
|
2018-06-25 15:12:08 +00:00
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
std::array<byte_t, SIZE>&
|
2018-12-20 16:03:55 +00:00
|
|
|
as_array()
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data;
|
2018-12-20 16:03:55 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
const std::array<byte_t, SIZE>&
|
2018-12-20 16:03:55 +00:00
|
|
|
as_array() const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data;
|
2018-12-20 16:03:55 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 01:04:04 +00:00
|
|
|
byte_t*
|
|
|
|
data()
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.data();
|
2019-01-02 01:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const byte_t*
|
|
|
|
data() const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.data();
|
2019-01-02 01:04:04 +00:00
|
|
|
}
|
|
|
|
|
2018-06-25 15:12:08 +00:00
|
|
|
bool
|
|
|
|
IsZero() const
|
|
|
|
{
|
2021-03-29 16:31:55 +00:00
|
|
|
const uint64_t* ptr = reinterpret_cast<const uint64_t*>(data());
|
|
|
|
for (size_t idx = 0; idx < SIZE / sizeof(uint64_t); idx++)
|
|
|
|
{
|
|
|
|
if (ptr[idx])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2018-06-25 15:12:08 +00:00
|
|
|
}
|
2018-06-14 14:04:42 +00:00
|
|
|
|
2018-06-01 14:08:54 +00:00
|
|
|
void
|
|
|
|
Zero()
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
_data.fill(0);
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
2021-03-12 13:50:21 +00:00
|
|
|
virtual void
|
2018-06-01 14:08:54 +00:00
|
|
|
Randomize()
|
|
|
|
{
|
2019-01-02 01:04:04 +00:00
|
|
|
randombytes(data(), SIZE);
|
2018-06-01 14:08:54 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
typename std::array<byte_t, SIZE>::iterator
|
2019-01-02 01:03:53 +00:00
|
|
|
begin()
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.begin();
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
typename std::array<byte_t, SIZE>::iterator
|
2019-01-02 01:03:53 +00:00
|
|
|
end()
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.end();
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
typename std::array<byte_t, SIZE>::const_iterator
|
2019-01-02 01:03:53 +00:00
|
|
|
begin() const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.cbegin();
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2023-09-27 14:09:48 +00:00
|
|
|
typename std::array<byte_t, SIZE>::const_iterator
|
2019-01-02 01:03:53 +00:00
|
|
|
end() const
|
|
|
|
{
|
2023-09-29 21:00:13 +00:00
|
|
|
return _data.cend();
|
2019-01-02 01:03:53 +00:00
|
|
|
}
|
|
|
|
|
2020-09-25 18:05:28 +00:00
|
|
|
bool
|
|
|
|
FromBytestring(llarp_buffer_t* buf)
|
|
|
|
{
|
|
|
|
if (buf->sz != sz)
|
|
|
|
{
|
|
|
|
llarp::LogError("bdecode buffer size mismatch ", buf->sz, "!=", sz);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
memcpy(data(), buf->base, sz);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-29 21:00:13 +00:00
|
|
|
bool
|
2023-10-18 15:44:37 +00:00
|
|
|
from_string(std::string_view b)
|
2023-09-29 21:00:13 +00:00
|
|
|
{
|
|
|
|
if (b.size() != sz)
|
|
|
|
{
|
|
|
|
log::error(util_cat, "Error: buffer size mismatch in aligned buffer!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::memcpy(_data.data(), b.data(), b.size());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-12 11:57:14 +00:00
|
|
|
bool
|
2023-08-31 16:28:02 +00:00
|
|
|
bt_encode(llarp_buffer_t* buf) const
|
2018-06-12 11:57:14 +00:00
|
|
|
{
|
2019-01-02 01:04:04 +00:00
|
|
|
return bencode_write_bytestring(buf, data(), sz);
|
2018-06-12 11:57:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-31 16:28:02 +00:00
|
|
|
std::string
|
|
|
|
bt_encode() const
|
|
|
|
{
|
|
|
|
return {reinterpret_cast<const char*>(data()), sz};
|
|
|
|
}
|
|
|
|
|
2018-06-12 11:57:14 +00:00
|
|
|
bool
|
|
|
|
BDecode(llarp_buffer_t* buf)
|
|
|
|
{
|
|
|
|
llarp_buffer_t strbuf;
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!bencode_read_string(buf, &strbuf))
|
2018-12-20 14:18:03 +00:00
|
|
|
{
|
2018-06-12 11:57:14 +00:00
|
|
|
return false;
|
2018-12-20 14:18:03 +00:00
|
|
|
}
|
2020-09-25 18:05:28 +00:00
|
|
|
return FromBytestring(&strbuf);
|
2018-06-12 11:57:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-05 19:35:16 +00:00
|
|
|
std::string_view
|
|
|
|
ToView() const
|
|
|
|
{
|
|
|
|
return {reinterpret_cast<const char*>(data()), sz};
|
|
|
|
}
|
|
|
|
|
2018-10-25 18:18:12 +00:00
|
|
|
std::string
|
|
|
|
ToHex() const
|
|
|
|
{
|
2022-02-17 18:44:31 +00:00
|
|
|
return oxenc::to_hex(begin(), end());
|
2018-10-25 18:18:12 +00:00
|
|
|
}
|
|
|
|
|
2020-03-01 02:15:25 +00:00
|
|
|
std::string
|
|
|
|
ShortHex() const
|
|
|
|
{
|
2022-02-17 18:44:31 +00:00
|
|
|
return oxenc::to_hex(begin(), begin() + 4);
|
2020-03-01 02:15:25 +00:00
|
|
|
}
|
|
|
|
|
2020-05-19 18:53:03 +00:00
|
|
|
bool
|
|
|
|
FromHex(std::string_view str)
|
|
|
|
{
|
2022-02-17 18:44:31 +00:00
|
|
|
if (str.size() != 2 * size() || !oxenc::is_hex(str))
|
2020-06-29 21:46:25 +00:00
|
|
|
return false;
|
2022-02-17 18:44:31 +00:00
|
|
|
oxenc::from_hex(str.begin(), str.end(), begin());
|
2020-06-29 21:46:25 +00:00
|
|
|
return true;
|
2020-05-19 18:53:03 +00:00
|
|
|
}
|
|
|
|
|
2018-12-20 14:18:03 +00:00
|
|
|
private:
|
2023-09-29 21:00:13 +00:00
|
|
|
std::array<byte_t, SIZE> _data;
|
2018-06-01 14:08:54 +00:00
|
|
|
};
|
2022-07-16 00:41:14 +00:00
|
|
|
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
template <size_t Sz>
|
|
|
|
static std::true_type
|
|
|
|
is_aligned_buffer_impl(AlignedBuffer<Sz>*);
|
|
|
|
|
|
|
|
static std::false_type
|
|
|
|
is_aligned_buffer_impl(...);
|
|
|
|
} // namespace detail
|
|
|
|
// True if T is or is derived from AlignedBuffer<N> for any N
|
|
|
|
template <typename T>
|
|
|
|
constexpr inline bool is_aligned_buffer =
|
|
|
|
decltype(detail::is_aligned_buffer_impl(static_cast<T*>(nullptr)))::value;
|
|
|
|
|
2018-06-18 22:03:50 +00:00
|
|
|
} // namespace llarp
|
2021-03-09 18:39:40 +00:00
|
|
|
|
2022-07-16 00:41:14 +00:00
|
|
|
namespace fmt
|
|
|
|
{
|
|
|
|
// Any AlignedBuffer<N> (or subclass) gets hex formatted when output:
|
|
|
|
template <typename T>
|
|
|
|
struct formatter<
|
|
|
|
T,
|
|
|
|
char,
|
|
|
|
std::enable_if_t<llarp::is_aligned_buffer<T> && !llarp::IsToStringFormattable<T>>>
|
|
|
|
: formatter<std::string_view>
|
|
|
|
{
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto
|
|
|
|
format(const T& val, FormatContext& ctx)
|
|
|
|
{
|
|
|
|
auto it = oxenc::hex_encoder{val.begin(), val.end()};
|
|
|
|
return std::copy(it, it.end(), ctx.out());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace fmt
|
|
|
|
|
2021-03-09 18:39:40 +00:00
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template <size_t sz>
|
|
|
|
struct hash<llarp::AlignedBuffer<sz>>
|
|
|
|
{
|
|
|
|
std::size_t
|
|
|
|
operator()(const llarp::AlignedBuffer<sz>& buf) const noexcept
|
|
|
|
{
|
|
|
|
std::size_t h = 0;
|
|
|
|
std::memcpy(&h, buf.data(), sizeof(std::size_t));
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace std
|