1 // Copyright 2023 The gRPC Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #ifndef GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H 15 #define GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H 16 #include <grpc/support/port_platform.h> 17 18 #ifdef GPR_APPLE 19 #include <AvailabilityMacros.h> 20 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER 21 22 #include <CoreFoundation/CoreFoundation.h> 23 #include <dns_sd.h> 24 #include <grpc/event_engine/event_engine.h> 25 26 #include "absl/container/flat_hash_map.h" 27 #include "absl/log/check.h" 28 #include "src/core/lib/event_engine/cf_engine/cf_engine.h" 29 #include "src/core/util/ref_counted.h" 30 #include "src/core/util/ref_counted_ptr.h" 31 32 namespace grpc_event_engine { 33 namespace experimental { 34 35 class DNSServiceResolverImpl 36 : public grpc_core::RefCounted<DNSServiceResolverImpl> { 37 struct DNSServiceRequest { 38 EventEngine::DNSResolver::LookupHostnameCallback on_resolve; 39 uint16_t port; 40 std::vector<EventEngine::ResolvedAddress> result; 41 bool has_ipv4_response = false; 42 bool has_ipv6_response = false; 43 }; 44 45 public: DNSServiceResolverImpl(std::shared_ptr<CFEventEngine> engine)46 explicit DNSServiceResolverImpl(std::shared_ptr<CFEventEngine> engine) 47 : engine_(std::move((engine))) {} ~DNSServiceResolverImpl()48 ~DNSServiceResolverImpl() override { 49 CHECK(requests_.empty()); 50 dispatch_release(queue_); 51 } 52 53 void Shutdown(); 54 55 void LookupHostname( 56 EventEngine::DNSResolver::LookupHostnameCallback on_resolve, 57 absl::string_view name, absl::string_view default_port); 58 59 private: 60 static void ResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, 61 uint32_t interfaceIndex, 62 DNSServiceErrorType errorCode, 63 const char* hostname, 64 const struct sockaddr* address, uint32_t ttl, 65 void* context); 66 67 private: 68 std::shared_ptr<CFEventEngine> engine_; 69 // DNSServiceSetDispatchQueue requires a serial dispatch queue 70 dispatch_queue_t queue_ = 71 dispatch_queue_create("dns_service_resolver", nullptr); 72 grpc_core::Mutex request_mu_; 73 absl::flat_hash_map<DNSServiceRef, DNSServiceRequest> requests_ 74 ABSL_GUARDED_BY(request_mu_); 75 }; 76 77 class DNSServiceResolver : public EventEngine::DNSResolver { 78 public: DNSServiceResolver(std::shared_ptr<CFEventEngine> engine)79 explicit DNSServiceResolver(std::shared_ptr<CFEventEngine> engine) 80 : engine_(std::move(engine)), 81 impl_(grpc_core::MakeRefCounted<DNSServiceResolverImpl>( 82 std::move((engine_)))) {} 83 ~DNSServiceResolver()84 ~DNSServiceResolver() override { impl_->Shutdown(); } 85 LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback on_resolve,absl::string_view name,absl::string_view default_port)86 void LookupHostname( 87 EventEngine::DNSResolver::LookupHostnameCallback on_resolve, 88 absl::string_view name, absl::string_view default_port) override { 89 impl_->LookupHostname(std::move(on_resolve), name, default_port); 90 }; 91 LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolve,absl::string_view)92 void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolve, 93 absl::string_view /* name */) override { 94 engine_->Run([on_resolve = std::move(on_resolve)]() mutable { 95 on_resolve(absl::UnimplementedError( 96 "The DNS Service resolver does not support looking up SRV records")); 97 }); 98 } 99 LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolve,absl::string_view)100 void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolve, 101 absl::string_view /* name */) override { 102 engine_->Run([on_resolve = std::move(on_resolve)]() mutable { 103 on_resolve(absl::UnimplementedError( 104 "The DNS Service resolver does not support looking up TXT records")); 105 }); 106 } 107 108 private: 109 std::shared_ptr<CFEventEngine> engine_; 110 grpc_core::RefCountedPtr<DNSServiceResolverImpl> impl_; 111 }; 112 113 } // namespace experimental 114 } // namespace grpc_event_engine 115 116 #endif // AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER 117 #endif // GPR_APPLE 118 119 #endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H 120