Return an IPv6 address text representation with zero compression as described in RFC 5952 ("A Recommendation for IPv6 Address Text Representation").
| 512 | // Return an IPv6 address text representation with zero compression as described in RFC 5952 |
| 513 | // ("A Recommendation for IPv6 Address Text Representation"). |
| 514 | static std::string IPv6ToString(std::span<const uint8_t> a, uint32_t scope_id) |
| 515 | { |
| 516 | assert(a.size() == ADDR_IPV6_SIZE); |
| 517 | const std::array groups{ |
| 518 | ReadBE16(&a[0]), |
| 519 | ReadBE16(&a[2]), |
| 520 | ReadBE16(&a[4]), |
| 521 | ReadBE16(&a[6]), |
| 522 | ReadBE16(&a[8]), |
| 523 | ReadBE16(&a[10]), |
| 524 | ReadBE16(&a[12]), |
| 525 | ReadBE16(&a[14]), |
| 526 | }; |
| 527 | |
| 528 | // The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see |
| 529 | // https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683 |
| 530 | struct ZeroSpan { |
| 531 | size_t start_index{0}; |
| 532 | size_t len{0}; |
| 533 | }; |
| 534 | |
| 535 | // Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more |
| 536 | // zero sequences of equal length are found. |
| 537 | ZeroSpan longest, current; |
| 538 | for (size_t i{0}; i < groups.size(); ++i) { |
| 539 | if (groups[i] != 0) { |
| 540 | current = {i + 1, 0}; |
| 541 | continue; |
| 542 | } |
| 543 | current.len += 1; |
| 544 | if (current.len > longest.len) { |
| 545 | longest = current; |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | std::string r; |
| 550 | r.reserve(39); |
| 551 | for (size_t i{0}; i < groups.size(); ++i) { |
| 552 | // Replace the longest sequence of consecutive all-zero fields with two colons ("::"). |
| 553 | if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len) { |
| 554 | if (i == longest.start_index) { |
| 555 | r += "::"; |
| 556 | } |
| 557 | continue; |
| 558 | } |
| 559 | r += strprintf("%s%x", ((!r.empty() && r.back() != ':') ? ":" : ""), groups[i]); |
| 560 | } |
| 561 | |
| 562 | if (scope_id != 0) { |
| 563 | r += strprintf("%%%u", scope_id); |
| 564 | } |
| 565 | |
| 566 | return r; |
| 567 | } |
| 568 | |
| 569 | std::string OnionToString(std::span<const uint8_t> addr) |
| 570 | { |