diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc941c0820c..5ad4e0c981a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2159,6 +2159,7 @@ add_library(grpc
src/core/lib/event_engine/ares_resolver.cc
src/core/lib/event_engine/cf_engine/cf_engine.cc
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
src/core/lib/event_engine/channel_args_endpoint_config.cc
src/core/lib/event_engine/default_event_engine.cc
src/core/lib/event_engine/default_event_engine_factory.cc
@@ -2868,6 +2869,7 @@ add_library(grpc_unsecure
src/core/lib/event_engine/ares_resolver.cc
src/core/lib/event_engine/cf_engine/cf_engine.cc
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
src/core/lib/event_engine/channel_args_endpoint_config.cc
src/core/lib/event_engine/default_event_engine.cc
src/core/lib/event_engine/default_event_engine_factory.cc
@@ -4406,6 +4408,7 @@ add_library(grpc_authorization_provider
src/core/lib/event_engine/ares_resolver.cc
src/core/lib/event_engine/cf_engine/cf_engine.cc
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
src/core/lib/event_engine/channel_args_endpoint_config.cc
src/core/lib/event_engine/default_event_engine.cc
src/core/lib/event_engine/default_event_engine_factory.cc
@@ -12485,6 +12488,7 @@ add_executable(frame_test
src/core/lib/event_engine/ares_resolver.cc
src/core/lib/event_engine/cf_engine/cf_engine.cc
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
src/core/lib/event_engine/channel_args_endpoint_config.cc
src/core/lib/event_engine/default_event_engine.cc
src/core/lib/event_engine/default_event_engine_factory.cc
diff --git a/Makefile b/Makefile
index f1a04b993b0..7e39779d5a1 100644
--- a/Makefile
+++ b/Makefile
@@ -1440,6 +1440,7 @@ LIBGRPC_SRC = \
src/core/lib/event_engine/ares_resolver.cc \
src/core/lib/event_engine/cf_engine/cf_engine.cc \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc \
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc \
src/core/lib/event_engine/channel_args_endpoint_config.cc \
src/core/lib/event_engine/default_event_engine.cc \
src/core/lib/event_engine/default_event_engine_factory.cc \
@@ -2002,6 +2003,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/event_engine/ares_resolver.cc \
src/core/lib/event_engine/cf_engine/cf_engine.cc \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc \
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc \
src/core/lib/event_engine/channel_args_endpoint_config.cc \
src/core/lib/event_engine/default_event_engine.cc \
src/core/lib/event_engine/default_event_engine_factory.cc \
diff --git a/Package.swift b/Package.swift
index b712cd822d9..56699d86e08 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1069,6 +1069,8 @@ let package = Package(
"src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc",
"src/core/lib/event_engine/cf_engine/cfstream_endpoint.h",
"src/core/lib/event_engine/cf_engine/cftype_unique_ref.h",
+ "src/core/lib/event_engine/cf_engine/dns_service_resolver.cc",
+ "src/core/lib/event_engine/cf_engine/dns_service_resolver.h",
"src/core/lib/event_engine/channel_args_endpoint_config.cc",
"src/core/lib/event_engine/channel_args_endpoint_config.h",
"src/core/lib/event_engine/common_closures.h",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 607b4493de8..93759c1d0a8 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -687,6 +687,7 @@ libs:
- src/core/lib/event_engine/cf_engine/cf_engine.h
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.h
- src/core/lib/event_engine/cf_engine/cftype_unique_ref.h
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.h
- src/core/lib/event_engine/channel_args_endpoint_config.h
- src/core/lib/event_engine/common_closures.h
- src/core/lib/event_engine/default_event_engine.h
@@ -1501,6 +1502,7 @@ libs:
- src/core/lib/event_engine/ares_resolver.cc
- src/core/lib/event_engine/cf_engine/cf_engine.cc
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
- src/core/lib/event_engine/channel_args_endpoint_config.cc
- src/core/lib/event_engine/default_event_engine.cc
- src/core/lib/event_engine/default_event_engine_factory.cc
@@ -2084,6 +2086,7 @@ libs:
- src/core/lib/event_engine/cf_engine/cf_engine.h
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.h
- src/core/lib/event_engine/cf_engine/cftype_unique_ref.h
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.h
- src/core/lib/event_engine/channel_args_endpoint_config.h
- src/core/lib/event_engine/common_closures.h
- src/core/lib/event_engine/default_event_engine.h
@@ -2505,6 +2508,7 @@ libs:
- src/core/lib/event_engine/ares_resolver.cc
- src/core/lib/event_engine/cf_engine/cf_engine.cc
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
- src/core/lib/event_engine/channel_args_endpoint_config.cc
- src/core/lib/event_engine/default_event_engine.cc
- src/core/lib/event_engine/default_event_engine_factory.cc
@@ -3592,6 +3596,7 @@ libs:
- src/core/lib/event_engine/cf_engine/cf_engine.h
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.h
- src/core/lib/event_engine/cf_engine/cftype_unique_ref.h
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.h
- src/core/lib/event_engine/channel_args_endpoint_config.h
- src/core/lib/event_engine/common_closures.h
- src/core/lib/event_engine/default_event_engine.h
@@ -3892,6 +3897,7 @@ libs:
- src/core/lib/event_engine/ares_resolver.cc
- src/core/lib/event_engine/cf_engine/cf_engine.cc
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
- src/core/lib/event_engine/channel_args_endpoint_config.cc
- src/core/lib/event_engine/default_event_engine.cc
- src/core/lib/event_engine/default_event_engine_factory.cc
@@ -8127,6 +8133,7 @@ targets:
- src/core/lib/event_engine/cf_engine/cf_engine.h
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.h
- src/core/lib/event_engine/cf_engine/cftype_unique_ref.h
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.h
- src/core/lib/event_engine/channel_args_endpoint_config.h
- src/core/lib/event_engine/common_closures.h
- src/core/lib/event_engine/default_event_engine.h
@@ -8409,6 +8416,7 @@ targets:
- src/core/lib/event_engine/ares_resolver.cc
- src/core/lib/event_engine/cf_engine/cf_engine.cc
- src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+ - src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
- src/core/lib/event_engine/channel_args_endpoint_config.cc
- src/core/lib/event_engine/default_event_engine.cc
- src/core/lib/event_engine/default_event_engine_factory.cc
diff --git a/config.m4 b/config.m4
index 7963168b683..93a4b2c5b50 100644
--- a/config.m4
+++ b/config.m4
@@ -522,6 +522,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/event_engine/ares_resolver.cc \
src/core/lib/event_engine/cf_engine/cf_engine.cc \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc \
+ src/core/lib/event_engine/cf_engine/dns_service_resolver.cc \
src/core/lib/event_engine/channel_args_endpoint_config.cc \
src/core/lib/event_engine/default_event_engine.cc \
src/core/lib/event_engine/default_event_engine_factory.cc \
diff --git a/config.w32 b/config.w32
index e8412bdeb19..6de00278ef0 100644
--- a/config.w32
+++ b/config.w32
@@ -487,6 +487,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\event_engine\\ares_resolver.cc " +
"src\\core\\lib\\event_engine\\cf_engine\\cf_engine.cc " +
"src\\core\\lib\\event_engine\\cf_engine\\cfstream_endpoint.cc " +
+ "src\\core\\lib\\event_engine\\cf_engine\\dns_service_resolver.cc " +
"src\\core\\lib\\event_engine\\channel_args_endpoint_config.cc " +
"src\\core\\lib\\event_engine\\default_event_engine.cc " +
"src\\core\\lib\\event_engine\\default_event_engine_factory.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 0ff4a859756..d9590738516 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -758,6 +758,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/cf_engine/cf_engine.h',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.h',
'src/core/lib/event_engine/cf_engine/cftype_unique_ref.h',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.h',
'src/core/lib/event_engine/channel_args_endpoint_config.h',
'src/core/lib/event_engine/common_closures.h',
'src/core/lib/event_engine/default_event_engine.h',
@@ -1807,6 +1808,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/cf_engine/cf_engine.h',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.h',
'src/core/lib/event_engine/cf_engine/cftype_unique_ref.h',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.h',
'src/core/lib/event_engine/channel_args_endpoint_config.h',
'src/core/lib/event_engine/common_closures.h',
'src/core/lib/event_engine/default_event_engine.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 1f7ee059f52..c6f4811efe8 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1170,6 +1170,8 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.h',
'src/core/lib/event_engine/cf_engine/cftype_unique_ref.h',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.h',
'src/core/lib/event_engine/channel_args_endpoint_config.cc',
'src/core/lib/event_engine/channel_args_endpoint_config.h',
'src/core/lib/event_engine/common_closures.h',
@@ -2542,6 +2544,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/cf_engine/cf_engine.h',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.h',
'src/core/lib/event_engine/cf_engine/cftype_unique_ref.h',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.h',
'src/core/lib/event_engine/channel_args_endpoint_config.h',
'src/core/lib/event_engine/common_closures.h',
'src/core/lib/event_engine/default_event_engine.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 8eecc38bea7..d3d4df3b6cc 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1075,6 +1075,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc )
s.files += %w( src/core/lib/event_engine/cf_engine/cfstream_endpoint.h )
s.files += %w( src/core/lib/event_engine/cf_engine/cftype_unique_ref.h )
+ s.files += %w( src/core/lib/event_engine/cf_engine/dns_service_resolver.cc )
+ s.files += %w( src/core/lib/event_engine/cf_engine/dns_service_resolver.h )
s.files += %w( src/core/lib/event_engine/channel_args_endpoint_config.cc )
s.files += %w( src/core/lib/event_engine/channel_args_endpoint_config.h )
s.files += %w( src/core/lib/event_engine/common_closures.h )
diff --git a/grpc.gyp b/grpc.gyp
index 9a53deff7e9..4ac488d26ea 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -744,6 +744,7 @@
'src/core/lib/event_engine/ares_resolver.cc',
'src/core/lib/event_engine/cf_engine/cf_engine.cc',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc',
'src/core/lib/event_engine/channel_args_endpoint_config.cc',
'src/core/lib/event_engine/default_event_engine.cc',
'src/core/lib/event_engine/default_event_engine_factory.cc',
@@ -1245,6 +1246,7 @@
'src/core/lib/event_engine/ares_resolver.cc',
'src/core/lib/event_engine/cf_engine/cf_engine.cc',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc',
'src/core/lib/event_engine/channel_args_endpoint_config.cc',
'src/core/lib/event_engine/default_event_engine.cc',
'src/core/lib/event_engine/default_event_engine_factory.cc',
@@ -1766,6 +1768,7 @@
'src/core/lib/event_engine/ares_resolver.cc',
'src/core/lib/event_engine/cf_engine/cf_engine.cc',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc',
'src/core/lib/event_engine/channel_args_endpoint_config.cc',
'src/core/lib/event_engine/default_event_engine.cc',
'src/core/lib/event_engine/default_event_engine_factory.cc',
diff --git a/package.xml b/package.xml
index 00f44d11922..3a8afe9b3fd 100644
--- a/package.xml
+++ b/package.xml
@@ -1057,6 +1057,8 @@
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index cda8d1c32ee..cf94603020d 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -2123,13 +2123,18 @@ grpc_cc_library(
srcs = [
"lib/event_engine/cf_engine/cf_engine.cc",
"lib/event_engine/cf_engine/cfstream_endpoint.cc",
+ "lib/event_engine/cf_engine/dns_service_resolver.cc",
],
hdrs = [
"lib/event_engine/cf_engine/cf_engine.h",
"lib/event_engine/cf_engine/cfstream_endpoint.h",
"lib/event_engine/cf_engine/cftype_unique_ref.h",
+ "lib/event_engine/cf_engine/dns_service_resolver.h",
+ ],
+ external_deps = [
+ "absl/container:flat_hash_map",
+ "absl/strings:str_format",
],
- external_deps = ["absl/strings:str_format"],
deps = [
"event_engine_common",
"event_engine_tcp_socket_utils",
@@ -2145,6 +2150,7 @@ grpc_cc_library(
"strerror",
"//:event_engine_base_hdrs",
"//:gpr",
+ "//:parse_address",
"//:ref_counted_ptr",
"//:sockaddr_utils",
],
diff --git a/src/core/lib/event_engine/cf_engine/cf_engine.cc b/src/core/lib/event_engine/cf_engine/cf_engine.cc
index f835e64a21e..af0b7248d19 100644
--- a/src/core/lib/event_engine/cf_engine/cf_engine.cc
+++ b/src/core/lib/event_engine/cf_engine/cf_engine.cc
@@ -22,6 +22,7 @@
#include "src/core/lib/event_engine/cf_engine/cf_engine.h"
#include "src/core/lib/event_engine/cf_engine/cfstream_endpoint.h"
+#include "src/core/lib/event_engine/cf_engine/dns_service_resolver.h"
#include "src/core/lib/event_engine/posix_engine/timer_manager.h"
#include "src/core/lib/event_engine/tcp_socket_utils.h"
#include "src/core/lib/event_engine/thread_pool/thread_pool.h"
@@ -156,9 +157,14 @@ bool CFEventEngine::CancelConnectInternal(ConnectionHandle handle,
bool CFEventEngine::IsWorkerThread() { grpc_core::Crash("unimplemented"); }
absl::StatusOr>
-CFEventEngine::GetDNSResolver(
- const DNSResolver::ResolverOptions& /* options */) {
- grpc_core::Crash("unimplemented");
+CFEventEngine::GetDNSResolver(const DNSResolver::ResolverOptions& options) {
+ if (!options.dns_server.empty()) {
+ return absl::InvalidArgumentError(
+ "CFEventEngine does not support custom DNS servers");
+ }
+
+ return std::make_unique(
+ std::static_pointer_cast(shared_from_this()));
}
void CFEventEngine::Run(EventEngine::Closure* closure) {
diff --git a/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc b/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
new file mode 100644
index 00000000000..6e30f478ffc
--- /dev/null
+++ b/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
@@ -0,0 +1,229 @@
+// Copyright 2023 The 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.
+
+#include
+
+#ifdef GPR_APPLE
+
+#include "absl/strings/str_format.h"
+
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/event_engine/cf_engine/dns_service_resolver.h"
+#include "src/core/lib/event_engine/posix_engine/lockfree_event.h"
+#include "src/core/lib/event_engine/tcp_socket_utils.h"
+#include "src/core/lib/event_engine/trace.h"
+#include "src/core/lib/gprpp/host_port.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+void DNSServiceResolverImpl::LookupHostname(
+ EventEngine::DNSResolver::LookupHostnameCallback on_resolve,
+ absl::string_view name, absl::string_view default_port) {
+ GRPC_EVENT_ENGINE_DNS_TRACE(
+ "DNSServiceResolverImpl::LookupHostname: name: %.*s, default_port: %.*s, "
+ "this: %p",
+ static_cast(name.length()), name.data(),
+ static_cast(default_port.length()), default_port.data(), this);
+
+ absl::string_view host;
+ absl::string_view port_string;
+ if (!grpc_core::SplitHostPort(name, &host, &port_string)) {
+ engine_->Run([on_resolve = std::move(on_resolve),
+ status = absl::InvalidArgumentError(
+ absl::StrCat("Unparseable name: ", name))]() mutable {
+ on_resolve(status);
+ });
+ return;
+ }
+ GPR_ASSERT(!host.empty());
+ if (port_string.empty()) {
+ if (default_port.empty()) {
+ engine_->Run([on_resolve = std::move(on_resolve),
+ status = absl::InvalidArgumentError(absl::StrFormat(
+ "No port in name %s or default_port argument",
+ name))]() mutable { on_resolve(std::move(status)); });
+ return;
+ }
+ port_string = default_port;
+ }
+
+ int port = 0;
+ if (port_string == "http") {
+ port = 80;
+ } else if (port_string == "https") {
+ port = 443;
+ } else if (!absl::SimpleAtoi(port_string, &port)) {
+ engine_->Run([on_resolve = std::move(on_resolve),
+ status = absl::InvalidArgumentError(absl::StrCat(
+ "Failed to parse port in name: ", name))]() mutable {
+ on_resolve(std::move(status));
+ });
+ return;
+ }
+
+ // TODO(yijiem): Change this when refactoring code in
+ // src/core/lib/address_utils to use EventEngine::ResolvedAddress.
+ grpc_resolved_address addr;
+ const std::string hostport = grpc_core::JoinHostPort(host, port);
+ if (grpc_parse_ipv4_hostport(hostport.c_str(), &addr,
+ /*log_errors=*/false) ||
+ grpc_parse_ipv6_hostport(hostport.c_str(), &addr,
+ /*log_errors=*/false)) {
+ // Early out if the target is an ipv4 or ipv6 literal, otherwise dns service
+ // responses with kDNSServiceErr_NoSuchRecord
+ std::vector result;
+ result.emplace_back(reinterpret_cast(addr.addr), addr.len);
+ engine_->Run([on_resolve = std::move(on_resolve),
+ result = std::move(result)]() mutable {
+ on_resolve(std::move(result));
+ });
+ return;
+ }
+
+ DNSServiceRef sdRef;
+ auto host_string = std::string{host};
+ auto error = DNSServiceGetAddrInfo(
+ &sdRef, kDNSServiceFlagsTimeout | kDNSServiceFlagsReturnIntermediates, 0,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, host_string.c_str(),
+ &DNSServiceResolverImpl::ResolveCallback, this /* do not Ref */);
+
+ if (error != kDNSServiceErr_NoError) {
+ engine_->Run([on_resolve = std::move(on_resolve),
+ status = absl::UnknownError(absl::StrFormat(
+ "DNSServiceGetAddrInfo failed with error:%d",
+ error))]() mutable { on_resolve(std::move(status)); });
+ return;
+ }
+
+ grpc_core::ReleasableMutexLock lock(&request_mu_);
+
+ error = DNSServiceSetDispatchQueue(sdRef, queue_);
+ if (error != kDNSServiceErr_NoError) {
+ engine_->Run([on_resolve = std::move(on_resolve),
+ status = absl::UnknownError(absl::StrFormat(
+ "DNSServiceSetDispatchQueue failed with error:%d",
+ error))]() mutable { on_resolve(std::move(status)); });
+ return;
+ }
+
+ requests_.try_emplace(
+ sdRef, DNSServiceRequest{
+ std::move(on_resolve), static_cast(port), {}});
+}
+
+/* static */
+void DNSServiceResolverImpl::ResolveCallback(
+ DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char* hostname,
+ const struct sockaddr* address, uint32_t ttl, void* context) {
+ GRPC_EVENT_ENGINE_DNS_TRACE(
+ "DNSServiceResolverImpl::ResolveCallback: sdRef: %p, flags: %x, "
+ "interface: %d, errorCode: %d, hostname: %s, addressFamily: %d, ttl: "
+ "%d, "
+ "this: %p",
+ sdRef, flags, interfaceIndex, errorCode, hostname, address->sa_family,
+ ttl, context);
+
+ // no need to increase refcount here, since ResolveCallback and Shutdown is
+ // called from the serial queue and it is guarenteed that it won't be called
+ // after the sdRef is deallocated
+ auto that = static_cast(context);
+
+ grpc_core::ReleasableMutexLock lock(&that->request_mu_);
+ auto request_it = that->requests_.find(sdRef);
+ GPR_ASSERT(request_it != that->requests_.end());
+ auto& request = request_it->second;
+
+ if (errorCode != kDNSServiceErr_NoError &&
+ errorCode != kDNSServiceErr_NoSuchRecord) {
+ request.on_resolve(absl::UnknownError(absl::StrFormat(
+ "address lookup failed for %s: errorCode: %d", hostname, errorCode)));
+ that->requests_.erase(request_it);
+ DNSServiceRefDeallocate(sdRef);
+ return;
+ }
+
+ // set received ipv4 or ipv6 response, even for kDNSServiceErr_NoSuchRecord to
+ // mark that the response for the stack is received, it is possible that the
+ // one stack receives some results and the other stack gets
+ // kDNSServiceErr_NoSuchRecord error.
+ if (address->sa_family == AF_INET) {
+ request.has_ipv4_response = true;
+ } else if (address->sa_family == AF_INET6) {
+ request.has_ipv6_response = true;
+ }
+
+ // collect results if there is no error (not kDNSServiceErr_NoSuchRecord)
+ if (errorCode == kDNSServiceErr_NoError) {
+ request.result.emplace_back(address, address->sa_len);
+ auto& resolved_address = request.result.back();
+ if (address->sa_family == AF_INET) {
+ (const_cast(
+ reinterpret_cast(resolved_address.address())))
+ ->sin_port = htons(request.port);
+ } else if (address->sa_family == AF_INET6) {
+ (const_cast(
+ reinterpret_cast(resolved_address.address())))
+ ->sin6_port = htons(request.port);
+ }
+
+ GRPC_EVENT_ENGINE_DNS_TRACE(
+ "DNSServiceResolverImpl::ResolveCallback: "
+ "sdRef: %p, hostname: %s, addressPort: %s, this: %p",
+ sdRef, hostname,
+ ResolvedAddressToString(resolved_address).value_or("ERROR").c_str(),
+ context);
+ }
+
+ // received both ipv4 and ipv6 responses, and no more responses (e.g. multiple
+ // IP addresses for a domain name) are coming, finish `LookupHostname` resolve
+ // with the collected results.
+ if (!(flags & kDNSServiceFlagsMoreComing) && request.has_ipv4_response &&
+ request.has_ipv6_response) {
+ if (request.result.empty()) {
+ request.on_resolve(absl::NotFoundError(absl::StrFormat(
+ "address lookup failed for %s: Domain name not found", hostname)));
+ } else {
+ request.on_resolve(std::move(request.result));
+ }
+ that->requests_.erase(request_it);
+ DNSServiceRefDeallocate(sdRef);
+ }
+}
+
+void DNSServiceResolverImpl::Shutdown() {
+ dispatch_async_f(queue_, Ref().release(), [](void* thatPtr) {
+ grpc_core::RefCountedPtr that{
+ static_cast(thatPtr)};
+ grpc_core::MutexLock lock(&that->request_mu_);
+ for (auto& kv : that->requests_) {
+ auto& sdRef = kv.first;
+ auto& request = kv.second;
+ GRPC_EVENT_ENGINE_DNS_TRACE(
+ "DNSServiceResolverImpl::Shutdown sdRef: %p, this: %p", sdRef,
+ thatPtr);
+
+ request.on_resolve(
+ absl::CancelledError("DNSServiceResolverImpl::Shutdown"));
+ DNSServiceRefDeallocate(static_cast(sdRef));
+ }
+ that->requests_.clear();
+ });
+}
+
+} // namespace experimental
+} // namespace grpc_event_engine
+
+#endif // GPR_APPLE
diff --git a/src/core/lib/event_engine/cf_engine/dns_service_resolver.h b/src/core/lib/event_engine/cf_engine/dns_service_resolver.h
new file mode 100644
index 00000000000..00a55a30500
--- /dev/null
+++ b/src/core/lib/event_engine/cf_engine/dns_service_resolver.h
@@ -0,0 +1,117 @@
+// Copyright 2023 The 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_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H
+#define GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H
+#include
+
+#ifdef GPR_APPLE
+
+#include
+#include
+
+#include "absl/container/flat_hash_map.h"
+
+#include
+
+#include "src/core/lib/event_engine/cf_engine/cf_engine.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+class DNSServiceResolverImpl
+ : public grpc_core::RefCounted {
+ struct DNSServiceRequest {
+ EventEngine::DNSResolver::LookupHostnameCallback on_resolve;
+ uint16_t port;
+ std::vector result;
+ bool has_ipv4_response = false;
+ bool has_ipv6_response = false;
+ };
+
+ public:
+ explicit DNSServiceResolverImpl(std::shared_ptr engine)
+ : engine_(std::move((engine))) {}
+ ~DNSServiceResolverImpl() override {
+ GPR_ASSERT(requests_.empty());
+ dispatch_release(queue_);
+ }
+
+ void Shutdown();
+
+ void LookupHostname(
+ EventEngine::DNSResolver::LookupHostnameCallback on_resolve,
+ absl::string_view name, absl::string_view default_port);
+
+ private:
+ static void ResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* hostname,
+ const struct sockaddr* address, uint32_t ttl,
+ void* context);
+
+ private:
+ std::shared_ptr engine_;
+ // DNSServiceSetDispatchQueue requires a serial dispatch queue
+ dispatch_queue_t queue_ =
+ dispatch_queue_create("dns_service_resolver", nullptr);
+ grpc_core::Mutex request_mu_;
+ absl::flat_hash_map requests_
+ ABSL_GUARDED_BY(request_mu_);
+};
+
+class DNSServiceResolver : public EventEngine::DNSResolver {
+ public:
+ explicit DNSServiceResolver(std::shared_ptr engine)
+ : engine_(std::move(engine)),
+ impl_(grpc_core::MakeRefCounted(
+ std::move((engine_)))) {}
+
+ ~DNSServiceResolver() override { impl_->Shutdown(); }
+
+ void LookupHostname(
+ EventEngine::DNSResolver::LookupHostnameCallback on_resolve,
+ absl::string_view name, absl::string_view default_port) override {
+ impl_->LookupHostname(std::move(on_resolve), name, default_port);
+ };
+
+ void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolve,
+ absl::string_view /* name */) override {
+ engine_->Run([on_resolve = std::move(on_resolve)]() mutable {
+ on_resolve(absl::UnimplementedError(
+ "The DNS Service resolver does not support looking up SRV records"));
+ });
+ }
+
+ void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolve,
+ absl::string_view /* name */) override {
+ engine_->Run([on_resolve = std::move(on_resolve)]() mutable {
+ on_resolve(absl::UnimplementedError(
+ "The DNS Service resolver does not support looking up TXT records"));
+ });
+ }
+
+ private:
+ std::shared_ptr engine_;
+ grpc_core::RefCountedPtr impl_;
+};
+
+} // namespace experimental
+} // namespace grpc_event_engine
+
+#endif // GPR_APPLE
+
+#endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H
diff --git a/src/objective-c/tests/BUILD b/src/objective-c/tests/BUILD
index 9eef39eaba6..d5544d6cdf2 100644
--- a/src/objective-c/tests/BUILD
+++ b/src/objective-c/tests/BUILD
@@ -334,20 +334,36 @@ grpc_objc_ios_unit_test(
)
grpc_objc_testing_library(
- name = "EventEngineTests-lib",
- srcs = glob(["EventEngineTests/*.mm"]),
+ name = "EventEngineClientTests-lib",
+ srcs = ["EventEngineTests/CFEventEngineClientTests.mm"],
# defines = ["GRPC_IOS_EVENT_ENGINE_CLIENT=1"],
deps = [
"//src/core:cf_event_engine",
"//test/core/event_engine/test_suite/posix:oracle_event_engine_posix",
"//test/core/event_engine/test_suite/tests:client",
+ ],
+)
+
+grpc_objc_testing_library(
+ name = "EventEngineUnitTests-lib",
+ srcs = ["EventEngineTests/CFEventEngineUnitTests.mm"],
+ defines = ["GRPC_IOS_EVENT_ENGINE_CLIENT=1"],
+ deps = [
+ "//src/core:cf_event_engine",
+ "//test/core/event_engine/cf:cf_engine_unit_test_lib",
+ "//test/core/event_engine/test_suite/tests:dns",
"//test/core/event_engine/test_suite/tests:timer",
],
)
grpc_objc_ios_unit_test(
- name = "EventEngineTests",
- deps = [":EventEngineTests-lib"],
+ name = "EventEngineClientTests",
+ deps = [":EventEngineClientTests-lib"],
+)
+
+grpc_objc_ios_unit_test(
+ name = "EventEngineUnitTests",
+ deps = [":EventEngineUnitTests-lib"],
)
# Note that bazel currently doesn't support running tvos_unit_test
diff --git a/src/objective-c/tests/EventEngineTests/CFEventEngineTests.mm b/src/objective-c/tests/EventEngineTests/CFEventEngineClientTests.mm
similarity index 94%
rename from src/objective-c/tests/EventEngineTests/CFEventEngineTests.mm
rename to src/objective-c/tests/EventEngineTests/CFEventEngineClientTests.mm
index 2f32a409314..c5a4e1c9cef 100644
--- a/src/objective-c/tests/EventEngineTests/CFEventEngineTests.mm
+++ b/src/objective-c/tests/EventEngineTests/CFEventEngineClientTests.mm
@@ -24,7 +24,6 @@
#include "test/core/event_engine/test_suite/event_engine_test_framework.h"
#include "test/core/event_engine/test_suite/posix/oracle_event_engine_posix.h"
#include "test/core/event_engine/test_suite/tests/client_test.h"
-#include "test/core/event_engine/test_suite/tests/timer_test.h"
#include "test/core/util/test_config.h"
@interface EventEngineTimerTests : XCTestCase
@@ -51,7 +50,6 @@
return std::make_unique();
};
SetEventEngineFactories(factory, oracle_factory);
- grpc_event_engine::experimental::InitTimerTests();
grpc_event_engine::experimental::InitClientTests();
// TODO(ctiller): EventEngine temporarily needs grpc to be initialized first
// until we clear out the iomgr shutdown code.
diff --git a/src/objective-c/tests/EventEngineTests/CFEventEngineUnitTests.mm b/src/objective-c/tests/EventEngineTests/CFEventEngineUnitTests.mm
new file mode 100644
index 00000000000..d81b25aa8c3
--- /dev/null
+++ b/src/objective-c/tests/EventEngineTests/CFEventEngineUnitTests.mm
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2023 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.
+ *
+ */
+
+#import
+
+#include
+
+#include "src/core/lib/event_engine/cf_engine/cf_engine.h"
+#include "test/core/event_engine/test_suite/event_engine_test_framework.h"
+#include "test/core/event_engine/test_suite/tests/dns_test.h"
+#include "test/core/event_engine/test_suite/tests/timer_test.h"
+#include "test/core/util/test_config.h"
+
+@interface EventEngineTimerTests : XCTestCase
+@end
+
+@implementation EventEngineTimerTests
+
+- (void)testAll {
+ NSArray *arguments = [NSProcessInfo processInfo].arguments;
+ int argc = (int)arguments.count;
+ char **argv = static_cast(alloca((sizeof(char *) * (argc + 1))));
+ for (int index = 0; index < argc; index++) {
+ argv[index] = const_cast([arguments[index] UTF8String]);
+ }
+ argv[argc] = NULL;
+
+ testing::InitGoogleTest(&argc, (char **)argv);
+ grpc::testing::TestEnvironment env(&argc, (char **)argv);
+
+ auto factory = []() {
+ return std::make_unique();
+ };
+ SetEventEngineFactories(factory, nullptr);
+ grpc_event_engine::experimental::InitTimerTests();
+ grpc_event_engine::experimental::InitDNSTests();
+ // TODO(ctiller): EventEngine temporarily needs grpc to be initialized first
+ // until we clear out the iomgr shutdown code.
+ grpc_init();
+ int r = RUN_ALL_TESTS();
+ grpc_shutdown();
+
+ XCTAssertEqual(r, 0);
+}
+
+@end
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 3a03e18ac08..76fbcce089e 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -496,6 +496,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/event_engine/ares_resolver.cc',
'src/core/lib/event_engine/cf_engine/cf_engine.cc',
'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc',
+ 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc',
'src/core/lib/event_engine/channel_args_endpoint_config.cc',
'src/core/lib/event_engine/default_event_engine.cc',
'src/core/lib/event_engine/default_event_engine_factory.cc',
diff --git a/test/core/event_engine/cf/BUILD b/test/core/event_engine/cf/BUILD
index 9bc735bc860..244df0d8860 100644
--- a/test/core/event_engine/cf/BUILD
+++ b/test/core/event_engine/cf/BUILD
@@ -12,10 +12,32 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test")
licenses(["notice"])
+grpc_cc_library(
+ name = "cf_engine_unit_test_lib",
+ testonly = True,
+ srcs = ["cf_engine_test.cc"],
+ external_deps = ["gtest"],
+ language = "C++",
+ tags = [
+ "no_linux",
+ "no_windows",
+ ],
+ visibility = [
+ "//src/objective-c/tests:__subpackages__",
+ "//test:__subpackages__",
+ ],
+ deps = [
+ "//:gpr_platform",
+ "//src/core:cf_event_engine",
+ "//test/core/util:grpc_test_util",
+ ],
+ alwayslink = 1,
+)
+
grpc_cc_test(
name = "cf_engine_test",
timeout = "short",
diff --git a/test/core/event_engine/cf/cf_engine_test.cc b/test/core/event_engine/cf/cf_engine_test.cc
index f50b40f82fa..ae9e540b359 100644
--- a/test/core/event_engine/cf/cf_engine_test.cc
+++ b/test/core/event_engine/cf/cf_engine_test.cc
@@ -19,6 +19,8 @@
#include
#include "absl/status/status.h"
+#include "absl/strings/str_format.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include
@@ -80,6 +82,215 @@ TEST(CFEventEngineTest, TestConnectionCancelled) {
client_signal.WaitForNotification();
}
+namespace {
+std::vector ResolvedAddressesToStrings(
+ const std::vector addresses) {
+ std::vector ip_strings;
+ std::transform(addresses.cbegin(), addresses.cend(),
+ std::back_inserter(ip_strings), [](auto const& address) {
+ return ResolvedAddressToString(address).value_or("ERROR");
+ });
+ return ip_strings;
+}
+} // namespace
+
+TEST(CFEventEngineTest, TestCreateDNSResolver) {
+ grpc_core::MemoryQuota memory_quota("cf_engine_test");
+ auto cf_engine = std::make_shared();
+
+ EXPECT_TRUE(cf_engine->GetDNSResolver({}).status().ok());
+ EXPECT_TRUE(cf_engine->GetDNSResolver({.dns_server = ""}).status().ok());
+ EXPECT_EQ(
+ cf_engine->GetDNSResolver({.dns_server = "8.8.8.8"}).status().code(),
+ absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(
+ cf_engine->GetDNSResolver({.dns_server = "8.8.8.8:53"}).status().code(),
+ absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(
+ cf_engine->GetDNSResolver({.dns_server = "invalid"}).status().code(),
+ absl::StatusCode::kInvalidArgument);
+}
+
+TEST(CFEventEngineTest, TestResolveLocalhost) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(ResolvedAddressesToStrings(result.value()),
+ testing::UnorderedElementsAre("127.0.0.1:80", "[::1]:80"));
+
+ resolve_signal.Notify();
+ },
+ "localhost", "80");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveRemote) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(ResolvedAddressesToStrings(result.value()),
+ testing::UnorderedElementsAre("127.0.0.1:80", "[::1]:80"));
+
+ resolve_signal.Notify();
+ },
+ "localtest.me:80", "443");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveIPv4Remote) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(ResolvedAddressesToStrings(result.value()),
+ testing::IsSubsetOf(
+ {"1.2.3.4:80", "[64:ff9b::102:304]:80" /*NAT64*/}));
+
+ resolve_signal.Notify();
+ },
+ "1.2.3.4.nip.io:80", "");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveIPv6Remote) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(
+ ResolvedAddressesToStrings(result.value()),
+ testing::UnorderedElementsAre("[2607:f8b0:400a:801::1002]:80"));
+
+ resolve_signal.Notify();
+ },
+ "2607-f8b0-400a-801--1002.sslip.io.", "80");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveIPv4Literal) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(ResolvedAddressesToStrings(result.value()),
+ testing::UnorderedElementsAre("1.2.3.4:443"));
+
+ resolve_signal.Notify();
+ },
+ "1.2.3.4", "https");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveIPv6Literal) {
+ grpc_core::Notification resolve_signal;
+
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = cf_engine->GetDNSResolver({});
+
+ dns_resolver.value()->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(
+ ResolvedAddressesToStrings(result.value()),
+ testing::UnorderedElementsAre("[2607:f8b0:400a:801::1002]:443"));
+
+ resolve_signal.Notify();
+ },
+ "[2607:f8b0:400a:801::1002]", "443");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveNoRecord) {
+ grpc_core::Notification resolve_signal;
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = std::move(cf_engine->GetDNSResolver({})).value();
+
+ dns_resolver->LookupHostname(
+ [&resolve_signal](auto result) {
+ EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound);
+
+ resolve_signal.Notify();
+ },
+ "nonexisting-target.dns-test.event-engine.", "443");
+
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveCanceled) {
+ grpc_core::Notification resolve_signal;
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = std::move(cf_engine->GetDNSResolver({})).value();
+
+ dns_resolver->LookupHostname(
+ [&resolve_signal](auto result) {
+ // query may have already finished before canceling, only verity the
+ // code if status is not ok
+ if (!result.status().ok()) {
+ EXPECT_EQ(result.status().code(), absl::StatusCode::kCancelled);
+ }
+
+ resolve_signal.Notify();
+ },
+ "dont-care-since-wont-be-resolved.localtest.me", "443");
+
+ dns_resolver.reset();
+ resolve_signal.WaitForNotification();
+}
+
+TEST(CFEventEngineTest, TestResolveMany) {
+ std::atomic times{10};
+ grpc_core::Notification resolve_signal;
+ auto cf_engine = std::make_shared();
+ auto dns_resolver = std::move(cf_engine->GetDNSResolver({})).value();
+
+ for (int i = times; i >= 1; --i) {
+ dns_resolver->LookupHostname(
+ [&resolve_signal, ×, i](auto result) {
+ EXPECT_TRUE(result.status().ok());
+ EXPECT_THAT(
+ ResolvedAddressesToStrings(result.value()),
+ testing::IsSubsetOf(
+ {absl::StrFormat("100.0.0.%d:443", i),
+ absl::StrFormat("[64:ff9b::6400:%x]:443", i) /*NAT64*/}));
+
+ if (--times == 0) {
+ resolve_signal.Notify();
+ }
+ },
+ absl::StrFormat("100.0.0.%d.nip.io", i), "443");
+ }
+
+ resolve_signal.WaitForNotification();
+}
+
} // namespace experimental
} // namespace grpc_event_engine
diff --git a/test/core/event_engine/test_suite/BUILD b/test/core/event_engine/test_suite/BUILD
index cc485a4d9a2..385aa7bb6a2 100644
--- a/test/core/event_engine/test_suite/BUILD
+++ b/test/core/event_engine/test_suite/BUILD
@@ -96,6 +96,7 @@ grpc_cc_test(
grpc_cc_test(
name = "cf_event_engine_test",
srcs = ["cf_event_engine_test.cc"],
+ copts = ["-DGRPC_IOS_EVENT_ENGINE_CLIENT=1"],
tags = [
"no_linux",
"no_windows",
diff --git a/test/core/event_engine/test_suite/cf_event_engine_test.cc b/test/core/event_engine/test_suite/cf_event_engine_test.cc
index 1d222514cb6..8372e448358 100644
--- a/test/core/event_engine/test_suite/cf_event_engine_test.cc
+++ b/test/core/event_engine/test_suite/cf_event_engine_test.cc
@@ -37,8 +37,6 @@ int main(int argc, char** argv) {
SetEventEngineFactories(factory, oracle_factory);
grpc_event_engine::experimental::InitTimerTests();
grpc_event_engine::experimental::InitClientTests();
- // TODO(vigneshbabu): remove when the experiment is over
- grpc_core::ForceEnableExperiment("event_engine_client", true);
// TODO(ctiller): EventEngine temporarily needs grpc to be initialized first
// until we clear out the iomgr shutdown code.
grpc_init();
diff --git a/test/core/event_engine/test_suite/tests/dns_test.cc b/test/core/event_engine/test_suite/tests/dns_test.cc
index cbd48e26bc7..5149959c82b 100644
--- a/test/core/event_engine/test_suite/tests/dns_test.cc
+++ b/test/core/event_engine/test_suite/tests/dns_test.cc
@@ -102,6 +102,7 @@ MATCHER(StatusCodeEq, "") {
class EventEngineDNSTest : public EventEngineTest {
protected:
static void SetUpTestSuite() {
+#ifndef GRPC_IOS_EVENT_ENGINE_CLIENT
std::string test_records_path = kDNSTestRecordGroupsYamlPath;
std::string dns_server_path = kDNSServerRelPath;
std::string dns_resolver_path = kDNSResolverRelPath;
@@ -143,12 +144,15 @@ class EventEngineDNSTest : public EventEngineTest {
int status = health_check.Join();
// TODO(yijiem): make this portable for Windows
ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+#endif // GRPC_IOS_EVENT_ENGINE_CLIENT
}
static void TearDownTestSuite() {
+#ifndef GRPC_IOS_EVENT_ENGINE_CLIENT
dns_server_.server_process->Interrupt();
dns_server_.server_process->Join();
delete dns_server_.server_process;
+#endif // GRPC_IOS_EVENT_ENGINE_CLIENT
}
std::unique_ptr CreateDefaultDNSResolver() {
@@ -194,6 +198,9 @@ class EventEngineDNSTest : public EventEngineTest {
EventEngineDNSTest::DNSServer EventEngineDNSTest::dns_server_;
+// TODO(hork): implement XFAIL for resolvers that don't support TXT or SRV
+#ifndef GRPC_IOS_EVENT_ENGINE_CLIENT
+
TEST_F(EventEngineDNSTest, QueryNXHostname) {
auto dns_resolver = CreateDefaultDNSResolver();
dns_resolver->LookupHostname(
@@ -365,6 +372,7 @@ TEST_F(EventEngineDNSTest, TestCancelActiveDNSQuery) {
dns_resolver.reset();
dns_resolver_signal_.WaitForNotification();
}
+#endif // GRPC_IOS_EVENT_ENGINE_CLIENT
#define EXPECT_SUCCESS() \
do { \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index ab7809664f8..637de7d2295 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -2072,6 +2072,8 @@ src/core/lib/event_engine/cf_engine/cf_engine.h \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.h \
src/core/lib/event_engine/cf_engine/cftype_unique_ref.h \
+src/core/lib/event_engine/cf_engine/dns_service_resolver.cc \
+src/core/lib/event_engine/cf_engine/dns_service_resolver.h \
src/core/lib/event_engine/channel_args_endpoint_config.cc \
src/core/lib/event_engine/channel_args_endpoint_config.h \
src/core/lib/event_engine/common_closures.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index d5b0b9258ab..17607e9339a 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1850,6 +1850,8 @@ src/core/lib/event_engine/cf_engine/cf_engine.h \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc \
src/core/lib/event_engine/cf_engine/cfstream_endpoint.h \
src/core/lib/event_engine/cf_engine/cftype_unique_ref.h \
+src/core/lib/event_engine/cf_engine/dns_service_resolver.cc \
+src/core/lib/event_engine/cf_engine/dns_service_resolver.h \
src/core/lib/event_engine/channel_args_endpoint_config.cc \
src/core/lib/event_engine/channel_args_endpoint_config.h \
src/core/lib/event_engine/common_closures.h \
diff --git a/tools/internal_ci/macos/grpc_objc_bazel_test.sh b/tools/internal_ci/macos/grpc_objc_bazel_test.sh
index 3ed4556dd99..fc82aee4aca 100644
--- a/tools/internal_ci/macos/grpc_objc_bazel_test.sh
+++ b/tools/internal_ci/macos/grpc_objc_bazel_test.sh
@@ -61,7 +61,8 @@ TEST_TARGETS=(
#//src/objective-c/tests:CronetTests
#//src/objective-c/tests:PerfTests
//src/objective-c/tests:CFStreamTests
- //src/objective-c/tests:EventEngineTests
+ # Needs oracle engine, which doesn't work with GRPC_IOS_EVENT_ENGINE_CLIENT=1
+ //src/objective-c/tests:EventEngineClientTests
//src/objective-c/tests:tvtests_build_test
# codegen plugin tests
//src/objective-c/tests:objc_codegen_plugin_test
@@ -128,6 +129,7 @@ EVENT_ENGINE_TEST_TARGETS=(
//src/objective-c/tests:InteropTestsRemote
//src/objective-c/tests:MacTests
//src/objective-c/tests:UnitTests
+ //src/objective-c/tests:EventEngineUnitTests
//src/objective-c/tests:tvtests_build_test
)