1 //
2 // Copyright 2015 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <grpc/impl/channel_arg_names.h>
18 #include <grpc/support/alloc.h>
19 #include <grpc/support/port_platform.h>
20 #include <stdint.h>
21
22 #include <algorithm>
23 #include <functional>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28
29 #include "absl/base/thread_annotations.h"
30 #include "absl/log/log.h"
31 #include "absl/status/status.h"
32 #include "absl/status/statusor.h"
33 #include "absl/strings/match.h"
34 #include "absl/strings/string_view.h"
35 #include "absl/strings/strip.h"
36 #include "absl/types/optional.h"
37 #include "src/core/config/core_configuration.h"
38 #include "src/core/lib/debug/trace.h"
39 #include "src/core/lib/iomgr/closure.h"
40 #include "src/core/lib/iomgr/error.h"
41 #include "src/core/lib/iomgr/iomgr_fwd.h"
42 #include "src/core/lib/iomgr/pollset_set.h"
43 #include "src/core/lib/iomgr/resolved_address.h"
44 #include "src/core/resolver/dns/event_engine/service_config_helper.h"
45 #include "src/core/resolver/resolver.h"
46 #include "src/core/resolver/resolver_factory.h"
47 #include "src/core/service_config/service_config.h"
48 #include "src/core/util/debug_location.h"
49 #include "src/core/util/orphanable.h"
50 #include "src/core/util/ref_counted_ptr.h"
51 #include "src/core/util/status_helper.h"
52 #include "src/core/util/sync.h"
53 #include "src/core/util/time.h"
54 #include "src/core/util/uri.h"
55
56 #if GRPC_ARES == 1
57
58 #include <address_sorting/address_sorting.h>
59
60 #include "absl/strings/str_cat.h"
61 #include "src/core/config/config_vars.h"
62 #include "src/core/lib/channel/channel_args.h"
63 #include "src/core/lib/iomgr/resolve_address.h"
64 #include "src/core/lib/transport/error_utils.h"
65 #include "src/core/load_balancing/grpclb/grpclb_balancer_addresses.h"
66 #include "src/core/resolver/dns/c_ares/grpc_ares_wrapper.h"
67 #include "src/core/resolver/endpoint_addresses.h"
68 #include "src/core/resolver/polling_resolver.h"
69 #include "src/core/service_config/service_config_impl.h"
70 #include "src/core/util/backoff.h"
71
72 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
73 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
74 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
75 #define GRPC_DNS_RECONNECT_JITTER 0.2
76
77 namespace grpc_core {
78
79 namespace {
80
81 class AresClientChannelDNSResolver final : public PollingResolver {
82 public:
83 AresClientChannelDNSResolver(ResolverArgs args,
84 Duration min_time_between_resolutions);
85
86 OrphanablePtr<Orphanable> StartRequest() override;
87
88 private:
89 class AresRequestWrapper final
90 : public InternallyRefCounted<AresRequestWrapper> {
91 public:
AresRequestWrapper(RefCountedPtr<AresClientChannelDNSResolver> resolver)92 explicit AresRequestWrapper(
93 RefCountedPtr<AresClientChannelDNSResolver> resolver)
94 : resolver_(std::move(resolver)) {
95 // TODO(hork): replace this callback bookkeeping with promises.
96 // Locking to prevent completion before all records are queried
97 MutexLock lock(&on_resolved_mu_);
98 Ref(DEBUG_LOCATION, "OnHostnameResolved").release();
99 GRPC_CLOSURE_INIT(&on_hostname_resolved_, OnHostnameResolved, this,
100 nullptr);
101 hostname_request_.reset(grpc_dns_lookup_hostname_ares(
102 resolver_->authority().c_str(), resolver_->name_to_resolve().c_str(),
103 kDefaultSecurePort, resolver_->interested_parties(),
104 &on_hostname_resolved_, &addresses_, resolver_->query_timeout_ms_));
105 GRPC_TRACE_VLOG(cares_resolver, 2)
106 << "(c-ares resolver) resolver:" << resolver_.get()
107 << " Started resolving hostnames. hostname_request_:"
108 << hostname_request_.get();
109 if (resolver_->enable_srv_queries_) {
110 Ref(DEBUG_LOCATION, "OnSRVResolved").release();
111 GRPC_CLOSURE_INIT(&on_srv_resolved_, OnSRVResolved, this, nullptr);
112 srv_request_.reset(grpc_dns_lookup_srv_ares(
113 resolver_->authority().c_str(),
114 resolver_->name_to_resolve().c_str(),
115 resolver_->interested_parties(), &on_srv_resolved_,
116 &balancer_addresses_, resolver_->query_timeout_ms_));
117 GRPC_TRACE_VLOG(cares_resolver, 2)
118 << "(c-ares resolver) resolver:" << resolver_.get()
119 << " Started resolving SRV records. srv_request_:"
120 << srv_request_.get();
121 }
122 if (resolver_->request_service_config_) {
123 Ref(DEBUG_LOCATION, "OnTXTResolved").release();
124 GRPC_CLOSURE_INIT(&on_txt_resolved_, OnTXTResolved, this, nullptr);
125 txt_request_.reset(grpc_dns_lookup_txt_ares(
126 resolver_->authority().c_str(),
127 resolver_->name_to_resolve().c_str(),
128 resolver_->interested_parties(), &on_txt_resolved_,
129 &service_config_json_, resolver_->query_timeout_ms_));
130 GRPC_TRACE_VLOG(cares_resolver, 2)
131 << "(c-ares resolver) resolver:" << resolver_.get()
132 << " Started resolving TXT records. txt_request_:"
133 << txt_request_.get();
134 }
135 }
136
~AresRequestWrapper()137 ~AresRequestWrapper() override {
138 gpr_free(service_config_json_);
139 resolver_.reset(DEBUG_LOCATION, "dns-resolving");
140 }
141
142 // Note that thread safety cannot be analyzed due to this being invoked from
143 // OrphanablePtr<>, and there's no way to pass the lock annotation through
144 // there.
Orphan()145 void Orphan() override ABSL_NO_THREAD_SAFETY_ANALYSIS {
146 {
147 MutexLock lock(&on_resolved_mu_);
148 if (hostname_request_ != nullptr) {
149 grpc_cancel_ares_request(hostname_request_.get());
150 }
151 if (srv_request_ != nullptr) {
152 grpc_cancel_ares_request(srv_request_.get());
153 }
154 if (txt_request_ != nullptr) {
155 grpc_cancel_ares_request(txt_request_.get());
156 }
157 }
158 Unref(DEBUG_LOCATION, "Orphan");
159 }
160
161 private:
162 static void OnHostnameResolved(void* arg, grpc_error_handle error);
163 static void OnSRVResolved(void* arg, grpc_error_handle error);
164 static void OnTXTResolved(void* arg, grpc_error_handle error);
165 absl::optional<Result> OnResolvedLocked(grpc_error_handle error)
166 ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
167
168 Mutex on_resolved_mu_;
169 RefCountedPtr<AresClientChannelDNSResolver> resolver_;
170 grpc_closure on_hostname_resolved_;
171 std::unique_ptr<grpc_ares_request> hostname_request_
172 ABSL_GUARDED_BY(on_resolved_mu_);
173 grpc_closure on_srv_resolved_;
174 std::unique_ptr<grpc_ares_request> srv_request_
175 ABSL_GUARDED_BY(on_resolved_mu_);
176 grpc_closure on_txt_resolved_;
177 std::unique_ptr<grpc_ares_request> txt_request_
178 ABSL_GUARDED_BY(on_resolved_mu_);
179 // Output fields from ares request.
180 std::unique_ptr<EndpointAddressesList> addresses_
181 ABSL_GUARDED_BY(on_resolved_mu_);
182 std::unique_ptr<EndpointAddressesList> balancer_addresses_
183 ABSL_GUARDED_BY(on_resolved_mu_);
184 char* service_config_json_ ABSL_GUARDED_BY(on_resolved_mu_) = nullptr;
185 };
186
187 ~AresClientChannelDNSResolver() override;
188
189 /// whether to request the service config
190 const bool request_service_config_;
191 // whether or not to enable SRV DNS queries
192 const bool enable_srv_queries_;
193 // timeout in milliseconds for active DNS queries
194 const int query_timeout_ms_;
195 };
196
AresClientChannelDNSResolver(ResolverArgs args,Duration min_time_between_resolutions)197 AresClientChannelDNSResolver::AresClientChannelDNSResolver(
198 ResolverArgs args, Duration min_time_between_resolutions)
199 : PollingResolver(std::move(args), min_time_between_resolutions,
200 BackOff::Options()
201 .set_initial_backoff(Duration::Seconds(
202 GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS))
203 .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
204 .set_jitter(GRPC_DNS_RECONNECT_JITTER)
205 .set_max_backoff(Duration::Seconds(
206 GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS)),
207 &cares_resolver_trace),
208 request_service_config_(
209 !channel_args()
210 .GetBool(GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION)
211 .value_or(true)),
212 enable_srv_queries_(channel_args()
213 .GetBool(GRPC_ARG_DNS_ENABLE_SRV_QUERIES)
214 .value_or(false)),
215 query_timeout_ms_(
216 std::max(0, channel_args()
217 .GetInt(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS)
218 .value_or(GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS))) {}
219
~AresClientChannelDNSResolver()220 AresClientChannelDNSResolver::~AresClientChannelDNSResolver() {
221 GRPC_TRACE_VLOG(cares_resolver, 2)
222 << "(c-ares resolver) resolver:" << this
223 << " destroying AresClientChannelDNSResolver";
224 }
225
StartRequest()226 OrphanablePtr<Orphanable> AresClientChannelDNSResolver::StartRequest() {
227 return MakeOrphanable<AresRequestWrapper>(
228 RefAsSubclass<AresClientChannelDNSResolver>(DEBUG_LOCATION,
229 "dns-resolving"));
230 }
231
OnHostnameResolved(void * arg,grpc_error_handle error)232 void AresClientChannelDNSResolver::AresRequestWrapper::OnHostnameResolved(
233 void* arg, grpc_error_handle error) {
234 auto* self = static_cast<AresRequestWrapper*>(arg);
235 absl::optional<Result> result;
236 {
237 MutexLock lock(&self->on_resolved_mu_);
238 self->hostname_request_.reset();
239 result = self->OnResolvedLocked(error);
240 }
241 if (result.has_value()) {
242 self->resolver_->OnRequestComplete(std::move(*result));
243 }
244 self->Unref(DEBUG_LOCATION, "OnHostnameResolved");
245 }
246
OnSRVResolved(void * arg,grpc_error_handle error)247 void AresClientChannelDNSResolver::AresRequestWrapper::OnSRVResolved(
248 void* arg, grpc_error_handle error) {
249 auto* self = static_cast<AresRequestWrapper*>(arg);
250 absl::optional<Result> result;
251 {
252 MutexLock lock(&self->on_resolved_mu_);
253 self->srv_request_.reset();
254 result = self->OnResolvedLocked(error);
255 }
256 if (result.has_value()) {
257 self->resolver_->OnRequestComplete(std::move(*result));
258 }
259 self->Unref(DEBUG_LOCATION, "OnSRVResolved");
260 }
261
OnTXTResolved(void * arg,grpc_error_handle error)262 void AresClientChannelDNSResolver::AresRequestWrapper::OnTXTResolved(
263 void* arg, grpc_error_handle error) {
264 auto* self = static_cast<AresRequestWrapper*>(arg);
265 absl::optional<Result> result;
266 {
267 MutexLock lock(&self->on_resolved_mu_);
268 self->txt_request_.reset();
269 result = self->OnResolvedLocked(error);
270 }
271 if (result.has_value()) {
272 self->resolver_->OnRequestComplete(std::move(*result));
273 }
274 self->Unref(DEBUG_LOCATION, "OnTXTResolved");
275 }
276
277 // Returns a Result if resolution is complete.
278 // callers must release the lock and call OnRequestComplete if a Result is
279 // returned. This is because OnRequestComplete may Orphan the resolver, which
280 // requires taking the lock.
281 absl::optional<AresClientChannelDNSResolver::Result>
OnResolvedLocked(grpc_error_handle error)282 AresClientChannelDNSResolver::AresRequestWrapper::OnResolvedLocked(
283 grpc_error_handle error) ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_) {
284 if (hostname_request_ != nullptr || srv_request_ != nullptr ||
285 txt_request_ != nullptr) {
286 GRPC_TRACE_VLOG(cares_resolver, 2)
287 << "(c-ares resolver) resolver:" << this
288 << " OnResolved() waiting for results (hostname: "
289 << (hostname_request_ != nullptr ? "waiting" : "done")
290 << ", srv: " << (srv_request_ != nullptr ? "waiting" : "done")
291 << ", txt: " << (txt_request_ != nullptr ? "waiting" : "done") << ")";
292 return absl::nullopt;
293 }
294 GRPC_TRACE_VLOG(cares_resolver, 2)
295 << "(c-ares resolver) resolver:" << this << " OnResolved() proceeding";
296 Result result;
297 result.args = resolver_->channel_args();
298 // TODO(roth): Change logic to be able to report failures for addresses
299 // and service config independently of each other.
300 if (addresses_ != nullptr || balancer_addresses_ != nullptr) {
301 if (addresses_ != nullptr) {
302 result.addresses = std::move(*addresses_);
303 } else {
304 result.addresses.emplace();
305 }
306 if (service_config_json_ != nullptr) {
307 auto service_config_string = ChooseServiceConfig(service_config_json_);
308 if (!service_config_string.ok()) {
309 result.service_config = absl::UnavailableError(
310 absl::StrCat("failed to parse service config: ",
311 StatusToString(service_config_string.status())));
312 } else if (!service_config_string->empty()) {
313 GRPC_TRACE_VLOG(cares_resolver, 2)
314 << "(c-ares resolver) resolver:" << this
315 << " selected service config choice: " << *service_config_string;
316 result.service_config = ServiceConfigImpl::Create(
317 resolver_->channel_args(), *service_config_string);
318 if (!result.service_config.ok()) {
319 result.service_config = absl::UnavailableError(
320 absl::StrCat("failed to parse service config: ",
321 result.service_config.status().message()));
322 }
323 }
324 }
325 if (balancer_addresses_ != nullptr) {
326 result.args =
327 SetGrpcLbBalancerAddresses(result.args, *balancer_addresses_);
328 }
329 } else {
330 GRPC_TRACE_VLOG(cares_resolver, 2)
331 << "(c-ares resolver) resolver:" << this
332 << " dns resolution failed: " << StatusToString(error);
333 std::string error_message;
334 grpc_error_get_str(error, StatusStrProperty::kDescription, &error_message);
335 absl::Status status = absl::UnavailableError(
336 absl::StrCat("DNS resolution failed for ", resolver_->name_to_resolve(),
337 ": ", error_message));
338 result.addresses = status;
339 result.service_config = status;
340 }
341
342 return std::move(result);
343 }
344
345 //
346 // Factory
347 //
348
349 class AresClientChannelDNSResolverFactory final : public ResolverFactory {
350 public:
scheme() const351 absl::string_view scheme() const override { return "dns"; }
352
IsValidUri(const URI & uri) const353 bool IsValidUri(const URI& uri) const override {
354 if (absl::StripPrefix(uri.path(), "/").empty()) {
355 LOG(ERROR) << "no server name supplied in dns URI";
356 return false;
357 }
358 return true;
359 }
360
CreateResolver(ResolverArgs args) const361 OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
362 Duration min_time_between_resolutions = std::max(
363 Duration::Zero(), args.args
364 .GetDurationFromIntMillis(
365 GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS)
366 .value_or(Duration::Seconds(30)));
367 return MakeOrphanable<AresClientChannelDNSResolver>(
368 std::move(args), min_time_between_resolutions);
369 }
370 };
371
372 class AresDNSResolver final : public DNSResolver {
373 public:
374 // Abstract class that centralizes common request handling logic via the
375 // template method pattern.
376 // This requires a two-phase initialization, where 1) a request is created via
377 // a subclass constructor, and 2) the request is initiated via Run()
378 class AresRequest {
379 public:
~AresRequest()380 virtual ~AresRequest() {
381 GRPC_TRACE_VLOG(cares_resolver, 2)
382 << "(c-ares resolver) AresRequest:" << this
383 << " dtor ares_request_:" << grpc_ares_request_.get();
384 resolver_->UnregisterRequest(task_handle());
385 grpc_pollset_set_destroy(pollset_set_);
386 }
387
388 // Initiates the low-level c-ares request and returns its handle.
389 virtual std::unique_ptr<grpc_ares_request> MakeRequestLocked() = 0;
390 // Called on ares resolution, but not upon cancellation.
391 // After execution, the AresRequest will perform any final cleanup and
392 // delete itself.
393 virtual void OnComplete(grpc_error_handle error) = 0;
394
395 // Called to initiate the request.
Run()396 void Run() {
397 MutexLock lock(&mu_);
398 grpc_ares_request_ = MakeRequestLocked();
399 }
400
Cancel()401 bool Cancel() {
402 MutexLock lock(&mu_);
403 if (grpc_ares_request_ != nullptr) {
404 GRPC_TRACE_VLOG(cares_resolver, 2)
405 << "(c-ares resolver) AresRequest:" << this
406 << " Cancel ares_request_:" << grpc_ares_request_.get();
407 if (completed_) return false;
408 // OnDnsLookupDone will still be run
409 completed_ = true;
410 grpc_cancel_ares_request(grpc_ares_request_.get());
411 } else {
412 completed_ = true;
413 OnDnsLookupDone(this, absl::CancelledError());
414 }
415 grpc_pollset_set_del_pollset_set(pollset_set_, interested_parties_);
416 return true;
417 }
418
task_handle()419 TaskHandle task_handle() {
420 return {reinterpret_cast<intptr_t>(this), aba_token_};
421 }
422
423 protected:
AresRequest(absl::string_view name,absl::string_view name_server,Duration timeout,grpc_pollset_set * interested_parties,AresDNSResolver * resolver,intptr_t aba_token)424 AresRequest(absl::string_view name, absl::string_view name_server,
425 Duration timeout, grpc_pollset_set* interested_parties,
426 AresDNSResolver* resolver, intptr_t aba_token)
427 : name_(name),
428 name_server_(name_server),
429 timeout_(timeout),
430 interested_parties_(interested_parties),
431 completed_(false),
432 resolver_(resolver),
433 aba_token_(aba_token),
434 pollset_set_(grpc_pollset_set_create()) {
435 GRPC_CLOSURE_INIT(&on_dns_lookup_done_, OnDnsLookupDone, this,
436 grpc_schedule_on_exec_ctx);
437 grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties_);
438 }
439
pollset_set()440 grpc_pollset_set* pollset_set() { return pollset_set_; };
on_dns_lookup_done()441 grpc_closure* on_dns_lookup_done() { return &on_dns_lookup_done_; };
name()442 const std::string& name() { return name_; }
name_server()443 const std::string& name_server() { return name_server_; }
timeout()444 const Duration& timeout() { return timeout_; }
445
446 private:
447 // Called by ares when lookup has completed or when cancelled. It is always
448 // called exactly once, and it triggers self-deletion.
OnDnsLookupDone(void * arg,grpc_error_handle error)449 static void OnDnsLookupDone(void* arg, grpc_error_handle error) {
450 AresRequest* r = static_cast<AresRequest*>(arg);
451 auto deleter = std::unique_ptr<AresRequest>(r);
452 {
453 MutexLock lock(&r->mu_);
454 grpc_pollset_set_del_pollset_set(r->pollset_set_,
455 r->interested_parties_);
456 if (r->completed_) {
457 return;
458 }
459 r->completed_ = true;
460 }
461 r->OnComplete(error);
462 }
463
464 // the name to resolve
465 const std::string name_;
466 // the name server to query
467 const std::string name_server_;
468 // request-specific timeout
469 Duration timeout_;
470 // mutex to synchronize access to this object (but not to the ares_request
471 // object itself).
472 Mutex mu_;
473 // parties interested in our I/O
474 grpc_pollset_set* const interested_parties_;
475 // underlying cares_request that the query is performed on
476 std::unique_ptr<grpc_ares_request> grpc_ares_request_ ABSL_GUARDED_BY(mu_);
477 // Set when the callback is either cancelled or executed.
478 // It is not the subclasses' responsibility to set this flag.
479 bool completed_ ABSL_GUARDED_BY(mu_);
480 // Parent resolver that created this request
481 AresDNSResolver* resolver_;
482 // Unique token to help distinguish this request from others that may later
483 // be created in the same memory location.
484 intptr_t aba_token_;
485 // closure to call when the ares resolution request completes. Subclasses
486 // should use this as the ares callback in MakeRequestLocked()
487 grpc_closure on_dns_lookup_done_ ABSL_GUARDED_BY(mu_);
488 // locally owned pollset_set, required to support cancellation of requests
489 // while ares still needs a valid pollset_set. Subclasses should give this
490 // pollset to ares in MakeRequestLocked();
491 grpc_pollset_set* pollset_set_;
492 };
493
494 class AresHostnameRequest final : public AresRequest {
495 public:
AresHostnameRequest(absl::string_view name,absl::string_view default_port,absl::string_view name_server,Duration timeout,grpc_pollset_set * interested_parties,std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolve_address_done,AresDNSResolver * resolver,intptr_t aba_token)496 AresHostnameRequest(
497 absl::string_view name, absl::string_view default_port,
498 absl::string_view name_server, Duration timeout,
499 grpc_pollset_set* interested_parties,
500 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
501 on_resolve_address_done,
502 AresDNSResolver* resolver, intptr_t aba_token)
503 : AresRequest(name, name_server, timeout, interested_parties, resolver,
504 aba_token),
505 default_port_(default_port),
506 on_resolve_address_done_(std::move(on_resolve_address_done)) {
507 GRPC_TRACE_VLOG(cares_resolver, 2)
508 << "(c-ares resolver) AresHostnameRequest:" << this << " ctor";
509 }
510
MakeRequestLocked()511 std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
512 auto ares_request =
513 std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_hostname_ares(
514 name_server().c_str(), name().c_str(), default_port_.c_str(),
515 pollset_set(), on_dns_lookup_done(), &addresses_,
516 timeout().millis()));
517 GRPC_TRACE_VLOG(cares_resolver, 2)
518 << "(c-ares resolver) AresHostnameRequest:" << this
519 << " Start ares_request_:" << ares_request.get();
520 return ares_request;
521 }
522
OnComplete(grpc_error_handle error)523 void OnComplete(grpc_error_handle error) override {
524 GRPC_TRACE_VLOG(cares_resolver, 2)
525 << "(c-ares resolver) AresHostnameRequest:" << this << " OnComplete";
526 if (!error.ok()) {
527 on_resolve_address_done_(grpc_error_to_absl_status(error));
528 return;
529 }
530 std::vector<grpc_resolved_address> resolved_addresses;
531 if (addresses_ != nullptr) {
532 resolved_addresses.reserve(addresses_->size());
533 for (const auto& server_address : *addresses_) {
534 resolved_addresses.push_back(server_address.address());
535 }
536 }
537 on_resolve_address_done_(std::move(resolved_addresses));
538 }
539
540 // the default port to use if name doesn't have one
541 const std::string default_port_;
542 // user-provided completion callback
543 const std::function<void(
544 absl::StatusOr<std::vector<grpc_resolved_address>>)>
545 on_resolve_address_done_;
546 // currently resolving addresses
547 std::unique_ptr<EndpointAddressesList> addresses_;
548 };
549
550 class AresSRVRequest final : public AresRequest {
551 public:
AresSRVRequest(absl::string_view name,absl::string_view name_server,Duration timeout,grpc_pollset_set * interested_parties,std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolve_address_done,AresDNSResolver * resolver,intptr_t aba_token)552 AresSRVRequest(
553 absl::string_view name, absl::string_view name_server, Duration timeout,
554 grpc_pollset_set* interested_parties,
555 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
556 on_resolve_address_done,
557 AresDNSResolver* resolver, intptr_t aba_token)
558 : AresRequest(name, name_server, timeout, interested_parties, resolver,
559 aba_token),
560 on_resolve_address_done_(std::move(on_resolve_address_done)) {
561 GRPC_TRACE_VLOG(cares_resolver, 2)
562 << "(c-ares resolver) AresSRVRequest:" << this << " ctor";
563 }
564
MakeRequestLocked()565 std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
566 auto ares_request =
567 std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_srv_ares(
568 name_server().c_str(), name().c_str(), pollset_set(),
569 on_dns_lookup_done(), &balancer_addresses_, timeout().millis()));
570 GRPC_TRACE_VLOG(cares_resolver, 2)
571 << "(c-ares resolver) AresSRVRequest:" << this
572 << " Start ares_request_:" << ares_request.get();
573 return ares_request;
574 }
575
OnComplete(grpc_error_handle error)576 void OnComplete(grpc_error_handle error) override {
577 GRPC_TRACE_VLOG(cares_resolver, 2)
578 << "(c-ares resolver) AresSRVRequest:" << this << " OnComplete";
579 if (!error.ok()) {
580 on_resolve_address_done_(grpc_error_to_absl_status(error));
581 return;
582 }
583 std::vector<grpc_resolved_address> resolved_addresses;
584 if (balancer_addresses_ != nullptr) {
585 resolved_addresses.reserve(balancer_addresses_->size());
586 for (const auto& server_address : *balancer_addresses_) {
587 resolved_addresses.push_back(server_address.address());
588 }
589 }
590 on_resolve_address_done_(std::move(resolved_addresses));
591 }
592
593 // user-provided completion callback
594 const std::function<void(
595 absl::StatusOr<std::vector<grpc_resolved_address>>)>
596 on_resolve_address_done_;
597 // currently resolving addresses
598 std::unique_ptr<EndpointAddressesList> balancer_addresses_;
599 };
600
601 class AresTXTRequest final : public AresRequest {
602 public:
AresTXTRequest(absl::string_view name,absl::string_view name_server,Duration timeout,grpc_pollset_set * interested_parties,std::function<void (absl::StatusOr<std::string>)> on_resolved,AresDNSResolver * resolver,intptr_t aba_token)603 AresTXTRequest(absl::string_view name, absl::string_view name_server,
604 Duration timeout, grpc_pollset_set* interested_parties,
605 std::function<void(absl::StatusOr<std::string>)> on_resolved,
606 AresDNSResolver* resolver, intptr_t aba_token)
607 : AresRequest(name, name_server, timeout, interested_parties, resolver,
608 aba_token),
609 on_resolved_(std::move(on_resolved)) {
610 GRPC_TRACE_VLOG(cares_resolver, 2)
611 << "(c-ares resolver) AresTXTRequest:" << this << " ctor";
612 }
613
~AresTXTRequest()614 ~AresTXTRequest() override { gpr_free(service_config_json_); }
615
MakeRequestLocked()616 std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
617 auto ares_request =
618 std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_txt_ares(
619 name_server().c_str(), name().c_str(), pollset_set(),
620 on_dns_lookup_done(), &service_config_json_, timeout().millis()));
621 GRPC_TRACE_VLOG(cares_resolver, 2)
622 << "(c-ares resolver) AresSRVRequest:" << this
623 << " Start ares_request_:" << ares_request.get();
624 return ares_request;
625 }
626
OnComplete(grpc_error_handle error)627 void OnComplete(grpc_error_handle error) override {
628 GRPC_TRACE_VLOG(cares_resolver, 2)
629 << "(c-ares resolver) AresSRVRequest:" << this << " OnComplete";
630 if (!error.ok()) {
631 on_resolved_(grpc_error_to_absl_status(error));
632 return;
633 }
634 on_resolved_(service_config_json_);
635 }
636
637 // service config from the TXT record
638 char* service_config_json_ = nullptr;
639 // user-provided completion callback
640 const std::function<void(absl::StatusOr<std::string>)> on_resolved_;
641 };
642
LookupHostname(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view name,absl::string_view default_port,Duration timeout,grpc_pollset_set * interested_parties,absl::string_view name_server)643 TaskHandle LookupHostname(
644 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
645 on_resolved,
646 absl::string_view name, absl::string_view default_port, Duration timeout,
647 grpc_pollset_set* interested_parties,
648 absl::string_view name_server) override {
649 MutexLock lock(&mu_);
650 auto* request = new AresHostnameRequest(
651 name, default_port, name_server, timeout, interested_parties,
652 std::move(on_resolved), this, aba_token_++);
653 request->Run();
654 auto handle = request->task_handle();
655 open_requests_.insert(handle);
656 return handle;
657 }
658
LookupHostnameBlocking(absl::string_view name,absl::string_view default_port)659 absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
660 absl::string_view name, absl::string_view default_port) override {
661 // TODO(apolcyn): change this to wrap the async version of the c-ares
662 // API with a promise, and remove the reference to the previous resolver.
663 return default_resolver_->LookupHostnameBlocking(name, default_port);
664 }
665
LookupSRV(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view name,Duration timeout,grpc_pollset_set * interested_parties,absl::string_view name_server)666 TaskHandle LookupSRV(
667 std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
668 on_resolved,
669 absl::string_view name, Duration timeout,
670 grpc_pollset_set* interested_parties,
671 absl::string_view name_server) override {
672 MutexLock lock(&mu_);
673 auto* request =
674 new AresSRVRequest(name, name_server, timeout, interested_parties,
675 std::move(on_resolved), this, aba_token_++);
676 request->Run();
677 auto handle = request->task_handle();
678 open_requests_.insert(handle);
679 return handle;
680 };
681
LookupTXT(std::function<void (absl::StatusOr<std::string>)> on_resolved,absl::string_view name,Duration timeout,grpc_pollset_set * interested_parties,absl::string_view name_server)682 TaskHandle LookupTXT(
683 std::function<void(absl::StatusOr<std::string>)> on_resolved,
684 absl::string_view name, Duration timeout,
685 grpc_pollset_set* interested_parties,
686 absl::string_view name_server) override {
687 MutexLock lock(&mu_);
688 auto* request =
689 new AresTXTRequest(name, name_server, timeout, interested_parties,
690 std::move(on_resolved), this, aba_token_++);
691 request->Run();
692 auto handle = request->task_handle();
693 open_requests_.insert(handle);
694 return handle;
695 };
696
Cancel(TaskHandle handle)697 bool Cancel(TaskHandle handle) override {
698 MutexLock lock(&mu_);
699 if (!open_requests_.contains(handle)) {
700 // Unknown request, possibly completed already, or an invalid handle.
701 GRPC_TRACE_VLOG(cares_resolver, 2)
702 << "(c-ares resolver) AresDNSResolver:" << this
703 << " attempt to cancel unknown TaskHandle:" << HandleToString(handle);
704 return false;
705 }
706 auto* request = reinterpret_cast<AresRequest*>(handle.keys[0]);
707 GRPC_TRACE_VLOG(cares_resolver, 2)
708 << "(c-ares resolver) AresDNSResolver:" << this
709 << " cancel ares_request:" << request;
710 return request->Cancel();
711 }
712
713 private:
714 // Called exclusively from the AresRequest destructor.
UnregisterRequest(TaskHandle handle)715 void UnregisterRequest(TaskHandle handle) {
716 MutexLock lock(&mu_);
717 open_requests_.erase(handle);
718 }
719
720 // the previous default DNS resolver, used to delegate blocking DNS calls to
721 std::shared_ptr<DNSResolver> default_resolver_ = GetDNSResolver();
722 Mutex mu_;
723 TaskHandleSet open_requests_ ABSL_GUARDED_BY(mu_);
724 intptr_t aba_token_ ABSL_GUARDED_BY(mu_) = 0;
725 };
726
727 } // namespace
728
ShouldUseAresDnsResolver(absl::string_view resolver_env)729 bool ShouldUseAresDnsResolver(absl::string_view resolver_env) {
730 return resolver_env.empty() || absl::EqualsIgnoreCase(resolver_env, "ares");
731 }
732
RegisterAresDnsResolver(CoreConfiguration::Builder * builder)733 void RegisterAresDnsResolver(CoreConfiguration::Builder* builder) {
734 builder->resolver_registry()->RegisterResolverFactory(
735 std::make_unique<AresClientChannelDNSResolverFactory>());
736 }
737
738 } // namespace grpc_core
739
grpc_resolver_dns_ares_init()740 void grpc_resolver_dns_ares_init() {
741 if (grpc_core::ShouldUseAresDnsResolver(
742 grpc_core::ConfigVars::Get().DnsResolver())) {
743 address_sorting_init();
744 grpc_error_handle error = grpc_ares_init();
745 if (!error.ok()) {
746 GRPC_LOG_IF_ERROR("grpc_ares_init() failed", error);
747 return;
748 }
749 grpc_core::ResetDNSResolver(std::make_unique<grpc_core::AresDNSResolver>());
750 }
751 }
752
grpc_resolver_dns_ares_shutdown()753 void grpc_resolver_dns_ares_shutdown() {
754 if (grpc_core::ShouldUseAresDnsResolver(
755 grpc_core::ConfigVars::Get().DnsResolver())) {
756 address_sorting_shutdown();
757 grpc_ares_cleanup();
758 }
759 }
760
grpc_resolver_dns_ares_reset_dns_resolver()761 void grpc_resolver_dns_ares_reset_dns_resolver() {
762 if (grpc_core::ShouldUseAresDnsResolver(
763 grpc_core::ConfigVars::Get().DnsResolver())) {
764 grpc_core::ResetDNSResolver(std::make_unique<grpc_core::AresDNSResolver>());
765 }
766 }
767
768 #else // GRPC_ARES == 1
769
770 namespace grpc_core {
ShouldUseAresDnsResolver(absl::string_view)771 bool ShouldUseAresDnsResolver(absl::string_view /* resolver_env */) {
772 return false;
773 }
RegisterAresDnsResolver(CoreConfiguration::Builder *)774 void RegisterAresDnsResolver(CoreConfiguration::Builder*) {}
775 } // namespace grpc_core
776
grpc_resolver_dns_ares_init()777 void grpc_resolver_dns_ares_init() {}
778
grpc_resolver_dns_ares_shutdown()779 void grpc_resolver_dns_ares_shutdown() {}
780
grpc_resolver_dns_ares_reset_dns_resolver()781 void grpc_resolver_dns_ares_reset_dns_resolver() {}
782
783 #endif // GRPC_ARES == 1
784