• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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