blob: 8054ec9304f32c507059ce79ea1bc50e75c5c12c [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/network/mdns/util/formatting.h"
#include <iomanip>
#include <iostream>
#include "src/lib/fostr/hex_dump.h"
#include "src/lib/fostr/zx_types.h"
namespace mdns {
std::ostream& operator<<(std::ostream& os, const std::vector<uint8_t>& value) {
if (value.empty()) {
return os << "<empty>";
}
if (std::all_of(value.cbegin(), value.cend(), [](uint8_t b) { return b >= ' ' && b <= '~'; })) {
std::cout << "\"" << std::string(value.begin(), value.end()) << "\"";
} else {
std::cout << fostr::NewLine << fostr::HexDump(value);
}
return os;
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::mdns::ServiceInstance& value) {
os << fostr::Indent;
if (value.has_addresses() && !value.addresses().empty()) {
os << fostr::NewLine << "addresses:" << value.addresses();
}
if (value.has_text_strings() && !value.text_strings().empty()) {
os << fostr::NewLine << "text:" << value.text();
}
if (value.has_target()) {
os << fostr::NewLine << "target: " << value.target();
}
if (value.has_srv_priority() && value.srv_priority() != 0) {
os << fostr::NewLine << "srv priority: " << value.srv_priority();
}
if (value.has_srv_weight() && value.srv_weight() != 0) {
os << fostr::NewLine << "srv weight: " << value.srv_weight();
}
return os << fostr::Outdent;
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::Ipv4Address& value) {
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(value.addr.data());
return os << static_cast<int>(bytes[0]) << '.' << static_cast<int>(bytes[1]) << '.'
<< static_cast<int>(bytes[2]) << '.' << static_cast<int>(bytes[3]);
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::Ipv6Address& value) {
// IPV6 text representation per RFC 5952:
// 1) Suppress leading zeros in hex representation of words.
// 2) Don't use '::' to shorten a just single zero word.
// 3) Shorten the longest sequence of zero words preferring the leftmost
// sequence if there's a tie.
// 4) Use lower-case hexadecimal.
const uint16_t* words = reinterpret_cast<const uint16_t*>(value.addr.data());
// Figure out where the longest span of zeros is.
uint8_t start_of_zeros;
uint8_t zeros_seen = 0;
uint8_t start_of_best_zeros = 255;
// Don't bother if the longest sequence is length 1.
uint8_t best_zeros_seen = 1;
for (uint8_t i = 0; i < 8; ++i) {
if (words[i] == 0) {
if (zeros_seen == 0) {
start_of_zeros = i;
}
++zeros_seen;
} else if (zeros_seen != 0) {
if (zeros_seen > best_zeros_seen) {
start_of_best_zeros = start_of_zeros;
best_zeros_seen = zeros_seen;
}
zeros_seen = 0;
}
}
if (zeros_seen > best_zeros_seen) {
start_of_best_zeros = start_of_zeros;
best_zeros_seen = zeros_seen;
}
os << std::hex;
for (uint8_t i = 0; i < 8; ++i) {
if (i < start_of_best_zeros || i >= start_of_best_zeros + best_zeros_seen) {
os << words[i];
if (i != 7) {
os << ":";
}
} else if (i == start_of_best_zeros) {
if (i == 0) {
os << "::";
} else {
os << ":"; // We just wrote a ':', so we only need one more.
}
}
}
return os << std::dec;
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::IpAddress& value) {
if (value.is_ipv4()) {
return os << value.ipv4();
} else {
return os << value.ipv6();
}
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::Ipv4SocketAddress& value) {
return os << value.address << ":" << value.port;
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::Ipv6SocketAddress& value) {
return os << "[" << value.address << "]:" << value.port;
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::SocketAddress& value) {
if (value.is_ipv4()) {
return os << value.ipv4();
} else {
return os << value.ipv6();
}
}
std::ostream& operator<<(std::ostream& os, const fuchsia::net::mdns::HostAddress& value) {
os << fostr::Indent;
os << fostr::NewLine << "address: " << value.address;
os << fostr::NewLine << "interface: " << value.interface;
os << fostr::NewLine << "ttl: " << zx::duration(value.ttl);
return os << fostr::Outdent;
}
} // namespace mdns