Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / ext / filters / client_channel / resolver / dns / native / dns_resolver.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include <inttypes.h>
22 #include <climits>
23 #include <cstring>
24
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/string_util.h>
27 #include <grpc/support/time.h>
28
29 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
30 #include "src/core/ext/filters/client_channel/resolver_registry.h"
31 #include "src/core/ext/filters/client_channel/server_address.h"
32 #include "src/core/lib/backoff/backoff.h"
33 #include "src/core/lib/channel/channel_args.h"
34 #include "src/core/lib/gpr/string.h"
35 #include "src/core/lib/gprpp/manual_constructor.h"
36 #include "src/core/lib/iomgr/combiner.h"
37 #include "src/core/lib/iomgr/resolve_address.h"
38 #include "src/core/lib/iomgr/timer.h"
39
40 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
41 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
42 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
43 #define GRPC_DNS_RECONNECT_JITTER 0.2
44
45 namespace grpc_core {
46
47 namespace {
48
49 const char kDefaultPort[] = "https";
50
51 class NativeDnsResolver : public Resolver {
52  public:
53   explicit NativeDnsResolver(ResolverArgs args);
54
55   void StartLocked() override;
56
57   void RequestReresolutionLocked() override;
58
59   void ResetBackoffLocked() override;
60
61   void ShutdownLocked() override;
62
63  private:
64   virtual ~NativeDnsResolver();
65
66   void MaybeStartResolvingLocked();
67   void StartResolvingLocked();
68
69   static void OnNextResolutionLocked(void* arg, grpc_error* error);
70   static void OnResolvedLocked(void* arg, grpc_error* error);
71
72   /// name to resolve
73   char* name_to_resolve_ = nullptr;
74   /// channel args
75   grpc_channel_args* channel_args_ = nullptr;
76   /// pollset_set to drive the name resolution process
77   grpc_pollset_set* interested_parties_ = nullptr;
78   /// are we shutting down?
79   bool shutdown_ = false;
80   /// are we currently resolving?
81   bool resolving_ = false;
82   grpc_closure on_resolved_;
83   /// next resolution timer
84   bool have_next_resolution_timer_ = false;
85   grpc_timer next_resolution_timer_;
86   grpc_closure on_next_resolution_;
87   /// min time between DNS requests
88   grpc_millis min_time_between_resolutions_;
89   /// timestamp of last DNS request
90   grpc_millis last_resolution_timestamp_ = -1;
91   /// retry backoff state
92   BackOff backoff_;
93   /// currently resolving addresses
94   grpc_resolved_addresses* addresses_ = nullptr;
95 };
96
97 NativeDnsResolver::NativeDnsResolver(ResolverArgs args)
98     : Resolver(args.combiner, std::move(args.result_handler)),
99       backoff_(
100           BackOff::Options()
101               .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
102                                    1000)
103               .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
104               .set_jitter(GRPC_DNS_RECONNECT_JITTER)
105               .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
106   char* path = args.uri->path;
107   if (path[0] == '/') ++path;
108   name_to_resolve_ = gpr_strdup(path);
109   channel_args_ = grpc_channel_args_copy(args.args);
110   const grpc_arg* arg = grpc_channel_args_find(
111       args.args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
112   min_time_between_resolutions_ =
113       grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
114   interested_parties_ = grpc_pollset_set_create();
115   if (args.pollset_set != nullptr) {
116     grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
117   }
118   GRPC_CLOSURE_INIT(&on_next_resolution_,
119                     NativeDnsResolver::OnNextResolutionLocked, this,
120                     grpc_combiner_scheduler(args.combiner));
121   GRPC_CLOSURE_INIT(&on_resolved_, NativeDnsResolver::OnResolvedLocked, this,
122                     grpc_combiner_scheduler(args.combiner));
123 }
124
125 NativeDnsResolver::~NativeDnsResolver() {
126   grpc_channel_args_destroy(channel_args_);
127   grpc_pollset_set_destroy(interested_parties_);
128   gpr_free(name_to_resolve_);
129 }
130
131 void NativeDnsResolver::StartLocked() { MaybeStartResolvingLocked(); }
132
133 void NativeDnsResolver::RequestReresolutionLocked() {
134   if (!resolving_) {
135     MaybeStartResolvingLocked();
136   }
137 }
138
139 void NativeDnsResolver::ResetBackoffLocked() {
140   if (have_next_resolution_timer_) {
141     grpc_timer_cancel(&next_resolution_timer_);
142   }
143   backoff_.Reset();
144 }
145
146 void NativeDnsResolver::ShutdownLocked() {
147   shutdown_ = true;
148   if (have_next_resolution_timer_) {
149     grpc_timer_cancel(&next_resolution_timer_);
150   }
151 }
152
153 void NativeDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
154   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
155   r->have_next_resolution_timer_ = false;
156   if (error == GRPC_ERROR_NONE && !r->resolving_) {
157     r->StartResolvingLocked();
158   }
159   r->Unref(DEBUG_LOCATION, "retry-timer");
160 }
161
162 void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
163   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
164   GPR_ASSERT(r->resolving_);
165   r->resolving_ = false;
166   if (r->shutdown_) {
167     r->Unref(DEBUG_LOCATION, "dns-resolving");
168     return;
169   }
170   if (r->addresses_ != nullptr) {
171     Result result;
172     for (size_t i = 0; i < r->addresses_->naddrs; ++i) {
173       result.addresses.emplace_back(&r->addresses_->addrs[i].addr,
174                                     r->addresses_->addrs[i].len,
175                                     nullptr /* args */);
176     }
177     grpc_resolved_addresses_destroy(r->addresses_);
178     result.args = grpc_channel_args_copy(r->channel_args_);
179     r->result_handler()->ReturnResult(std::move(result));
180     // Reset backoff state so that we start from the beginning when the
181     // next request gets triggered.
182     r->backoff_.Reset();
183   } else {
184     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
185             grpc_error_string(error));
186     // Return transient error.
187     r->result_handler()->ReturnError(grpc_error_set_int(
188         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
189             "DNS resolution failed", &error, 1),
190         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
191     // Set up for retry.
192     grpc_millis next_try = r->backoff_.NextAttemptTime();
193     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
194     GPR_ASSERT(!r->have_next_resolution_timer_);
195     r->have_next_resolution_timer_ = true;
196     // TODO(roth): We currently deal with this ref manually.  Once the
197     // new closure API is done, find a way to track this ref with the timer
198     // callback as part of the type system.
199     r->Ref(DEBUG_LOCATION, "next_resolution_timer").release();
200     if (timeout > 0) {
201       gpr_log(GPR_DEBUG, "retrying in %" PRId64 " milliseconds", timeout);
202     } else {
203       gpr_log(GPR_DEBUG, "retrying immediately");
204     }
205     grpc_timer_init(&r->next_resolution_timer_, next_try,
206                     &r->on_next_resolution_);
207   }
208   r->Unref(DEBUG_LOCATION, "dns-resolving");
209 }
210
211 void NativeDnsResolver::MaybeStartResolvingLocked() {
212   // If there is an existing timer, the time it fires is the earliest time we
213   // can start the next resolution.
214   if (have_next_resolution_timer_) return;
215   if (last_resolution_timestamp_ >= 0) {
216     const grpc_millis earliest_next_resolution =
217         last_resolution_timestamp_ + min_time_between_resolutions_;
218     const grpc_millis ms_until_next_resolution =
219         earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
220     if (ms_until_next_resolution > 0) {
221       const grpc_millis last_resolution_ago =
222           grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
223       gpr_log(GPR_DEBUG,
224               "In cooldown from last resolution (from %" PRId64
225               " ms ago). Will resolve again in %" PRId64 " ms",
226               last_resolution_ago, ms_until_next_resolution);
227       have_next_resolution_timer_ = true;
228       // TODO(roth): We currently deal with this ref manually.  Once the
229       // new closure API is done, find a way to track this ref with the timer
230       // callback as part of the type system.
231       Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown").release();
232       grpc_timer_init(&next_resolution_timer_,
233                       ExecCtx::Get()->Now() + ms_until_next_resolution,
234                       &on_next_resolution_);
235       return;
236     }
237   }
238   StartResolvingLocked();
239 }
240
241 void NativeDnsResolver::StartResolvingLocked() {
242   gpr_log(GPR_DEBUG, "Start resolving.");
243   // TODO(roth): We currently deal with this ref manually.  Once the
244   // new closure API is done, find a way to track this ref with the timer
245   // callback as part of the type system.
246   Ref(DEBUG_LOCATION, "dns-resolving").release();
247   GPR_ASSERT(!resolving_);
248   resolving_ = true;
249   addresses_ = nullptr;
250   grpc_resolve_address(name_to_resolve_, kDefaultPort, interested_parties_,
251                        &on_resolved_, &addresses_);
252   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
253 }
254
255 //
256 // Factory
257 //
258
259 class NativeDnsResolverFactory : public ResolverFactory {
260  public:
261   bool IsValidUri(const grpc_uri* uri) const override {
262     if (GPR_UNLIKELY(0 != strcmp(uri->authority, ""))) {
263       gpr_log(GPR_ERROR, "authority based dns uri's not supported");
264       return false;
265     }
266     return true;
267   }
268
269   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
270     if (!IsValidUri(args.uri)) return nullptr;
271     return OrphanablePtr<Resolver>(New<NativeDnsResolver>(std::move(args)));
272   }
273
274   const char* scheme() const override { return "dns"; }
275 };
276
277 }  // namespace
278
279 }  // namespace grpc_core
280
281 void grpc_resolver_dns_native_init() {
282   grpc_core::UniquePtr<char> resolver =
283       GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
284   if (gpr_stricmp(resolver.get(), "native") == 0) {
285     gpr_log(GPR_DEBUG, "Using native dns resolver");
286     grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
287         grpc_core::UniquePtr<grpc_core::ResolverFactory>(
288             grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
289   } else {
290     grpc_core::ResolverRegistry::Builder::InitRegistry();
291     grpc_core::ResolverFactory* existing_factory =
292         grpc_core::ResolverRegistry::LookupResolverFactory("dns");
293     if (existing_factory == nullptr) {
294       gpr_log(GPR_DEBUG, "Using native dns resolver");
295       grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
296           grpc_core::UniquePtr<grpc_core::ResolverFactory>(
297               grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
298     }
299   }
300 }
301
302 void grpc_resolver_dns_native_shutdown() {}