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_ARES_RESOLVER_H 15 #define GRPC_SRC_CORE_LIB_EVENT_ENGINE_ARES_RESOLVER_H 16 17 #include <grpc/support/port_platform.h> 18 19 #include <utility> 20 21 #include "absl/status/status.h" 22 #include "src/core/lib/debug/trace.h" 23 24 #if GRPC_ARES == 1 25 26 #include <ares.h> 27 #include <grpc/event_engine/event_engine.h> 28 29 #include <list> 30 #include <memory> 31 32 #include "absl/base/thread_annotations.h" 33 #include "absl/container/flat_hash_map.h" 34 #include "absl/status/statusor.h" 35 #include "absl/strings/string_view.h" 36 #include "absl/types/optional.h" 37 #include "absl/types/variant.h" 38 #include "src/core/lib/event_engine/grpc_polled_fd.h" 39 #include "src/core/lib/event_engine/ref_counted_dns_resolver_interface.h" 40 #include "src/core/util/orphanable.h" 41 #include "src/core/util/sync.h" 42 43 namespace grpc_event_engine { 44 namespace experimental { 45 46 class AresResolver : public RefCountedDNSResolverInterface { 47 public: 48 static absl::StatusOr<grpc_core::OrphanablePtr<AresResolver>> 49 CreateAresResolver(absl::string_view dns_server, 50 std::unique_ptr<GrpcPolledFdFactory> polled_fd_factory, 51 std::shared_ptr<EventEngine> event_engine); 52 53 // Do not instantiate directly -- use CreateAresResolver() instead. 54 AresResolver(std::unique_ptr<GrpcPolledFdFactory> polled_fd_factory, 55 std::shared_ptr<EventEngine> event_engine, ares_channel channel); 56 ~AresResolver() override; 57 void Orphan() override ABSL_LOCKS_EXCLUDED(mutex_); 58 59 void LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback callback, 60 absl::string_view name, absl::string_view default_port) 61 ABSL_LOCKS_EXCLUDED(mutex_) override; 62 void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback callback, 63 absl::string_view name) ABSL_LOCKS_EXCLUDED(mutex_) override; 64 void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback callback, 65 absl::string_view name) ABSL_LOCKS_EXCLUDED(mutex_) override; 66 67 private: 68 // A FdNode saves (not owns) a live socket/fd which c-ares creates, and owns a 69 // GrpcPolledFd object which has a platform-agnostic interface to interact 70 // with the poller. The liveness of the socket means that c-ares needs us to 71 // monitor r/w events on this socket and notifies c-ares when such events have 72 // happened which we achieve through the GrpcPolledFd object. FdNode also 73 // handles the shutdown (maybe due to socket no longer used, finished request, 74 // cancel or timeout) and the destruction of the poller handle. Note that 75 // FdNode does not own the socket and it's the c-ares' responsibility to 76 // close the socket (possibly through ares_destroy). 77 struct FdNode { 78 FdNode() = default; FdNodeFdNode79 FdNode(ares_socket_t as, std::unique_ptr<GrpcPolledFd> pf) 80 : as(as), polled_fd(std::move(pf)) {} 81 ares_socket_t as; 82 std::unique_ptr<GrpcPolledFd> polled_fd; 83 // true if the readable closure has been registered 84 bool readable_registered = false; 85 // true if the writable closure has been registered 86 bool writable_registered = false; 87 bool already_shutdown = false; 88 }; 89 using FdNodeList = std::list<std::unique_ptr<FdNode>>; 90 91 using CallbackType = 92 absl::variant<EventEngine::DNSResolver::LookupHostnameCallback, 93 EventEngine::DNSResolver::LookupSRVCallback, 94 EventEngine::DNSResolver::LookupTXTCallback>; 95 96 void CheckSocketsLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); 97 void MaybeStartTimerLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); 98 void OnReadable(FdNode* fd_node, absl::Status status) 99 ABSL_LOCKS_EXCLUDED(mutex_); 100 void OnWritable(FdNode* fd_node, absl::Status status) 101 ABSL_LOCKS_EXCLUDED(mutex_); 102 void OnAresBackupPollAlarm() ABSL_LOCKS_EXCLUDED(mutex_); 103 104 // These callbacks are invoked from the c-ares library, so disable thread 105 // safety analysis. We are guaranteed to be holding mutex_. 106 static void OnHostbynameDoneLocked(void* arg, int status, int /*timeouts*/, 107 struct hostent* hostent) 108 ABSL_NO_THREAD_SAFETY_ANALYSIS; 109 static void OnSRVQueryDoneLocked(void* arg, int status, int /*timeouts*/, 110 unsigned char* abuf, 111 int alen) ABSL_NO_THREAD_SAFETY_ANALYSIS; 112 static void OnTXTDoneLocked(void* arg, int status, int /*timeouts*/, 113 unsigned char* buf, 114 int len) ABSL_NO_THREAD_SAFETY_ANALYSIS; 115 116 grpc_core::Mutex mutex_; 117 bool shutting_down_ ABSL_GUARDED_BY(mutex_) = false; 118 ares_channel channel_ ABSL_GUARDED_BY(mutex_); 119 FdNodeList fd_node_list_ ABSL_GUARDED_BY(mutex_); 120 int id_ ABSL_GUARDED_BY(mutex_) = 0; 121 absl::flat_hash_map<int, CallbackType> callback_map_ ABSL_GUARDED_BY(mutex_); 122 absl::optional<EventEngine::TaskHandle> ares_backup_poll_alarm_handle_ 123 ABSL_GUARDED_BY(mutex_); 124 std::unique_ptr<GrpcPolledFdFactory> polled_fd_factory_; 125 std::shared_ptr<EventEngine> event_engine_; 126 }; 127 128 } // namespace experimental 129 } // namespace grpc_event_engine 130 131 // Exposed in this header for C-core tests only 132 extern void (*event_engine_grpc_ares_test_only_inject_config)( 133 ares_channel* channel); 134 135 // Exposed in this header for C-core tests only 136 extern bool g_event_engine_grpc_ares_test_only_force_tcp; 137 138 #endif // GRPC_ARES == 1 139 140 bool ShouldUseAresDnsResolver(); 141 absl::Status AresInit(); 142 void AresShutdown(); 143 144 #endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_ARES_RESOLVER_H 145