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