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 25 #include "absl/container/flat_hash_map.h" 26 27 #include <grpc/event_engine/event_engine.h> 28 29 #include "src/core/lib/event_engine/cf_engine/cf_engine.h" 30 #include "src/core/lib/gprpp/ref_counted.h" 31 #include "src/core/lib/gprpp/ref_counted_ptr.h" 32 33 namespace grpc_event_engine { 34 namespace experimental { 35 36 class DNSServiceResolverImpl 37 : public grpc_core::RefCounted<DNSServiceResolverImpl> { 38 struct DNSServiceRequest { 39 EventEngine::DNSResolver::LookupHostnameCallback on_resolve; 40 uint16_t port; 41 std::vector<EventEngine::ResolvedAddress> result; 42 bool has_ipv4_response = false; 43 bool has_ipv6_response = false; 44 }; 45 46 public: DNSServiceResolverImpl(std::shared_ptr<CFEventEngine> engine)47 explicit DNSServiceResolverImpl(std::shared_ptr<CFEventEngine> engine) 48 : engine_(std::move((engine))) {} ~DNSServiceResolverImpl()49 ~DNSServiceResolverImpl() override { 50 GPR_ASSERT(requests_.empty()); 51 dispatch_release(queue_); 52 } 53 54 void Shutdown(); 55 56 void LookupHostname( 57 EventEngine::DNSResolver::LookupHostnameCallback on_resolve, 58 absl::string_view name, absl::string_view default_port); 59 60 private: 61 static void ResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, 62 uint32_t interfaceIndex, 63 DNSServiceErrorType errorCode, 64 const char* hostname, 65 const struct sockaddr* address, uint32_t ttl, 66 void* context); 67 68 private: 69 std::shared_ptr<CFEventEngine> engine_; 70 // DNSServiceSetDispatchQueue requires a serial dispatch queue 71 dispatch_queue_t queue_ = 72 dispatch_queue_create("dns_service_resolver", nullptr); 73 grpc_core::Mutex request_mu_; 74 absl::flat_hash_map<DNSServiceRef, DNSServiceRequest> requests_ 75 ABSL_GUARDED_BY(request_mu_); 76 }; 77 78 class DNSServiceResolver : public EventEngine::DNSResolver { 79 public: DNSServiceResolver(std::shared_ptr<CFEventEngine> engine)80 explicit DNSServiceResolver(std::shared_ptr<CFEventEngine> engine) 81 : engine_(std::move(engine)), 82 impl_(grpc_core::MakeRefCounted<DNSServiceResolverImpl>( 83 std::move((engine_)))) {} 84 ~DNSServiceResolver()85 ~DNSServiceResolver() override { impl_->Shutdown(); } 86 LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback on_resolve,absl::string_view name,absl::string_view default_port)87 void LookupHostname( 88 EventEngine::DNSResolver::LookupHostnameCallback on_resolve, 89 absl::string_view name, absl::string_view default_port) override { 90 impl_->LookupHostname(std::move(on_resolve), name, default_port); 91 }; 92 LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolve,absl::string_view)93 void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolve, 94 absl::string_view /* name */) override { 95 engine_->Run([on_resolve = std::move(on_resolve)]() mutable { 96 on_resolve(absl::UnimplementedError( 97 "The DNS Service resolver does not support looking up SRV records")); 98 }); 99 } 100 LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolve,absl::string_view)101 void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolve, 102 absl::string_view /* name */) override { 103 engine_->Run([on_resolve = std::move(on_resolve)]() mutable { 104 on_resolve(absl::UnimplementedError( 105 "The DNS Service resolver does not support looking up TXT records")); 106 }); 107 } 108 109 private: 110 std::shared_ptr<CFEventEngine> engine_; 111 grpc_core::RefCountedPtr<DNSServiceResolverImpl> impl_; 112 }; 113 114 } // namespace experimental 115 } // namespace grpc_event_engine 116 117 #endif // AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER 118 #endif // GPR_APPLE 119 120 #endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_CF_ENGINE_DNS_SERVICE_RESOLVER_H 121