net: Make IPv6ToString do zero compression as described in RFC 5952

pull/826/head
practicalswift 4 years ago
parent 4b5659c6b1
commit c10f27fdb2

@ -556,11 +556,12 @@ static std::string IPv4ToString(Span<const uint8_t> a)
return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]); return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
} }
// Return an IPv6 address text representation with zero compression as described in RFC 5952
// ("A Recommendation for IPv6 Address Text Representation").
static std::string IPv6ToString(Span<const uint8_t> a) static std::string IPv6ToString(Span<const uint8_t> a)
{ {
assert(a.size() == ADDR_IPV6_SIZE); assert(a.size() == ADDR_IPV6_SIZE);
// clang-format off const std::array groups{
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
ReadBE16(&a[0]), ReadBE16(&a[0]),
ReadBE16(&a[2]), ReadBE16(&a[2]),
ReadBE16(&a[4]), ReadBE16(&a[4]),
@ -568,8 +569,44 @@ static std::string IPv6ToString(Span<const uint8_t> a)
ReadBE16(&a[8]), ReadBE16(&a[8]),
ReadBE16(&a[10]), ReadBE16(&a[10]),
ReadBE16(&a[12]), ReadBE16(&a[12]),
ReadBE16(&a[14])); ReadBE16(&a[14]),
// clang-format on };
// The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see
// https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683
struct ZeroSpan {
size_t start_index{0};
size_t len{0};
};
// Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more
// zero sequences of equal length are found.
ZeroSpan longest, current;
for (size_t i{0}; i < groups.size(); ++i) {
if (groups[i] != 0) {
current = {i + 1, 0};
continue;
}
current.len += 1;
if (current.len > longest.len) {
longest = current;
}
}
std::string r;
r.reserve(39);
for (size_t i{0}; i < groups.size(); ++i) {
// Replace the longest sequence of consecutive all-zero fields with two colons ("::").
if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len) {
if (i == longest.start_index) {
r += "::";
}
continue;
}
r += strprintf("%s%x", ((!r.empty() && r.back() != ':') ? ":" : ""), groups[i]);
}
return r;
} }
std::string CNetAddr::ToStringIP() const std::string CNetAddr::ToStringIP() const

Loading…
Cancel
Save