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