Re-Reland: Add SRV and TXT record lookup methods to the iomgr API (#30246)

* Revert "Revert "Reland: Add SRV and TXT record lookup methods to the iomgr PAI (#30242)"

This reverts commit b5966f39eb.

* release lock before unreffing
pull/30255/head
AJ Heller 3 years ago committed by GitHub
parent d7e6878ec4
commit 64939531f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 503
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  2. 255
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  3. 27
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
  4. 7
      src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
  5. 3
      src/core/ext/transport/chttp2/server/chttp2_server.cc
  6. 7
      src/core/lib/http/httpcli.cc
  7. 58
      src/core/lib/iomgr/event_engine/resolver.h
  8. 35
      src/core/lib/iomgr/resolve_address.h
  9. 46
      src/core/lib/iomgr/resolve_address_posix.cc
  10. 24
      src/core/lib/iomgr/resolve_address_posix.h
  11. 48
      src/core/lib/iomgr/resolve_address_windows.cc
  12. 24
      src/core/lib/iomgr/resolve_address_windows.h
  13. 62
      test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
  14. 4
      test/core/end2end/dualstack_socket_test.cc
  15. 4
      test/core/end2end/fixtures/http_proxy_fixture.cc
  16. 45
      test/core/end2end/fuzzers/api_fuzzer.cc
  17. 66
      test/core/end2end/goaway_server_test.cc
  18. 8
      test/core/iomgr/resolve_address_posix_test.cc
  19. 123
      test/core/iomgr/resolve_address_test.cc
  20. 2
      test/core/surface/server_test.cc
  21. 2
      test/core/transport/chttp2/settings_timeout_test.cc
  22. 2
      test/core/util/resolve_localhost_ip46.cc

@ -108,17 +108,43 @@ class AresClientChannelDNSResolver : public PollingResolver {
explicit AresRequestWrapper( explicit AresRequestWrapper(
RefCountedPtr<AresClientChannelDNSResolver> resolver) RefCountedPtr<AresClientChannelDNSResolver> resolver)
: resolver_(std::move(resolver)) { : resolver_(std::move(resolver)) {
Ref(DEBUG_LOCATION, "OnResolved").release(); // TODO(hork): replace this callback bookkeeping with promises.
GRPC_CLOSURE_INIT(&on_resolved_, OnResolved, this, nullptr); // Locking to prevent completion before all records are queried
request_.reset(grpc_dns_lookup_ares( MutexLock lock(&on_resolved_mu_);
Ref(DEBUG_LOCATION, "OnHostnameResolved").release();
GRPC_CLOSURE_INIT(&on_hostname_resolved_, OnHostnameResolved, this,
nullptr);
hostname_request_.reset(grpc_dns_lookup_hostname_ares(
resolver_->authority().c_str(), resolver_->name_to_resolve().c_str(), resolver_->authority().c_str(), resolver_->name_to_resolve().c_str(),
kDefaultSecurePort, resolver_->interested_parties(), &on_resolved_, kDefaultSecurePort, resolver_->interested_parties(),
&addresses_, &on_hostname_resolved_, &addresses_, resolver_->query_timeout_ms_));
resolver_->enable_srv_queries_ ? &balancer_addresses_ : nullptr, GRPC_CARES_TRACE_LOG(
resolver_->request_service_config_ ? &service_config_json_ : nullptr, "resolver:%p Started resolving hostnames. hostname_request_:%p",
resolver_->query_timeout_ms_)); resolver_.get(), hostname_request_.get());
GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. request_:%p", if (resolver_->enable_srv_queries_) {
resolver_.get(), request_.get()); Ref(DEBUG_LOCATION, "OnSRVResolved").release();
GRPC_CLOSURE_INIT(&on_srv_resolved_, OnSRVResolved, this, nullptr);
srv_request_.reset(grpc_dns_lookup_srv_ares(
resolver_->authority().c_str(),
resolver_->name_to_resolve().c_str(),
resolver_->interested_parties(), &on_srv_resolved_,
&balancer_addresses_, resolver_->query_timeout_ms_));
GRPC_CARES_TRACE_LOG(
"resolver:%p Started resolving SRV records. srv_request_:%p",
resolver_.get(), srv_request_.get());
}
if (resolver_->request_service_config_) {
Ref(DEBUG_LOCATION, "OnTXTResolved").release();
GRPC_CLOSURE_INIT(&on_txt_resolved_, OnTXTResolved, this, nullptr);
txt_request_.reset(grpc_dns_lookup_txt_ares(
resolver_->authority().c_str(),
resolver_->name_to_resolve().c_str(),
resolver_->interested_parties(), &on_txt_resolved_,
&service_config_json_, resolver_->query_timeout_ms_));
GRPC_CARES_TRACE_LOG(
"resolver:%p Started resolving TXT records. txt_request_:%p",
resolver_.get(), srv_request_.get());
}
} }
~AresRequestWrapper() override { ~AresRequestWrapper() override {
@ -126,22 +152,49 @@ class AresClientChannelDNSResolver : public PollingResolver {
resolver_.reset(DEBUG_LOCATION, "dns-resolving"); resolver_.reset(DEBUG_LOCATION, "dns-resolving");
} }
void Orphan() override { // Note that thread safety cannot be analyzed due to this being invoked from
grpc_cancel_ares_request(request_.get()); // OrphanablePtr<>, and there's no way to pass the lock annotation through
// there.
void Orphan() override ABSL_NO_THREAD_SAFETY_ANALYSIS {
{
MutexLock lock(&on_resolved_mu_);
if (hostname_request_ != nullptr) {
grpc_cancel_ares_request(hostname_request_.get());
}
if (srv_request_ != nullptr) {
grpc_cancel_ares_request(srv_request_.get());
}
if (txt_request_ != nullptr) {
grpc_cancel_ares_request(txt_request_.get());
}
}
Unref(DEBUG_LOCATION, "Orphan"); Unref(DEBUG_LOCATION, "Orphan");
} }
private: private:
static void OnResolved(void* arg, grpc_error_handle error); static void OnHostnameResolved(void* arg, grpc_error_handle error);
void OnResolved(grpc_error_handle error); static void OnSRVResolved(void* arg, grpc_error_handle error);
static void OnTXTResolved(void* arg, grpc_error_handle error);
absl::optional<Result> OnResolvedLocked(grpc_error_handle error)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_);
Mutex on_resolved_mu_;
RefCountedPtr<AresClientChannelDNSResolver> resolver_; RefCountedPtr<AresClientChannelDNSResolver> resolver_;
std::unique_ptr<grpc_ares_request> request_; grpc_closure on_hostname_resolved_;
grpc_closure on_resolved_; std::unique_ptr<grpc_ares_request> hostname_request_
ABSL_GUARDED_BY(on_resolved_mu_);
grpc_closure on_srv_resolved_;
std::unique_ptr<grpc_ares_request> srv_request_
ABSL_GUARDED_BY(on_resolved_mu_);
grpc_closure on_txt_resolved_;
std::unique_ptr<grpc_ares_request> txt_request_
ABSL_GUARDED_BY(on_resolved_mu_);
// Output fields from ares request. // Output fields from ares request.
std::unique_ptr<ServerAddressList> addresses_; std::unique_ptr<ServerAddressList> addresses_
std::unique_ptr<ServerAddressList> balancer_addresses_; ABSL_GUARDED_BY(on_resolved_mu_);
char* service_config_json_ = nullptr; std::unique_ptr<ServerAddressList> balancer_addresses_
ABSL_GUARDED_BY(on_resolved_mu_);
char* service_config_json_ ABSL_GUARDED_BY(on_resolved_mu_) = nullptr;
}; };
~AresClientChannelDNSResolver() override; ~AresClientChannelDNSResolver() override;
@ -278,15 +331,69 @@ std::string ChooseServiceConfig(char* service_config_choice_json,
return service_config->Dump(); return service_config->Dump();
} }
void AresClientChannelDNSResolver::AresRequestWrapper::OnResolved( void AresClientChannelDNSResolver::AresRequestWrapper::OnHostnameResolved(
void* arg, grpc_error_handle error) {
auto* self = static_cast<AresRequestWrapper*>(arg);
absl::optional<Result> result;
{
MutexLock lock(&self->on_resolved_mu_);
self->hostname_request_.reset();
result = self->OnResolvedLocked(error);
}
if (result.has_value()) {
self->resolver_->OnRequestComplete(std::move(*result));
}
self->Unref(DEBUG_LOCATION, "OnHostnameResolved");
}
void AresClientChannelDNSResolver::AresRequestWrapper::OnSRVResolved(
void* arg, grpc_error_handle error) {
auto* self = static_cast<AresRequestWrapper*>(arg);
absl::optional<Result> result;
{
MutexLock lock(&self->on_resolved_mu_);
self->srv_request_.reset();
result = self->OnResolvedLocked(error);
}
if (result.has_value()) {
self->resolver_->OnRequestComplete(std::move(*result));
}
self->Unref(DEBUG_LOCATION, "OnSRVResolved");
}
void AresClientChannelDNSResolver::AresRequestWrapper::OnTXTResolved(
void* arg, grpc_error_handle error) { void* arg, grpc_error_handle error) {
auto* self = static_cast<AresRequestWrapper*>(arg); auto* self = static_cast<AresRequestWrapper*>(arg);
self->OnResolved(error); absl::optional<Result> result;
{
MutexLock lock(&self->on_resolved_mu_);
self->txt_request_.reset();
result = self->OnResolvedLocked(error);
}
if (result.has_value()) {
self->resolver_->OnRequestComplete(std::move(*result));
}
self->Unref(DEBUG_LOCATION, "OnTXTResolved");
} }
void AresClientChannelDNSResolver::AresRequestWrapper::OnResolved( // Returns a Result if resolution is complete.
grpc_error_handle error) { // callers must release the lock and call OnRequestComplete if a Result is
GRPC_CARES_TRACE_LOG("resolver:%p OnResolved()", this); // returned. This is because OnRequestComplete may Orphan the resolver, which
// requires taking the lock.
absl::optional<AresClientChannelDNSResolver::Result>
AresClientChannelDNSResolver::AresRequestWrapper::OnResolvedLocked(
grpc_error_handle error) ABSL_EXCLUSIVE_LOCKS_REQUIRED(on_resolved_mu_) {
if (hostname_request_ != nullptr || srv_request_ != nullptr ||
txt_request_ != nullptr) {
GRPC_CARES_TRACE_LOG(
"resolver:%p OnResolved() waiting for results (hostname: %s, srv: %s, "
"txt: %s)",
this, hostname_request_ != nullptr ? "waiting" : "done",
srv_request_ != nullptr ? "waiting" : "done",
txt_request_ != nullptr ? "waiting" : "done");
return absl::nullopt;
}
GRPC_CARES_TRACE_LOG("resolver:%p OnResolved() proceeding", this);
Result result; Result result;
result.args = resolver_->channel_args(); result.args = resolver_->channel_args();
// TODO(roth): Change logic to be able to report failures for addresses // TODO(roth): Change logic to be able to report failures for addresses
@ -334,8 +441,8 @@ void AresClientChannelDNSResolver::AresRequestWrapper::OnResolved(
result.addresses = status; result.addresses = status;
result.service_config = status; result.service_config = status;
} }
resolver_->OnRequestComplete(std::move(result));
Unref(DEBUG_LOCATION, "OnResolved"); return std::move(result);
} }
// //
@ -363,51 +470,45 @@ class AresClientChannelDNSResolverFactory : public ResolverFactory {
class AresDNSResolver : public DNSResolver { class AresDNSResolver : public DNSResolver {
public: public:
// Abstract class that centralizes common request handling logic via the
// template method pattern.
// This requires a two-phase initialization, where 1) a request is created via
// a subclass constructor, and 2) the request is initiated via Run()
class AresRequest { class AresRequest {
public: public:
AresRequest( virtual ~AresRequest() {
absl::string_view name, absl::string_view default_port,
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)
: name_(std::string(name)),
default_port_(std::string(default_port)),
interested_parties_(interested_parties),
pollset_set_(grpc_pollset_set_create()),
on_resolve_address_done_(std::move(on_resolve_address_done)),
completed_(false),
resolver_(resolver),
aba_token_(aba_token) {
GRPC_CARES_TRACE_LOG("AresRequest:%p ctor", this);
GRPC_CLOSURE_INIT(&on_dns_lookup_done_, OnDnsLookupDone, this,
grpc_schedule_on_exec_ctx);
MutexLock lock(&mu_);
grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties);
ares_request_ = std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_ares(
/*dns_server=*/"", name_.c_str(), default_port_.c_str(), pollset_set_,
&on_dns_lookup_done_, &addresses_,
/*balancer_addresses=*/nullptr, /*service_config_json=*/nullptr,
GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS));
GRPC_CARES_TRACE_LOG("AresRequest:%p Start ares_request_:%p", this,
ares_request_.get());
}
~AresRequest() {
GRPC_CARES_TRACE_LOG("AresRequest:%p dtor ares_request_:%p", this, GRPC_CARES_TRACE_LOG("AresRequest:%p dtor ares_request_:%p", this,
ares_request_.get()); grpc_ares_request_.get());
resolver_->UnregisterRequest(task_handle()); resolver_->UnregisterRequest(task_handle());
grpc_pollset_set_destroy(pollset_set_); grpc_pollset_set_destroy(pollset_set_);
} }
// Initiates the low-level c-ares request and returns its handle.
virtual std::unique_ptr<grpc_ares_request> MakeRequestLocked() = 0;
// Called on ares resolution, but not upon cancellation.
// After execution, the AresRequest will perform any final cleanup and
// delete itself.
virtual void OnComplete(grpc_error_handle error) = 0;
// Called to initiate the request.
void Run() {
MutexLock lock(&mu_);
grpc_ares_request_ = MakeRequestLocked();
}
bool Cancel() { bool Cancel() {
MutexLock lock(&mu_); MutexLock lock(&mu_);
GRPC_CARES_TRACE_LOG("AresRequest:%p Cancel ares_request_:%p", this, if (grpc_ares_request_ != nullptr) {
ares_request_.get()); GRPC_CARES_TRACE_LOG("AresRequest:%p Cancel ares_request_:%p", this,
if (completed_) return false; grpc_ares_request_.get());
// OnDnsLookupDone will still be run if (completed_) return false;
grpc_cancel_ares_request(ares_request_.get()); // OnDnsLookupDone will still be run
completed_ = true; completed_ = true;
grpc_cancel_ares_request(grpc_ares_request_.get());
} else {
completed_ = true;
OnDnsLookupDone(this, GRPC_ERROR_CANCELLED);
}
grpc_pollset_set_del_pollset_set(pollset_set_, interested_parties_); grpc_pollset_set_del_pollset_set(pollset_set_, interested_parties_);
return true; return true;
} }
@ -416,65 +517,215 @@ class AresDNSResolver : public DNSResolver {
return {reinterpret_cast<intptr_t>(this), aba_token_}; return {reinterpret_cast<intptr_t>(this), aba_token_};
} }
protected:
AresRequest(absl::string_view name, absl::string_view name_server,
Duration timeout, grpc_pollset_set* interested_parties,
AresDNSResolver* resolver, intptr_t aba_token)
: name_(name),
name_server_(name_server),
timeout_(timeout),
interested_parties_(interested_parties),
completed_(false),
resolver_(resolver),
aba_token_(aba_token),
pollset_set_(grpc_pollset_set_create()) {
GRPC_CLOSURE_INIT(&on_dns_lookup_done_, OnDnsLookupDone, this,
grpc_schedule_on_exec_ctx);
grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties_);
}
grpc_pollset_set* pollset_set() { return pollset_set_; };
grpc_closure* on_dns_lookup_done() { return &on_dns_lookup_done_; };
const std::string& name() { return name_; }
const std::string& name_server() { return name_server_; }
const Duration& timeout() { return timeout_; }
private: private:
// Called by ares when lookup has completed or when cancelled. It is always // Called by ares when lookup has completed or when cancelled. It is always
// called exactly once. // called exactly once, and it triggers self-deletion.
static void OnDnsLookupDone(void* arg, grpc_error_handle error) { static void OnDnsLookupDone(void* arg, grpc_error_handle error) {
AresRequest* request = static_cast<AresRequest*>(arg); AresRequest* r = static_cast<AresRequest*>(arg);
GRPC_CARES_TRACE_LOG("AresRequest:%p OnDnsLookupDone", request); auto deleter = std::unique_ptr<AresRequest>(r);
// This request is deleted and unregistered upon any exit.
std::unique_ptr<AresRequest> deleter(request);
std::vector<grpc_resolved_address> resolved_addresses;
{ {
MutexLock lock(&request->mu_); MutexLock lock(&r->mu_);
if (request->completed_) return; grpc_pollset_set_del_pollset_set(r->pollset_set_,
request->completed_ = true; r->interested_parties_);
if (request->addresses_ != nullptr) { if (r->completed_) {
resolved_addresses.reserve(request->addresses_->size()); return;
for (const auto& server_address : *request->addresses_) {
resolved_addresses.push_back(server_address.address());
}
} }
r->completed_ = true;
} }
grpc_pollset_set_del_pollset_set(request->pollset_set_, r->OnComplete(error);
request->interested_parties_);
if (!GRPC_ERROR_IS_NONE(error)) {
request->on_resolve_address_done_(grpc_error_to_absl_status(error));
return;
}
request->on_resolve_address_done_(std::move(resolved_addresses));
} }
// the name to resolve
const std::string name_;
// the name server to query
const std::string name_server_;
// request-specific timeout
Duration timeout_;
// mutex to synchronize access to this object (but not to the ares_request // mutex to synchronize access to this object (but not to the ares_request
// object itself). // object itself).
Mutex mu_; Mutex mu_;
// the name to resolve
const std::string name_;
// the default port to use if name doesn't have one
const std::string default_port_;
// parties interested in our I/O // parties interested in our I/O
grpc_pollset_set* const interested_parties_; grpc_pollset_set* const interested_parties_;
// underlying cares_request that the query is performed on
std::unique_ptr<grpc_ares_request> grpc_ares_request_ ABSL_GUARDED_BY(mu_);
// Set when the callback is either cancelled or executed.
// It is not the subclasses' responsibility to set this flag.
bool completed_ ABSL_GUARDED_BY(mu_);
// Parent resolver that created this request
AresDNSResolver* resolver_;
// Unique token to help distinguish this request from others that may later
// be created in the same memory location.
intptr_t aba_token_;
// closure to call when the ares resolution request completes. Subclasses
// should use this as the ares callback in MakeRequestLocked()
grpc_closure on_dns_lookup_done_ ABSL_GUARDED_BY(mu_);
// locally owned pollset_set, required to support cancellation of requests // locally owned pollset_set, required to support cancellation of requests
// while ares still needs a valid pollset_set. // while ares still needs a valid pollset_set. Subclasses should give this
// pollset to ares in MakeRequestLocked();
grpc_pollset_set* pollset_set_; grpc_pollset_set* pollset_set_;
};
class AresHostnameRequest : public AresRequest {
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)
: AresRequest(name, name_server, timeout, interested_parties, resolver,
aba_token),
default_port_(default_port),
on_resolve_address_done_(std::move(on_resolve_address_done)) {
GRPC_CARES_TRACE_LOG("AresHostnameRequest:%p ctor", this);
}
std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
auto ares_request =
std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_hostname_ares(
name_server().c_str(), name().c_str(), default_port_.c_str(),
pollset_set(), on_dns_lookup_done(), &addresses_,
timeout().millis()));
GRPC_CARES_TRACE_LOG("AresHostnameRequest:%p Start ares_request_:%p",
this, ares_request.get());
return ares_request;
}
void OnComplete(grpc_error_handle error) override {
GRPC_CARES_TRACE_LOG("AresHostnameRequest:%p OnComplete", this);
if (!GRPC_ERROR_IS_NONE(error)) {
on_resolve_address_done_(grpc_error_to_absl_status(error));
return;
}
std::vector<grpc_resolved_address> resolved_addresses;
if (addresses_ != nullptr) {
resolved_addresses.reserve(addresses_->size());
for (const auto& server_address : *addresses_) {
resolved_addresses.push_back(server_address.address());
}
}
on_resolve_address_done_(std::move(resolved_addresses));
}
// the default port to use if name doesn't have one
const std::string default_port_;
// user-provided completion callback // user-provided completion callback
const std::function<void( const std::function<void(
absl::StatusOr<std::vector<grpc_resolved_address>>)> absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolve_address_done_; on_resolve_address_done_;
// currently resolving addresses // currently resolving addresses
std::unique_ptr<ServerAddressList> addresses_ ABSL_GUARDED_BY(mu_); std::unique_ptr<ServerAddressList> addresses_;
// closure to call when the resolve_address_ares request completes };
// a closure wrapping on_resolve_address_done, which should be invoked
// when the grpc_dns_lookup_ares operation is done. class AresSRVRequest : public AresRequest {
grpc_closure on_dns_lookup_done_ ABSL_GUARDED_BY(mu_); public:
// underlying ares_request that the query is performed on AresSRVRequest(
std::unique_ptr<grpc_ares_request> ares_request_ ABSL_GUARDED_BY(mu_); absl::string_view name, absl::string_view name_server, Duration timeout,
bool completed_ ABSL_GUARDED_BY(mu_); grpc_pollset_set* interested_parties,
// Parent resolver that created this request std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
AresDNSResolver* resolver_; on_resolve_address_done,
// Unique token to help distinguish this request from others that may later AresDNSResolver* resolver, intptr_t aba_token)
// be created in the same memory location. : AresRequest(name, name_server, timeout, interested_parties, resolver,
intptr_t aba_token_; aba_token),
on_resolve_address_done_(std::move(on_resolve_address_done)) {
GRPC_CARES_TRACE_LOG("AresSRVRequest:%p ctor", this);
}
std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
auto ares_request =
std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_srv_ares(
name_server().c_str(), name().c_str(), pollset_set(),
on_dns_lookup_done(), &balancer_addresses_, timeout().millis()));
GRPC_CARES_TRACE_LOG("AresSRVRequest:%p Start ares_request_:%p", this,
ares_request.get());
return ares_request;
}
void OnComplete(grpc_error_handle error) override {
GRPC_CARES_TRACE_LOG("AresSRVRequest:%p OnComplete", this);
if (!GRPC_ERROR_IS_NONE(error)) {
on_resolve_address_done_(grpc_error_to_absl_status(error));
return;
}
std::vector<grpc_resolved_address> resolved_addresses;
if (balancer_addresses_ != nullptr) {
resolved_addresses.reserve(balancer_addresses_->size());
for (const auto& server_address : *balancer_addresses_) {
resolved_addresses.push_back(server_address.address());
}
}
on_resolve_address_done_(std::move(resolved_addresses));
}
// user-provided completion callback
const std::function<void(
absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolve_address_done_;
// currently resolving addresses
std::unique_ptr<ServerAddressList> balancer_addresses_;
};
class AresTXTRequest : public AresRequest {
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)
: AresRequest(name, name_server, timeout, interested_parties, resolver,
aba_token),
on_resolved_(std::move(on_resolved)) {
GRPC_CARES_TRACE_LOG("AresTXTRequest:%p ctor", this);
}
~AresTXTRequest() override { gpr_free(service_config_json_); }
std::unique_ptr<grpc_ares_request> MakeRequestLocked() override {
auto ares_request =
std::unique_ptr<grpc_ares_request>(grpc_dns_lookup_txt_ares(
name_server().c_str(), name().c_str(), pollset_set(),
on_dns_lookup_done(), &service_config_json_, timeout().millis()));
GRPC_CARES_TRACE_LOG("AresSRVRequest:%p Start ares_request_:%p", this,
ares_request.get());
return ares_request;
}
void OnComplete(grpc_error_handle error) override {
GRPC_CARES_TRACE_LOG("AresSRVRequest:%p OnComplete", this);
if (!GRPC_ERROR_IS_NONE(error)) {
on_resolved_(grpc_error_to_absl_status(error));
return;
}
on_resolved_(service_config_json_);
}
// service config from the TXT record
char* service_config_json_ = nullptr;
// user-provided completion callback
const std::function<void(absl::StatusOr<std::string>)> on_resolved_;
}; };
// gets the singleton instance, possibly creating it first // gets the singleton instance, possibly creating it first
@ -483,26 +734,60 @@ class AresDNSResolver : public DNSResolver {
return instance; return instance;
} }
TaskHandle ResolveName( TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* interested_parties,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override { on_resolved,
absl::string_view name, absl::string_view default_port, Duration timeout,
grpc_pollset_set* interested_parties,
absl::string_view name_server) override {
MutexLock lock(&mu_); MutexLock lock(&mu_);
auto* request = new AresRequest(name, default_port, interested_parties, auto* request = new AresHostnameRequest(
std::move(on_done), this, aba_token_++); name, default_port, name_server, timeout, interested_parties,
std::move(on_resolved), this, aba_token_++);
request->Run();
auto handle = request->task_handle(); auto handle = request->task_handle();
open_requests_.insert(handle); open_requests_.insert(handle);
return handle; return handle;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view name, absl::string_view default_port) override { absl::string_view name, absl::string_view default_port) override {
// TODO(apolcyn): change this to wrap the async version of the c-ares // TODO(apolcyn): change this to wrap the async version of the c-ares
// API with a promise, and remove the reference to the previous resolver. // API with a promise, and remove the reference to the previous resolver.
return default_resolver_->ResolveNameBlocking(name, default_port); return default_resolver_->LookupHostnameBlocking(name, default_port);
} }
TaskHandle 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) override {
MutexLock lock(&mu_);
auto* request =
new AresSRVRequest(name, name_server, timeout, interested_parties,
std::move(on_resolved), this, aba_token_++);
request->Run();
auto handle = request->task_handle();
open_requests_.insert(handle);
return handle;
};
TaskHandle 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) override {
MutexLock lock(&mu_);
auto* request =
new AresTXTRequest(name, name_server, timeout, interested_parties,
std::move(on_resolved), this, aba_token_++);
request->Run();
auto handle = request->task_handle();
open_requests_.insert(handle);
return handle;
};
bool Cancel(TaskHandle handle) override { bool Cancel(TaskHandle handle) override {
MutexLock lock(&mu_); MutexLock lock(&mu_);
if (!open_requests_.contains(handle)) { if (!open_requests_.contains(handle)) {

@ -21,6 +21,8 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include "absl/strings/string_view.h"
#include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr.h"
// IWYU pragma: no_include <arpa/nameser.h> // IWYU pragma: no_include <arpa/nameser.h>
@ -597,12 +599,10 @@ static void grpc_ares_request_unref_locked(grpc_ares_request* r)
void grpc_ares_complete_request_locked(grpc_ares_request* r) void grpc_ares_complete_request_locked(grpc_ares_request* r)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(r->mu) { ABSL_EXCLUSIVE_LOCKS_REQUIRED(r->mu) {
/* Invoke on_done callback and destroy the // Invoke on_done callback and destroy the request
request */
r->ev_driver = nullptr; r->ev_driver = nullptr;
ServerAddressList* addresses = r->addresses_out->get(); if (r->addresses_out != nullptr && *r->addresses_out != nullptr) {
if (addresses != nullptr) { grpc_cares_wrapper_address_sorting_sort(r, r->addresses_out->get());
grpc_cares_wrapper_address_sorting_sort(r, addresses);
GRPC_ERROR_UNREF(r->error); GRPC_ERROR_UNREF(r->error);
r->error = GRPC_ERROR_NONE; r->error = GRPC_ERROR_NONE;
// TODO(apolcyn): allow c-ares to return a service config // TODO(apolcyn): allow c-ares to return a service config
@ -812,6 +812,7 @@ static void on_txt_done_locked(void* arg, int status, int /*timeouts*/,
} }
// Clean up. // Clean up.
ares_free_data(reply); ares_free_data(reply);
grpc_ares_request_unref_locked(r);
return; return;
fail: fail:
std::string error_msg = std::string error_msg =
@ -823,38 +824,14 @@ fail:
r->error = grpc_error_add_child(error, r->error); r->error = grpc_error_add_child(error, r->error);
} }
void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( grpc_error_handle set_request_dns_server(grpc_ares_request* r,
grpc_ares_request* r, const char* dns_server, const char* name, absl::string_view dns_server)
const char* default_port, grpc_pollset_set* interested_parties, ABSL_EXCLUSIVE_LOCKS_REQUIRED(r->mu) {
int query_timeout_ms) ABSL_EXCLUSIVE_LOCKS_REQUIRED(r->mu) { if (!dns_server.empty()) {
grpc_error_handle error = GRPC_ERROR_NONE; GRPC_CARES_TRACE_LOG("request:%p Using DNS server %s", r,
grpc_ares_hostbyname_request* hr = nullptr; dns_server.data());
/* parse name, splitting it into host and port parts */
std::string host;
std::string port;
grpc_core::SplitHostPort(name, &host, &port);
if (host.empty()) {
error = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"),
GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto error_cleanup;
} else if (port.empty()) {
if (default_port == nullptr || strlen(default_port) == 0) {
error = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"),
GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto error_cleanup;
}
port = default_port;
}
error = grpc_ares_ev_driver_create_locked(&r->ev_driver, interested_parties,
query_timeout_ms, r);
if (!GRPC_ERROR_IS_NONE(error)) goto error_cleanup;
// If dns_server is specified, use it.
if (dns_server != nullptr && dns_server[0] != '\0') {
GRPC_CARES_TRACE_LOG("request:%p Using DNS server %s", r, dns_server);
grpc_resolved_address addr; grpc_resolved_address addr;
if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) { if (grpc_parse_ipv4_hostport(dns_server, &addr, /*log_errors=*/false)) {
r->dns_server_addr.family = AF_INET; r->dns_server_addr.family = AF_INET;
struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(addr.addr); struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(addr.addr);
memcpy(&r->dns_server_addr.addr.addr4, &in->sin_addr, memcpy(&r->dns_server_addr.addr.addr4, &in->sin_addr,
@ -862,7 +839,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr); r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr); r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr);
} else if (grpc_parse_ipv6_hostport(dns_server, &addr, } else if (grpc_parse_ipv6_hostport(dns_server, &addr,
false /* log_errors */)) { /*log_errors=*/false)) {
r->dns_server_addr.family = AF_INET6; r->dns_server_addr.family = AF_INET6;
struct sockaddr_in6* in6 = struct sockaddr_in6* in6 =
reinterpret_cast<struct sockaddr_in6*>(addr.addr); reinterpret_cast<struct sockaddr_in6*>(addr.addr);
@ -871,51 +848,49 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr); r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr); r->dns_server_addr.udp_port = grpc_sockaddr_get_port(&addr);
} else { } else {
error = grpc_error_set_str( return GRPC_ERROR_CREATE_FROM_CPP_STRING(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("cannot parse authority"), absl::StrCat("cannot parse authority ", dns_server));
GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto error_cleanup;
} }
int status = int status =
ares_set_servers_ports(r->ev_driver->channel, &r->dns_server_addr); ares_set_servers_ports(r->ev_driver->channel, &r->dns_server_addr);
if (status != ARES_SUCCESS) { if (status != ARES_SUCCESS) {
error = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"C-ares status is not ARES_SUCCESS: ", ares_strerror(status))); "C-ares status is not ARES_SUCCESS: ", ares_strerror(status)));
goto error_cleanup;
} }
} }
r->pending_queries = 1; return GRPC_ERROR_NONE;
if (grpc_ares_query_ipv6()) { }
hr = create_hostbyname_request_locked(r, host.c_str(),
grpc_strhtons(port.c_str()),
/*is_balancer=*/false, "AAAA");
ares_gethostbyname(r->ev_driver->channel, hr->host, AF_INET6,
on_hostbyname_done_locked, hr);
}
hr = create_hostbyname_request_locked(r, host.c_str(),
grpc_strhtons(port.c_str()),
/*is_balancer=*/false, "A");
ares_gethostbyname(r->ev_driver->channel, hr->host, AF_INET,
on_hostbyname_done_locked, hr);
if (r->balancer_addresses_out != nullptr) {
/* Query the SRV record */
std::string service_name = absl::StrCat("_grpclb._tcp.", host);
GrpcAresQuery* srv_query = new GrpcAresQuery(r, service_name);
ares_query(r->ev_driver->channel, service_name.c_str(), ns_c_in, ns_t_srv,
on_srv_query_done_locked, srv_query);
}
if (r->service_config_json_out != nullptr) {
std::string config_name = absl::StrCat("_grpc_config.", host);
GrpcAresQuery* txt_query = new GrpcAresQuery(r, config_name);
ares_search(r->ev_driver->channel, config_name.c_str(), ns_c_in, ns_t_txt,
on_txt_done_locked, txt_query);
}
grpc_ares_ev_driver_start_locked(r->ev_driver);
grpc_ares_request_unref_locked(r);
return;
error_cleanup: // Common logic for all lookup methods.
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error); // If an error occurs, callers must run the client callback.
grpc_error_handle grpc_dns_lookup_ares_continued(
grpc_ares_request* r, const char* dns_server, const char* name,
const char* default_port, grpc_pollset_set* interested_parties,
int query_timeout_ms, std::string* host, std::string* port, bool check_port)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(r->mu) {
grpc_error_handle error = GRPC_ERROR_NONE;
/* parse name, splitting it into host and port parts */
grpc_core::SplitHostPort(name, host, port);
if (host->empty()) {
error = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"),
GRPC_ERROR_STR_TARGET_ADDRESS, name);
return error;
} else if (check_port && port->empty()) {
if (default_port == nullptr || strlen(default_port) == 0) {
error = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"),
GRPC_ERROR_STR_TARGET_ADDRESS, name);
return error;
}
*port = default_port;
}
error = grpc_ares_ev_driver_create_locked(&r->ev_driver, interested_parties,
query_timeout_ms, r);
if (!GRPC_ERROR_IS_NONE(error)) return error;
// If dns_server is specified, use it.
error = set_request_dns_server(r, dns_server);
return error;
} }
static bool inner_resolve_as_ip_literal_locked( static bool inner_resolve_as_ip_literal_locked(
@ -1047,21 +1022,18 @@ static bool grpc_ares_maybe_resolve_localhost_manually_locked(
} }
#endif /* GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY */ #endif /* GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY */
static grpc_ares_request* grpc_dns_lookup_ares_impl( static grpc_ares_request* grpc_dns_lookup_hostname_ares_impl(
const char* dns_server, const char* name, const char* default_port, const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addrs, std::unique_ptr<grpc_core::ServerAddressList>* addrs,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addrs, int query_timeout_ms) {
char** service_config_json, int query_timeout_ms) {
grpc_ares_request* r = new grpc_ares_request(); grpc_ares_request* r = new grpc_ares_request();
grpc_core::MutexLock lock(&r->mu); grpc_core::MutexLock lock(&r->mu);
r->ev_driver = nullptr; r->ev_driver = nullptr;
r->on_done = on_done; r->on_done = on_done;
r->addresses_out = addrs; r->addresses_out = addrs;
r->balancer_addresses_out = balancer_addrs;
r->service_config_json_out = service_config_json;
GRPC_CARES_TRACE_LOG( GRPC_CARES_TRACE_LOG(
"request:%p c-ares grpc_dns_lookup_ares_impl name=%s, " "request:%p c-ares grpc_dns_lookup_hostname_ares_impl name=%s, "
"default_port=%s", "default_port=%s",
r, name, default_port); r, name, default_port);
// Early out if the target is an ipv4 or ipv6 literal. // Early out if the target is an ipv4 or ipv6 literal.
@ -1075,26 +1047,129 @@ static grpc_ares_request* grpc_dns_lookup_ares_impl(
grpc_ares_complete_request_locked(r); grpc_ares_complete_request_locked(r);
return r; return r;
} }
// Don't query for SRV and TXT records if the target is "localhost", so // Look up name using c-ares lib.
// as to cut down on lookups over the network, especially in tests: std::string host;
// https://github.com/grpc/proposal/pull/79 std::string port;
grpc_error_handle error = grpc_dns_lookup_ares_continued(
r, dns_server, name, default_port, interested_parties, query_timeout_ms,
&host, &port, true);
if (!GRPC_ERROR_IS_NONE(error)) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
return r;
}
r->pending_queries = 1;
grpc_ares_hostbyname_request* hr = nullptr;
if (grpc_ares_query_ipv6()) {
hr = create_hostbyname_request_locked(r, host.c_str(),
grpc_strhtons(port.c_str()),
/*is_balancer=*/false, "AAAA");
ares_gethostbyname(r->ev_driver->channel, hr->host, AF_INET6,
on_hostbyname_done_locked, hr);
}
hr = create_hostbyname_request_locked(r, host.c_str(),
grpc_strhtons(port.c_str()),
/*is_balancer=*/false, "A");
ares_gethostbyname(r->ev_driver->channel, hr->host, AF_INET,
on_hostbyname_done_locked, hr);
grpc_ares_ev_driver_start_locked(r->ev_driver);
grpc_ares_request_unref_locked(r);
return r;
}
grpc_ares_request* grpc_dns_lookup_srv_ares_impl(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses,
int query_timeout_ms) {
grpc_ares_request* r = new grpc_ares_request();
grpc_core::MutexLock lock(&r->mu);
r->ev_driver = nullptr;
r->on_done = on_done;
r->balancer_addresses_out = balancer_addresses;
GRPC_CARES_TRACE_LOG(
"request:%p c-ares grpc_dns_lookup_srv_ares_impl name=%s", r, name);
grpc_error_handle error = GRPC_ERROR_NONE;
// Don't query for SRV records if the target is "localhost"
if (target_matches_localhost(name)) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
return r;
}
// Look up name using c-ares lib.
std::string host;
std::string port;
error = grpc_dns_lookup_ares_continued(r, dns_server, name, nullptr,
interested_parties, query_timeout_ms,
&host, &port, false);
if (!GRPC_ERROR_IS_NONE(error)) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
return r;
}
r->pending_queries = 1;
/* Query the SRV record */
std::string service_name = absl::StrCat("_grpclb._tcp.", host);
GrpcAresQuery* srv_query = new GrpcAresQuery(r, service_name);
ares_query(r->ev_driver->channel, service_name.c_str(), ns_c_in, ns_t_srv,
on_srv_query_done_locked, srv_query);
grpc_ares_ev_driver_start_locked(r->ev_driver);
grpc_ares_request_unref_locked(r);
return r;
}
grpc_ares_request* grpc_dns_lookup_txt_ares_impl(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
char** service_config_json, int query_timeout_ms) {
grpc_ares_request* r = new grpc_ares_request();
grpc_core::MutexLock lock(&r->mu);
r->ev_driver = nullptr;
r->on_done = on_done;
r->service_config_json_out = service_config_json;
GRPC_CARES_TRACE_LOG(
"request:%p c-ares grpc_dns_lookup_txt_ares_impl name=%s", r, name);
grpc_error_handle error = GRPC_ERROR_NONE;
// Don't query for TXT records if the target is "localhost"
if (target_matches_localhost(name)) { if (target_matches_localhost(name)) {
r->balancer_addresses_out = nullptr; grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
r->service_config_json_out = nullptr; return r;
} }
// Look up name using c-ares lib. // Look up name using c-ares lib.
grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked( std::string host;
r, dns_server, name, default_port, interested_parties, query_timeout_ms); std::string port;
error = grpc_dns_lookup_ares_continued(r, dns_server, name, nullptr,
interested_parties, query_timeout_ms,
&host, &port, false);
if (!GRPC_ERROR_IS_NONE(error)) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
return r;
}
r->pending_queries = 1;
/* Query the TXT record */
std::string config_name = absl::StrCat("_grpc_config.", host);
GrpcAresQuery* txt_query = new GrpcAresQuery(r, config_name);
ares_search(r->ev_driver->channel, config_name.c_str(), ns_c_in, ns_t_txt,
on_txt_done_locked, txt_query);
grpc_ares_ev_driver_start_locked(r->ev_driver);
grpc_ares_request_unref_locked(r);
return r; return r;
} }
grpc_ares_request* (*grpc_dns_lookup_ares)( grpc_ares_request* (*grpc_dns_lookup_hostname_ares)(
const char* dns_server, const char* name, const char* default_port, const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addrs, std::unique_ptr<grpc_core::ServerAddressList>* addrs,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addrs, int query_timeout_ms) = grpc_dns_lookup_hostname_ares_impl;
grpc_ares_request* (*grpc_dns_lookup_srv_ares)(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses,
int query_timeout_ms) = grpc_dns_lookup_srv_ares_impl;
grpc_ares_request* (*grpc_dns_lookup_txt_ares)(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
char** service_config_json, char** service_config_json,
int query_timeout_ms) = grpc_dns_lookup_ares_impl; int query_timeout_ms) = grpc_dns_lookup_txt_ares_impl;
static void grpc_cancel_ares_request_impl(grpc_ares_request* r) { static void grpc_cancel_ares_request_impl(grpc_ares_request* r) {
GPR_ASSERT(r != nullptr); GPR_ASSERT(r != nullptr);

@ -78,23 +78,36 @@ struct grpc_ares_request {
grpc_error_handle error ABSL_GUARDED_BY(mu) = GRPC_ERROR_NONE; grpc_error_handle error ABSL_GUARDED_BY(mu) = GRPC_ERROR_NONE;
}; };
/* Asynchronously resolve \a name. It will try to resolve grpclb SRV records in /* Asynchronously resolve \a name (A/AAAA records only).
addition to the normal address records. For normal address records, it uses It uses \a default_port if a port isn't designated in \a name, otherwise it
\a default_port if a port isn't designated in \a name, otherwise it uses the uses the port in \a name. grpc_ares_init() must be called at least once before
port in \a name. grpc_ares_init() must be called at least once before this this function. The returned grpc_ares_request object is owned by the caller
function. The returned grpc_ares_request object is owned by the caller and it and it is safe to free after on_done is called back.
is safe to free after on_done is called back.
Note on synchronization: \a as on_done might be called from another thread Note on synchronization: \a as on_done might be called from another thread
~immediately, access to the grpc_ares_request* return value must be ~immediately, access to the grpc_ares_request* return value must be
synchronized by the caller. TODO(apolcyn): we should remove this requirement synchronized by the caller. TODO(apolcyn): we should remove this requirement
by changing this API to use two phase initialization - one API to create by changing this API to use two phase initialization - one API to create
the grpc_ares_request* and another to start the async work. */ the grpc_ares_request* and another to start the async work. */
extern grpc_ares_request* (*grpc_dns_lookup_ares)( extern grpc_ares_request* (*grpc_dns_lookup_hostname_ares)(
const char* dns_server, const char* name, const char* default_port, const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
int query_timeout_ms);
// Asynchronously resolve a SRV record.
// See \a grpc_dns_lookup_hostname_ares for usage details and caveats.
extern grpc_ares_request* (*grpc_dns_lookup_srv_ares)(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses, std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses,
int query_timeout_ms);
// Asynchronously resolve a TXT record.
// See \a grpc_dns_lookup_hostname_ares for usage details and caveats.
extern grpc_ares_request* (*grpc_dns_lookup_txt_ares)(
const char* dns_server, const char* name,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
char** service_config_json, int query_timeout_ms); char** service_config_json, int query_timeout_ms);
/* Cancel the pending grpc_ares_request \a request */ /* Cancel the pending grpc_ares_request \a request */

@ -119,9 +119,10 @@ NativeClientChannelDNSResolver::~NativeClientChannelDNSResolver() {
OrphanablePtr<Orphanable> NativeClientChannelDNSResolver::StartRequest() { OrphanablePtr<Orphanable> NativeClientChannelDNSResolver::StartRequest() {
Ref(DEBUG_LOCATION, "dns_request").release(); Ref(DEBUG_LOCATION, "dns_request").release();
auto dns_request_handle = GetDNSResolver()->ResolveName( auto dns_request_handle = GetDNSResolver()->LookupHostname(
name_to_resolve(), kDefaultSecurePort, interested_parties(), absl::bind_front(&NativeClientChannelDNSResolver::OnResolved, this),
absl::bind_front(&NativeClientChannelDNSResolver::OnResolved, this)); name_to_resolve(), kDefaultSecurePort, kDefaultDNSRequestTimeout,
interested_parties(), /*name_server=*/"");
if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_dns_resolver)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_dns_resolver)) {
gpr_log(GPR_DEBUG, "[dns_resolver=%p] starting request=%p", this, gpr_log(GPR_DEBUG, "[dns_resolver=%p] starting request=%p", this,
DNSResolver::HandleToString(dns_request_handle).c_str()); DNSResolver::HandleToString(dns_request_handle).c_str());

@ -930,7 +930,8 @@ grpc_error_handle Chttp2ServerAddPort(Server* server, const char* addr,
resolved_or = resolved_or =
grpc_resolve_unix_abstract_domain_address(parsed_addr_unprefixed); grpc_resolve_unix_abstract_domain_address(parsed_addr_unprefixed);
} else { } else {
resolved_or = GetDNSResolver()->ResolveNameBlocking(parsed_addr, "https"); resolved_or =
GetDNSResolver()->LookupHostnameBlocking(parsed_addr, "https");
} }
if (!resolved_or.ok()) { if (!resolved_or.ok()) {
return absl_status_to_grpc_error(resolved_or.status()); return absl_status_to_grpc_error(resolved_or.status());

@ -209,9 +209,10 @@ void HttpRequest::Start() {
return; return;
} }
Ref().release(); // ref held by pending DNS resolution Ref().release(); // ref held by pending DNS resolution
dns_request_handle_ = GetDNSResolver()->ResolveName( dns_request_handle_ = GetDNSResolver()->LookupHostname(
uri_.authority(), uri_.scheme(), pollset_set_, absl::bind_front(&HttpRequest::OnResolved, this), uri_.authority(),
absl::bind_front(&HttpRequest::OnResolved, this)); uri_.scheme(), kDefaultDNSRequestTimeout, pollset_set_,
/*name_server=*/"");
} }
void HttpRequest::Orphan() { void HttpRequest::Orphan() {

@ -1,58 +0,0 @@
//
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_LIB_IOMGR_EVENT_ENGINE_RESOLVER_H
#define GRPC_CORE_LIB_IOMGR_EVENT_ENGINE_RESOLVER_H
#include <grpc/support/port_platform.h>
#include <string.h>
#include <sys/types.h>
#include <functional>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/port.h"
#include "src/core/lib/iomgr/resolve_address.h"
namespace grpc_core {
namespace experimental {
#ifdef GRPC_USE_EVENT_ENGINE
class EventEngineDNSResolver : public DNSResolver {
public:
// Gets the singleton instance, creating it first if it doesn't exist
static EventEngineDNSResolver* GetOrCreate();
OrphanablePtr<DNSResolver::Request> ResolveName(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* interested_parties,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override;
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking(
absl::string_view name, absl::string_view default_port) override;
};
#endif // GRPC_USE_EVENT_ENGINE
} // namespace experimental
} // namespace grpc_core
#endif // GRPC_CORE_LIB_IOMGR_EVENT_ENGINE_RESOLVER_H

@ -37,6 +37,7 @@
namespace grpc_core { namespace grpc_core {
extern const char* kDefaultSecurePort; extern const char* kDefaultSecurePort;
constexpr int kDefaultSecurePortInt = 443; constexpr int kDefaultSecurePortInt = 443;
constexpr Duration kDefaultDNSRequestTimeout = Duration::Minutes(2);
// A singleton class used for async and blocking DNS resolution // A singleton class used for async and blocking DNS resolution
class DNSResolver { class DNSResolver {
@ -60,17 +61,39 @@ class DNSResolver {
// address this. // address this.
// //
// \a interested_parties may be deleted after a request is cancelled. // \a interested_parties may be deleted after a request is cancelled.
virtual TaskHandle ResolveName( virtual TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* interested_parties,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) = 0; on_resolved,
absl::string_view name, absl::string_view default_port, Duration timeout,
grpc_pollset_set* interested_parties, absl::string_view name_server) = 0;
// Resolve name in a blocking fashion. Use \a default_port if a port isn't // Resolve name in a blocking fashion. Use \a default_port if a port isn't
// designated in \a name, otherwise use the port in \a name. // designated in \a name, otherwise use the port in \a name.
virtual absl::StatusOr<std::vector<grpc_resolved_address>> virtual absl::StatusOr<std::vector<grpc_resolved_address>>
ResolveNameBlocking(absl::string_view name, LookupHostnameBlocking(absl::string_view name,
absl::string_view default_port) = 0; absl::string_view default_port) = 0;
// Asynchronously resolve an SRV Record to Hostnames.
// On completion, \a on_done is invoked with the result.
//
// The same caveats in \a LookupHostname apply here as well.
//
// TODO(hork): return std::vector<SRVRecord> and ask the client to do the
// subsequent hostname lookups.
virtual TaskHandle 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) = 0;
// Asynchronously resolve a TXT Record. On completion, \a on_done is invoked
// with the resulting string.
//
// The same caveats in \a LookupHostname apply here.
virtual TaskHandle 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) = 0;
// This shares the same semantics with \a EventEngine::Cancel: successfully // This shares the same semantics with \a EventEngine::Cancel: successfully
// cancelled lookups will not have their callbacks executed, and this // cancelled lookups will not have their callbacks executed, and this

@ -29,6 +29,7 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/lib/event_engine/event_engine_factory.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h" #include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/host_port.h" #include "src/core/lib/gprpp/host_port.h"
@ -45,6 +46,8 @@
namespace grpc_core { namespace grpc_core {
namespace { namespace {
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
class NativeDNSRequest { class NativeDNSRequest {
public: public:
NativeDNSRequest( NativeDNSRequest(
@ -58,11 +61,11 @@ class NativeDNSRequest {
private: private:
// Callback to be passed to grpc Executor to asynch-ify // Callback to be passed to grpc Executor to asynch-ify
// ResolveNameBlocking // LookupHostnameBlocking
static void DoRequestThread(void* rp, grpc_error_handle /*error*/) { static void DoRequestThread(void* rp, grpc_error_handle /*error*/) {
NativeDNSRequest* r = static_cast<NativeDNSRequest*>(rp); NativeDNSRequest* r = static_cast<NativeDNSRequest*>(rp);
auto result = auto result =
GetDNSResolver()->ResolveNameBlocking(r->name_, r->default_port_); GetDNSResolver()->LookupHostnameBlocking(r->name_, r->default_port_);
// running inline is safe since we've already been scheduled on the executor // running inline is safe since we've already been scheduled on the executor
r->on_done_(std::move(result)); r->on_done_(std::move(result));
delete r; delete r;
@ -82,19 +85,20 @@ NativeDNSResolver* NativeDNSResolver::GetOrCreate() {
return instance; return instance;
} }
DNSResolver::TaskHandle NativeDNSResolver::ResolveName( DNSResolver::TaskHandle NativeDNSResolver::LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* /* interested_parties */,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) { on_done,
absl::string_view name, absl::string_view default_port,
Duration /* timeout */, grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) {
// self-deleting class // self-deleting class
new NativeDNSRequest(name, default_port, std::move(on_done)); new NativeDNSRequest(name, default_port, std::move(on_done));
return kNullHandle; return kNullHandle;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> absl::StatusOr<std::vector<grpc_resolved_address>>
NativeDNSResolver::ResolveNameBlocking(absl::string_view name, NativeDNSResolver::LookupHostnameBlocking(absl::string_view name,
absl::string_view default_port) { absl::string_view default_port) {
ExecCtx exec_ctx; ExecCtx exec_ctx;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result = nullptr, *resp; struct addrinfo *result = nullptr, *resp;
@ -173,6 +177,32 @@ done:
return error_result; return error_result;
} }
DNSResolver::TaskHandle NativeDNSResolver::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 */) {
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Native resolver does not support looking up SRV records"));
});
return {-1, -1};
};
DNSResolver::TaskHandle NativeDNSResolver::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 */) {
// Not supported
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Native resolver does not support looking up TXT records"));
});
return {-1, -1};
};
bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; } bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; }
} // namespace grpc_core } // namespace grpc_core

@ -32,15 +32,29 @@ class NativeDNSResolver : public DNSResolver {
// Gets the singleton instance, creating it first if it doesn't exist // Gets the singleton instance, creating it first if it doesn't exist
static NativeDNSResolver* GetOrCreate(); static NativeDNSResolver* GetOrCreate();
TaskHandle ResolveName( TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* /* interested_parties */,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override; on_done,
absl::string_view name, absl::string_view default_port, Duration timeout,
grpc_pollset_set* interested_parties,
absl::string_view name_server) override;
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view name, absl::string_view default_port) override; absl::string_view name, absl::string_view default_port) override;
TaskHandle 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) override;
TaskHandle 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) override;
// NativeDNSResolver does not support cancellation. // NativeDNSResolver does not support cancellation.
bool Cancel(TaskHandle handle) override; bool Cancel(TaskHandle handle) override;
}; };

@ -34,6 +34,7 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/lib/address_utils/sockaddr_utils.h" #include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/event_engine/event_engine_factory.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/host_port.h" #include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/thd.h" #include "src/core/lib/gprpp/thd.h"
@ -48,6 +49,8 @@
namespace grpc_core { namespace grpc_core {
namespace { namespace {
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
class NativeDNSRequest { class NativeDNSRequest {
public: public:
NativeDNSRequest( NativeDNSRequest(
@ -61,11 +64,11 @@ class NativeDNSRequest {
private: private:
// Callback to be passed to grpc Executor to asynch-ify // Callback to be passed to grpc Executor to asynch-ify
// ResolveNameBlocking // LookupHostnameBlocking
static void DoRequestThread(void* rp, grpc_error_handle /*error*/) { static void DoRequestThread(void* rp, grpc_error_handle /*error*/) {
NativeDNSRequest* r = static_cast<NativeDNSRequest*>(rp); NativeDNSRequest* r = static_cast<NativeDNSRequest*>(rp);
auto result = auto result =
GetDNSResolver()->ResolveNameBlocking(r->name_, r->default_port_); GetDNSResolver()->LookupHostnameBlocking(r->name_, r->default_port_);
// running inline is safe since we've already been scheduled on the executor // running inline is safe since we've already been scheduled on the executor
r->on_done_(std::move(result)); r->on_done_(std::move(result));
delete r; delete r;
@ -85,18 +88,19 @@ NativeDNSResolver* NativeDNSResolver::GetOrCreate() {
return instance; return instance;
} }
DNSResolver::TaskHandle NativeDNSResolver::ResolveName( DNSResolver::TaskHandle NativeDNSResolver::LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* /* interested_parties */,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) { on_resolved,
new NativeDNSRequest(name, default_port, std::move(on_done)); absl::string_view name, absl::string_view default_port,
Duration /* timeout */, grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) {
new NativeDNSRequest(name, default_port, std::move(on_resolved));
return kNullHandle; return kNullHandle;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> absl::StatusOr<std::vector<grpc_resolved_address>>
NativeDNSResolver::ResolveNameBlocking(absl::string_view name, NativeDNSResolver::LookupHostnameBlocking(absl::string_view name,
absl::string_view default_port) { absl::string_view default_port) {
ExecCtx exec_ctx; ExecCtx exec_ctx;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result = NULL, *resp; struct addrinfo *result = NULL, *resp;
@ -157,6 +161,32 @@ done:
return error_result; return error_result;
} }
DNSResolver::TaskHandle NativeDNSResolver::LookupSRV(
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolved,
absl::string_view /* name */, Duration /* deadline */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) {
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Native resolver does not support looking up SRV records"));
});
return {-1, -1};
};
DNSResolver::TaskHandle NativeDNSResolver::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 */) {
// Not supported
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Native resolver does not support looking up TXT records"));
});
return {-1, -1};
};
bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; } bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; }
} // namespace grpc_core } // namespace grpc_core

@ -32,15 +32,29 @@ class NativeDNSResolver : public DNSResolver {
// Gets the singleton instance, creating it first if it doesn't exist // Gets the singleton instance, creating it first if it doesn't exist
static NativeDNSResolver* GetOrCreate(); static NativeDNSResolver* GetOrCreate();
TaskHandle ResolveName( TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* /* interested_parties */,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override; on_resolved,
absl::string_view name, absl::string_view default_port, Duration timeout,
grpc_pollset_set* interested_parties,
absl::string_view name_server) override;
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view name, absl::string_view default_port) override; absl::string_view name, absl::string_view default_port) override;
TaskHandle 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) override;
TaskHandle 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) override;
// NativeDNSResolver does not support cancellation. // NativeDNSResolver does not support cancellation.
bool Cancel(TaskHandle handle) override; bool Cancel(TaskHandle handle) override;
}; };

