1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "osp/impl/discovery/mdns/domain_name.h"
6
7 #include <algorithm>
8 #include <iterator>
9
10 #include "util/stringprintf.h"
11
12 namespace openscreen {
13 namespace osp {
14
15 // static
GetLocalDomain()16 DomainName DomainName::GetLocalDomain() {
17 return DomainName{{5, 'l', 'o', 'c', 'a', 'l', 0}};
18 }
19
20 // static
Append(const DomainName & first,const DomainName & second)21 ErrorOr<DomainName> DomainName::Append(const DomainName& first,
22 const DomainName& second) {
23 OSP_CHECK(first.domain_name_.size());
24 OSP_CHECK(second.domain_name_.size());
25
26 // Both vectors should represent null terminated domain names.
27 OSP_DCHECK_EQ(first.domain_name_.back(), '\0');
28 OSP_DCHECK_EQ(second.domain_name_.back(), '\0');
29 if ((first.domain_name_.size() + second.domain_name_.size() - 1) >
30 kDomainNameMaxLength) {
31 return Error::Code::kDomainNameTooLong;
32 }
33
34 DomainName result;
35 result.domain_name_.clear();
36 result.domain_name_.insert(result.domain_name_.begin(),
37 first.domain_name_.begin(),
38 first.domain_name_.end());
39 result.domain_name_.insert(result.domain_name_.end() - 1,
40 second.domain_name_.begin(),
41 second.domain_name_.end() - 1);
42 return result;
43 }
44
DomainName()45 DomainName::DomainName() : domain_name_{0u} {}
DomainName(std::vector<uint8_t> && domain_name)46 DomainName::DomainName(std::vector<uint8_t>&& domain_name)
47 : domain_name_(std::move(domain_name)) {
48 OSP_CHECK_LE(domain_name_.size(), kDomainNameMaxLength);
49 }
50 DomainName::DomainName(const DomainName&) = default;
51 DomainName::DomainName(DomainName&&) noexcept = default;
52 DomainName::~DomainName() = default;
53 DomainName& DomainName::operator=(const DomainName&) = default;
54 DomainName& DomainName::operator=(DomainName&&) noexcept = default;
55
operator ==(const DomainName & other) const56 bool DomainName::operator==(const DomainName& other) const {
57 if (domain_name_.size() != other.domain_name_.size()) {
58 return false;
59 }
60 for (size_t i = 0; i < domain_name_.size(); ++i) {
61 if (tolower(domain_name_[i]) != tolower(other.domain_name_[i])) {
62 return false;
63 }
64 }
65 return true;
66 }
67
operator !=(const DomainName & other) const68 bool DomainName::operator!=(const DomainName& other) const {
69 return !(*this == other);
70 }
71
EndsWithLocalDomain() const72 bool DomainName::EndsWithLocalDomain() const {
73 const DomainName local_domain = GetLocalDomain();
74 if (domain_name_.size() < local_domain.domain_name_.size())
75 return false;
76
77 return std::equal(local_domain.domain_name_.begin(),
78 local_domain.domain_name_.end(),
79 domain_name_.end() - local_domain.domain_name_.size());
80 }
81
Append(const DomainName & after)82 Error DomainName::Append(const DomainName& after) {
83 OSP_CHECK(after.domain_name_.size());
84 OSP_DCHECK_EQ(after.domain_name_.back(), 0u);
85
86 if ((domain_name_.size() + after.domain_name_.size() - 1) >
87 kDomainNameMaxLength) {
88 return Error::Code::kDomainNameTooLong;
89 }
90
91 domain_name_.insert(domain_name_.end() - 1, after.domain_name_.begin(),
92 after.domain_name_.end() - 1);
93 return Error::None();
94 }
95
GetLabels() const96 std::vector<absl::string_view> DomainName::GetLabels() const {
97 OSP_DCHECK_GT(domain_name_.size(), 0u);
98 OSP_DCHECK_LT(domain_name_.size(), kDomainNameMaxLength);
99
100 std::vector<absl::string_view> result;
101 const uint8_t* data = domain_name_.data();
102 while (*data != 0) {
103 const size_t label_length = *data;
104 OSP_DCHECK_LT(label_length, kDomainNameMaxLabelLength);
105
106 ++data;
107 result.emplace_back(reinterpret_cast<const char*>(data), label_length);
108 data += label_length;
109 }
110 return result;
111 }
112
operator ()(const DomainName & a,const DomainName & b) const113 bool DomainNameComparator::operator()(const DomainName& a,
114 const DomainName& b) const {
115 return a.domain_name() < b.domain_name();
116 }
117
operator <<(std::ostream & os,const DomainName & domain_name)118 std::ostream& operator<<(std::ostream& os, const DomainName& domain_name) {
119 const auto& data = domain_name.domain_name();
120 OSP_DCHECK_GT(data.size(), 0u);
121 auto it = data.begin();
122 while (*it != 0) {
123 size_t length = *it++;
124 PrettyPrintAsciiHex(os, it, it + length);
125 it += length;
126 os << ".";
127 }
128 return os;
129 }
130
131 } // namespace osp
132 } // namespace openscreen
133