Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / ext / filters / client_channel / resolver / dns / c_ares / dns_resolver_ares.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 #if GRPC_ARES == 1
22
23 #include <limits.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/string_util.h>
29
30 #include <address_sorting/address_sorting.h>
31
32 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
33 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
34 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
35 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
36 #include "src/core/ext/filters/client_channel/resolver_registry.h"
37 #include "src/core/ext/filters/client_channel/server_address.h"
38 #include "src/core/ext/filters/client_channel/service_config.h"
39 #include "src/core/lib/backoff/backoff.h"
40 #include "src/core/lib/channel/channel_args.h"
41 #include "src/core/lib/gpr/string.h"
42 #include "src/core/lib/gprpp/manual_constructor.h"
43 #include "src/core/lib/iomgr/combiner.h"
44 #include "src/core/lib/iomgr/gethostname.h"
45 #include "src/core/lib/iomgr/iomgr_custom.h"
46 #include "src/core/lib/iomgr/resolve_address.h"
47 #include "src/core/lib/iomgr/timer.h"
48 #include "src/core/lib/json/json.h"
49
50 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
51 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
52 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
53 #define GRPC_DNS_RECONNECT_JITTER 0.2
54
55 namespace grpc_core {
56
57 namespace {
58
59 const char kDefaultPort[] = "https";
60
61 class AresDnsResolver : public Resolver {
62  public:
63   explicit AresDnsResolver(ResolverArgs args);
64
65   void StartLocked() override;
66
67   void RequestReresolutionLocked() override;
68
69   void ResetBackoffLocked() override;
70
71   void ShutdownLocked() override;
72
73  private:
74   virtual ~AresDnsResolver();
75
76   void MaybeStartResolvingLocked();
77   void StartResolvingLocked();
78
79   static void OnNextResolutionLocked(void* arg, grpc_error* error);
80   static void OnResolvedLocked(void* arg, grpc_error* error);
81
82   /// DNS server to use (if not system default)
83   char* dns_server_;
84   /// name to resolve (usually the same as target_name)
85   char* name_to_resolve_;
86   /// channel args
87   grpc_channel_args* channel_args_;
88   /// whether to request the service config
89   bool request_service_config_;
90   /// pollset_set to drive the name resolution process
91   grpc_pollset_set* interested_parties_;
92   /// closures used by the combiner
93   grpc_closure on_next_resolution_;
94   grpc_closure on_resolved_;
95   /// are we currently resolving?
96   bool resolving_ = false;
97   /// the pending resolving request
98   grpc_ares_request* pending_request_ = nullptr;
99   /// next resolution timer
100   bool have_next_resolution_timer_ = false;
101   grpc_timer next_resolution_timer_;
102   /// min interval between DNS requests
103   grpc_millis min_time_between_resolutions_;
104   /// timestamp of last DNS request
105   grpc_millis last_resolution_timestamp_ = -1;
106   /// retry backoff state
107   BackOff backoff_;
108   /// currently resolving addresses
109   UniquePtr<ServerAddressList> addresses_;
110   /// currently resolving service config
111   char* service_config_json_ = nullptr;
112   // has shutdown been initiated
113   bool shutdown_initiated_ = false;
114   // timeout in milliseconds for active DNS queries
115   int query_timeout_ms_;
116   // whether or not to enable SRV DNS queries
117   bool enable_srv_queries_;
118 };
119
120 AresDnsResolver::AresDnsResolver(ResolverArgs args)
121     : Resolver(args.combiner, std::move(args.result_handler)),
122       backoff_(
123           BackOff::Options()
124               .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
125                                    1000)
126               .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
127               .set_jitter(GRPC_DNS_RECONNECT_JITTER)
128               .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
129   // Get name to resolve from URI path.
130   const char* path = args.uri->path;
131   if (path[0] == '/') ++path;
132   name_to_resolve_ = gpr_strdup(path);
133   // Get DNS server from URI authority.
134   dns_server_ = nullptr;
135   if (0 != strcmp(args.uri->authority, "")) {
136     dns_server_ = gpr_strdup(args.uri->authority);
137   }
138   channel_args_ = grpc_channel_args_copy(args.args);
139   // Disable service config option
140   const grpc_arg* arg = grpc_channel_args_find(
141       channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
142   request_service_config_ = !grpc_channel_arg_get_bool(arg, true);
143   // Min time b/t resolutions option
144   arg = grpc_channel_args_find(channel_args_,
145                                GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
146   min_time_between_resolutions_ =
147       grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
148   // Enable SRV queries option
149   arg = grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ENABLE_SRV_QUERIES);
150   enable_srv_queries_ = grpc_channel_arg_get_bool(arg, false);
151   interested_parties_ = grpc_pollset_set_create();
152   if (args.pollset_set != nullptr) {
153     grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
154   }
155   GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolutionLocked, this,
156                     grpc_combiner_scheduler(combiner()));
157   GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this,
158                     grpc_combiner_scheduler(combiner()));
159   const grpc_arg* query_timeout_ms_arg =
160       grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
161   query_timeout_ms_ = grpc_channel_arg_get_integer(
162       query_timeout_ms_arg,
163       {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX});
164 }
165
166 AresDnsResolver::~AresDnsResolver() {
167   GRPC_CARES_TRACE_LOG("resolver:%p destroying AresDnsResolver", this);
168   grpc_pollset_set_destroy(interested_parties_);
169   gpr_free(dns_server_);
170   gpr_free(name_to_resolve_);
171   grpc_channel_args_destroy(channel_args_);
172 }
173
174 void AresDnsResolver::StartLocked() {
175   GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::StartLocked() is called.",
176                        this);
177   MaybeStartResolvingLocked();
178 }
179
180 void AresDnsResolver::RequestReresolutionLocked() {
181   if (!resolving_) {
182     MaybeStartResolvingLocked();
183   }
184 }
185
186 void AresDnsResolver::ResetBackoffLocked() {
187   if (have_next_resolution_timer_) {
188     grpc_timer_cancel(&next_resolution_timer_);
189   }
190   backoff_.Reset();
191 }
192
193 void AresDnsResolver::ShutdownLocked() {
194   shutdown_initiated_ = true;
195   if (have_next_resolution_timer_) {
196     grpc_timer_cancel(&next_resolution_timer_);
197   }
198   if (pending_request_ != nullptr) {
199     grpc_cancel_ares_request_locked(pending_request_);
200   }
201 }
202
203 void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
204   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
205   GRPC_CARES_TRACE_LOG(
206       "resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: "
207       "%d",
208       r, grpc_error_string(error), r->shutdown_initiated_);
209   r->have_next_resolution_timer_ = false;
210   if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) {
211     if (!r->resolving_) {
212       GRPC_CARES_TRACE_LOG(
213           "resolver:%p start resolving due to re-resolution timer", r);
214       r->StartResolvingLocked();
215     }
216   }
217   r->Unref(DEBUG_LOCATION, "next_resolution_timer");
218 }
219
220 bool ValueInJsonArray(grpc_json* array, const char* value) {
221   for (grpc_json* entry = array->child; entry != nullptr; entry = entry->next) {
222     if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) {
223       return true;
224     }
225   }
226   return false;
227 }
228
229 char* ChooseServiceConfig(char* service_config_choice_json,
230                           grpc_error** error) {
231   grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
232   if (choices_json == nullptr) {
233     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
234         "Service Config JSON Parsing, error: could not parse");
235     return nullptr;
236   }
237   if (choices_json->type != GRPC_JSON_ARRAY) {
238     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
239         "Service Config Choices, error: should be of type array");
240     return nullptr;
241   }
242   char* service_config = nullptr;
243   InlinedVector<grpc_error*, 4> error_list;
244   bool found_choice = false;  // have we found a choice?
245   for (grpc_json* choice = choices_json->child; choice != nullptr;
246        choice = choice->next) {
247     if (choice->type != GRPC_JSON_OBJECT) {
248       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
249           "Service Config Choice, error: should be of type object"));
250       continue;
251     }
252     grpc_json* service_config_json = nullptr;
253     bool selected = true;  // has this choice been rejected?
254     for (grpc_json* field = choice->child; field != nullptr;
255          field = field->next) {
256       // Check client language, if specified.
257       if (strcmp(field->key, "clientLanguage") == 0) {
258         if (field->type != GRPC_JSON_ARRAY) {
259           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
260               "field:clientLanguage error:should be of type array"));
261         } else if (!ValueInJsonArray(field, "c++")) {
262           selected = false;
263         }
264       }
265       // Check client hostname, if specified.
266       if (strcmp(field->key, "clientHostname") == 0) {
267         if (field->type != GRPC_JSON_ARRAY) {
268           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
269               "field:clientHostname error:should be of type array"));
270           continue;
271         }
272         char* hostname = grpc_gethostname();
273         if (hostname == nullptr || !ValueInJsonArray(field, hostname)) {
274           selected = false;
275         }
276       }
277       // Check percentage, if specified.
278       if (strcmp(field->key, "percentage") == 0) {
279         if (field->type != GRPC_JSON_NUMBER) {
280           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
281               "field:percentage error:should be of type number"));
282           continue;
283         }
284         int random_pct = rand() % 100;
285         int percentage;
286         if (sscanf(field->value, "%d", &percentage) != 1) {
287           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
288               "field:percentage error:should be of type integer"));
289           continue;
290         }
291         if (random_pct > percentage || percentage == 0) {
292           selected = false;
293         }
294       }
295       // Save service config.
296       if (strcmp(field->key, "serviceConfig") == 0) {
297         if (field->type == GRPC_JSON_OBJECT) {
298           service_config_json = field;
299         } else {
300           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
301               "field:serviceConfig error:should be of type object"));
302         }
303       }
304     }
305     if (!found_choice && selected && service_config_json != nullptr) {
306       service_config = grpc_json_dump_to_string(service_config_json, 0);
307       found_choice = true;
308     }
309   }
310   grpc_json_destroy(choices_json);
311   if (!error_list.empty()) {
312     gpr_free(service_config);
313     service_config = nullptr;
314     *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser",
315                                            &error_list);
316   }
317   return service_config;
318 }
319
320 void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
321   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
322   GPR_ASSERT(r->resolving_);
323   r->resolving_ = false;
324   gpr_free(r->pending_request_);
325   r->pending_request_ = nullptr;
326   if (r->shutdown_initiated_) {
327     r->Unref(DEBUG_LOCATION, "OnResolvedLocked() shutdown");
328     return;
329   }
330   if (r->addresses_ != nullptr) {
331     Result result;
332     result.addresses = std::move(*r->addresses_);
333     if (r->service_config_json_ != nullptr) {
334       char* service_config_string = ChooseServiceConfig(
335           r->service_config_json_, &result.service_config_error);
336       gpr_free(r->service_config_json_);
337       if (result.service_config_error == GRPC_ERROR_NONE &&
338           service_config_string != nullptr) {
339         GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s",
340                              r, service_config_string);
341         result.service_config = ServiceConfig::Create(
342             service_config_string, &result.service_config_error);
343       }
344       gpr_free(service_config_string);
345     }
346     result.args = grpc_channel_args_copy(r->channel_args_);
347     r->result_handler()->ReturnResult(std::move(result));
348     r->addresses_.reset();
349     // Reset backoff state so that we start from the beginning when the
350     // next request gets triggered.
351     r->backoff_.Reset();
352   } else {
353     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", r,
354                          grpc_error_string(error));
355     r->result_handler()->ReturnError(grpc_error_set_int(
356         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
357             "DNS resolution failed", &error, 1),
358         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
359     // Set retry timer.
360     grpc_millis next_try = r->backoff_.NextAttemptTime();
361     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
362     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s",
363                          r, grpc_error_string(error));
364     GPR_ASSERT(!r->have_next_resolution_timer_);
365     r->have_next_resolution_timer_ = true;
366     // TODO(roth): We currently deal with this ref manually.  Once the
367     // new closure API is done, find a way to track this ref with the timer
368     // callback as part of the type system.
369     r->Ref(DEBUG_LOCATION, "retry-timer").release();
370     if (timeout > 0) {
371       GRPC_CARES_TRACE_LOG("resolver:%p retrying in %" PRId64 " milliseconds",
372                            r, timeout);
373     } else {
374       GRPC_CARES_TRACE_LOG("resolver:%p retrying immediately", r);
375     }
376     grpc_timer_init(&r->next_resolution_timer_, next_try,
377                     &r->on_next_resolution_);
378   }
379   r->Unref(DEBUG_LOCATION, "dns-resolving");
380 }
381
382 void AresDnsResolver::MaybeStartResolvingLocked() {
383   // If there is an existing timer, the time it fires is the earliest time we
384   // can start the next resolution.
385   if (have_next_resolution_timer_) return;
386   if (last_resolution_timestamp_ >= 0) {
387     const grpc_millis earliest_next_resolution =
388         last_resolution_timestamp_ + min_time_between_resolutions_;
389     const grpc_millis ms_until_next_resolution =
390         earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
391     if (ms_until_next_resolution > 0) {
392       const grpc_millis last_resolution_ago =
393           grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
394       GRPC_CARES_TRACE_LOG(
395           "resolver:%p In cooldown from last resolution (from %" PRId64
396           " ms ago). Will resolve again in %" PRId64 " ms",
397           this, last_resolution_ago, ms_until_next_resolution);
398       have_next_resolution_timer_ = true;
399       // TODO(roth): We currently deal with this ref manually.  Once the
400       // new closure API is done, find a way to track this ref with the timer
401       // callback as part of the type system.
402       Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown").release();
403       grpc_timer_init(&next_resolution_timer_,
404                       ExecCtx::Get()->Now() + ms_until_next_resolution,
405                       &on_next_resolution_);
406       return;
407     }
408   }
409   StartResolvingLocked();
410 }
411
412 void AresDnsResolver::StartResolvingLocked() {
413   // TODO(roth): We currently deal with this ref manually.  Once the
414   // new closure API is done, find a way to track this ref with the timer
415   // callback as part of the type system.
416   Ref(DEBUG_LOCATION, "dns-resolving").release();
417   GPR_ASSERT(!resolving_);
418   resolving_ = true;
419   service_config_json_ = nullptr;
420   pending_request_ = grpc_dns_lookup_ares_locked(
421       dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
422       &on_resolved_, &addresses_, enable_srv_queries_ /* check_grpclb */,
423       request_service_config_ ? &service_config_json_ : nullptr,
424       query_timeout_ms_, combiner());
425   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
426   GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. pending_request_:%p",
427                        this, pending_request_);
428 }
429
430 //
431 // Factory
432 //
433
434 class AresDnsResolverFactory : public ResolverFactory {
435  public:
436   bool IsValidUri(const grpc_uri* uri) const override { return true; }
437
438   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
439     return OrphanablePtr<Resolver>(New<AresDnsResolver>(std::move(args)));
440   }
441
442   const char* scheme() const override { return "dns"; }
443 };
444
445 }  // namespace
446
447 }  // namespace grpc_core
448
449 extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
450 static grpc_address_resolver_vtable* default_resolver;
451
452 static grpc_error* blocking_resolve_address_ares(
453     const char* name, const char* default_port,
454     grpc_resolved_addresses** addresses) {
455   return default_resolver->blocking_resolve_address(name, default_port,
456                                                     addresses);
457 }
458
459 static grpc_address_resolver_vtable ares_resolver = {
460     grpc_resolve_address_ares, blocking_resolve_address_ares};
461
462 #ifdef GRPC_UV
463 /* TODO(murgatroid99): Remove this when we want the cares resolver to be the
464  * default when using libuv */
465 static bool should_use_ares(const char* resolver_env) {
466   return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0;
467 }
468 #else  /* GRPC_UV */
469 static bool should_use_ares(const char* resolver_env) {
470   // TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support
471   // custom IO managers (e.g. gevent).
472   return !g_custom_iomgr_enabled &&
473          (resolver_env == nullptr || strlen(resolver_env) == 0 ||
474           gpr_stricmp(resolver_env, "ares") == 0);
475 }
476 #endif /* GRPC_UV */
477
478 static bool g_use_ares_dns_resolver;
479
480 void grpc_resolver_dns_ares_init() {
481   grpc_core::UniquePtr<char> resolver =
482       GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
483   if (should_use_ares(resolver.get())) {
484     g_use_ares_dns_resolver = true;
485     gpr_log(GPR_DEBUG, "Using ares dns resolver");
486     address_sorting_init();
487     grpc_error* error = grpc_ares_init();
488     if (error != GRPC_ERROR_NONE) {
489       GRPC_LOG_IF_ERROR("grpc_ares_init() failed", error);
490       return;
491     }
492     if (default_resolver == nullptr) {
493       default_resolver = grpc_resolve_address_impl;
494     }
495     grpc_set_resolver_impl(&ares_resolver);
496     grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
497         grpc_core::UniquePtr<grpc_core::ResolverFactory>(
498             grpc_core::New<grpc_core::AresDnsResolverFactory>()));
499   } else {
500     g_use_ares_dns_resolver = false;
501   }
502 }
503
504 void grpc_resolver_dns_ares_shutdown() {
505   if (g_use_ares_dns_resolver) {
506     address_sorting_shutdown();
507     grpc_ares_cleanup();
508   }
509 }
510
511 #else /* GRPC_ARES == 1 */
512
513 void grpc_resolver_dns_ares_init(void) {}
514
515 void grpc_resolver_dns_ares_shutdown(void) {}
516
517 #endif /* GRPC_ARES == 1 */