@ -29,6 +29,7 @@
#include "src/core/lib/address_utils/sockaddr_utils.h" #include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/event_engine/event_engine_factory.h"
#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/resolve_address.h"
@ -45,10 +46,9 @@ static grpc_ares_request* (*g_default_dns_lookup_ares)(
const char* dns_server, const char* name, const char* default_port, const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses, int query_timeout_ms);
char** service_config_json, int query_timeout_ms);
// Counter incremented by TestDNSResolver::ResolveName indicating the // Counter incremented by TestDNSResolver::LookupHostname indicating the
// number of times a system-level resolution has happened. // number of times a system-level resolution has happened.
static int g_resolution_count; static int g_resolution_count;
@ -62,19 +62,23 @@ static struct iomgr_args {
namespace { namespace {
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
grpc_core::DNSResolver* g_default_dns_resolver; grpc_core::DNSResolver* g_default_dns_resolver;
class TestDNSResolver : public grpc_core::DNSResolver { class TestDNSResolver : public grpc_core::DNSResolver {
public: public:
// Wrapper around default resolve_address in order to count the number of // Wrapper around default resolve_address in order to count the number of
// times we incur in a system-level name resolution. // times we incur in a system-level name resolution.
TaskHandle ResolveName( TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* interested_parties,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override { on_resolved,
auto result = g_default_dns_resolver->ResolveName( absl::string_view name, absl::string_view default_port,
name, default_port, interested_parties, std::move(on_done)); grpc_core::Duration timeout, grpc_pollset_set* interested_parties,
absl::string_view name_server) override {
auto result = g_default_dns_resolver->LookupHostname(
std::move(on_resolved), name, default_port, timeout, interested_parties,
name_server);
++g_resolution_count; ++g_resolution_count;
static grpc_core::Timestamp last_resolution_time = static grpc_core::Timestamp last_resolution_time =
grpc_core::Timestamp::ProcessEpoch(); grpc_core::Timestamp::ProcessEpoch();
@ -98,11 +102,37 @@ class TestDNSResolver : public grpc_core::DNSResolver {
return result; return result;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view name, absl::string_view default_port) override { absl::string_view name, absl::string_view default_port) override {
return g_default_dns_resolver->ResolveNameBlocking(name, default_port); return g_default_dns_resolver->LookupHostnameBlocking(name, default_port);
} }
TaskHandle LookupSRV(
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Testing DNS resolver does not support looking up SRV records"));
});
return {-1, -1};
};
TaskHandle LookupTXT(
std::function<void(absl::StatusOr<std::string>)> on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
// Not supported
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Testing DNS resolver does not support looking up TXT records"));
});
return {-1, -1};
};
// Not cancellable // Not cancellable
bool Cancel(TaskHandle /*handle*/) override { return false; } bool Cancel(TaskHandle /*handle*/) override { return false; }
}; };
@ -113,11 +143,11 @@ static grpc_ares_request* test_dns_lookup_ares(
const char* dns_server, const char* name, const char* default_port, const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done, grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses, int query_timeout_ms) {
char** service_config_json, int query_timeout_ms) { // A records should suffice
grpc_ares_request* result = g_default_dns_lookup_ares( grpc_ares_request* result = g_default_dns_lookup_ares(
dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, dns_server, name, default_port, g_iomgr_args.pollset_set, on_done,
addresses, balancer_addresses, service_config_json, query_timeout_ms); addresses, query_timeout_ms);
++g_resolution_count; ++g_resolution_count;
static auto last_resolution_time = grpc_core::Timestamp::ProcessEpoch(); static auto last_resolution_time = grpc_core::Timestamp::ProcessEpoch();
auto now = auto now =
@ -345,8 +375,8 @@ TEST(DnsResolverCooldownTest, MainTest) {
auto work_serializer = std::make_shared<grpc_core::WorkSerializer>(); auto work_serializer = std::make_shared<grpc_core::WorkSerializer>();
g_work_serializer = &work_serializer; g_work_serializer = &work_serializer;
g_default_dns_lookup_ares = grpc_dns_lookup_ares; g_default_dns_lookup_ares = grpc_dns_lookup_hostname_ares;
grpc_dns_lookup_ares = test_dns_lookup_ares; grpc_dns_lookup_hostname_ares = test_dns_lookup_ares;
g_default_dns_resolver = grpc_core::GetDNSResolver(); g_default_dns_resolver = grpc_core::GetDNSResolver();
grpc_core::SetDNSResolver(new TestDNSResolver()); grpc_core::SetDNSResolver(new TestDNSResolver());

@ -62,7 +62,7 @@ static void drain_cq(grpc_completion_queue* cq) {
static void log_resolved_addrs(const char* label, const char* hostname) { static void log_resolved_addrs(const char* label, const char* hostname) {
absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or = absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or =
grpc_core::GetDNSResolver()->ResolveNameBlocking(hostname, "80"); grpc_core::GetDNSResolver()->LookupHostnameBlocking(hostname, "80");
if (!addresses_or.ok()) { if (!addresses_or.ok()) {
GRPC_LOG_IF_ERROR(hostname, GRPC_LOG_IF_ERROR(hostname,
absl_status_to_grpc_error(addresses_or.status())); absl_status_to_grpc_error(addresses_or.status()));
@ -281,7 +281,7 @@ void test_connect(const char* server_host, const char* client_host, int port,
int external_dns_works(const char* host) { int external_dns_works(const char* host) {
auto addresses_or = auto addresses_or =
grpc_core::GetDNSResolver()->ResolveNameBlocking(host, "80"); grpc_core::GetDNSResolver()->LookupHostnameBlocking(host, "80");
if (!addresses_or.ok()) { if (!addresses_or.ok()) {
return 0; return 0;
} }

@ -532,8 +532,8 @@ static void on_read_request_done_locked(void* arg, grpc_error_handle error) {
} }
// Resolve address. // Resolve address.
absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or = absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or =
grpc_core::GetDNSResolver()->ResolveNameBlocking(conn->http_request.path, grpc_core::GetDNSResolver()->LookupHostnameBlocking(
"80"); conn->http_request.path, "80");
if (!addresses_or.ok()) { if (!addresses_or.ok()) {
proxy_connection_failed(conn, SETUP_FAILED, "HTTP proxy DNS lookup", proxy_connection_failed(conn, SETUP_FAILED, "HTTP proxy DNS lookup",
GRPC_ERROR_REF(error)); GRPC_ERROR_REF(error));

@ -105,6 +105,8 @@ static void finish_resolve(void* arg, grpc_error_handle error) {
namespace { namespace {
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
class FuzzerDNSResolver : public grpc_core::DNSResolver { class FuzzerDNSResolver : public grpc_core::DNSResolver {
public: public:
class FuzzerDNSRequest { class FuzzerDNSRequest {
@ -148,21 +150,49 @@ class FuzzerDNSResolver : public grpc_core::DNSResolver {
return instance; return instance;
} }
TaskHandle ResolveName( TaskHandle LookupHostname(
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolved,
absl::string_view name, absl::string_view /* default_port */, absl::string_view name, absl::string_view /* default_port */,
grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */, grpc_pollset_set* /* interested_parties */,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> absl::string_view /* name_server */) override {
on_done) override { new FuzzerDNSRequest(name, std::move(on_resolved));
new FuzzerDNSRequest(name, std::move(on_done));
return kNullHandle; return kNullHandle;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view /* name */, absl::string_view /* name */,
absl::string_view /* default_port */) override { absl::string_view /* default_port */) override {
GPR_ASSERT(0); GPR_ASSERT(0);
} }
TaskHandle LookupSRV(
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Fuzzing DNS resolver does not support looking up SRV records"));
});
return {-1, -1};
};
TaskHandle LookupTXT(
std::function<void(absl::StatusOr<std::string>)> on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
// Not supported
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Fuzing DNS resolver does not support looking up TXT records"));
});
return {-1, -1};
};
// FuzzerDNSResolver does not support cancellation. // FuzzerDNSResolver does not support cancellation.
bool Cancel(TaskHandle /*handle*/) override { return false; } bool Cancel(TaskHandle /*handle*/) override { return false; }
}; };
@ -173,8 +203,7 @@ grpc_ares_request* my_dns_lookup_ares(
const char* /*dns_server*/, const char* addr, const char* /*default_port*/, const char* /*dns_server*/, const char* addr, const char* /*default_port*/,
grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done, grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* /*balancer_addresses*/, int /*query_timeout*/) {
char** /*service_config_json*/, int /*query_timeout*/) {
addr_req* r = new addr_req(); addr_req* r = new addr_req();
r->addr = gpr_strdup(addr); r->addr = gpr_strdup(addr);
r->on_done = on_done; r->on_done = on_done;
@ -771,7 +800,7 @@ DEFINE_PROTO_FUZZER(const api_fuzzer::Msg& msg) {
grpc_core::Executor::SetThreadingAll(false); grpc_core::Executor::SetThreadingAll(false);
} }
grpc_core::SetDNSResolver(FuzzerDNSResolver::GetOrCreate()); grpc_core::SetDNSResolver(FuzzerDNSResolver::GetOrCreate());
grpc_dns_lookup_ares = my_dns_lookup_ares; grpc_dns_lookup_hostname_ares = my_dns_lookup_ares;
grpc_cancel_ares_request = my_cancel_ares_request; grpc_cancel_ares_request = my_cancel_ares_request;
GPR_ASSERT(g_channel == nullptr); GPR_ASSERT(g_channel == nullptr);

@ -28,6 +28,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/event_engine/event_engine_factory.h"
#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/resolve_address_impl.h" #include "src/core/lib/iomgr/resolve_address_impl.h"
#include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr.h"
@ -46,8 +47,7 @@ static grpc_ares_request* (*iomgr_dns_lookup_ares)(
const char* dns_server, const char* addr, const char* default_port, const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses, int query_timeout_ms);
char** service_config_json, int query_timeout_ms);
static void (*iomgr_cancel_ares_request)(grpc_ares_request* request); static void (*iomgr_cancel_ares_request)(grpc_ares_request* request);
@ -59,28 +59,58 @@ static void set_resolve_port(int port) {
namespace { namespace {
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
grpc_core::DNSResolver* g_default_dns_resolver; grpc_core::DNSResolver* g_default_dns_resolver;
class TestDNSResolver : public grpc_core::DNSResolver { class TestDNSResolver : public grpc_core::DNSResolver {
public: public:
TaskHandle ResolveName( TaskHandle LookupHostname(
absl::string_view name, absl::string_view default_port,
grpc_pollset_set* interested_parties,
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)> std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_done) override { on_resolved,
absl::string_view name, absl::string_view default_port,
grpc_core::Duration timeout, grpc_pollset_set* interested_parties,
absl::string_view name_server) override {
if (name != "test") { if (name != "test") {
return g_default_dns_resolver->ResolveName( return g_default_dns_resolver->LookupHostname(
name, default_port, interested_parties, std::move(on_done)); std::move(on_resolved), name, default_port, timeout,
interested_parties, name_server);
} }
MakeDNSRequest(std::move(on_done)); MakeDNSRequest(std::move(on_resolved));
return kNullHandle; return kNullHandle;
} }
absl::StatusOr<std::vector<grpc_resolved_address>> ResolveNameBlocking( absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
absl::string_view name, absl::string_view default_port) override { absl::string_view name, absl::string_view default_port) override {
return g_default_dns_resolver->ResolveNameBlocking(name, default_port); return g_default_dns_resolver->LookupHostnameBlocking(name, default_port);
} }
TaskHandle LookupSRV(
std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Testing DNS resolver does not support looking up SRV records"));
});
return {-1, -1};
};
TaskHandle LookupTXT(
std::function<void(absl::StatusOr<std::string>)> on_resolved,
absl::string_view /* name */, grpc_core::Duration /* timeout */,
grpc_pollset_set* /* interested_parties */,
absl::string_view /* name_server */) override {
// Not supported
GetDefaultEventEngine()->Run([on_resolved] {
on_resolved(absl::UnimplementedError(
"The Testing DNS resolver does not support looking up TXT records"));
});
return {-1, -1};
};
bool Cancel(TaskHandle /*handle*/) override { return false; } bool Cancel(TaskHandle /*handle*/) override { return false; }
private: private:
@ -114,12 +144,12 @@ static grpc_ares_request* my_dns_lookup_ares(
const char* dns_server, const char* addr, const char* default_port, const char* dns_server, const char* addr, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_pollset_set* interested_parties, grpc_closure* on_done,
std::unique_ptr<grpc_core::ServerAddressList>* addresses, std::unique_ptr<grpc_core::ServerAddressList>* addresses,
std::unique_ptr<grpc_core::ServerAddressList>* balancer_addresses, int query_timeout_ms) {
char** service_config_json, int query_timeout_ms) {
if (0 != strcmp(addr, "test")) { if (0 != strcmp(addr, "test")) {
return iomgr_dns_lookup_ares( // A records should suffice
dns_server, addr, default_port, interested_parties, on_done, addresses, return iomgr_dns_lookup_ares(dns_server, addr, default_port,
balancer_addresses, service_config_json, query_timeout_ms); interested_parties, on_done, addresses,
query_timeout_ms);
} }
grpc_error_handle error = GRPC_ERROR_NONE; grpc_error_handle error = GRPC_ERROR_NONE;
@ -160,9 +190,9 @@ int main(int argc, char** argv) {
g_default_dns_resolver = grpc_core::GetDNSResolver(); g_default_dns_resolver = grpc_core::GetDNSResolver();
auto* resolver = new TestDNSResolver(); auto* resolver = new TestDNSResolver();
grpc_core::SetDNSResolver(resolver); grpc_core::SetDNSResolver(resolver);
iomgr_dns_lookup_ares = grpc_dns_lookup_ares; iomgr_dns_lookup_ares = grpc_dns_lookup_hostname_ares;
iomgr_cancel_ares_request = grpc_cancel_ares_request; iomgr_cancel_ares_request = grpc_cancel_ares_request;
grpc_dns_lookup_ares = my_dns_lookup_ares; grpc_dns_lookup_hostname_ares = my_dns_lookup_ares;
grpc_cancel_ares_request = my_cancel_ares_request; grpc_cancel_ares_request = my_cancel_ares_request;
int was_cancelled1; int was_cancelled1;

@ -135,11 +135,13 @@ static void resolve_address_must_succeed(const char* target) {
args_struct args; args_struct args;
args_init(&args); args_init(&args);
poll_pollset_until_request_done(&args); poll_pollset_until_request_done(&args);
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
target, "1" /* port number */, args.pollset_set,
[&args](absl::StatusOr<std::vector<grpc_resolved_address>> result) { [&args](absl::StatusOr<std::vector<grpc_resolved_address>> result) {
MustSucceed(&args, std::move(result)); MustSucceed(&args, std::move(result));
}); },
target, /*port number=*/"1", grpc_core::kDefaultDNSRequestTimeout,
args.pollset_set,
/*name_server=*/"");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
args_finish(&args); args_finish(&args);
} }

@ -182,18 +182,18 @@ class ResolveAddressTest : public ::testing::Test {
TEST_F(ResolveAddressTest, Localhost) { TEST_F(ResolveAddressTest, Localhost) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost:1", "", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, this), "localhost:1",
absl::bind_front(&ResolveAddressTest::MustSucceed, this)); "", grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
TEST_F(ResolveAddressTest, DefaultPort) { TEST_F(ResolveAddressTest, DefaultPort) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost", "1", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, this), "localhost",
absl::bind_front(&ResolveAddressTest::MustSucceed, this)); "1", grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
@ -203,9 +203,10 @@ TEST_F(ResolveAddressTest, LocalhostResultHasIPv6First) {
GTEST_SKIP() << "this test is only valid with the c-ares resolver"; GTEST_SKIP() << "this test is only valid with the c-ares resolver";
} }
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost:1", "", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceedWithIPv6First, this),
absl::bind_front(&ResolveAddressTest::MustSucceedWithIPv6First, this)); "localhost:1", "", grpc_core::kDefaultDNSRequestTimeout, pollset_set(),
"");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
@ -250,45 +251,47 @@ TEST_F(ResolveAddressTest, LocalhostResultHasIPv4FirstWhenIPv6IsntAvalailable) {
address_sorting_override_source_addr_factory_for_testing(mock); address_sorting_override_source_addr_factory_for_testing(mock);
// run the test // run the test
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost:1", "", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceedWithIPv4First, this),
absl::bind_front(&ResolveAddressTest::MustSucceedWithIPv4First, this)); "localhost:1", "", grpc_core::kDefaultDNSRequestTimeout, pollset_set(),
"");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
TEST_F(ResolveAddressTest, NonNumericDefaultPort) { TEST_F(ResolveAddressTest, NonNumericDefaultPort) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost", "http", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, this), "localhost",
absl::bind_front(&ResolveAddressTest::MustSucceed, this)); "http", grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
TEST_F(ResolveAddressTest, MissingDefaultPort) { TEST_F(ResolveAddressTest, MissingDefaultPort) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"localhost", "", pollset_set(), absl::bind_front(&ResolveAddressTest::MustFail, this), "localhost", "",
absl::bind_front(&ResolveAddressTest::MustFail, this)); grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
TEST_F(ResolveAddressTest, IPv6WithPort) { TEST_F(ResolveAddressTest, IPv6WithPort) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
"[2001:db8::1]:1", "", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, this),
absl::bind_front(&ResolveAddressTest::MustSucceed, this)); "[2001:db8::1]:1", "", grpc_core::kDefaultDNSRequestTimeout,
pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
void TestIPv6WithoutPort(ResolveAddressTest* test, const char* target) { void TestIPv6WithoutPort(ResolveAddressTest* test, const char* target) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
target, "80", test->pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, test), target, "80",
absl::bind_front(&ResolveAddressTest::MustSucceed, test)); grpc_core::kDefaultDNSRequestTimeout, test->pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
test->PollPollsetUntilRequestDone(); test->PollPollsetUntilRequestDone();
} }
@ -307,9 +310,9 @@ TEST_F(ResolveAddressTest, IPv6WithoutPortV4MappedV6) {
void TestInvalidIPAddress(ResolveAddressTest* test, const char* target) { void TestInvalidIPAddress(ResolveAddressTest* test, const char* target) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
target, "", test->pollset_set(), absl::bind_front(&ResolveAddressTest::MustFail, test), target, "",
absl::bind_front(&ResolveAddressTest::MustFail, test)); grpc_core::kDefaultDNSRequestTimeout, test->pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
test->PollPollsetUntilRequestDone(); test->PollPollsetUntilRequestDone();
} }
@ -324,9 +327,9 @@ TEST_F(ResolveAddressTest, InvalidIPv6Addresses) {
void TestUnparseableHostPort(ResolveAddressTest* test, const char* target) { void TestUnparseableHostPort(ResolveAddressTest* test, const char* target) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->ResolveName( grpc_core::GetDNSResolver()->LookupHostname(
target, "1", test->pollset_set(), absl::bind_front(&ResolveAddressTest::MustFail, test), target, "1",
absl::bind_front(&ResolveAddressTest::MustFail, test)); grpc_core::kDefaultDNSRequestTimeout, test->pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
test->PollPollsetUntilRequestDone(); test->PollPollsetUntilRequestDone();
} }
@ -359,9 +362,9 @@ TEST_F(ResolveAddressTest, UnparseableHostPortsBadLocalhostWithPort) {
// test doesn't care what the result is, just that we don't crash etc. // test doesn't care what the result is, just that we don't crash etc.
TEST_F(ResolveAddressTest, ImmediateCancel) { TEST_F(ResolveAddressTest, ImmediateCancel) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
auto request_handle = grpc_core::GetDNSResolver()->ResolveName( auto request_handle = grpc_core::GetDNSResolver()->LookupHostname(
"localhost:1", "1", pollset_set(), absl::bind_front(&ResolveAddressTest::DontCare, this), "localhost:1", "1",
absl::bind_front(&ResolveAddressTest::DontCare, this)); grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
if (grpc_core::GetDNSResolver()->Cancel(request_handle)) { if (grpc_core::GetDNSResolver()->Cancel(request_handle)) {
Finish(); Finish();
} }
@ -372,9 +375,9 @@ TEST_F(ResolveAddressTest, ImmediateCancel) {
// Attempt to cancel a request after it has completed. // Attempt to cancel a request after it has completed.
TEST_F(ResolveAddressTest, CancelDoesNotSucceed) { TEST_F(ResolveAddressTest, CancelDoesNotSucceed) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
auto request_handle = grpc_core::GetDNSResolver()->ResolveName( auto request_handle = grpc_core::GetDNSResolver()->LookupHostname(
"localhost:1", "1", pollset_set(), absl::bind_front(&ResolveAddressTest::MustSucceed, this), "localhost:1",
absl::bind_front(&ResolveAddressTest::MustSucceed, this)); "1", grpc_core::kDefaultDNSRequestTimeout, pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
ASSERT_FALSE(grpc_core::GetDNSResolver()->Cancel(request_handle)); ASSERT_FALSE(grpc_core::GetDNSResolver()->Cancel(request_handle));
@ -416,9 +419,10 @@ TEST_F(ResolveAddressTest, CancelWithNonResponsiveDNSServer) {
grpc_ares_test_only_inject_config = InjectNonResponsiveDNSServer; grpc_ares_test_only_inject_config = InjectNonResponsiveDNSServer;
// Run the test // Run the test
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
auto request_handle = grpc_core::GetDNSResolver()->ResolveName( auto request_handle = grpc_core::GetDNSResolver()->LookupHostname(
"foo.bar.com:1", "1", pollset_set(), absl::bind_front(&ResolveAddressTest::MustNotBeCalled, this),
absl::bind_front(&ResolveAddressTest::MustNotBeCalled, this)); "foo.bar.com:1", "1", grpc_core::kDefaultDNSRequestTimeout, pollset_set(),
"");
grpc_core::ExecCtx::Get()->Flush(); // initiate DNS requests grpc_core::ExecCtx::Get()->Flush(); // initiate DNS requests
ASSERT_TRUE(grpc_core::GetDNSResolver()->Cancel(request_handle)); ASSERT_TRUE(grpc_core::GetDNSResolver()->Cancel(request_handle));
Finish(); Finish();
@ -479,9 +483,10 @@ TEST_F(ResolveAddressTest, DeleteInterestedPartiesAfterCancellation) {
// Create a pollset_set, destroyed immediately after cancellation // Create a pollset_set, destroyed immediately after cancellation
std::unique_ptr<PollsetSetWrapper> pss = PollsetSetWrapper::Create(); std::unique_ptr<PollsetSetWrapper> pss = PollsetSetWrapper::Create();
// Run the test // Run the test
auto request_handle = grpc_core::GetDNSResolver()->ResolveName( auto request_handle = grpc_core::GetDNSResolver()->LookupHostname(
"foo.bar.com:1", "1", pss->pollset_set(), absl::bind_front(&ResolveAddressTest::MustNotBeCalled, this),
absl::bind_front(&ResolveAddressTest::MustNotBeCalled, this)); "foo.bar.com:1", "1", grpc_core::kDefaultDNSRequestTimeout,
pss->pollset_set(), "");
grpc_core::ExecCtx::Get()->Flush(); // initiate DNS requests grpc_core::ExecCtx::Get()->Flush(); // initiate DNS requests
ASSERT_TRUE(grpc_core::GetDNSResolver()->Cancel(request_handle)); ASSERT_TRUE(grpc_core::GetDNSResolver()->Cancel(request_handle));
} }
@ -493,6 +498,40 @@ TEST_F(ResolveAddressTest, DeleteInterestedPartiesAfterCancellation) {
PollPollsetUntilRequestDone(); PollPollsetUntilRequestDone();
} }
TEST_F(ResolveAddressTest, NativeResolverCannotLookupSRVRecords) {
if (absl::string_view(g_resolver_type) == "ares") {
GTEST_SKIP() << "this test is only for native resolvers";
}
grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->LookupSRV(
[this](absl::StatusOr<std::vector<grpc_resolved_address>> error) {
grpc_core::ExecCtx exec_ctx;
EXPECT_EQ(error.status().code(), absl::StatusCode::kUnimplemented);
Finish();
},
"localhost", grpc_core::kDefaultDNSRequestTimeout, pollset_set(),
/*name_server=*/"");
grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone();
}
TEST_F(ResolveAddressTest, NativeResolverCannotLookupTXTRecords) {
if (absl::string_view(g_resolver_type) == "ares") {
GTEST_SKIP() << "this test is only for native resolvers";
}
grpc_core::ExecCtx exec_ctx;
grpc_core::GetDNSResolver()->LookupTXT(
[this](absl::StatusOr<std::string> error) {
grpc_core::ExecCtx exec_ctx;
EXPECT_EQ(error.status().code(), absl::StatusCode::kUnimplemented);
Finish();
},
"localhost", grpc_core::kDefaultDNSRequestTimeout, pollset_set(),
/*name_server=*/"");
grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone();
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
// Configure the DNS resolver (c-ares vs. native) based on the // Configure the DNS resolver (c-ares vs. native) based on the
// name of the binary. TODO(apolcyn): is there a way to pass command // name of the binary. TODO(apolcyn): is there a way to pass command

@ -127,7 +127,7 @@ void test_bind_server_to_addr(const char* host, bool secure) {
} }
static bool external_dns_works(const char* host) { static bool external_dns_works(const char* host) {
return grpc_core::GetDNSResolver()->ResolveNameBlocking(host, "80").ok(); return grpc_core::GetDNSResolver()->LookupHostnameBlocking(host, "80").ok();
} }
static void test_bind_server_to_addrs(const char** addrs, size_t n) { static void test_bind_server_to_addrs(const char** addrs, size_t n) {

@ -114,7 +114,7 @@ class Client {
void Connect() { void Connect() {
ExecCtx exec_ctx; ExecCtx exec_ctx;
absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or = absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or =
GetDNSResolver()->ResolveNameBlocking(server_address_, "80"); GetDNSResolver()->LookupHostnameBlocking(server_address_, "80");
ASSERT_EQ(absl::OkStatus(), addresses_or.status()) ASSERT_EQ(absl::OkStatus(), addresses_or.status())
<< addresses_or.status().ToString(); << addresses_or.status().ToString();
ASSERT_GE(addresses_or->size(), 1UL); ASSERT_GE(addresses_or->size(), 1UL);

@ -33,7 +33,7 @@ gpr_once g_resolve_localhost_ipv46 = GPR_ONCE_INIT;
void InitResolveLocalhost() { void InitResolveLocalhost() {
absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or = absl::StatusOr<std::vector<grpc_resolved_address>> addresses_or =
GetDNSResolver()->ResolveNameBlocking("localhost", "https"); GetDNSResolver()->LookupHostnameBlocking("localhost", "https");
GPR_ASSERT(addresses_or.ok()); GPR_ASSERT(addresses_or.ok());
for (const auto& addr : *addresses_or) { for (const auto& addr : *addresses_or) {
const grpc_sockaddr* sock_addr = const grpc_sockaddr* sock_addr =

Loading…
Cancel
Save