• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The gRPC Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "src/core/resolver/dns/event_engine/event_engine_client_channel_resolver.h"
15 
16 #include <grpc/event_engine/event_engine.h>
17 #include <grpc/impl/channel_arg_names.h>
18 #include <grpc/support/port_platform.h>
19 #include <inttypes.h>
20 #include <stddef.h>
21 
22 #include <algorithm>
23 #include <chrono>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "absl/base/thread_annotations.h"
30 #include "absl/cleanup/cleanup.h"
31 #include "absl/log/check.h"
32 #include "absl/log/log.h"
33 #include "absl/status/status.h"
34 #include "absl/status/statusor.h"
35 #include "absl/strings/match.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/strip.h"
38 #include "absl/types/optional.h"
39 #include "src/core/lib/channel/channel_args.h"
40 #include "src/core/lib/debug/trace.h"
41 #include "src/core/lib/event_engine/resolved_address_internal.h"
42 #include "src/core/lib/iomgr/exec_ctx.h"
43 #include "src/core/lib/iomgr/resolve_address.h"
44 #include "src/core/load_balancing/grpclb/grpclb_balancer_addresses.h"
45 #include "src/core/resolver/dns/event_engine/service_config_helper.h"
46 #include "src/core/resolver/endpoint_addresses.h"
47 #include "src/core/resolver/polling_resolver.h"
48 #include "src/core/resolver/resolver.h"
49 #include "src/core/resolver/resolver_factory.h"
50 #include "src/core/service_config/service_config.h"
51 #include "src/core/service_config/service_config_impl.h"
52 #include "src/core/util/backoff.h"
53 #include "src/core/util/debug_location.h"
54 #include "src/core/util/ref_counted_ptr.h"
55 #include "src/core/util/sync.h"
56 #include "src/core/util/time.h"
57 #include "src/core/util/validation_errors.h"
58 
59 // IWYU pragma: no_include <ratio>
60 
61 namespace grpc_core {
62 namespace {
63 
64 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
65 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
66 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
67 #define GRPC_DNS_RECONNECT_JITTER 0.2
68 #define GRPC_DNS_DEFAULT_QUERY_TIMEOUT_MS 120000
69 
70 using grpc_event_engine::experimental::EventEngine;
71 
72 // TODO(hork): Investigate adding a resolver test scenario where the first
73 // balancer hostname lookup result is an error, and the second contains valid
74 // addresses.
75 // TODO(hork): Add a test that checks for proper authority from balancer
76 // addresses.
77 
78 // ----------------------------------------------------------------------------
79 // EventEngineClientChannelDNSResolver
80 // ----------------------------------------------------------------------------
81 class EventEngineClientChannelDNSResolver final : public PollingResolver {
82  public:
83   EventEngineClientChannelDNSResolver(ResolverArgs args,
84                                       Duration min_time_between_resolutions);
85   OrphanablePtr<Orphanable> StartRequest() override;
86 
87  private:
88   // ----------------------------------------------------------------------------
89   // EventEngineDNSRequestWrapper declaration
90   // ----------------------------------------------------------------------------
91   class EventEngineDNSRequestWrapper final
92       : public InternallyRefCounted<EventEngineDNSRequestWrapper> {
93    public:
94     EventEngineDNSRequestWrapper(
95         RefCountedPtr<EventEngineClientChannelDNSResolver> resolver,
96         std::unique_ptr<EventEngine::DNSResolver> event_engine_resolver);
97     ~EventEngineDNSRequestWrapper() override;
98 
99     // Note that thread safety cannot be analyzed due to this being invoked from
100     // OrphanablePtr<>, and there's no way to pass the lock annotation through
101     // there.
102     void Orphan() override ABSL_NO_THREAD_SAFETY_ANALYSIS;
103 
104    private:
105     void OnTimeout() ABSL_LOCKS_EXCLUDED(on_resolved_mu_);
106     void OnHostnameResolved(
107         absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> addresses);
108     void OnSRVResolved(
109         absl::StatusOr<std::vector<EventEngine::DNSResolver::SRVRecord>>
110             srv_records);
111     void OnBalancerHostnamesResolved(
112         std::string authority,
113         absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> addresses);
114     void OnTXTResolved(absl::StatusOr<std::vector<std::string>> service_config);
115     // Returns a Result if resolution is complete.
116     // callers must release the lock and call OnRequestComplete if a Result is
117     // returned. This is because OnRequestComplete may Orphan the resolver,
118     // which requires taking the lock.
119     absl::optional<Resolver::Result> OnResolvedLocked()
120         ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
121     // Helper method to populate server addresses on resolver result.
122     void MaybePopulateAddressesLocked(Resolver::Result* result)
123         ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
124     // Helper method to populate balancer addresses on resolver result.
125     void MaybePopulateBalancerAddressesLocked(Resolver::Result* result)
126         ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
127     // Helper method to populate service config on resolver result.
128     void MaybePopulateServiceConfigLocked(Resolver::Result* result)
129         ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
130 
131     RefCountedPtr<EventEngineClientChannelDNSResolver> resolver_;
132     Mutex on_resolved_mu_;
133     // Lookup callbacks
134     bool is_hostname_inflight_ ABSL_GUARDED_BY(on_resolved_mu_) = false;
135     bool is_srv_inflight_ ABSL_GUARDED_BY(on_resolved_mu_) = false;
136     bool is_txt_inflight_ ABSL_GUARDED_BY(on_resolved_mu_) = false;
137     // Output fields from requests.
138     EndpointAddressesList addresses_ ABSL_GUARDED_BY(on_resolved_mu_);
139     EndpointAddressesList balancer_addresses_ ABSL_GUARDED_BY(on_resolved_mu_);
140     ValidationErrors errors_ ABSL_GUARDED_BY(on_resolved_mu_);
141     absl::StatusOr<std::string> service_config_json_
142         ABSL_GUARDED_BY(on_resolved_mu_);
143     // Other internal state
144     size_t number_of_balancer_hostnames_initiated_
145         ABSL_GUARDED_BY(on_resolved_mu_) = 0;
146     size_t number_of_balancer_hostnames_resolved_
147         ABSL_GUARDED_BY(on_resolved_mu_) = 0;
148     bool orphaned_ ABSL_GUARDED_BY(on_resolved_mu_) = false;
149     absl::optional<EventEngine::TaskHandle> timeout_handle_
150         ABSL_GUARDED_BY(on_resolved_mu_);
151     std::unique_ptr<EventEngine::DNSResolver> event_engine_resolver_;
152   };
153 
154   /// whether to request the service config
155   const bool request_service_config_;
156   // whether or not to enable SRV DNS queries
157   const bool enable_srv_queries_;
158   // timeout in milliseconds for active DNS queries
159   EventEngine::Duration query_timeout_ms_;
160   std::shared_ptr<EventEngine> event_engine_;
161 };
162 
EventEngineClientChannelDNSResolver(ResolverArgs args,Duration min_time_between_resolutions)163 EventEngineClientChannelDNSResolver::EventEngineClientChannelDNSResolver(
164     ResolverArgs args, Duration min_time_between_resolutions)
165     : PollingResolver(std::move(args), min_time_between_resolutions,
166                       BackOff::Options()
167                           .set_initial_backoff(Duration::Milliseconds(
168                               GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000))
169                           .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
170                           .set_jitter(GRPC_DNS_RECONNECT_JITTER)
171                           .set_max_backoff(Duration::Milliseconds(
172                               GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)),
173                       &event_engine_client_channel_resolver_trace),
174       request_service_config_(
175           !channel_args()
176                .GetBool(GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION)
177                .value_or(true)),
178       enable_srv_queries_(channel_args()
179                               .GetBool(GRPC_ARG_DNS_ENABLE_SRV_QUERIES)
180                               .value_or(false)),
181       // TODO(yijiem): decide if the ares channel arg timeout should be reused.
182       query_timeout_ms_(std::chrono::milliseconds(
183           std::max(0, channel_args()
184                           .GetInt(GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS)
185                           .value_or(GRPC_DNS_DEFAULT_QUERY_TIMEOUT_MS)))),
186       event_engine_(channel_args().GetObjectRef<EventEngine>()) {}
187 
StartRequest()188 OrphanablePtr<Orphanable> EventEngineClientChannelDNSResolver::StartRequest() {
189   auto dns_resolver =
190       event_engine_->GetDNSResolver({/*dns_server=*/authority()});
191   if (!dns_resolver.ok()) {
192     Result result;
193     result.addresses = dns_resolver.status();
194     result.service_config = dns_resolver.status();
195     OnRequestComplete(std::move(result));
196     return nullptr;
197   }
198   return MakeOrphanable<EventEngineDNSRequestWrapper>(
199       RefAsSubclass<EventEngineClientChannelDNSResolver>(DEBUG_LOCATION,
200                                                          "dns-resolving"),
201       std::move(*dns_resolver));
202 }
203 
204 // ----------------------------------------------------------------------------
205 // EventEngineDNSRequestWrapper definition
206 // ----------------------------------------------------------------------------
207 
208 EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
EventEngineDNSRequestWrapper(RefCountedPtr<EventEngineClientChannelDNSResolver> resolver,std::unique_ptr<EventEngine::DNSResolver> event_engine_resolver)209     EventEngineDNSRequestWrapper(
210         RefCountedPtr<EventEngineClientChannelDNSResolver> resolver,
211         std::unique_ptr<EventEngine::DNSResolver> event_engine_resolver)
212     : resolver_(std::move(resolver)),
213       event_engine_resolver_(std::move(event_engine_resolver)) {
214   // Locking to prevent completion before all records are queried
215   MutexLock lock(&on_resolved_mu_);
216   GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
217       << "(event_engine client channel resolver) DNSResolver::"
218       << resolver_.get() << " Starting hostname resolution for "
219       << resolver_->name_to_resolve();
220   is_hostname_inflight_ = true;
221   event_engine_resolver_->LookupHostname(
222       [self = Ref(DEBUG_LOCATION, "OnHostnameResolved")](
223           absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
224               addresses) mutable {
225         ApplicationCallbackExecCtx callback_exec_ctx;
226         ExecCtx exec_ctx;
227         self->OnHostnameResolved(std::move(addresses));
228         self.reset();
229       },
230       resolver_->name_to_resolve(), kDefaultSecurePort);
231   if (resolver_->enable_srv_queries_) {
232     GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
233         << "(event_engine client channel resolver) DNSResolver::"
234         << resolver_.get() << " Starting SRV record resolution for "
235         << resolver_->name_to_resolve();
236     is_srv_inflight_ = true;
237     event_engine_resolver_->LookupSRV(
238         [self = Ref(DEBUG_LOCATION, "OnSRVResolved")](
239             absl::StatusOr<std::vector<EventEngine::DNSResolver::SRVRecord>>
240                 srv_records) mutable {
241           ApplicationCallbackExecCtx callback_exec_ctx;
242           ExecCtx exec_ctx;
243           self->OnSRVResolved(std::move(srv_records));
244           self.reset();
245         },
246         absl::StrCat("_grpclb._tcp.", resolver_->name_to_resolve()));
247   }
248   if (resolver_->request_service_config_) {
249     GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
250         << "(event_engine client channel resolver) DNSResolver::"
251         << resolver_.get() << " Starting TXT record resolution for "
252         << resolver_->name_to_resolve();
253     is_txt_inflight_ = true;
254     event_engine_resolver_->LookupTXT(
255         [self = Ref(DEBUG_LOCATION, "OnTXTResolved")](
256             absl::StatusOr<std::vector<std::string>> service_config) mutable {
257           ApplicationCallbackExecCtx callback_exec_ctx;
258           ExecCtx exec_ctx;
259           self->OnTXTResolved(std::move(service_config));
260           self.reset();
261         },
262         absl::StrCat("_grpc_config.", resolver_->name_to_resolve()));
263   }
264   // Initialize overall DNS resolution timeout alarm.
265   auto timeout = resolver_->query_timeout_ms_.count() == 0
266                      ? EventEngine::Duration::max()
267                      : resolver_->query_timeout_ms_;
268   timeout_handle_ = resolver_->event_engine_->RunAfter(
269       timeout, [self = Ref(DEBUG_LOCATION, "OnTimeout")]() mutable {
270         ApplicationCallbackExecCtx callback_exec_ctx;
271         ExecCtx exec_ctx;
272         self->OnTimeout();
273         self.reset();
274       });
275 }
276 
277 EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
~EventEngineDNSRequestWrapper()278     ~EventEngineDNSRequestWrapper() {
279   resolver_.reset(DEBUG_LOCATION, "dns-resolving");
280 }
281 
282 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
Orphan()283     Orphan() {
284   {
285     MutexLock lock(&on_resolved_mu_);
286     orphaned_ = true;
287     if (timeout_handle_.has_value()) {
288       resolver_->event_engine_->Cancel(*timeout_handle_);
289       timeout_handle_.reset();
290     }
291     // Even if cancellation fails here, OnResolvedLocked will return early, and
292     // the resolver will never see a completed request.
293     event_engine_resolver_.reset();
294   }
295   Unref(DEBUG_LOCATION, "Orphan");
296 }
297 
298 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
OnTimeout()299     OnTimeout() {
300   MutexLock lock(&on_resolved_mu_);
301   GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
302       << "(event_engine client channel resolver) DNSResolver::"
303       << resolver_.get() << " OnTimeout";
304   timeout_handle_.reset();
305   event_engine_resolver_.reset();
306 }
307 
308 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
OnHostnameResolved(absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> new_addresses)309     OnHostnameResolved(absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
310                            new_addresses) {
311   absl::optional<Resolver::Result> result;
312   {
313     MutexLock lock(&on_resolved_mu_);
314     // Make sure field destroys before cleanup.
315     ValidationErrors::ScopedField field(&errors_, "hostname lookup");
316     if (orphaned_) return;
317     is_hostname_inflight_ = false;
318     if (!new_addresses.ok()) {
319       errors_.AddError(new_addresses.status().message());
320     } else {
321       addresses_.reserve(addresses_.size() + new_addresses->size());
322       for (const auto& addr : *new_addresses) {
323         addresses_.emplace_back(CreateGRPCResolvedAddress(addr), ChannelArgs());
324       }
325     }
326     result = OnResolvedLocked();
327   }
328   if (result.has_value()) {
329     resolver_->OnRequestComplete(std::move(*result));
330   }
331 }
332 
333 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
OnSRVResolved(absl::StatusOr<std::vector<EventEngine::DNSResolver::SRVRecord>> srv_records)334     OnSRVResolved(
335         absl::StatusOr<std::vector<EventEngine::DNSResolver::SRVRecord>>
336             srv_records) {
337   absl::optional<Resolver::Result> result;
338   auto cleanup = absl::MakeCleanup([&]() {
339     if (result.has_value()) {
340       resolver_->OnRequestComplete(std::move(*result));
341     }
342   });
343   MutexLock lock(&on_resolved_mu_);
344   // Make sure field destroys before cleanup.
345   ValidationErrors::ScopedField field(&errors_, "srv lookup");
346   if (orphaned_) return;
347   is_srv_inflight_ = false;
348   if (!srv_records.ok()) {
349     // An error has occurred, finish resolving.
350     errors_.AddError(srv_records.status().message());
351     result = OnResolvedLocked();
352     return;
353   }
354   if (srv_records->empty()) {
355     result = OnResolvedLocked();
356     return;
357   }
358   if (!timeout_handle_.has_value()) {
359     // We could reach here if timeout happened while an SRV query was finishing.
360     errors_.AddError(
361         "timed out - not initiating subsequent balancer hostname requests");
362     result = OnResolvedLocked();
363     return;
364   }
365   // Do a subsequent hostname query since SRV records were returned
366   for (auto& srv_record : *srv_records) {
367     GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
368         << "(event_engine client channel resolver) DNSResolver::"
369         << resolver_.get() << " Starting balancer hostname resolution for "
370         << srv_record.host << ":" << srv_record.port;
371     ++number_of_balancer_hostnames_initiated_;
372     event_engine_resolver_->LookupHostname(
373         [host = srv_record.host,
374          self = Ref(DEBUG_LOCATION, "OnBalancerHostnamesResolved")](
375             absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
376                 new_balancer_addresses) mutable {
377           ApplicationCallbackExecCtx callback_exec_ctx;
378           ExecCtx exec_ctx;
379           self->OnBalancerHostnamesResolved(std::move(host),
380                                             std::move(new_balancer_addresses));
381           self.reset();
382         },
383         srv_record.host, std::to_string(srv_record.port));
384   }
385 }
386 
387 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
OnBalancerHostnamesResolved(std::string authority,absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> new_balancer_addresses)388     OnBalancerHostnamesResolved(
389         std::string authority,
390         absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
391             new_balancer_addresses) {
392   absl::optional<Resolver::Result> result;
393   auto cleanup = absl::MakeCleanup([&]() {
394     if (result.has_value()) {
395       resolver_->OnRequestComplete(std::move(*result));
396     }
397   });
398   MutexLock lock(&on_resolved_mu_);
399   // Make sure field destroys before cleanup.
400   ValidationErrors::ScopedField field(
401       &errors_, absl::StrCat("balancer lookup for ", authority));
402   if (orphaned_) return;
403   ++number_of_balancer_hostnames_resolved_;
404   if (!new_balancer_addresses.ok()) {
405     // An error has occurred, finish resolving.
406     errors_.AddError(new_balancer_addresses.status().message());
407   } else {
408     // Capture the addresses and finish resolving.
409     balancer_addresses_.reserve(balancer_addresses_.size() +
410                                 new_balancer_addresses->size());
411     auto srv_channel_args =
412         ChannelArgs().Set(GRPC_ARG_DEFAULT_AUTHORITY, authority);
413     for (const auto& addr : *new_balancer_addresses) {
414       balancer_addresses_.emplace_back(CreateGRPCResolvedAddress(addr),
415                                        srv_channel_args);
416     }
417   }
418   result = OnResolvedLocked();
419 }
420 
421 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
OnTXTResolved(absl::StatusOr<std::vector<std::string>> service_config)422     OnTXTResolved(absl::StatusOr<std::vector<std::string>> service_config) {
423   absl::optional<Resolver::Result> result;
424   {
425     MutexLock lock(&on_resolved_mu_);
426     // Make sure field destroys before cleanup.
427     ValidationErrors::ScopedField field(&errors_, "txt lookup");
428     if (orphaned_) return;
429     CHECK(is_txt_inflight_);
430     is_txt_inflight_ = false;
431     if (!service_config.ok()) {
432       errors_.AddError(service_config.status().message());
433       service_config_json_ = service_config.status();
434     } else {
435       static constexpr absl::string_view kServiceConfigAttributePrefix =
436           "grpc_config=";
437       auto result = std::find_if(service_config->begin(), service_config->end(),
438                                  [&](absl::string_view s) {
439                                    return absl::StartsWith(
440                                        s, kServiceConfigAttributePrefix);
441                                  });
442       if (result != service_config->end()) {
443         // Found a service config record.
444         service_config_json_ =
445             result->substr(kServiceConfigAttributePrefix.size());
446         GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
447             << "(event_engine client channel resolver) DNSResolver::"
448             << event_engine_resolver_.get()
449             << " found service config: " << service_config_json_->c_str();
450       } else {
451         service_config_json_ = absl::UnavailableError(absl::StrCat(
452             "failed to find attribute prefix: ", kServiceConfigAttributePrefix,
453             " in TXT records"));
454         errors_.AddError(service_config_json_.status().message());
455       }
456     }
457     result = OnResolvedLocked();
458   }
459   if (result.has_value()) {
460     resolver_->OnRequestComplete(std::move(*result));
461   }
462 }
463 
464 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
MaybePopulateAddressesLocked(Resolver::Result * result)465     MaybePopulateAddressesLocked(Resolver::Result* result) {
466   if (addresses_.empty()) return;
467   result->addresses = std::move(addresses_);
468 }
469 
470 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
MaybePopulateBalancerAddressesLocked(Resolver::Result * result)471     MaybePopulateBalancerAddressesLocked(Resolver::Result* result) {
472   if (!balancer_addresses_.empty()) {
473     result->args =
474         SetGrpcLbBalancerAddresses(result->args, balancer_addresses_);
475   }
476 }
477 
478 void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper::
MaybePopulateServiceConfigLocked(Resolver::Result * result)479     MaybePopulateServiceConfigLocked(Resolver::Result* result) {
480   // This function is called only if we are returning addresses.  In that case,
481   // we currently ignore TXT lookup failures.
482   // TODO(roth): Consider differentiating between NXDOMAIN and other failures,
483   // so that we can return an error in the non-NXDOMAIN case.
484   if (!service_config_json_.ok()) return;
485   // TXT lookup succeeded, so parse the config.
486   auto service_config = ChooseServiceConfig(*service_config_json_);
487   if (!service_config.ok()) {
488     result->service_config = absl::UnavailableError(absl::StrCat(
489         "failed to parse service config: ", service_config.status().message()));
490     return;
491   }
492   if (service_config->empty()) return;
493   GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
494       << "(event_engine client channel resolver) DNSResolver::"
495       << event_engine_resolver_.get()
496       << " selected service config choice: " << service_config->c_str();
497   result->service_config =
498       ServiceConfigImpl::Create(resolver_->channel_args(), *service_config);
499   if (!result->service_config.ok()) {
500     result->service_config = absl::UnavailableError(
501         absl::StrCat("failed to parse service config: ",
502                      result->service_config.status().message()));
503   }
504 }
505 
506 absl::optional<Resolver::Result> EventEngineClientChannelDNSResolver::
OnResolvedLocked()507     EventEngineDNSRequestWrapper::OnResolvedLocked() {
508   if (orphaned_) return absl::nullopt;
509   // Wait for all requested queries to return.
510   if (is_hostname_inflight_ || is_srv_inflight_ || is_txt_inflight_ ||
511       number_of_balancer_hostnames_resolved_ !=
512           number_of_balancer_hostnames_initiated_) {
513     GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
514         << "(event_engine client channel resolver) DNSResolver::" << this
515         << " OnResolved() waiting for results (hostname: "
516         << (is_hostname_inflight_ ? "waiting" : "done")
517         << ", srv: " << (is_srv_inflight_ ? "waiting" : "done")
518         << ", txt: " << (is_txt_inflight_ ? "waiting" : "done")
519         << ", balancer addresses: " << number_of_balancer_hostnames_resolved_
520         << "/" << number_of_balancer_hostnames_initiated_ << " complete";
521     return absl::nullopt;
522   }
523   GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
524       << "(event_engine client channel resolver) DNSResolver::" << this
525       << " OnResolvedLocked() proceeding";
526   Resolver::Result result;
527   result.args = resolver_->channel_args();
528   // If both addresses and balancer addresses failed, return an error for both
529   // addresses and service config.
530   if (addresses_.empty() && balancer_addresses_.empty()) {
531     absl::Status status = errors_.status(
532         absl::StatusCode::kUnavailable,
533         absl::StrCat("errors resolving ", resolver_->name_to_resolve()));
534     if (status.ok()) {
535       // If no errors were returned, but the results are empty, we still need to
536       // return an error. Validation errors may be empty.
537       status = absl::UnavailableError("No results from DNS queries");
538     }
539     GRPC_TRACE_VLOG(event_engine_client_channel_resolver, 2)
540         << "(event_engine client channel resolver) " << status.message().data();
541     result.addresses = status;
542     result.service_config = status;
543     return std::move(result);
544   }
545   if (!errors_.ok()) {
546     result.resolution_note = errors_.message(
547         absl::StrCat("errors resolving ", resolver_->name_to_resolve()));
548   }
549   // We have at least one of addresses or balancer addresses, so we're going to
550   // return a non-error for addresses.
551   result.addresses.emplace();
552   MaybePopulateAddressesLocked(&result);
553   MaybePopulateServiceConfigLocked(&result);
554   MaybePopulateBalancerAddressesLocked(&result);
555   return std::move(result);
556 }
557 
558 }  // namespace
559 
IsValidUri(const URI & uri) const560 bool EventEngineClientChannelDNSResolverFactory::IsValidUri(
561     const URI& uri) const {
562   if (absl::StripPrefix(uri.path(), "/").empty()) {
563     LOG(ERROR) << "no server name supplied in dns URI";
564     return false;
565   }
566   return true;
567 }
568 
569 OrphanablePtr<Resolver>
CreateResolver(ResolverArgs args) const570 EventEngineClientChannelDNSResolverFactory::CreateResolver(
571     ResolverArgs args) const {
572   Duration min_time_between_resolutions = std::max(
573       Duration::Zero(), args.args
574                             .GetDurationFromIntMillis(
575                                 GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS)
576                             .value_or(Duration::Seconds(30)));
577   return MakeOrphanable<EventEngineClientChannelDNSResolver>(
578       std::move(args), min_time_between_resolutions);
579 }
580 
581 }  // namespace grpc_core
582