0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 02:02:38 +01:00

ircd::net: Refactor dual stack integration.

This commit is contained in:
Jason Volk 2019-03-24 18:27:49 -07:00
parent f098848386
commit fe81c30806
4 changed files with 303 additions and 178 deletions

View file

@ -25,10 +25,17 @@ namespace ircd::net
using asio::steady_timer;
using ircd::string;
string_view string(const mutable_buffer &, const ip::address_v6 &);
string_view string(const mutable_buffer &, const ip::address_v4 &);
string_view string(const mutable_buffer &, const ip::address &);
std::string string(const ip::address_v6 &);
std::string string(const ip::address_v4 &);
std::string string(const ip::address &);
uint16_t port(const ip::tcp::endpoint &);
ip::address addr(const ip::tcp::endpoint &);
std::string host(const ip::tcp::endpoint &);
std::string string(const ip::address &);
string_view string(const mutable_buffer &, const ip::tcp::endpoint &);
std::string string(const ip::tcp::endpoint &);
ipport make_ipport(const boost::asio::ip::tcp::endpoint &);

View file

@ -15,6 +15,8 @@
namespace boost::asio::ip
{
struct address;
struct address_v4;
struct address_v6;
};
namespace ircd::net
@ -26,6 +28,10 @@ namespace ircd::net
uint128_t &host6(ipaddr &);
uint32_t &host4(ipaddr &);
bool is_loop(const ipaddr &);
bool is_v6(const ipaddr &);
bool is_v4(const ipaddr &);
bool operator!(const ipaddr &);
bool operator<(const ipaddr &, const ipaddr &);
bool operator==(const ipaddr &, const ipaddr &);
@ -33,21 +39,40 @@ namespace ircd::net
string_view string_ip4(const mutable_buffer &out, const uint32_t &);
string_view string_ip6(const mutable_buffer &out, const uint128_t &);
string_view string(const mutable_buffer &out, const ipaddr &);
std::ostream &operator<<(std::ostream &, const ipaddr &);
boost::asio::ip::address_v6 make_address(const uint128_t &);
boost::asio::ip::address_v4 make_address(const uint32_t &);
boost::asio::ip::address make_address(const ipaddr &);
boost::asio::ip::address make_address(const string_view &ip);
}
union ircd::net::ipaddr
{
struct cmp;
uint32_t v4;
uint128_t v6 {0};
std::array<uint8_t, 16> byte;
explicit operator bool() const;
ipaddr(const uint32_t &ip);
ipaddr(const uint128_t &ip);
ipaddr(const rfc1035::record::A &);
ipaddr(const rfc1035::record::AAAA &);
ipaddr(const boost::asio::ip::address &);
ipaddr(const string_view &ip);
ipaddr() = default;
};
static_assert(std::alignment_of<ircd::net::ipaddr>() >= 16);
struct ircd::net::ipaddr::cmp
{
bool operator()(const ipaddr &a, const ipaddr &b) const;
};
inline ircd::net::ipaddr::operator
bool() const
{

View file

@ -15,17 +15,18 @@ namespace ircd::net
{
struct ipport;
const uint16_t &port(const ipport &);
uint16_t &port(ipport &);
bool is_v6(const ipport &);
bool is_v4(const ipport &);
const uint128_t &host6(const ipport &);
const uint32_t &host4(const ipport &);
uint128_t &host6(ipport &);
uint32_t &host4(ipport &);
const uint16_t &port(const ipport &);
uint16_t &port(ipport &);
bool is_loop(const ipport &);
bool is_v6(const ipport &);
bool is_v4(const ipport &);
string_view string(const mutable_buffer &out, const ipport &);
std::ostream &operator<<(std::ostream &, const ipport &);
}
@ -42,14 +43,10 @@ namespace ircd
/// serve as input to a reverse resolution. Either way, this allocation-free
/// structure is useful for storing raw IP/port data, even in large sets.
///
/// The TYPE field is only a boolean for now indicating IPv4 or IPv6; the
/// official way to query this is to use net::is_v6(ipport) etc and not
/// std::get the type directly.
///
struct ircd::net::ipport
:std::tuple<ipaddr, uint16_t, bool>
:std::pair<ipaddr, uint16_t>
{
enum { IP, PORT, TYPE };
enum { IP, PORT };
struct cmp;
struct cmp_ip;
@ -58,13 +55,8 @@ struct ircd::net::ipport
explicit operator bool() const;
bool operator!() const { return !static_cast<bool>(*this); }
ipport(const uint32_t &ip, const uint16_t &port);
ipport(const uint128_t &ip, const uint16_t &port);
ipport(const rfc1035::record::A &, const uint16_t &port);
ipport(const rfc1035::record::AAAA &, const uint16_t &port);
ipport(const boost::asio::ip::address &, const uint16_t &port);
ipport(const string_view &ip, const uint16_t &port);
ipport(const string_view &ip, const string_view &port);
template<class iparg> ipport(iparg&&, const uint16_t &port);
template<class iparg> ipport(iparg&&, const string_view &port);
ipport();
};
@ -86,10 +78,29 @@ struct ircd::net::ipport::cmp
inline
ircd::net::ipport::ipport()
:std::pair<ipaddr, uint16_t>
{
std::get<PORT>(*this) = 0;
std::get<TYPE>(*this) = 0;
{}, 0
}
{}
template<class iparg>
ircd::net::ipport::ipport(iparg&& arg,
const string_view &port)
:ipport
{
std::forward<iparg>(arg), lex_cast<uint16_t>(port)
}
{}
template<class iparg>
ircd::net::ipport::ipport(iparg&& arg,
const uint16_t &port)
:std::pair<ipaddr, uint16_t>
{
std::forward<iparg>(arg), port
}
{}
inline ircd::net::ipport::operator
bool()
@ -113,7 +124,7 @@ ircd::net::host6(const ipport &ipp)
inline bool
ircd::net::is_v6(const ipport &ipp)
{
return std::get<ipp.TYPE>(ipp) == true;
return is_v6(std::get<ipp.IP>(ipp));
}
inline uint32_t &
@ -131,7 +142,7 @@ ircd::net::host4(const ipport &ipp)
inline bool
ircd::net::is_v4(const ipport &ipp)
{
return std::get<ipp.TYPE>(ipp) == false;
return is_v4(std::get<ipp.IP>(ipp));
}
inline uint16_t &
@ -145,3 +156,9 @@ ircd::net::port(const ipport &ipp)
{
return std::get<ipp.PORT>(ipp);
}
inline bool
ircd::net::is_loop(const ipport &ipp)
{
return is_loop(std::get<ipp.IP>(ipp));
}

View file

@ -3629,7 +3629,7 @@ ircd::net::dns::cache::make_type(const mutable_buffer &out,
std::ostream &
ircd::net::operator<<(std::ostream &s, const ipport &t)
{
thread_local char buf[256];
thread_local char buf[128];
const critical_assertion ca;
s << net::string(buf, t);
return s;
@ -3639,24 +3639,11 @@ ircd::string_view
ircd::net::string(const mutable_buffer &buf,
const ipport &ipp)
{
const auto len
{
is_v4(ipp)? fmt::sprintf
{
buf, "%s:%u",
ip::address_v4{host4(ipp)}.to_string(),
port(ipp)
}:
is_v6(ipp)? fmt::sprintf
{
buf, "%s:%u",
ip::address_v6{std::get<ipp.IP>(ipp).byte}.to_string(),
port(ipp)
}:
0
};
return { data(buf), size_t(len) };
mutable_buffer out{buf};
consume(out, size(string(out, std::get<ipp.IP>(ipp))));
consume(out, copy(out, ":"_sv));
consume(out, size(lex_cast(port(ipp), out)));
return { data(buf), data(out) };
}
ircd::net::ipport
@ -3682,14 +3669,7 @@ ircd::net::make_endpoint_udp(const ipport &ipport)
{
return
{
is_v6(ipport)? ip::udp::endpoint
{
asio::ip::address_v6 { std::get<ipport.IP>(ipport).byte }, port(ipport)
}
: ip::udp::endpoint
{
asio::ip::address_v4 { host4(ipport) }, port(ipport)
},
make_address(std::get<ipport.IP>(ipport)), port(ipport)
};
}
@ -3698,29 +3678,19 @@ ircd::net::make_endpoint(const ipport &ipport)
{
return
{
is_v6(ipport)? ip::tcp::endpoint
{
asio::ip::address_v6 { std::get<ipport.IP>(ipport).byte }, port(ipport)
}
: ip::tcp::endpoint
{
asio::ip::address_v4 { host4(ipport) }, port(ipport)
},
make_address(std::get<ipport.IP>(ipport)), port(ipport)
};
}
//
// cmp
//
bool
ircd::net::ipport::cmp_ip::operator()(const ipport &a, const ipport &b)
const
{
if(is_v4(a) && is_v6(b))
return true;
if(is_v6(a) && is_v4(b))
return false;
assert((is_v4(a) && is_v4(b)) || (is_v6(a) && is_v6(b)));
return std::get<a.IP>(a).byte < std::get<b.IP>(b).byte;
return ipaddr::cmp()(std::get<a.IP>(a), std::get<b.IP>(b));
}
bool
@ -3730,137 +3700,178 @@ const
return std::get<a.PORT>(a) < std::get<b.PORT>(b);
}
//
// ipport::ipport
//
ircd::net::ipport::ipport(const string_view &ip,
const string_view &port)
:ipport
{
ip, lex_cast<uint16_t>(port)
}
{
}
ircd::net::ipport::ipport(const string_view &ip,
const uint16_t &port)
:ipport
{
make_address(ip), port
}
{
}
ircd::net::ipport::ipport(const rfc1035::record::A &rr,
const uint16_t &port)
:ipport
{
rr.ip4, port
}
{
}
ircd::net::ipport::ipport(const rfc1035::record::AAAA &rr,
const uint16_t &port)
:ipport
{
rr.ip6, port
}
{
}
ircd::net::ipport::ipport(const boost::asio::ip::address &address,
const uint16_t &port)
{
std::get<TYPE>(*this) = address.is_v6();
std::get<PORT>(*this) = port;
if(is_v6(*this))
{
std::get<IP>(*this).byte = address.to_v6().to_bytes();
std::reverse(std::get<IP>(*this).byte.begin(), std::get<IP>(*this).byte.end());
}
else host4(*this) = address.to_v4().to_ulong();
}
ircd::net::ipport::ipport(const uint32_t &ip,
const uint16_t &p)
{
std::get<TYPE>(*this) = false;
host6(*this) = 0;
host4(*this) = ip;
port(*this) = p;
}
ircd::net::ipport::ipport(const uint128_t &ip,
const uint16_t &p)
{
std::get<TYPE>(*this) = true;
host6(*this) = ip;
port(*this) = p;
}
///////////////////////////////////////////////////////////////////////////////
//
// net/ipaddr.h
//
boost::asio::ip::address
ircd::net::make_address(const ipaddr &ipaddr)
{
return is_v6(ipaddr)?
ip::address(make_address(ipaddr.v6)):
ip::address(make_address(ipaddr.v4));
}
boost::asio::ip::address
ircd::net::make_address(const string_view &ip)
try
{
return ip && ip != "*"?
boost::asio::ip::make_address(ip):
boost::asio::ip::address{};
return
ip && ip == "*"?
boost::asio::ip::address_v6::any():
ip?
boost::asio::ip::make_address(ip):
boost::asio::ip::address{};
}
catch(const boost::system::system_error &e)
{
throw_system_error(e);
}
ircd::string_view
ircd::net::string(const mutable_buffer &buf,
const ipaddr &ipaddr)
boost::asio::ip::address_v4
ircd::net::make_address(const uint32_t &ip)
{
throw not_implemented
{
"string(ipaddr): not implemented yet"
};
return ip::address_v4{ip};
}
ircd::string_view
ircd::net::string_ip4(const mutable_buffer &buf,
const uint32_t &ip)
{
const auto len
{
ip::address_v4{ip}.to_string().copy(data(buf), size(buf))
};
return { data(buf), size_t(len) };
}
ircd::string_view
ircd::net::string_ip6(const mutable_buffer &buf,
const uint128_t &ip)
boost::asio::ip::address_v6
ircd::net::make_address(const uint128_t &ip)
{
const auto &pun
{
reinterpret_cast<const uint8_t (&)[16]>(ip)
};
const auto &punpun
auto punpun
{
reinterpret_cast<const std::array<uint8_t, 16> &>(pun)
};
const auto len
std::reverse(begin(punpun), end(punpun));
return ip::address_v6{punpun};
}
std::ostream &
ircd::net::operator<<(std::ostream &s, const ipaddr &ipa)
{
thread_local char buf[128];
const critical_assertion ca;
s << net::string(buf, ipa);
return s;
}
ircd::string_view
ircd::net::string(const mutable_buffer &buf,
const ipaddr &ipaddr)
{
return is_v6(ipaddr)?
string_ip6(buf, ipaddr.v6):
string_ip4(buf, ipaddr.v4);
}
ircd::string_view
ircd::net::string_ip4(const mutable_buffer &buf,
const uint32_t &ip)
{
return string(buf, make_address(ip));
}
ircd::string_view
ircd::net::string_ip6(const mutable_buffer &buf,
const uint128_t &ip)
{
return string(buf, make_address(ip));
}
bool
ircd::net::is_loop(const ipaddr &ipaddr)
{
return is_v6(ipaddr)?
make_address(ipaddr.v6).is_loopback():
make_address(ipaddr.v4).is_loopback();
}
bool
ircd::net::is_v4(const ipaddr &ipaddr)
{
return ipaddr.v6 == 0 ||
(ipaddr.byte[4] == 0xff && ipaddr.byte[5] == 0xff);
}
bool
ircd::net::is_v6(const ipaddr &ipaddr)
{
return ipaddr.v6 == 0 ||
!(ipaddr.byte[4] == 0xff && ipaddr.byte[5] == 0xff);
}
//
// ipaddr::ipaddr
//
ircd::net::ipaddr::ipaddr(const string_view &ip)
:ipaddr
{
make_address(ip)
}
{
}
ircd::net::ipaddr::ipaddr(const rfc1035::record::A &rr)
:ipaddr
{
rr.ip4
}
{
}
ircd::net::ipaddr::ipaddr(const rfc1035::record::AAAA &rr)
:ipaddr
{
rr.ip6
}
{
}
ircd::net::ipaddr::ipaddr(const uint32_t &ip)
:ipaddr
{
make_address(ip)
}
{
}
ircd::net::ipaddr::ipaddr(const uint128_t &ip)
:ipaddr
{
make_address(ip)
}
{
}
ircd::net::ipaddr::ipaddr(const asio::ip::address &address)
{
const auto address_
{
ip::address_v6{punpun}.to_string().copy(data(buf), size(buf))
address.is_v6()?
address.to_v6():
make_address_v6(ip::v4_mapped, address.to_v4())
};
return { data(buf), size_t(len) };
byte = address_.to_bytes();
std::reverse(byte.begin(), byte.end());
}
//
// ipaddr::ipaddr
//
bool
ircd::net::ipaddr::cmp::operator()(const ipaddr &a, const ipaddr &b)
const
{
return a.byte < b.byte;
}
///////////////////////////////////////////////////////////////////////////////
@ -3955,20 +3966,25 @@ ircd::net::string(const mutable_buffer &buf,
// net/asio.h
//
std::string
ircd::net::string(const ip::address &addr)
{
return addr.to_string();
}
std::string
ircd::net::string(const ip::tcp::endpoint &ep)
{
std::string ret(128, char{});
const auto addr{string(net::addr(ep))};
const auto data{const_cast<char *>(ret.data())};
ret.resize(snprintf(data, ret.size(), "%s:%u", addr.c_str(), port(ep)));
return ret;
return util::string(64, [&ep]
(const mutable_buffer &out)
{
return string(out, ep);
});
}
ircd::string_view
ircd::net::string(const mutable_buffer &buf,
const ip::tcp::endpoint &ep)
{
mutable_buffer out{buf};
consume(out, size(string(out, net::addr(ep))));
consume(out, copy(out, ":"_sv));
consume(out, size(lex_cast(port(ep), out)));
return {data(buf), data(out)};
}
std::string
@ -3989,6 +4005,66 @@ ircd::net::port(const ip::tcp::endpoint &ep)
return ep.port();
}
std::string
ircd::net::string(const ip::address &addr)
{
return
addr.is_v4()?
string(addr.to_v4()):
string(addr.to_v6());
}
std::string
ircd::net::string(const ip::address_v4 &addr)
{
return util::string(16, [&addr]
(const mutable_buffer &out)
{
return string(out, addr);
});
}
std::string
ircd::net::string(const ip::address_v6 &addr)
{
return addr.to_string();
}
ircd::string_view
ircd::net::string(const mutable_buffer &out,
const ip::address &addr)
{
return
addr.is_v4()?
string(out, addr.to_v4()):
string(out, addr.to_v6());
}
ircd::string_view
ircd::net::string(const mutable_buffer &out,
const ip::address_v4 &addr)
{
const uint32_t a(addr.to_ulong());
return fmt::sprintf
{
out, "%u.%u.%u.%u",
(a & 0xFF000000U) >> 24,
(a & 0x00FF0000U) >> 16,
(a & 0x0000FF00U) >> 8,
(a & 0x000000FFU) >> 0,
};
}
ircd::string_view
ircd::net::string(const mutable_buffer &out,
const ip::address_v6 &addr)
{
return
{
data(out), string(addr).copy(data(out), size(out))
};
}
///////////////////////////////////////////////////////////////////////////////
//
// buffer.h - provide definition for the null buffers and asio conversion