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