blob: 4a5a3f30038e3cedc26fb4474b1a4bec045c8225 [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 <iomanip>
#include <iostream>
#include "garnet/bin/netconnector/mdns/dns_formatting.h"
#include "garnet/bin/netconnector/mdns/dns_message.h"
namespace netconnector {
namespace mdns {
namespace {
int ostream_indent_index() {
static int i = std::ios_base::xalloc();
return i;
}
static constexpr size_t kBytesPerLine = 16;
} // namespace
std::ostream& begl(std::ostream& os) {
for (long i = 0; i < os.iword(ostream_indent_index()); i++) {
os << " ";
}
return os;
}
std::ostream& indent(std::ostream& os) {
++os.iword(ostream_indent_index());
return os;
}
std::ostream& outdent(std::ostream& os) {
--os.iword(ostream_indent_index());
return os;
}
template <>
std::ostream& operator<<(std::ostream& os, const std::vector<uint8_t>& value) {
os << indent;
size_t line_offset = 0;
size_t byte_count = value.size();
const uint8_t* bytes = value.data();
while (true) {
os << "\n"
<< begl << std::hex << std::setw(4) << std::setfill('0') << line_offset
<< " ";
std::string chars(kBytesPerLine, ' ');
for (size_t i = 0; i < kBytesPerLine; ++i) {
if (i == kBytesPerLine / 2) {
os << " ";
}
if (i >= byte_count) {
os << " ";
++bytes;
} else {
os << " " << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<uint16_t>(*bytes);
if (*bytes >= ' ' && *bytes <= '~') {
chars[i] = *bytes;
} else {
chars[i] = '.';
}
++bytes;
}
}
os << " " << chars;
if (byte_count <= kBytesPerLine) {
break;
}
line_offset += kBytesPerLine;
byte_count -= kBytesPerLine;
}
return os << std::dec << outdent;
}
std::ostream& operator<<(std::ostream& os, DnsType value) {
switch (value) {
case DnsType::kA:
return os << "A";
case DnsType::kNs:
return os << "NS";
case DnsType::kCName:
return os << "CNAME";
case DnsType::kPtr:
return os << "PTR";
case DnsType::kTxt:
return os << "TXT";
case DnsType::kAaaa:
return os << "AAAA";
case DnsType::kSrv:
return os << "SRV";
case DnsType::kOpt:
return os << "OPT";
case DnsType::kNSec:
return os << "NSEC";
case DnsType::kAny:
return os << "any";
default:
return os << "TYPE " << static_cast<uint16_t>(value);
}
}
std::ostream& operator<<(std::ostream& os, DnsClass value) {
switch (value) {
case DnsClass::kIn:
return os << "IN";
case DnsClass::kCs:
return os << "CS";
case DnsClass::kCh:
return os << "CH";
case DnsClass::kHs:
return os << "HS";
case DnsClass::kNone:
return os << "none";
case DnsClass::kAny:
return os << "any";
default:
return os << "CLASS " << static_cast<uint16_t>(value);
}
}
std::ostream& operator<<(std::ostream& os, const DnsName& value) {
return os << value.dotted_string_;
}
std::ostream& operator<<(std::ostream& os, const DnsV4Address& value) {
return os << value.address_;
}
std::ostream& operator<<(std::ostream& os, const DnsV6Address& value) {
return os << value.address_;
}
std::ostream& operator<<(std::ostream& os, const DnsHeader& value) {
os << "\n";
os << indent;
os << begl << "id: " << value.id_ << "\n";
os << begl << "flags: 0x" << std::hex << std::setw(4) << std::setfill('0')
<< value.flags_ << std::dec;
return os << outdent;
}
std::ostream& operator<<(std::ostream& os, const DnsQuestion& value) {
os << "\n";
os << indent;
os << begl << "name: " << value.name_ << "\n";
os << begl << "type: " << value.type_ << "\n";
os << begl << "class: " << value.class_ << "\n";
os << begl << "unicast_response: " << value.unicast_response_;
return os << outdent;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataA& value) {
return os << begl << "address: " << value.address_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataNs& value) {
return os << begl
<< "name_server_domain_name: " << value.name_server_domain_name_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataCName& value) {
return os << begl << "canonical_name: " << value.canonical_name_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataPtr& value) {
return os << begl << "pointer_domain_name_: " << value.pointer_domain_name_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataTxt& value) {
os << begl << "text: ";
os << indent;
for (auto& string : value.strings_) {
os << "\n" << begl << "\"" << string << "\"";
}
return os << outdent;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataAaaa& value) {
return os << begl << "address: " << value.address_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataSrv& value) {
os << begl << "priority: " << value.priority_ << "\n";
os << begl << "weight: " << value.weight_ << "\n";
os << begl << "port: " << value.port_ << "\n";
return os << begl << "target: " << value.target_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataOpt& value) {
return os << begl << "options: " << value.options_;
}
std::ostream& operator<<(std::ostream& os, const DnsResourceDataNSec& value) {
os << begl << "next_domain: " << value.next_domain_ << "\n";
return os << begl << "bits: " << value.bits_;
}
std::ostream& operator<<(std::ostream& os, const DnsResource& value) {
os << "\n";
os << indent;
os << begl << "name: " << value.name_ << "\n";
os << begl << "type: " << value.type_ << "\n";
os << begl << "class: " << value.class_ << "\n";
os << begl << "cache_flush: " << value.cache_flush_ << "\n";
os << begl << "time_to_live: " << value.time_to_live_ << "\n";
switch (value.type_) {
case DnsType::kA:
os << value.a_;
break;
case DnsType::kNs:
os << value.ns_;
break;
case DnsType::kCName:
os << value.cname_;
break;
case DnsType::kPtr:
os << value.ptr_;
break;
case DnsType::kTxt:
os << value.txt_;
break;
case DnsType::kAaaa:
os << value.aaaa_;
break;
case DnsType::kSrv:
os << value.srv_;
break;
case DnsType::kOpt:
os << value.opt_;
break;
case DnsType::kNSec:
os << value.nsec_;
break;
default:
break;
}
return os << outdent;
}
std::ostream& operator<<(std::ostream& os, const DnsMessage& value) {
os << "\n";
os << indent;
os << begl << "header: " << value.header_;
if (!value.questions_.empty()) {
os << "\n" << begl << "questions: " << value.questions_;
}
if (!value.answers_.empty()) {
os << "\n" << begl << "answers: " << value.answers_;
}
if (!value.authorities_.empty()) {
os << "\n" << begl << "authorities: " << value.authorities_;
}
if (!value.additionals_.empty()) {
os << "\n" << begl << "additionals: " << value.additionals_;
}
return os << outdent;
}
} // namespace mdns
} // namespace netconnector