|
|
|
@@ -29,11 +29,12 @@
|
|
|
|
|
#ifndef _NET_UTILS_BASE_H_
|
|
|
|
|
#define _NET_UTILS_BASE_H_
|
|
|
|
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
|
#include <boost/asio/io_service.hpp>
|
|
|
|
|
#include <boost/uuid/uuid.hpp>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <typeinfo>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include "serialization/keyvalue_serialization.h"
|
|
|
|
|
#include "net/local_ip.h"
|
|
|
|
|
#include "string_tools.h"
|
|
|
|
|
#include "misc_log_ex.h"
|
|
|
|
|
|
|
|
|
@@ -49,78 +50,119 @@ namespace epee
|
|
|
|
|
{
|
|
|
|
|
namespace net_utils
|
|
|
|
|
{
|
|
|
|
|
struct network_address_base
|
|
|
|
|
class ipv4_network_address
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
|
|
|
|
|
bool operator!=(const network_address_base &other) const { return !operator==(other); }
|
|
|
|
|
bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
|
|
|
|
|
bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
|
|
|
|
|
virtual std::string str() const = 0;
|
|
|
|
|
virtual std::string host_str() const = 0;
|
|
|
|
|
virtual bool is_loopback() const = 0;
|
|
|
|
|
virtual bool is_local() const = 0;
|
|
|
|
|
virtual uint8_t get_type_id() const = 0;
|
|
|
|
|
protected:
|
|
|
|
|
// A very simple non cryptographic hash function by Fowler, Noll, Vo
|
|
|
|
|
uint64_t fnv1a(const uint8_t *data, size_t len) const {
|
|
|
|
|
uint64_t h = 0xcbf29ce484222325;
|
|
|
|
|
while (len--)
|
|
|
|
|
h = (h ^ *data++) * 0x100000001b3;
|
|
|
|
|
return h;
|
|
|
|
|
}
|
|
|
|
|
uint64_t m_host_id;
|
|
|
|
|
uint64_t m_full_id;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual ~network_address_base() {}
|
|
|
|
|
};
|
|
|
|
|
struct ipv4_network_address: public network_address_base
|
|
|
|
|
{
|
|
|
|
|
void init_ids()
|
|
|
|
|
{
|
|
|
|
|
m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
|
|
|
|
|
m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
|
|
|
|
|
uint32_t ip() const { return m_ip; }
|
|
|
|
|
uint16_t port() const { return m_port; }
|
|
|
|
|
virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
|
|
|
|
|
virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
|
|
|
|
|
virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
|
|
|
|
|
virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
|
|
|
|
|
virtual uint8_t get_type_id() const { return ID; }
|
|
|
|
|
public: // serialization
|
|
|
|
|
static const uint8_t ID = 1;
|
|
|
|
|
#pragma pack(push)
|
|
|
|
|
#pragma pack(1)
|
|
|
|
|
uint32_t m_ip;
|
|
|
|
|
uint16_t m_port;
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
constexpr ipv4_network_address(uint32_t ip, uint16_t port) noexcept
|
|
|
|
|
: m_ip(ip), m_port(port) {}
|
|
|
|
|
|
|
|
|
|
bool equal(const ipv4_network_address& other) const noexcept;
|
|
|
|
|
bool less(const ipv4_network_address& other) const noexcept;
|
|
|
|
|
constexpr bool is_same_host(const ipv4_network_address& other) const noexcept
|
|
|
|
|
{ return ip() == other.ip(); }
|
|
|
|
|
|
|
|
|
|
constexpr uint32_t ip() const noexcept { return m_ip; }
|
|
|
|
|
constexpr uint16_t port() const noexcept { return m_port; }
|
|
|
|
|
std::string str() const;
|
|
|
|
|
std::string host_str() const;
|
|
|
|
|
bool is_loopback() const;
|
|
|
|
|
bool is_local() const;
|
|
|
|
|
static constexpr uint8_t get_type_id() noexcept { return ID; }
|
|
|
|
|
|
|
|
|
|
static const uint8_t ID = 1;
|
|
|
|
|
BEGIN_KV_SERIALIZE_MAP()
|
|
|
|
|
KV_SERIALIZE(m_ip)
|
|
|
|
|
KV_SERIALIZE(m_port)
|
|
|
|
|
if (!is_store)
|
|
|
|
|
const_cast<ipv4_network_address&>(this_ref).init_ids();
|
|
|
|
|
END_KV_SERIALIZE_MAP()
|
|
|
|
|
};
|
|
|
|
|
class network_address: public boost::shared_ptr<network_address_base>
|
|
|
|
|
|
|
|
|
|
inline bool operator==(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return lhs.equal(rhs); }
|
|
|
|
|
inline bool operator!=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return !lhs.equal(rhs); }
|
|
|
|
|
inline bool operator<(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return lhs.less(rhs); }
|
|
|
|
|
inline bool operator<=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return !rhs.less(lhs); }
|
|
|
|
|
inline bool operator>(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return rhs.less(lhs); }
|
|
|
|
|
inline bool operator>=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
|
|
|
|
|
{ return !lhs.less(rhs); }
|
|
|
|
|
|
|
|
|
|
class network_address
|
|
|
|
|
{
|
|
|
|
|
struct interface
|
|
|
|
|
{
|
|
|
|
|
virtual ~interface() {};
|
|
|
|
|
|
|
|
|
|
virtual bool equal(const interface&) const = 0;
|
|
|
|
|
virtual bool less(const interface&) const = 0;
|
|
|
|
|
virtual bool is_same_host(const interface&) const = 0;
|
|
|
|
|
|
|
|
|
|
virtual std::string str() const = 0;
|
|
|
|
|
virtual std::string host_str() const = 0;
|
|
|
|
|
virtual bool is_loopback() const = 0;
|
|
|
|
|
virtual bool is_local() const = 0;
|
|
|
|
|
virtual uint8_t get_type_id() const = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct implementation final : interface
|
|
|
|
|
{
|
|
|
|
|
T value;
|
|
|
|
|
|
|
|
|
|
implementation(const T& src) : value(src) {}
|
|
|
|
|
~implementation() = default;
|
|
|
|
|
|
|
|
|
|
// Type-checks for cast are done in cpp
|
|
|
|
|
static const T& cast(const interface& src) noexcept
|
|
|
|
|
{ return static_cast<const implementation<T>&>(src).value; }
|
|
|
|
|
|
|
|
|
|
virtual bool equal(const interface& other) const override
|
|
|
|
|
{ return value.equal(cast(other)); }
|
|
|
|
|
|
|
|
|
|
virtual bool less(const interface& other) const override
|
|
|
|
|
{ return value.less(cast(other)); }
|
|
|
|
|
|
|
|
|
|
virtual bool is_same_host(const interface& other) const override
|
|
|
|
|
{ return value.is_same_host(cast(other)); }
|
|
|
|
|
|
|
|
|
|
virtual std::string str() const override { return value.str(); }
|
|
|
|
|
virtual std::string host_str() const override { return value.host_str(); }
|
|
|
|
|
virtual bool is_loopback() const override { return value.is_loopback(); }
|
|
|
|
|
virtual bool is_local() const override { return value.is_local(); }
|
|
|
|
|
virtual uint8_t get_type_id() const override { return value.get_type_id(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<interface> self;
|
|
|
|
|
|
|
|
|
|
template<typename Type>
|
|
|
|
|
Type& as_mutable() const
|
|
|
|
|
{
|
|
|
|
|
// types `implmentation<Type>` and `implementation<const Type>` are unique
|
|
|
|
|
using Type_ = typename std::remove_const<Type>::type;
|
|
|
|
|
network_address::interface* const self_ = self.get(); // avoid clang warning in typeid
|
|
|
|
|
if (!self_ || typeid(implementation<Type_>) != typeid(*self_))
|
|
|
|
|
throw std::bad_cast{};
|
|
|
|
|
return static_cast<implementation<Type_>*>(self_)->value;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
network_address() {}
|
|
|
|
|
network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {}
|
|
|
|
|
bool operator==(const network_address &other) const { return (*this)->operator==(*other); }
|
|
|
|
|
bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); }
|
|
|
|
|
bool operator<(const network_address &other) const { return (*this)->operator<(*other); }
|
|
|
|
|
bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); }
|
|
|
|
|
std::string str() const { return (*this) ? (*this)->str() : "<none>"; }
|
|
|
|
|
std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; }
|
|
|
|
|
bool is_loopback() const { return (*this)->is_loopback(); }
|
|
|
|
|
bool is_local() const { return (*this)->is_local(); }
|
|
|
|
|
uint8_t get_type_id() const { return (*this)->get_type_id(); }
|
|
|
|
|
template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); }
|
|
|
|
|
template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); }
|
|
|
|
|
network_address() : self(nullptr) {}
|
|
|
|
|
template<typename T>
|
|
|
|
|
network_address(const T& src)
|
|
|
|
|
: self(std::make_shared<implementation<T>>(src)) {}
|
|
|
|
|
bool equal(const network_address &other) const;
|
|
|
|
|
bool less(const network_address &other) const;
|
|
|
|
|
bool is_same_host(const network_address &other) const;
|
|
|
|
|
std::string str() const { return self ? self->str() : "<none>"; }
|
|
|
|
|
std::string host_str() const { return self ? self->host_str() : "<none>"; }
|
|
|
|
|
bool is_loopback() const { return self ? self->is_loopback() : false; }
|
|
|
|
|
bool is_local() const { return self ? self->is_local() : false; }
|
|
|
|
|
uint8_t get_type_id() const { return self ? self->get_type_id() : 0; }
|
|
|
|
|
template<typename Type> const Type &as() const { return as_mutable<const Type>(); }
|
|
|
|
|
|
|
|
|
|
BEGIN_KV_SERIALIZE_MAP()
|
|
|
|
|
uint8_t type = is_store ? this_ref.get_type_id() : 0;
|
|
|
|
@@ -129,13 +171,27 @@ namespace net_utils
|
|
|
|
|
{
|
|
|
|
|
case ipv4_network_address::ID:
|
|
|
|
|
if (!is_store)
|
|
|
|
|
const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0));
|
|
|
|
|
KV_SERIALIZE(template as<ipv4_network_address>());
|
|
|
|
|
const_cast<network_address&>(this_ref) = ipv4_network_address{0, 0};
|
|
|
|
|
KV_SERIALIZE(template as_mutable<ipv4_network_address>());
|
|
|
|
|
break;
|
|
|
|
|
default: MERROR("Unsupported network address type: " << type); return false;
|
|
|
|
|
}
|
|
|
|
|
END_KV_SERIALIZE_MAP()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline bool operator==(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return lhs.equal(rhs); }
|
|
|
|
|
inline bool operator!=(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return !lhs.equal(rhs); }
|
|
|
|
|
inline bool operator<(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return lhs.less(rhs); }
|
|
|
|
|
inline bool operator<=(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return !rhs.less(lhs); }
|
|
|
|
|
inline bool operator>(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return rhs.less(lhs); }
|
|
|
|
|
inline bool operator>=(const network_address& lhs, const network_address& rhs)
|
|
|
|
|
{ return !lhs.less(rhs); }
|
|
|
|
|
|
|
|
|
|
inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
|
|
|
|
|
{
|
|
|
|
|
uint32_t ip;
|
|
|
|
@@ -144,7 +200,7 @@ namespace net_utils
|
|
|
|
|
{
|
|
|
|
|
if (default_port && !port)
|
|
|
|
|
port = default_port;
|
|
|
|
|
address.reset(new ipv4_network_address(ip, port));
|
|
|
|
|
address = ipv4_network_address{ip, port};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
@@ -182,7 +238,7 @@ namespace net_utils
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
connection_context_base(): m_connection_id(),
|
|
|
|
|
m_remote_address(new ipv4_network_address(0,0)),
|
|
|
|
|
m_remote_address(ipv4_network_address{0,0}),
|
|
|
|
|
m_is_income(false),
|
|
|
|
|
m_started(time(NULL)),
|
|
|
|
|
m_last_recv(0),
|
|
|
|
@@ -235,7 +291,7 @@ namespace net_utils
|
|
|
|
|
std::string print_connection_context(const connection_context_base& ctx)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
|
|
|
|
|
ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -243,7 +299,7 @@ namespace net_utils
|
|
|
|
|
std::string print_connection_context_short(const connection_context_base& ctx)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT");
|
|
|
|
|
ss << ctx.m_remote_address.str() << (ctx.m_is_income ? " INC":" OUT");
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|