1 //
2 //
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/resolver/server_address.h"
22 
23 #include <string.h>
24 
25 #include <algorithm>
26 #include <initializer_list>
27 #include <memory>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include "absl/status/status.h"
33 #include "absl/status/statusor.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/strings/str_format.h"
36 #include "absl/strings/str_join.h"
37 
38 #include "src/core/lib/address_utils/sockaddr_utils.h"
39 #include "src/core/lib/channel/channel_args.h"
40 
41 // IWYU pragma: no_include <sys/socket.h>
42 
43 namespace grpc_core {
44 
45 //
46 // ServerAddressWeightAttribute
47 //
48 const char* ServerAddressWeightAttribute::kServerAddressWeightAttributeKey =
49     "server_address_weight";
50 
51 //
52 // ServerAddress
53 //
54 
ServerAddress(const grpc_resolved_address & address,const ChannelArgs & args,std::map<const char *,std::unique_ptr<AttributeInterface>> attributes)55 ServerAddress::ServerAddress(
56     const grpc_resolved_address& address, const ChannelArgs& args,
57     std::map<const char*, std::unique_ptr<AttributeInterface>> attributes)
58     : address_(address), args_(args), attributes_(std::move(attributes)) {}
59 
ServerAddress(const ServerAddress & other)60 ServerAddress::ServerAddress(const ServerAddress& other)
61     : address_(other.address_), args_(other.args_) {
62   for (const auto& p : other.attributes_) {
63     attributes_[p.first] = p.second->Copy();
64   }
65 }
operator =(const ServerAddress & other)66 ServerAddress& ServerAddress::operator=(const ServerAddress& other) {
67   if (&other == this) {
68     return *this;
69   }
70   address_ = other.address_;
71   args_ = other.args_;
72   attributes_.clear();
73   for (const auto& p : other.attributes_) {
74     attributes_[p.first] = p.second->Copy();
75   }
76   return *this;
77 }
78 
ServerAddress(ServerAddress && other)79 ServerAddress::ServerAddress(ServerAddress&& other) noexcept
80     : address_(other.address_),
81       args_(std::move(other.args_)),
82       attributes_(std::move(other.attributes_)) {}
83 
operator =(ServerAddress && other)84 ServerAddress& ServerAddress::operator=(ServerAddress&& other) noexcept {
85   address_ = other.address_;
86   args_ = std::move(other.args_);
87   attributes_ = std::move(other.attributes_);
88   return *this;
89 }
90 
91 namespace {
92 
CompareAttributes(const std::map<const char *,std::unique_ptr<ServerAddress::AttributeInterface>> & attributes1,const std::map<const char *,std::unique_ptr<ServerAddress::AttributeInterface>> & attributes2)93 int CompareAttributes(
94     const std::map<const char*,
95                    std::unique_ptr<ServerAddress::AttributeInterface>>&
96         attributes1,
97     const std::map<const char*,
98                    std::unique_ptr<ServerAddress::AttributeInterface>>&
99         attributes2) {
100   auto it2 = attributes2.begin();
101   for (auto it1 = attributes1.begin(); it1 != attributes1.end(); ++it1) {
102     // attributes2 has fewer elements than attributes1
103     if (it2 == attributes2.end()) return -1;
104     // compare keys
105     int retval = strcmp(it1->first, it2->first);
106     if (retval != 0) return retval;
107     // compare values
108     retval = it1->second->Cmp(it2->second.get());
109     if (retval != 0) return retval;
110     ++it2;
111   }
112   // attributes1 has fewer elements than attributes2
113   if (it2 != attributes2.end()) return 1;
114   // equal
115   return 0;
116 }
117 
118 }  // namespace
119 
Cmp(const ServerAddress & other) const120 int ServerAddress::Cmp(const ServerAddress& other) const {
121   if (address_.len > other.address_.len) return 1;
122   if (address_.len < other.address_.len) return -1;
123   int retval = memcmp(address_.addr, other.address_.addr, address_.len);
124   if (retval != 0) return retval;
125   retval = QsortCompare(args_, other.args_);
126   if (retval != 0) return retval;
127   return CompareAttributes(attributes_, other.attributes_);
128 }
129 
GetAttribute(const char * key) const130 const ServerAddress::AttributeInterface* ServerAddress::GetAttribute(
131     const char* key) const {
132   auto it = attributes_.find(key);
133   if (it == attributes_.end()) return nullptr;
134   return it->second.get();
135 }
136 
137 // Returns a copy of the address with a modified attribute.
138 // If the new value is null, the attribute is removed.
WithAttribute(const char * key,std::unique_ptr<AttributeInterface> value) const139 ServerAddress ServerAddress::WithAttribute(
140     const char* key, std::unique_ptr<AttributeInterface> value) const {
141   ServerAddress address = *this;
142   if (value == nullptr) {
143     address.attributes_.erase(key);
144   } else {
145     address.attributes_[key] = std::move(value);
146   }
147   return address;
148 }
149 
ToString() const150 std::string ServerAddress::ToString() const {
151   auto addr_str = grpc_sockaddr_to_string(&address_, false);
152   std::vector<std::string> parts = {
153       addr_str.ok() ? addr_str.value() : addr_str.status().ToString(),
154   };
155   if (args_ != ChannelArgs()) {
156     parts.emplace_back(absl::StrCat("args=", args_.ToString()));
157   }
158   if (!attributes_.empty()) {
159     std::vector<std::string> attrs;
160     attrs.reserve(attributes_.size());
161     for (const auto& p : attributes_) {
162       attrs.emplace_back(absl::StrCat(p.first, "=", p.second->ToString()));
163     }
164     parts.emplace_back(
165         absl::StrCat("attributes={", absl::StrJoin(attrs, ", "), "}"));
166   }
167   return absl::StrJoin(parts, " ");
168 }
169 
ToString() const170 std::string ServerAddressWeightAttribute::ToString() const {
171   return absl::StrFormat("%d", weight_);
172 }
173 
174 }  // namespace grpc_core
175