Convert resolver API to C++.

pull/13684/head
Mark D. Roth 7 years ago
parent 7bd5e18fea
commit 209f644f04
  1. 8
      BUILD
  2. 6
      CMakeLists.txt
  3. 6
      Makefile
  4. 1
      build.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 1
      gRPC-Core.podspec
  8. 1
      grpc.gemspec
  9. 4
      grpc.gyp
  10. 1
      package.xml
  11. 29
      src/core/ext/filters/client_channel/client_channel.cc
  12. 14
      src/core/ext/filters/client_channel/client_channel_plugin.cc
  13. 21
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  14. 5
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
  15. 2
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
  16. 5
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
  17. 58
      src/core/ext/filters/client_channel/resolver.cc
  18. 153
      src/core/ext/filters/client_channel/resolver.h
  19. 507
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  20. 449
      src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
  21. 326
      src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
  22. 77
      src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
  23. 250
      src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
  24. 40
      src/core/ext/filters/client_channel/resolver_factory.cc
  25. 65
      src/core/ext/filters/client_channel/resolver_factory.h
  26. 200
      src/core/ext/filters/client_channel/resolver_registry.cc
  27. 85
      src/core/ext/filters/client_channel/resolver_registry.h
  28. 8
      src/core/ext/transport/chttp2/client/insecure/channel_create.cc
  29. 8
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
  30. 1
      src/python/grpcio/grpc_core_dependencies.py
  31. 44
      test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
  32. 67
      test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
  33. 34
      test/core/client_channel/resolvers/dns_resolver_test.cc
  34. 113
      test/core/client_channel/resolvers/fake_resolver_test.cc
  35. 42
      test/core/client_channel/resolvers/sockaddr_resolver_test.cc
  36. 4
      test/core/surface/channel_create_test.cc
  37. 4
      test/core/surface/secure_channel_create_test.cc
  38. 13
      test/cpp/client/client_channel_stress_test.cc
  39. 30
      test/cpp/end2end/client_lb_end2end_test.cc
  40. 18
      test/cpp/end2end/grpclb_end2end_test.cc
  41. 22
      test/cpp/grpclb/grpclb_test.cc
  42. 30
      test/cpp/naming/resolver_component_test.cc
  43. 1
      tools/doxygen/Doxyfile.core.internal
  44. 1
      tools/run_tests/generated/sources_and_headers.json

@ -950,7 +950,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/proxy_mapper.cc",
"src/core/ext/filters/client_channel/proxy_mapper_registry.cc",
"src/core/ext/filters/client_channel/resolver.cc",
"src/core/ext/filters/client_channel/resolver_factory.cc",
"src/core/ext/filters/client_channel/resolver_registry.cc",
"src/core/ext/filters/client_channel/retry_throttle.cc",
"src/core/ext/filters/client_channel/subchannel.cc",
@ -980,10 +979,13 @@ grpc_cc_library(
],
language = "c++",
deps = [
"grpc_base",
"grpc_deadline_filter",
"inlined_vector",
"orphanable",
"ref_counted",
"ref_counted_ptr",
"gpr_base",
"grpc_base",
"grpc_deadline_filter",
],
)

@ -1002,7 +1002,6 @@ add_library(grpc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
@ -1313,7 +1312,6 @@ add_library(grpc_cronet
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
@ -1605,7 +1603,6 @@ add_library(grpc_test_util
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
@ -1872,7 +1869,6 @@ add_library(grpc_test_util_unsecure
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
@ -2155,7 +2151,6 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc
@ -2857,7 +2852,6 @@ add_library(grpc++_cronet
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_factory.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/subchannel.cc

@ -3231,7 +3231,6 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
@ -3544,7 +3543,6 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
@ -3837,7 +3835,6 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
@ -4097,7 +4094,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
@ -4360,7 +4356,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \
@ -5063,7 +5058,6 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \

@ -471,7 +471,6 @@ filegroups:
- src/core/ext/filters/client_channel/proxy_mapper.cc
- src/core/ext/filters/client_channel/proxy_mapper_registry.cc
- src/core/ext/filters/client_channel/resolver.cc
- src/core/ext/filters/client_channel/resolver_factory.cc
- src/core/ext/filters/client_channel/resolver_registry.cc
- src/core/ext/filters/client_channel/retry_throttle.cc
- src/core/ext/filters/client_channel/subchannel.cc

@ -293,7 +293,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/subchannel.cc \

@ -270,7 +270,6 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver_factory.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
"src\\core\\ext\\filters\\client_channel\\subchannel.cc " +

@ -679,7 +679,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',

@ -609,7 +609,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver_factory.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel.cc )

@ -434,7 +434,6 @@
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
@ -668,7 +667,6 @@
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
@ -880,7 +878,6 @@
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
@ -1107,7 +1104,6 @@
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',

@ -616,7 +616,6 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" />

@ -165,7 +165,7 @@ struct external_connectivity_watcher;
typedef struct client_channel_channel_data {
/** resolver for this channel */
grpc_resolver* resolver;
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
/** have we started resolving this channel */
bool started_resolving;
/** is deadline checking enabled? */
@ -300,8 +300,8 @@ static void start_resolving_locked(channel_data* chand) {
GPR_ASSERT(!chand->started_resolving);
chand->started_resolving = true;
GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next_locked(chand->resolver, &chand->resolver_result,
&chand->on_resolver_result_changed);
chand->resolver->NextLocked(&chand->resolver_result,
&chand->on_resolver_result_changed);
}
typedef struct {
@ -378,7 +378,7 @@ static void request_reresolution_locked(void* arg, grpc_error* error) {
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_DEBUG, "chand=%p: started name re-resolving", chand);
}
grpc_resolver_channel_saw_error_locked(chand->resolver);
chand->resolver->RequestReresolutionLocked();
// Give back the closure to the LB policy.
grpc_lb_policy_set_reresolve_closure_locked(chand->lb_policy, &args->closure);
}
@ -568,9 +568,7 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand);
}
grpc_resolver_shutdown_locked(chand->resolver);
GRPC_RESOLVER_UNREF(chand->resolver, "channel");
chand->resolver = nullptr;
chand->resolver.reset();
}
set_channel_connectivity_state_locked(
chand, GRPC_CHANNEL_SHUTDOWN,
@ -606,8 +604,8 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
set_channel_connectivity_state_locked(
chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver");
}
grpc_resolver_next_locked(chand->resolver, &chand->resolver_result,
&chand->on_resolver_result_changed);
chand->resolver->NextLocked(&chand->resolver_result,
&chand->on_resolver_result_changed);
GRPC_ERROR_UNREF(state_error);
}
}
@ -648,9 +646,7 @@ static void start_transport_op_locked(void* arg, grpc_error* error_ignored) {
set_channel_connectivity_state_locked(
chand, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
grpc_resolver_shutdown_locked(chand->resolver);
GRPC_RESOLVER_UNREF(chand->resolver, "channel");
chand->resolver = nullptr;
chand->resolver.reset();
if (!chand->started_resolving) {
grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
GRPC_ERROR_REF(op->disconnect_with_error));
@ -759,7 +755,7 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
grpc_proxy_mappers_map_name(arg->value.string, args->channel_args,
&proxy_name, &new_args);
// Instantiate resolver.
chand->resolver = grpc_resolver_create(
chand->resolver = grpc_core::ResolverRegistry::CreateResolver(
proxy_name != nullptr ? proxy_name : arg->value.string,
new_args != nullptr ? new_args : args->channel_args,
chand->interested_parties, chand->combiner);
@ -774,9 +770,8 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
}
static void shutdown_resolver_locked(void* arg, grpc_error* error) {
grpc_resolver* resolver = (grpc_resolver*)arg;
grpc_resolver_shutdown_locked(resolver);
GRPC_RESOLVER_UNREF(resolver, "channel");
grpc_core::Resolver* resolver = static_cast<grpc_core::Resolver*>(arg);
resolver->Orphan();
}
/* Destructor for channel_data */
@ -784,7 +779,7 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) {
channel_data* chand = (channel_data*)elem->channel_data;
if (chand->resolver != nullptr) {
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver,
GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver.release(),
grpc_combiner_scheduler(chand->combiner)),
GRPC_ERROR_NONE);
}

@ -49,14 +49,14 @@ static bool set_default_host_if_unset(grpc_channel_stack_builder* builder,
return true;
}
}
char* default_authority = grpc_get_default_authority(
grpc_channel_stack_builder_get_target(builder));
if (default_authority != nullptr) {
grpc_core::UniquePtr<char> default_authority =
grpc_core::ResolverRegistry::GetDefaultAuthority(
grpc_channel_stack_builder_get_target(builder));
if (default_authority.get() != nullptr) {
grpc_arg arg = grpc_channel_arg_string_create(
(char*)GRPC_ARG_DEFAULT_AUTHORITY, default_authority);
(char*)GRPC_ARG_DEFAULT_AUTHORITY, default_authority.get());
grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
gpr_free(default_authority);
grpc_channel_args_destroy(new_args);
}
return true;
@ -64,7 +64,7 @@ static bool set_default_host_if_unset(grpc_channel_stack_builder* builder,
void grpc_client_channel_init(void) {
grpc_lb_policy_registry_init();
grpc_resolver_registry_init();
grpc_core::ResolverRegistry::Builder::InitRegistry();
grpc_retry_throttle_map_init();
grpc_proxy_mapper_registry_init();
grpc_register_http_proxy_mapper();
@ -82,6 +82,6 @@ void grpc_client_channel_shutdown(void) {
grpc_channel_init_shutdown();
grpc_proxy_mapper_registry_shutdown();
grpc_retry_throttle_map_shutdown();
grpc_resolver_registry_shutdown();
grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
grpc_lb_policy_registry_shutdown();
}

@ -108,6 +108,7 @@
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
@ -242,7 +243,8 @@ typedef struct glb_lb_policy {
glb_lb_call_data* lb_calld;
/** response generator to inject address updates into \a lb_channel */
grpc_fake_resolver_response_generator* response_generator;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator;
/** the RR policy to use of the backend servers returned by the LB server */
grpc_lb_policy* rr_policy;
@ -872,7 +874,7 @@ static int balancer_name_cmp_fn(void* a, void* b) {
* - \a args: other args inherited from the grpclb policy. */
static grpc_channel_args* build_lb_channel_args(
const grpc_lb_addresses* addresses,
grpc_fake_resolver_response_generator* response_generator,
grpc_core::FakeResolverResponseGenerator* response_generator,
const grpc_channel_args* args) {
size_t num_grpclb_addrs = 0;
for (size_t i = 0; i < addresses->num_addresses; ++i) {
@ -941,7 +943,8 @@ static void glb_destroy(grpc_lb_policy* pol) {
if (glb_policy->fallback_backend_addresses != nullptr) {
grpc_lb_addresses_destroy(glb_policy->fallback_backend_addresses);
}
grpc_fake_resolver_response_generator_unref(glb_policy->response_generator);
// TODO(roth): Remove this once the LB policy becomes a C++ object.
glb_policy->response_generator.reset();
grpc_subchannel_index_unref();
gpr_free(glb_policy);
}
@ -1701,9 +1704,8 @@ static void glb_update_locked(grpc_lb_policy* policy,
// Propagate updates to the LB channel (pick_first) through the fake
// resolver.
grpc_channel_args* lb_channel_args = build_lb_channel_args(
addresses, glb_policy->response_generator, args->args);
grpc_fake_resolver_response_generator_set_response(
glb_policy->response_generator, lb_channel_args);
addresses, glb_policy->response_generator.get(), args->args);
glb_policy->response_generator->SetResponse(lb_channel_args);
grpc_channel_args_destroy(lb_channel_args);
// Start watching the LB channel connectivity for connection, if not
// already doing so.
@ -1858,17 +1860,16 @@ static grpc_lb_policy* glb_create(grpc_lb_policy_factory* factory,
/* Create a client channel over them to communicate with a LB service */
glb_policy->response_generator =
grpc_fake_resolver_response_generator_create();
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
grpc_channel_args* lb_channel_args = build_lb_channel_args(
addresses, glb_policy->response_generator, args->args);
addresses, glb_policy->response_generator.get(), args->args);
char* uri_str;
gpr_asprintf(&uri_str, "fake:///%s", glb_policy->server_name);
glb_policy->lb_channel = grpc_lb_policy_grpclb_create_lb_channel(
uri_str, args->client_channel_factory, lb_channel_args);
/* Propagate initial resolution */
grpc_fake_resolver_response_generator_set_response(
glb_policy->response_generator, lb_channel_args);
glb_policy->response_generator->SetResponse(lb_channel_args);
grpc_channel_args_destroy(lb_channel_args);
gpr_free(uri_str);
if (glb_policy->lb_channel == nullptr) {

@ -37,10 +37,11 @@ grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
grpc_slice_hash_table* targets_info,
grpc_fake_resolver_response_generator* response_generator,
grpc_core::FakeResolverResponseGenerator* response_generator,
const grpc_channel_args* args) {
const grpc_arg to_add[] = {
grpc_fake_resolver_response_generator_arg(response_generator)};
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator)};
/* We remove:
*
* - The channel arg for the LB policy name, since we want to use the default

@ -37,7 +37,7 @@ grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
grpc_slice_hash_table* targets_info,
grpc_fake_resolver_response_generator* response_generator,
grpc_core::FakeResolverResponseGenerator* response_generator,
const grpc_channel_args* args);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \

@ -63,11 +63,12 @@ grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
grpc_slice_hash_table* targets_info,
grpc_fake_resolver_response_generator* response_generator,
grpc_core::FakeResolverResponseGenerator* response_generator,
const grpc_channel_args* args) {
const grpc_arg to_add[] = {
grpc_lb_targets_info_create_channel_arg(targets_info),
grpc_fake_resolver_response_generator_arg(response_generator)};
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator)};
/* We remove:
*
* - The channel arg for the LB policy name, since we want to use the default

@ -22,58 +22,12 @@
grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount(false,
"resolver_refcount");
void grpc_resolver_init(grpc_resolver* resolver,
const grpc_resolver_vtable* vtable,
grpc_combiner* combiner) {
resolver->vtable = vtable;
resolver->combiner = GRPC_COMBINER_REF(combiner, "resolver");
gpr_ref_init(&resolver->refs, 1);
}
namespace grpc_core {
#ifndef NDEBUG
void grpc_resolver_ref(grpc_resolver* resolver, const char* file, int line,
const char* reason) {
if (grpc_trace_resolver_refcount.enabled()) {
gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"RESOLVER:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
old_refs, old_refs + 1, reason);
}
#else
void grpc_resolver_ref(grpc_resolver* resolver) {
#endif
gpr_ref(&resolver->refs);
}
Resolver::Resolver(grpc_combiner* combiner)
: InternallyRefCountedWithTracing(&grpc_trace_resolver_refcount),
combiner_(GRPC_COMBINER_REF(combiner, "resolver")) {}
#ifndef NDEBUG
void grpc_resolver_unref(grpc_resolver* resolver, const char* file, int line,
const char* reason) {
if (grpc_trace_resolver_refcount.enabled()) {
gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"RESOLVER:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
old_refs, old_refs - 1, reason);
}
#else
void grpc_resolver_unref(grpc_resolver* resolver) {
#endif
if (gpr_unref(&resolver->refs)) {
grpc_combiner* combiner = resolver->combiner;
resolver->vtable->destroy(resolver);
GRPC_COMBINER_UNREF(combiner, "resolver");
}
}
Resolver::~Resolver() { GRPC_COMBINER_UNREF(combiner_, "resolver"); }
void grpc_resolver_shutdown_locked(grpc_resolver* resolver) {
resolver->vtable->shutdown_locked(resolver);
}
void grpc_resolver_channel_saw_error_locked(grpc_resolver* resolver) {
resolver->vtable->channel_saw_error_locked(resolver);
}
void grpc_resolver_next_locked(grpc_resolver* resolver,
grpc_channel_args** result,
grpc_closure* on_complete) {
resolver->vtable->next_locked(resolver, result, on_complete);
}
} // namespace grpc_core

@ -19,67 +19,110 @@
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/lib/iomgr/iomgr.h"
#include <grpc/impl/codegen/grpc_types.h>
typedef struct grpc_resolver grpc_resolver;
typedef struct grpc_resolver_vtable grpc_resolver_vtable;
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/iomgr.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount;
/** \a grpc_resolver provides \a grpc_channel_args objects to its caller */
struct grpc_resolver {
const grpc_resolver_vtable* vtable;
gpr_refcount refs;
grpc_combiner* combiner;
};
namespace grpc_core {
/// Interface for name resolution.
///
/// This interface is designed to support both push-based and pull-based
/// mechanisms. A push-based mechanism is one where the resolver will
/// subscribe to updates for a given name, and the name service will
/// proactively send new data to the resolver whenever the data associated
/// with the name changes. A pull-based mechanism is one where the resolver
/// needs to query the name service again to get updated information (e.g.,
/// DNS).
///
/// Note: All methods with a "Locked" suffix must be called from the
/// combiner passed to the constructor.
class Resolver : public InternallyRefCountedWithTracing<Resolver> {
public:
// Not copyable nor movable.
Resolver(const Resolver&) = delete;
Resolver& operator=(const Resolver&) = delete;
/// Requests a callback when a new result becomes available.
/// When the new result is available, sets \a *result to the new result
/// and schedules \a on_complete for execution.
/// If resolution is fatally broken, sets \a *result to nullptr and
/// schedules \a on_complete with an error.
///
/// Note that the client channel will almost always have a request
/// to \a NextLocked() pending. When it gets the callback, it will
/// process the new result and then immediately make another call to
/// \a NextLocked(). This allows push-based resolvers to provide new
/// data as soon as it becomes available.
virtual void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) GRPC_ABSTRACT;
/// Asks the resolver to obtain an updated resolver result, if
/// applicable.
///
/// This is useful for pull-based implementations to decide when to
/// re-resolve. However, the implementation is not required to
/// re-resolve immediately upon receiving this call; it may instead
/// elect to delay based on some configured minimum time between
/// queries, to avoid hammering the name service with queries.
///
/// For push-based implementations, this may be a no-op.
///
/// If this causes new data to become available, then the currently
/// pending call to \a NextLocked() will return the new result.
///
/// Note: Currently, all resolvers are required to return a new result
/// shortly after this method is called. For pull-based mechanisms, if
/// the implementation decides to delay querying the name service, it
/// should immediately return a new copy of the previously returned
/// result (and it can then return the updated data later, when it
/// actually does query the name service). For push-based mechanisms,
/// the implementation should immediately return a new copy of the
/// last-seen result.
/// TODO(roth): Remove this requirement once we fix pick_first to not
/// throw away unselected subchannels.
virtual void RequestReresolutionLocked() GRPC_ABSTRACT;
void Orphan() override {
// Invoke ShutdownAndUnrefLocked() inside of the combiner.
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(&Resolver::ShutdownAndUnrefLocked, this,
grpc_combiner_scheduler(combiner_)),
GRPC_ERROR_NONE);
}
GRPC_ABSTRACT_BASE_CLASS
protected:
/// Does NOT take ownership of the reference to \a combiner.
// TODO(roth): Once we have a C++-like interface for combiners, this
// API should change to take a RefCountedPtr<>, so that we always take
// ownership of a new ref.
explicit Resolver(grpc_combiner* combiner);
virtual ~Resolver();
/// Shuts down the resolver. If there is a pending call to
/// NextLocked(), the callback will be scheduled with an error.
virtual void ShutdownLocked() GRPC_ABSTRACT;
grpc_combiner* combiner() const { return combiner_; }
private:
static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored) {
Resolver* resolver = static_cast<Resolver*>(arg);
resolver->ShutdownLocked();
resolver->Unref();
}
struct grpc_resolver_vtable {
void (*destroy)(grpc_resolver* resolver);
void (*shutdown_locked)(grpc_resolver* resolver);
void (*channel_saw_error_locked)(grpc_resolver* resolver);
void (*next_locked)(grpc_resolver* resolver, grpc_channel_args** result,
grpc_closure* on_complete);
grpc_combiner* combiner_;
};
#ifndef NDEBUG
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r))
#define GRPC_RESOLVER_UNREF(p, r) \
grpc_resolver_unref((p), __FILE__, __LINE__, (r))
void grpc_resolver_ref(grpc_resolver* policy, const char* file, int line,
const char* reason);
void grpc_resolver_unref(grpc_resolver* policy, const char* file, int line,
const char* reason);
#else
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
#define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p))
void grpc_resolver_ref(grpc_resolver* policy);
void grpc_resolver_unref(grpc_resolver* policy);
#endif
void grpc_resolver_init(grpc_resolver* resolver,
const grpc_resolver_vtable* vtable,
grpc_combiner* combiner);
void grpc_resolver_shutdown_locked(grpc_resolver* resolver);
/** Notification that the channel has seen an error on some address.
Can be used as a hint that re-resolution is desirable soon.
Must be called from the combiner passed as a resolver_arg at construction
time.*/
void grpc_resolver_channel_saw_error_locked(grpc_resolver* resolver);
/** Get the next result from the resolver. Expected to set \a *result with
new channel args and then schedule \a on_complete for execution.
If resolution is fatally broken, set \a *result to NULL and
schedule \a on_complete.
Must be called from the combiner passed as a resolver_arg at construction
time.*/
void grpc_resolver_next_locked(grpc_resolver* resolver,
grpc_channel_args** result,
grpc_closure* on_complete);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H */

@ -49,109 +49,168 @@
#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** DNS server to use (if not system default) */
char* dns_server;
/** name to resolve (usually the same as target_name) */
char* name_to_resolve;
/** default port to use */
char* default_port;
/** channel args. */
grpc_channel_args* channel_args;
/** whether to request the service config */
bool request_service_config;
/** pollset_set to drive the name resolution process */
grpc_pollset_set* interested_parties;
/** Closures used by the combiner */
grpc_closure dns_ares_on_next_resolution_timer_closure;
grpc_closure dns_ares_on_resolved_closure;
/** Combiner guarding the rest of the state */
grpc_combiner* combiner;
/** are we currently resolving? */
bool resolving;
/** the pending resolving request */
grpc_ares_request* pending_request;
/** which version of the result have we published? */
int published_version;
/** which version of the result is current? */
int resolved_version;
/** pending next completion, or NULL */
grpc_closure* next_completion;
/** target result address for next completion */
grpc_channel_args** target_result;
/** current (fully resolved) result */
grpc_channel_args* resolved_result;
/** next resolution timer */
bool have_next_resolution_timer;
grpc_timer next_resolution_timer;
/** retry backoff state */
grpc_core::ManualConstructor<grpc_core::BackOff> backoff;
/** min resolution period. Max one resolution will happen per period */
grpc_millis min_time_between_resolutions;
/** when was the last resolution? -1 if no resolution has happened yet */
grpc_millis last_resolution_timestamp;
/** currently resolving addresses */
grpc_lb_addresses* lb_addresses;
/** currently resolving service config */
char* service_config_json;
} ares_dns_resolver;
static void dns_ares_destroy(grpc_resolver* r);
static void dns_ares_start_resolving_locked(ares_dns_resolver* r);
static void dns_ares_maybe_start_resolving_locked(ares_dns_resolver* r);
static void dns_ares_maybe_finish_next_locked(ares_dns_resolver* r);
static void dns_ares_shutdown_locked(grpc_resolver* r);
static void dns_ares_channel_saw_error_locked(grpc_resolver* r);
static void dns_ares_next_locked(grpc_resolver* r,
grpc_channel_args** target_result,
grpc_closure* on_complete);
static const grpc_resolver_vtable dns_ares_resolver_vtable = {
dns_ares_destroy, dns_ares_shutdown_locked,
dns_ares_channel_saw_error_locked, dns_ares_next_locked};
static void dns_ares_shutdown_locked(grpc_resolver* resolver) {
ares_dns_resolver* r = (ares_dns_resolver*)resolver;
if (r->have_next_resolution_timer) {
grpc_timer_cancel(&r->next_resolution_timer);
namespace grpc_core {
namespace {
const char kDefaultPort[] = "https";
class AresDnsResolver : public Resolver {
public:
explicit AresDnsResolver(const ResolverArgs& args);
void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) override;
void RequestReresolutionLocked() override;
void ShutdownLocked() override;
private:
virtual ~AresDnsResolver();
void MaybeStartResolvingLocked();
void StartResolvingLocked();
void MaybeFinishNextLocked();
static void OnNextResolutionLocked(void* arg, grpc_error* error);
static void OnResolvedLocked(void* arg, grpc_error* error);
/// DNS server to use (if not system default)
char* dns_server_;
/// name to resolve (usually the same as target_name)
char* name_to_resolve_;
/// channel args
grpc_channel_args* channel_args_;
/// whether to request the service config
bool request_service_config_;
/// pollset_set to drive the name resolution process
grpc_pollset_set* interested_parties_;
/// closures used by the combiner
grpc_closure on_next_resolution_;
grpc_closure on_resolved_;
/// are we currently resolving?
bool resolving_ = false;
/// the pending resolving request
grpc_ares_request* pending_request_ = nullptr;
/// which version of the result have we published?
int published_version_ = 0;
/// which version of the result is current?
int resolved_version_ = 0;
/// pending next completion, or NULL
grpc_closure* next_completion_ = nullptr;
/// target result address for next completion
grpc_channel_args** target_result_ = nullptr;
/// current (fully resolved) result
grpc_channel_args* resolved_result_ = nullptr;
/// next resolution timer
bool have_next_resolution_timer_ = false;
grpc_timer next_resolution_timer_;
/// min interval between DNS requests
grpc_millis min_time_between_resolutions_;
/// timestamp of last DNS request
grpc_millis last_resolution_timestamp_ = -1;
/// retry backoff state
BackOff backoff_;
/// currently resolving addresses
grpc_lb_addresses* lb_addresses_ = nullptr;
/// currently resolving service config
char* service_config_json_ = nullptr;
};
AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
: Resolver(args.combiner),
backoff_(
BackOff::Options()
.set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
1000)
.set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
.set_jitter(GRPC_DNS_RECONNECT_JITTER)
.set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
// Get name to resolve from URI path.
const char* path = args.uri->path;
if (path[0] == '/') ++path;
name_to_resolve_ = gpr_strdup(path);
// Get DNS server from URI authority.
if (0 != strcmp(args.uri->authority, "")) {
dns_server_ = gpr_strdup(args.uri->authority);
}
channel_args_ = grpc_channel_args_copy(args.args);
const grpc_arg* arg = grpc_channel_args_find(
channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
request_service_config_ = !grpc_channel_arg_get_integer(
arg, (grpc_integer_options){false, false, true});
arg = grpc_channel_args_find(channel_args_,
GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
min_time_between_resolutions_ =
grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
interested_parties_ = grpc_pollset_set_create();
if (args.pollset_set != nullptr) {
grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
}
GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolutionLocked, this,
grpc_combiner_scheduler(combiner()));
GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this,
grpc_combiner_scheduler(combiner()));
}
AresDnsResolver::~AresDnsResolver() {
gpr_log(GPR_DEBUG, "destroying AresDnsResolver");
if (resolved_result_ != nullptr) {
grpc_channel_args_destroy(resolved_result_);
}
if (r->pending_request != nullptr) {
grpc_cancel_ares_request(r->pending_request);
grpc_pollset_set_destroy(interested_parties_);
gpr_free(dns_server_);
gpr_free(name_to_resolve_);
grpc_channel_args_destroy(channel_args_);
}
void AresDnsResolver::NextLocked(grpc_channel_args** target_result,
grpc_closure* on_complete) {
gpr_log(GPR_DEBUG, "AresDnsResolver::NextLocked() is called.");
GPR_ASSERT(next_completion_ == nullptr);
next_completion_ = on_complete;
target_result_ = target_result;
if (resolved_version_ == 0 && !resolving_) {
MaybeStartResolvingLocked();
} else {
MaybeFinishNextLocked();
}
if (r->next_completion != nullptr) {
*r->target_result = nullptr;
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
r->next_completion = nullptr;
}
void AresDnsResolver::RequestReresolutionLocked() {
if (!resolving_) {
MaybeStartResolvingLocked();
}
}
static void dns_ares_channel_saw_error_locked(grpc_resolver* resolver) {
ares_dns_resolver* r = (ares_dns_resolver*)resolver;
if (!r->resolving) {
dns_ares_maybe_start_resolving_locked(r);
void AresDnsResolver::ShutdownLocked() {
if (have_next_resolution_timer_) {
grpc_timer_cancel(&next_resolution_timer_);
}
if (pending_request_ != nullptr) {
grpc_cancel_ares_request(pending_request_);
}
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
next_completion_ = nullptr;
}
}
static void dns_ares_on_next_resolution_timer_locked(void* arg,
grpc_error* error) {
ares_dns_resolver* r = (ares_dns_resolver*)arg;
r->have_next_resolution_timer = false;
void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
r->have_next_resolution_timer_ = false;
if (error == GRPC_ERROR_NONE) {
if (!r->resolving) {
dns_ares_start_resolving_locked(r);
if (!r->resolving_) {
r->StartResolvingLocked();
}
}
GRPC_RESOLVER_UNREF(&r->base, "next_resolution_timer");
r->Unref(DEBUG_LOCATION, "next_resolution_timer");
}
static bool value_in_json_array(grpc_json* array, const char* value) {
bool ValueInJsonArray(grpc_json* array, const char* value) {
for (grpc_json* entry = array->child; entry != nullptr; entry = entry->next) {
if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) {
return true;
@ -160,7 +219,7 @@ static bool value_in_json_array(grpc_json* array, const char* value) {
return false;
}
static char* choose_service_config(char* service_config_choice_json) {
char* ChooseServiceConfig(char* service_config_choice_json) {
grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
if (choices_json == nullptr || choices_json->type != GRPC_JSON_ARRAY) {
gpr_log(GPR_ERROR, "cannot parse service config JSON string");
@ -178,8 +237,7 @@ static char* choose_service_config(char* service_config_choice_json) {
field = field->next) {
// Check client language, if specified.
if (strcmp(field->key, "clientLanguage") == 0) {
if (field->type != GRPC_JSON_ARRAY ||
!value_in_json_array(field, "c++")) {
if (field->type != GRPC_JSON_ARRAY || !ValueInJsonArray(field, "c++")) {
service_config_json = nullptr;
break;
}
@ -188,7 +246,7 @@ static char* choose_service_config(char* service_config_choice_json) {
if (strcmp(field->key, "clientHostname") == 0) {
char* hostname = grpc_gethostname();
if (hostname == nullptr || field->type != GRPC_JSON_ARRAY ||
!value_in_json_array(field, hostname)) {
!ValueInJsonArray(field, hostname)) {
service_config_json = nullptr;
break;
}
@ -223,24 +281,24 @@ static char* choose_service_config(char* service_config_choice_json) {
return service_config;
}
static void dns_ares_on_resolved_locked(void* arg, grpc_error* error) {
ares_dns_resolver* r = (ares_dns_resolver*)arg;
void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
grpc_channel_args* result = nullptr;
GPR_ASSERT(r->resolving);
r->resolving = false;
r->pending_request = nullptr;
if (r->lb_addresses != nullptr) {
GPR_ASSERT(r->resolving_);
r->resolving_ = false;
r->pending_request_ = nullptr;
if (r->lb_addresses_ != nullptr) {
static const char* args_to_remove[2];
size_t num_args_to_remove = 0;
grpc_arg new_args[3];
size_t num_args_to_add = 0;
new_args[num_args_to_add++] =
grpc_lb_addresses_create_channel_arg(r->lb_addresses);
grpc_lb_addresses_create_channel_arg(r->lb_addresses_);
grpc_service_config* service_config = nullptr;
char* service_config_string = nullptr;
if (r->service_config_json != nullptr) {
service_config_string = choose_service_config(r->service_config_json);
gpr_free(r->service_config_json);
if (r->service_config_json_ != nullptr) {
service_config_string = ChooseServiceConfig(r->service_config_json_);
gpr_free(r->service_config_json_);
if (service_config_string != nullptr) {
gpr_log(GPR_INFO, "selected service config choice: %s",
service_config_string);
@ -260,221 +318,150 @@ static void dns_ares_on_resolved_locked(void* arg, grpc_error* error) {
}
}
result = grpc_channel_args_copy_and_add_and_remove(
r->channel_args, args_to_remove, num_args_to_remove, new_args,
r->channel_args_, args_to_remove, num_args_to_remove, new_args,
num_args_to_add);
if (service_config != nullptr) grpc_service_config_destroy(service_config);
gpr_free(service_config_string);
grpc_lb_addresses_destroy(r->lb_addresses);
grpc_lb_addresses_destroy(r->lb_addresses_);
// Reset backoff state so that we start from the beginning when the
// next request gets triggered.
r->backoff->Reset();
r->backoff_.Reset();
} else {
const char* msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
grpc_millis next_try = r->backoff->NextAttemptTime();
grpc_millis timeout = next_try - grpc_core::ExecCtx::Get()->Now();
grpc_millis next_try = r->backoff_.NextAttemptTime();
grpc_millis timeout = next_try - ExecCtx::Get()->Now();
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
GPR_ASSERT(!r->have_next_resolution_timer);
r->have_next_resolution_timer = true;
GRPC_RESOLVER_REF(&r->base, "next_resolution_timer");
GPR_ASSERT(!r->have_next_resolution_timer_);
r->have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self = r->Ref(DEBUG_LOCATION, "retry-timer");
self.release();
if (timeout > 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
} else {
gpr_log(GPR_DEBUG, "retrying immediately");
}
grpc_timer_init(&r->next_resolution_timer, next_try,
&r->dns_ares_on_next_resolution_timer_closure);
grpc_timer_init(&r->next_resolution_timer_, next_try,
&r->on_next_resolution_);
}
if (r->resolved_result != nullptr) {
grpc_channel_args_destroy(r->resolved_result);
}
r->resolved_result = result;
r->last_resolution_timestamp = grpc_core::ExecCtx::Get()->Now();
r->resolved_version++;
dns_ares_maybe_finish_next_locked(r);
GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
}
static void dns_ares_next_locked(grpc_resolver* resolver,
grpc_channel_args** target_result,
grpc_closure* on_complete) {
gpr_log(GPR_DEBUG, "dns_ares_next is called.");
ares_dns_resolver* r = (ares_dns_resolver*)resolver;
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
if (r->resolved_version == 0 && !r->resolving) {
dns_ares_maybe_start_resolving_locked(r);
} else {
dns_ares_maybe_finish_next_locked(r);
if (r->resolved_result_ != nullptr) {
grpc_channel_args_destroy(r->resolved_result_);
}
r->resolved_result_ = result;
++r->resolved_version_;
r->MaybeFinishNextLocked();
r->Unref(DEBUG_LOCATION, "dns-resolving");
}
static void dns_ares_start_resolving_locked(ares_dns_resolver* r) {
GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving);
r->resolving = true;
r->lb_addresses = nullptr;
r->service_config_json = nullptr;
r->pending_request = grpc_dns_lookup_ares(
r->dns_server, r->name_to_resolve, r->default_port, r->interested_parties,
&r->dns_ares_on_resolved_closure, &r->lb_addresses,
true /* check_grpclb */,
r->request_service_config ? &r->service_config_json : nullptr);
}
static void dns_ares_maybe_finish_next_locked(ares_dns_resolver* r) {
if (r->next_completion != nullptr &&
r->resolved_version != r->published_version) {
*r->target_result = r->resolved_result == nullptr
? nullptr
: grpc_channel_args_copy(r->resolved_result);
gpr_log(GPR_DEBUG, "dns_ares_maybe_finish_next_locked");
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
r->next_completion = nullptr;
r->published_version = r->resolved_version;
}
}
static void dns_ares_maybe_start_resolving_locked(ares_dns_resolver* r) {
if (r->last_resolution_timestamp >= 0) {
void AresDnsResolver::MaybeStartResolvingLocked() {
if (last_resolution_timestamp_ >= 0) {
const grpc_millis earliest_next_resolution =
r->last_resolution_timestamp + r->min_time_between_resolutions;
last_resolution_timestamp_ + min_time_between_resolutions_;
const grpc_millis ms_until_next_resolution =
earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
if (ms_until_next_resolution > 0) {
const grpc_millis last_resolution_ago =
grpc_core::ExecCtx::Get()->Now() - r->last_resolution_timestamp;
grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
gpr_log(GPR_DEBUG,
"In cooldown from last resolution (from %" PRIdPTR
" ms ago). Will resolve again in %" PRIdPTR " ms",
last_resolution_ago, ms_until_next_resolution);
if (!r->have_next_resolution_timer) {
r->have_next_resolution_timer = true;
GRPC_RESOLVER_REF(&r->base, "next_resolution_timer_cooldown");
grpc_timer_init(&r->next_resolution_timer, ms_until_next_resolution,
&r->dns_ares_on_next_resolution_timer_closure);
if (!have_next_resolution_timer_) {
have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self =
Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown");
self.release();
grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
&on_next_resolution_);
}
// TODO(dgq): remove the following two lines once Pick First stops
// discarding subchannels after selecting.
++r->resolved_version;
dns_ares_maybe_finish_next_locked(r);
++resolved_version_;
MaybeFinishNextLocked();
return;
}
}
dns_ares_start_resolving_locked(r);
StartResolvingLocked();
}
static void dns_ares_destroy(grpc_resolver* gr) {
gpr_log(GPR_DEBUG, "dns_ares_destroy");
ares_dns_resolver* r = (ares_dns_resolver*)gr;
if (r->resolved_result != nullptr) {
grpc_channel_args_destroy(r->resolved_result);
}
grpc_pollset_set_destroy(r->interested_parties);
gpr_free(r->dns_server);
gpr_free(r->name_to_resolve);
gpr_free(r->default_port);
grpc_channel_args_destroy(r->channel_args);
gpr_free(r);
void AresDnsResolver::StartResolvingLocked() {
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self = Ref(DEBUG_LOCATION, "dns-resolving");
self.release();
GPR_ASSERT(!resolving_);
resolving_ = true;
lb_addresses_ = nullptr;
service_config_json_ = nullptr;
pending_request_ = grpc_dns_lookup_ares(
dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
&on_resolved_, &lb_addresses_, true /* check_grpclb */,
request_service_config_ ? &service_config_json_ : nullptr);
last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
}
static grpc_resolver* dns_ares_create(grpc_resolver_args* args,
const char* default_port) {
/* Get name from args. */
const char* path = args->uri->path;
if (path[0] == '/') ++path;
/* Create resolver. */
ares_dns_resolver* r =
(ares_dns_resolver*)gpr_zalloc(sizeof(ares_dns_resolver));
grpc_resolver_init(&r->base, &dns_ares_resolver_vtable, args->combiner);
if (0 != strcmp(args->uri->authority, "")) {
r->dns_server = gpr_strdup(args->uri->authority);
}
r->name_to_resolve = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
r->channel_args = grpc_channel_args_copy(args->args);
const grpc_arg* arg = grpc_channel_args_find(
r->channel_args, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
r->request_service_config = !grpc_channel_arg_get_integer(
arg, (grpc_integer_options){false, false, true});
r->interested_parties = grpc_pollset_set_create();
if (args->pollset_set != nullptr) {
grpc_pollset_set_add_pollset_set(r->interested_parties, args->pollset_set);
void AresDnsResolver::MaybeFinishNextLocked() {
if (next_completion_ != nullptr && resolved_version_ != published_version_) {
*target_result_ = resolved_result_ == nullptr
? nullptr
: grpc_channel_args_copy(resolved_result_);
gpr_log(GPR_DEBUG, "AresDnsResolver::MaybeFinishNextLocked()");
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
published_version_ = resolved_version_;
}
grpc_core::BackOff::Options backoff_options;
backoff_options
.set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
.set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
.set_jitter(GRPC_DNS_RECONNECT_JITTER)
.set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
r->backoff.Init(grpc_core::BackOff(backoff_options));
GRPC_CLOSURE_INIT(&r->dns_ares_on_next_resolution_timer_closure,
dns_ares_on_next_resolution_timer_locked, r,
grpc_combiner_scheduler(r->base.combiner));
GRPC_CLOSURE_INIT(&r->dns_ares_on_resolved_closure,
dns_ares_on_resolved_locked, r,
grpc_combiner_scheduler(r->base.combiner));
const grpc_arg* period_arg = grpc_channel_args_find(
args->args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
r->min_time_between_resolutions =
grpc_channel_arg_get_integer(period_arg, {1000, 0, INT_MAX});
r->last_resolution_timestamp = -1;
return &r->base;
}
/*
* FACTORY
*/
static void dns_ares_factory_ref(grpc_resolver_factory* factory) {}
//
// Factory
//
static void dns_ares_factory_unref(grpc_resolver_factory* factory) {}
static grpc_resolver* dns_factory_create_resolver(
grpc_resolver_factory* factory, grpc_resolver_args* args) {
return dns_ares_create(args, "https");
}
class AresDnsResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
return OrphanablePtr<Resolver>(New<AresDnsResolver>(args));
}
static char* dns_ares_factory_get_default_host_name(
grpc_resolver_factory* factory, grpc_uri* uri) {
const char* path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
}
const char* scheme() const override { return "dns"; }
};
static const grpc_resolver_factory_vtable dns_ares_factory_vtable = {
dns_ares_factory_ref, dns_ares_factory_unref, dns_factory_create_resolver,
dns_ares_factory_get_default_host_name, "dns"};
static grpc_resolver_factory dns_resolver_factory = {&dns_ares_factory_vtable};
} // namespace
static grpc_resolver_factory* dns_ares_resolver_factory_create() {
return &dns_resolver_factory;
}
} // namespace grpc_core
void grpc_resolver_dns_ares_init(void) {
char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
void grpc_resolver_dns_ares_init() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
/* TODO(zyc): Turn on c-ares based resolver by default after the address
sorter and the CNAME support are added. */
if (resolver != nullptr && gpr_stricmp(resolver, "ares") == 0) {
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
grpc_error* error = grpc_ares_init();
if (error != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("ares_library_init() failed", error);
return;
}
grpc_resolve_address = grpc_resolve_address_ares;
grpc_register_resolver_type(dns_ares_resolver_factory_create());
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::AresDnsResolverFactory>()));
}
gpr_free(resolver);
gpr_free(resolver_env);
}
void grpc_resolver_dns_ares_shutdown(void) {
char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver != nullptr && gpr_stricmp(resolver, "ares") == 0) {
void grpc_resolver_dns_ares_shutdown() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
grpc_ares_cleanup();
}
gpr_free(resolver);
gpr_free(resolver_env);
}
#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */

@ -43,301 +43,298 @@
#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** name to resolve */
char* name_to_resolve;
/** default port to use */
char* default_port;
/** channel args. */
grpc_channel_args* channel_args;
/** pollset_set to drive the name resolution process */
grpc_pollset_set* interested_parties;
/** are we currently resolving? */
bool resolving;
/** which version of the result have we published? */
int published_version;
/** which version of the result is current? */
int resolved_version;
/** pending next completion, or NULL */
grpc_closure* next_completion;
/** target result address for next completion */
grpc_channel_args** target_result;
/** current (fully resolved) result */
grpc_channel_args* resolved_result;
/** next resolution timer */
bool have_next_resolution_timer;
grpc_timer next_resolution_timer;
grpc_closure next_resolution_closure;
/** retry backoff state */
grpc_core::ManualConstructor<grpc_core::BackOff> backoff;
/** min resolution period. Max one resolution will happen per period */
grpc_millis min_time_between_resolutions;
/** when was the last resolution? -1 if no resolution has happened yet */
grpc_millis last_resolution_timestamp;
/** currently resolving addresses */
grpc_resolved_addresses* addresses;
} dns_resolver;
static void dns_destroy(grpc_resolver* r);
static void dns_start_resolving_locked(dns_resolver* r);
static void maybe_start_resolving_locked(dns_resolver* r);
static void dns_maybe_finish_next_locked(dns_resolver* r);
static void dns_shutdown_locked(grpc_resolver* r);
static void dns_channel_saw_error_locked(grpc_resolver* r);
static void dns_next_locked(grpc_resolver* r, grpc_channel_args** target_result,
grpc_closure* on_complete);
static const grpc_resolver_vtable dns_resolver_vtable = {
dns_destroy, dns_shutdown_locked, dns_channel_saw_error_locked,
dns_next_locked};
static void dns_shutdown_locked(grpc_resolver* resolver) {
dns_resolver* r = (dns_resolver*)resolver;
if (r->have_next_resolution_timer) {
grpc_timer_cancel(&r->next_resolution_timer);
}
if (r->next_completion != nullptr) {
*r->target_result = nullptr;
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
r->next_completion = nullptr;
namespace grpc_core {
namespace {
const char kDefaultPort[] = "https";
class NativeDnsResolver : public Resolver {
public:
explicit NativeDnsResolver(const ResolverArgs& args);
void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) override;
void RequestReresolutionLocked() override;
void ShutdownLocked() override;
private:
virtual ~NativeDnsResolver();
void MaybeStartResolvingLocked();
void StartResolvingLocked();
void MaybeFinishNextLocked();
static void OnNextResolutionLocked(void* arg, grpc_error* error);
static void OnResolvedLocked(void* arg, grpc_error* error);
/// name to resolve
char* name_to_resolve_ = nullptr;
/// channel args
grpc_channel_args* channel_args_ = nullptr;
/// pollset_set to drive the name resolution process
grpc_pollset_set* interested_parties_ = nullptr;
/// are we currently resolving?
bool resolving_ = false;
grpc_closure on_resolved_;
/// which version of the result have we published?
int published_version_ = 0;
/// which version of the result is current?
int resolved_version_ = 0;
/// pending next completion, or nullptr
grpc_closure* next_completion_ = nullptr;
/// target result address for next completion
grpc_channel_args** target_result_ = nullptr;
/// current (fully resolved) result
grpc_channel_args* resolved_result_ = nullptr;
/// next resolution timer
bool have_next_resolution_timer_ = false;
grpc_timer next_resolution_timer_;
grpc_closure on_next_resolution_;
/// min time between DNS requests
grpc_millis min_time_between_resolutions_;
/// timestamp of last DNS request
grpc_millis last_resolution_timestamp_ = -1;
/// retry backoff state
BackOff backoff_;
/// currently resolving addresses
grpc_resolved_addresses* addresses_ = nullptr;
};
NativeDnsResolver::NativeDnsResolver(const ResolverArgs& args)
: Resolver(args.combiner),
backoff_(
BackOff::Options()
.set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
1000)
.set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
.set_jitter(GRPC_DNS_RECONNECT_JITTER)
.set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
char* path = args.uri->path;
if (path[0] == '/') ++path;
name_to_resolve_ = gpr_strdup(path);
channel_args_ = grpc_channel_args_copy(args.args);
const grpc_arg* arg = grpc_channel_args_find(
args.args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
min_time_between_resolutions_ =
grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
interested_parties_ = grpc_pollset_set_create();
if (args.pollset_set != nullptr) {
grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
}
GRPC_CLOSURE_INIT(&on_next_resolution_,
NativeDnsResolver::OnNextResolutionLocked, this,
grpc_combiner_scheduler(args.combiner));
GRPC_CLOSURE_INIT(&on_resolved_, NativeDnsResolver::OnResolvedLocked, this,
grpc_combiner_scheduler(args.combiner));
}
static void dns_channel_saw_error_locked(grpc_resolver* resolver) {
dns_resolver* r = (dns_resolver*)resolver;
if (!r->resolving) {
maybe_start_resolving_locked(r);
NativeDnsResolver::~NativeDnsResolver() {
if (resolved_result_ != nullptr) {
grpc_channel_args_destroy(resolved_result_);
}
grpc_pollset_set_destroy(interested_parties_);
gpr_free(name_to_resolve_);
grpc_channel_args_destroy(channel_args_);
}
static void dns_next_locked(grpc_resolver* resolver,
grpc_channel_args** target_result,
grpc_closure* on_complete) {
dns_resolver* r = (dns_resolver*)resolver;
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
if (r->resolved_version == 0 && !r->resolving) {
maybe_start_resolving_locked(r);
void NativeDnsResolver::NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) {
GPR_ASSERT(next_completion_ == nullptr);
next_completion_ = on_complete;
target_result_ = result;
if (resolved_version_ == 0 && !resolving_) {
MaybeStartResolvingLocked();
} else {
dns_maybe_finish_next_locked(r);
MaybeFinishNextLocked();
}
}
void NativeDnsResolver::RequestReresolutionLocked() {
if (!resolving_) {
MaybeStartResolvingLocked();
}
}
void NativeDnsResolver::ShutdownLocked() {
if (have_next_resolution_timer_) {
grpc_timer_cancel(&next_resolution_timer_);
}
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
next_completion_ = nullptr;
}
}
static void dns_on_next_resolution_timer_locked(void* arg, grpc_error* error) {
dns_resolver* r = (dns_resolver*)arg;
r->have_next_resolution_timer = false;
if (error == GRPC_ERROR_NONE && !r->resolving) {
dns_start_resolving_locked(r);
void NativeDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
r->have_next_resolution_timer_ = false;
if (error == GRPC_ERROR_NONE && !r->resolving_) {
r->StartResolvingLocked();
}
GRPC_RESOLVER_UNREF(&r->base, "next_resolution_timer");
r->Unref(DEBUG_LOCATION, "retry-timer");
}
static void dns_on_resolved_locked(void* arg, grpc_error* error) {
dns_resolver* r = (dns_resolver*)arg;
void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
grpc_channel_args* result = nullptr;
GPR_ASSERT(r->resolving);
r->resolving = false;
GPR_ASSERT(r->resolving_);
r->resolving_ = false;
GRPC_ERROR_REF(error);
error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(r->name_to_resolve));
if (r->addresses != nullptr) {
error =
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(r->name_to_resolve_));
if (r->addresses_ != nullptr) {
grpc_lb_addresses* addresses = grpc_lb_addresses_create(
r->addresses->naddrs, nullptr /* user_data_vtable */);
for (size_t i = 0; i < r->addresses->naddrs; ++i) {
r->addresses_->naddrs, nullptr /* user_data_vtable */);
for (size_t i = 0; i < r->addresses_->naddrs; ++i) {
grpc_lb_addresses_set_address(
addresses, i, &r->addresses->addrs[i].addr,
r->addresses->addrs[i].len, false /* is_balancer */,
addresses, i, &r->addresses_->addrs[i].addr,
r->addresses_->addrs[i].len, false /* is_balancer */,
nullptr /* balancer_name */, nullptr /* user_data */);
}
grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
grpc_resolved_addresses_destroy(r->addresses);
result = grpc_channel_args_copy_and_add(r->channel_args_, &new_arg, 1);
grpc_resolved_addresses_destroy(r->addresses_);
grpc_lb_addresses_destroy(addresses);
// Reset backoff state so that we start from the beginning when the
// next request gets triggered.
r->backoff->Reset();
r->backoff_.Reset();
} else {
grpc_millis next_try = r->backoff->NextAttemptTime();
grpc_millis timeout = next_try - grpc_core::ExecCtx::Get()->Now();
grpc_millis next_try = r->backoff_.NextAttemptTime();
grpc_millis timeout = next_try - ExecCtx::Get()->Now();
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
GPR_ASSERT(!r->have_next_resolution_timer);
r->have_next_resolution_timer = true;
GRPC_RESOLVER_REF(&r->base, "next_resolution_timer");
GPR_ASSERT(!r->have_next_resolution_timer_);
r->have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self =
r->Ref(DEBUG_LOCATION, "next_resolution_timer");
self.release();
if (timeout > 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
} else {
gpr_log(GPR_DEBUG, "retrying immediately");
}
grpc_timer_init(&r->next_resolution_timer, next_try,
&r->next_resolution_closure);
grpc_timer_init(&r->next_resolution_timer_, next_try,
&r->on_next_resolution_);
}
if (r->resolved_result != nullptr) {
grpc_channel_args_destroy(r->resolved_result);
if (r->resolved_result_ != nullptr) {
grpc_channel_args_destroy(r->resolved_result_);
}
r->resolved_result = result;
r->resolved_version++;
dns_maybe_finish_next_locked(r);
r->resolved_result_ = result;
++r->resolved_version_;
r->MaybeFinishNextLocked();
GRPC_ERROR_UNREF(error);
GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
r->Unref(DEBUG_LOCATION, "dns-resolving");
}
static void maybe_start_resolving_locked(dns_resolver* r) {
if (r->last_resolution_timestamp >= 0) {
void NativeDnsResolver::MaybeStartResolvingLocked() {
if (last_resolution_timestamp_ >= 0) {
const grpc_millis earliest_next_resolution =
r->last_resolution_timestamp + r->min_time_between_resolutions;
last_resolution_timestamp_ + min_time_between_resolutions_;
const grpc_millis ms_until_next_resolution =
earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
if (ms_until_next_resolution > 0) {
const grpc_millis last_resolution_ago =
grpc_core::ExecCtx::Get()->Now() - r->last_resolution_timestamp;
grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
gpr_log(GPR_DEBUG,
"In cooldown from last resolution (from %" PRIdPTR
" ms ago). Will resolve again in %" PRIdPTR " ms",
last_resolution_ago, ms_until_next_resolution);
if (!r->have_next_resolution_timer) {
r->have_next_resolution_timer = true;
GRPC_RESOLVER_REF(&r->base, "next_resolution_timer_cooldown");
grpc_timer_init(&r->next_resolution_timer, ms_until_next_resolution,
&r->next_resolution_closure);
if (!have_next_resolution_timer_) {
have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self =
Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown");
self.release();
grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
&on_next_resolution_);
}
// TODO(dgq): remove the following two lines once Pick First stops
// discarding subchannels after selecting.
++r->resolved_version;
dns_maybe_finish_next_locked(r);
++resolved_version_;
MaybeFinishNextLocked();
return;
}
}
dns_start_resolving_locked(r);
StartResolvingLocked();
}
static void dns_start_resolving_locked(dns_resolver* r) {
GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving);
r->resolving = true;
r->addresses = nullptr;
grpc_resolve_address(
r->name_to_resolve, r->default_port, r->interested_parties,
GRPC_CLOSURE_CREATE(dns_on_resolved_locked, r,
grpc_combiner_scheduler(r->base.combiner)),
&r->addresses);
r->last_resolution_timestamp = grpc_core::ExecCtx::Get()->Now();
void NativeDnsResolver::StartResolvingLocked() {
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
RefCountedPtr<Resolver> self = Ref(DEBUG_LOCATION, "dns-resolving");
self.release();
GPR_ASSERT(!resolving_);
resolving_ = true;
addresses_ = nullptr;
grpc_resolve_address(name_to_resolve_, kDefaultPort, interested_parties_,
&on_resolved_, &addresses_);
last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
}
static void dns_maybe_finish_next_locked(dns_resolver* r) {
if (r->next_completion != nullptr &&
r->resolved_version != r->published_version) {
*r->target_result = r->resolved_result == nullptr
? nullptr
: grpc_channel_args_copy(r->resolved_result);
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
r->next_completion = nullptr;
r->published_version = r->resolved_version;
void NativeDnsResolver::MaybeFinishNextLocked() {
if (next_completion_ != nullptr && resolved_version_ != published_version_) {
*target_result_ = resolved_result_ == nullptr
? nullptr
: grpc_channel_args_copy(resolved_result_);
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
published_version_ = resolved_version_;
}
}
static void dns_destroy(grpc_resolver* gr) {
dns_resolver* r = (dns_resolver*)gr;
if (r->resolved_result != nullptr) {
grpc_channel_args_destroy(r->resolved_result);
}
grpc_pollset_set_destroy(r->interested_parties);
gpr_free(r->name_to_resolve);
gpr_free(r->default_port);
grpc_channel_args_destroy(r->channel_args);
gpr_free(r);
}
//
// Factory
//
static grpc_resolver* dns_create(grpc_resolver_args* args,
const char* default_port) {
if (0 != strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based dns uri's not supported");
return nullptr;
}
// Get name from args.
char* path = args->uri->path;
if (path[0] == '/') ++path;
// Create resolver.
dns_resolver* r = (dns_resolver*)gpr_zalloc(sizeof(dns_resolver));
grpc_resolver_init(&r->base, &dns_resolver_vtable, args->combiner);
r->name_to_resolve = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
r->channel_args = grpc_channel_args_copy(args->args);
r->interested_parties = grpc_pollset_set_create();
if (args->pollset_set != nullptr) {
grpc_pollset_set_add_pollset_set(r->interested_parties, args->pollset_set);
class NativeDnsResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
if (0 != strcmp(args.uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based dns uri's not supported");
return OrphanablePtr<Resolver>(nullptr);
}
return OrphanablePtr<Resolver>(New<NativeDnsResolver>(args));
}
grpc_core::BackOff::Options backoff_options;
backoff_options
.set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
.set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
.set_jitter(GRPC_DNS_RECONNECT_JITTER)
.set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
r->backoff.Init(grpc_core::BackOff(backoff_options));
const grpc_arg* period_arg = grpc_channel_args_find(
args->args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
r->min_time_between_resolutions =
grpc_channel_arg_get_integer(period_arg, {1000, 0, INT_MAX});
r->last_resolution_timestamp = -1;
GRPC_CLOSURE_INIT(&r->next_resolution_closure,
dns_on_next_resolution_timer_locked, r,
grpc_combiner_scheduler(r->base.combiner));
return &r->base;
}
/*
* FACTORY
*/
const char* scheme() const override { return "dns"; }
};
static void dns_factory_ref(grpc_resolver_factory* factory) {}
} // namespace
static void dns_factory_unref(grpc_resolver_factory* factory) {}
} // namespace grpc_core
static grpc_resolver* dns_factory_create_resolver(
grpc_resolver_factory* factory, grpc_resolver_args* args) {
return dns_create(args, "https");
}
static char* dns_factory_get_default_host_name(grpc_resolver_factory* factory,
grpc_uri* uri) {
const char* path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
}
static const grpc_resolver_factory_vtable dns_factory_vtable = {
dns_factory_ref, dns_factory_unref, dns_factory_create_resolver,
dns_factory_get_default_host_name, "dns"};
static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable};
static grpc_resolver_factory* dns_resolver_factory_create() {
return &dns_resolver_factory;
}
void grpc_resolver_dns_native_init(void) {
char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver != nullptr && gpr_stricmp(resolver, "native") == 0) {
void grpc_resolver_dns_native_init() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "native") == 0) {
gpr_log(GPR_DEBUG, "Using native dns resolver");
grpc_register_resolver_type(dns_resolver_factory_create());
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
} else {
grpc_resolver_factory* existing_factory =
grpc_resolver_factory_lookup("dns");
grpc_core::ResolverRegistry::Builder::InitRegistry();
grpc_core::ResolverFactory* existing_factory =
grpc_core::ResolverRegistry::LookupResolverFactory("dns");
if (existing_factory == nullptr) {
gpr_log(GPR_DEBUG, "Using native dns resolver");
grpc_register_resolver_type(dns_resolver_factory_create());
} else {
grpc_resolver_factory_unref(existing_factory);
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
}
}
gpr_free(resolver);
gpr_free(resolver_env);
}
void grpc_resolver_dns_native_shutdown(void) {}
void grpc_resolver_dns_native_shutdown() {}

@ -42,190 +42,177 @@
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
//
// fake_resolver
//
namespace grpc_core {
typedef struct {
// Base class -- must be first
grpc_resolver base;
// This cannot be in an anonymous namespace, because it is a friend of
// FakeResolverResponseGenerator.
class FakeResolver : public Resolver {
public:
explicit FakeResolver(const ResolverArgs& args);
// Passed-in parameters
grpc_channel_args* channel_args;
void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) override;
// If not NULL, the next set of resolution results to be returned to
// grpc_resolver_next_locked()'s closure.
grpc_channel_args* next_results;
void RequestReresolutionLocked() override;
// Results to use for the pretended re-resolution in
// fake_resolver_channel_saw_error_locked().
grpc_channel_args* results_upon_error;
private:
friend class FakeResolverResponseGenerator;
virtual ~FakeResolver();
void MaybeFinishNextLocked();
void ShutdownLocked() override;
// passed-in parameters
grpc_channel_args* channel_args_ = nullptr;
// If not NULL, the next set of resolution results to be returned to
// NextLocked()'s closure.
grpc_channel_args* next_results_ = nullptr;
// Results to use for the pretended re-resolution in
// RequestReresolutionLocked().
grpc_channel_args* reresolution_results_ = nullptr;
// TODO(juanlishen): This can go away once pick_first is changed to not throw
// away its subchannels, since that will eliminate its dependence on
// channel_saw_error_locked() causing an immediate resolver return.
// A copy of the most-recently used resolution results.
grpc_channel_args* last_used_results;
// Pending next completion, or NULL
grpc_closure* next_completion;
// Target result address for next completion
grpc_channel_args** target_result;
} fake_resolver;
static void fake_resolver_destroy(grpc_resolver* gr) {
fake_resolver* r = (fake_resolver*)gr;
grpc_channel_args_destroy(r->next_results);
grpc_channel_args_destroy(r->results_upon_error);
grpc_channel_args_destroy(r->last_used_results);
grpc_channel_args_destroy(r->channel_args);
gpr_free(r);
grpc_channel_args* last_used_results_ = nullptr;
// pending next completion, or NULL
grpc_closure* next_completion_ = nullptr;
// target result address for next completion
grpc_channel_args** target_result_ = nullptr;
};
FakeResolver::FakeResolver(const ResolverArgs& args) : Resolver(args.combiner) {
channel_args_ = grpc_channel_args_copy(args.args);
FakeResolverResponseGenerator* response_generator =
FakeResolverResponseGenerator::GetFromArgs(args.args);
if (response_generator != nullptr) response_generator->resolver_ = this;
}
static void fake_resolver_shutdown_locked(grpc_resolver* resolver) {
fake_resolver* r = (fake_resolver*)resolver;
if (r->next_completion != nullptr) {
*r->target_result = nullptr;
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
r->next_completion = nullptr;
}
FakeResolver::~FakeResolver() {
grpc_channel_args_destroy(next_results_);
grpc_channel_args_destroy(reresolution_results_);
grpc_channel_args_destroy(last_used_results_);
grpc_channel_args_destroy(channel_args_);
}
static void fake_resolver_maybe_finish_next_locked(fake_resolver* r) {
if (r->next_completion != nullptr && r->next_results != nullptr) {
*r->target_result =
grpc_channel_args_union(r->next_results, r->channel_args);
grpc_channel_args_destroy(r->next_results);
r->next_results = nullptr;
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
r->next_completion = nullptr;
}
void FakeResolver::NextLocked(grpc_channel_args** target_result,
grpc_closure* on_complete) {
GPR_ASSERT(next_completion_ == nullptr);
next_completion_ = on_complete;
target_result_ = target_result;
MaybeFinishNextLocked();
}
static void fake_resolver_channel_saw_error_locked(grpc_resolver* resolver) {
fake_resolver* r = (fake_resolver*)resolver;
void FakeResolver::RequestReresolutionLocked() {
// A resolution must have been returned before an error is seen.
GPR_ASSERT(r->last_used_results != nullptr);
grpc_channel_args_destroy(r->next_results);
if (r->results_upon_error != nullptr) {
r->next_results = grpc_channel_args_copy(r->results_upon_error);
GPR_ASSERT(last_used_results_ != nullptr);
grpc_channel_args_destroy(next_results_);
if (reresolution_results_ != nullptr) {
next_results_ = grpc_channel_args_copy(reresolution_results_);
} else {
// If results_upon_error is unavailable, re-resolve with the most-recently
// If reresolution_results is unavailable, re-resolve with the most-recently
// used results to avoid a no-op re-resolution.
r->next_results = grpc_channel_args_copy(r->last_used_results);
next_results_ = grpc_channel_args_copy(last_used_results_);
}
fake_resolver_maybe_finish_next_locked(r);
}
static void fake_resolver_next_locked(grpc_resolver* resolver,
grpc_channel_args** target_result,
grpc_closure* on_complete) {
fake_resolver* r = (fake_resolver*)resolver;
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
fake_resolver_maybe_finish_next_locked(r);
}
static const grpc_resolver_vtable fake_resolver_vtable = {
fake_resolver_destroy, fake_resolver_shutdown_locked,
fake_resolver_channel_saw_error_locked, fake_resolver_next_locked};
struct grpc_fake_resolver_response_generator {
fake_resolver* resolver; // Set by the fake_resolver constructor to itself.
gpr_refcount refcount;
};
grpc_fake_resolver_response_generator*
grpc_fake_resolver_response_generator_create() {
grpc_fake_resolver_response_generator* generator =
(grpc_fake_resolver_response_generator*)gpr_zalloc(sizeof(*generator));
gpr_ref_init(&generator->refcount, 1);
return generator;
MaybeFinishNextLocked();
}
grpc_fake_resolver_response_generator*
grpc_fake_resolver_response_generator_ref(
grpc_fake_resolver_response_generator* generator) {
gpr_ref(&generator->refcount);
return generator;
void FakeResolver::MaybeFinishNextLocked() {
if (next_completion_ != nullptr && next_results_ != nullptr) {
*target_result_ = grpc_channel_args_union(next_results_, channel_args_);
grpc_channel_args_destroy(next_results_);
next_results_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
}
}
void grpc_fake_resolver_response_generator_unref(
grpc_fake_resolver_response_generator* generator) {
if (gpr_unref(&generator->refcount)) {
gpr_free(generator);
void FakeResolver::ShutdownLocked() {
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
next_completion_ = nullptr;
}
}
typedef struct set_response_closure_arg {
//
// FakeResolverResponseGenerator
//
struct SetResponseClosureArg {
grpc_closure set_response_closure;
grpc_fake_resolver_response_generator* generator;
FakeResolverResponseGenerator* generator;
grpc_channel_args* response;
bool upon_error;
} set_response_closure_arg;
static void set_response_closure_locked(void* arg, grpc_error* error) {
set_response_closure_arg* closure_arg = (set_response_closure_arg*)arg;
grpc_fake_resolver_response_generator* generator = closure_arg->generator;
fake_resolver* r = generator->resolver;
if (!closure_arg->upon_error) {
grpc_channel_args_destroy(r->next_results);
r->next_results = closure_arg->response;
grpc_channel_args_destroy(r->last_used_results);
r->last_used_results = grpc_channel_args_copy(closure_arg->response);
fake_resolver_maybe_finish_next_locked(r);
} else {
grpc_channel_args_destroy(r->results_upon_error);
r->results_upon_error = closure_arg->response;
}
gpr_free(closure_arg);
};
void FakeResolverResponseGenerator::SetResponseLocked(void* arg,
grpc_error* error) {
SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
FakeResolver* resolver = closure_arg->generator->resolver_;
grpc_channel_args_destroy(resolver->next_results_);
resolver->next_results_ = closure_arg->response;
grpc_channel_args_destroy(resolver->last_used_results_);
resolver->last_used_results_ = grpc_channel_args_copy(closure_arg->response);
resolver->MaybeFinishNextLocked();
Delete(closure_arg);
}
void grpc_fake_resolver_response_generator_set_response(
grpc_fake_resolver_response_generator* generator,
grpc_channel_args* response) {
GPR_ASSERT(generator->resolver != nullptr);
void FakeResolverResponseGenerator::SetResponse(grpc_channel_args* response) {
GPR_ASSERT(response != nullptr);
set_response_closure_arg* closure_arg =
(set_response_closure_arg*)gpr_zalloc(sizeof(*closure_arg));
closure_arg->generator = generator;
GPR_ASSERT(resolver_ != nullptr);
SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
closure_arg->generator = this;
closure_arg->response = grpc_channel_args_copy(response);
closure_arg->upon_error = false;
GRPC_CLOSURE_SCHED(GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
set_response_closure_locked, closure_arg,
grpc_combiner_scheduler(
generator->resolver->base.combiner)),
GRPC_ERROR_NONE);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&closure_arg->set_response_closure, SetResponseLocked,
closure_arg,
grpc_combiner_scheduler(resolver_->combiner())),
GRPC_ERROR_NONE);
}
void grpc_fake_resolver_response_generator_set_response_upon_error(
grpc_fake_resolver_response_generator* generator,
void FakeResolverResponseGenerator::SetReresolutionResponseLocked(
void* arg, grpc_error* error) {
SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
FakeResolver* resolver = closure_arg->generator->resolver_;
grpc_channel_args_destroy(resolver->reresolution_results_);
resolver->reresolution_results_ = closure_arg->response;
Delete(closure_arg);
}
void FakeResolverResponseGenerator::SetReresolutionResponse(
grpc_channel_args* response) {
GPR_ASSERT(generator->resolver != nullptr);
set_response_closure_arg* closure_arg =
(set_response_closure_arg*)gpr_zalloc(sizeof(*closure_arg));
closure_arg->generator = generator;
GPR_ASSERT(resolver_ != nullptr);
SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
closure_arg->generator = this;
closure_arg->response =
response != nullptr ? grpc_channel_args_copy(response) : nullptr;
closure_arg->upon_error = true;
GRPC_CLOSURE_SCHED(GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
set_response_closure_locked, closure_arg,
grpc_combiner_scheduler(
generator->resolver->base.combiner)),
GRPC_ERROR_NONE);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
SetReresolutionResponseLocked, closure_arg,
grpc_combiner_scheduler(resolver_->combiner())),
GRPC_ERROR_NONE);
}
namespace {
static void* response_generator_arg_copy(void* p) {
return grpc_fake_resolver_response_generator_ref(
(grpc_fake_resolver_response_generator*)p);
FakeResolverResponseGenerator* generator =
static_cast<FakeResolverResponseGenerator*>(p);
// TODO(roth): We currently deal with this ref manually. Once the
// new channel args code is converted to C++, find a way to track this ref
// in a cleaner way.
RefCountedPtr<FakeResolverResponseGenerator> copy = generator->Ref();
copy.release();
return p;
}
static void response_generator_arg_destroy(void* p) {
grpc_fake_resolver_response_generator_unref(
(grpc_fake_resolver_response_generator*)p);
FakeResolverResponseGenerator* generator =
static_cast<FakeResolverResponseGenerator*>(p);
generator->Unref();
}
static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
@ -234,8 +221,10 @@ static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
response_generator_arg_copy, response_generator_arg_destroy,
response_generator_cmp};
grpc_arg grpc_fake_resolver_response_generator_arg(
grpc_fake_resolver_response_generator* generator) {
} // namespace
grpc_arg FakeResolverResponseGenerator::MakeChannelArg(
FakeResolverResponseGenerator* generator) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
arg.key = (char*)GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR;
@ -244,49 +233,38 @@ grpc_arg grpc_fake_resolver_response_generator_arg(
return arg;
}
grpc_fake_resolver_response_generator*
grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) {
FakeResolverResponseGenerator* FakeResolverResponseGenerator::GetFromArgs(
const grpc_channel_args* args) {
const grpc_arg* arg =
grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr;
return (grpc_fake_resolver_response_generator*)arg->value.pointer.p;
return static_cast<FakeResolverResponseGenerator*>(arg->value.pointer.p);
}
//
// fake_resolver_factory
// Factory
//
static void fake_resolver_factory_ref(grpc_resolver_factory* factory) {}
static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {}
namespace {
static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
grpc_resolver_args* args) {
fake_resolver* r = (fake_resolver*)gpr_zalloc(sizeof(*r));
r->channel_args = grpc_channel_args_copy(args->args);
grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner);
grpc_fake_resolver_response_generator* response_generator =
grpc_fake_resolver_get_response_generator(args->args);
if (response_generator != nullptr) response_generator->resolver = r;
return &r->base;
}
class FakeResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
return OrphanablePtr<Resolver>(New<FakeResolver>(args));
}
static char* fake_resolver_get_default_authority(grpc_resolver_factory* factory,
grpc_uri* uri) {
const char* path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
}
const char* scheme() const override { return "fake"; }
};
static const grpc_resolver_factory_vtable fake_resolver_factory_vtable = {
fake_resolver_factory_ref, fake_resolver_factory_unref,
fake_resolver_create, fake_resolver_get_default_authority, "fake"};
} // namespace
static grpc_resolver_factory fake_resolver_factory = {
&fake_resolver_factory_vtable};
} // namespace grpc_core
void grpc_resolver_fake_init(void) {
grpc_register_resolver_type(&fake_resolver_factory);
void grpc_resolver_fake_init() {
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::FakeResolverFactory>()));
}
void grpc_resolver_fake_shutdown(void) {}
void grpc_resolver_fake_shutdown() {}

@ -20,50 +20,57 @@
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted.h"
#define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
"grpc.fake_resolver.response_generator"
void grpc_resolver_fake_init();
namespace grpc_core {
// Instances of \a grpc_fake_resolver_response_generator are passed to the
// fake resolver in a channel argument (see \a
// grpc_fake_resolver_response_generator_arg) in order to inject and trigger
// custom resolutions. See also \a
// grpc_fake_resolver_response_generator_set_response.
typedef struct grpc_fake_resolver_response_generator
grpc_fake_resolver_response_generator;
grpc_fake_resolver_response_generator*
grpc_fake_resolver_response_generator_create();
class FakeResolver;
// Set next response of the fake resolver associated with the \a
// response_generator instance and trigger a new resolution.
void grpc_fake_resolver_response_generator_set_response(
grpc_fake_resolver_response_generator* generator,
grpc_channel_args* response);
/// A mechanism for generating responses for the fake resolver.
/// An instance of this class is passed to the fake resolver via a channel
/// argument (see \a MakeChannelArg()) and used to inject and trigger custom
/// resolutions.
// TODO(roth): I would ideally like this to be InternallyRefCounted
// instead of RefCounted, but external refs are currently needed to
// encode this in channel args. Once channel_args are converted to C++,
// see if we can find a way to fix this.
class FakeResolverResponseGenerator
: public RefCounted<FakeResolverResponseGenerator> {
public:
FakeResolverResponseGenerator() {}
// Set results_upon_error of the fake resolver associated with the \a
// response_generator instance. When fake_resolver_channel_saw_error_locked() is
// called, results_upon_error will be returned as long as it's non-NULL,
// otherwise the last value set by
// grpc_fake_resolver_response_generator_set_response() will be returned.
void grpc_fake_resolver_response_generator_set_response_upon_error(
grpc_fake_resolver_response_generator* generator,
grpc_channel_args* response);
// Instructs the fake resolver associated with the response generator
// instance to trigger a new resolution with the specified response.
void SetResponse(grpc_channel_args* next_response);
// Return a \a grpc_arg for a \a grpc_fake_resolver_response_generator instance.
grpc_arg grpc_fake_resolver_response_generator_arg(
grpc_fake_resolver_response_generator* generator);
// Return the \a grpc_fake_resolver_response_generator instance in \a args or
// NULL.
grpc_fake_resolver_response_generator*
grpc_fake_resolver_get_response_generator(const grpc_channel_args* args);
// Sets the re-resolution response, which is returned by the fake resolver
// when re-resolution is requested (via \a RequestReresolutionLocked()).
// The new re-resolution response replaces any previous re-resolution
// response that may have been set by a previous call.
// If the re-resolution response is set to NULL, then the fake
// resolver will return the last value set via \a SetResponse().
void SetReresolutionResponse(grpc_channel_args* response);
grpc_fake_resolver_response_generator*
grpc_fake_resolver_response_generator_ref(
grpc_fake_resolver_response_generator* generator);
void grpc_fake_resolver_response_generator_unref(
grpc_fake_resolver_response_generator* generator);
// Returns a channel arg containing \a generator.
static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
// Returns the response generator in \a args, or null if not found.
static FakeResolverResponseGenerator* GetFromArgs(
const grpc_channel_args* args);
private:
friend class FakeResolver;
static void SetResponseLocked(void* arg, grpc_error* error);
static void SetReresolutionResponseLocked(void* arg, grpc_error* error);
FakeResolver* resolver_ = nullptr; // Do not own.
};
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \
*/

@ -37,115 +37,99 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** the addresses that we've 'resolved' */
grpc_lb_addresses* addresses;
/** channel args */
grpc_channel_args* channel_args;
/** have we published? */
bool published;
/** pending next completion, or NULL */
grpc_closure* next_completion;
/** target result address for next completion */
grpc_channel_args** target_result;
} sockaddr_resolver;
static void sockaddr_destroy(grpc_resolver* r);
static void sockaddr_maybe_finish_next_locked(sockaddr_resolver* r);
static void sockaddr_shutdown_locked(grpc_resolver* r);
static void sockaddr_channel_saw_error_locked(grpc_resolver* r);
static void sockaddr_next_locked(grpc_resolver* r,
grpc_channel_args** target_result,
grpc_closure* on_complete);
static const grpc_resolver_vtable sockaddr_resolver_vtable = {
sockaddr_destroy, sockaddr_shutdown_locked,
sockaddr_channel_saw_error_locked, sockaddr_next_locked};
static void sockaddr_shutdown_locked(grpc_resolver* resolver) {
sockaddr_resolver* r = (sockaddr_resolver*)resolver;
if (r->next_completion != nullptr) {
*r->target_result = nullptr;
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
r->next_completion = nullptr;
}
}
namespace grpc_core {
static void sockaddr_channel_saw_error_locked(grpc_resolver* resolver) {
sockaddr_resolver* r = (sockaddr_resolver*)resolver;
r->published = false;
sockaddr_maybe_finish_next_locked(r);
}
namespace {
static void sockaddr_next_locked(grpc_resolver* resolver,
grpc_channel_args** target_result,
grpc_closure* on_complete) {
sockaddr_resolver* r = (sockaddr_resolver*)resolver;
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
sockaddr_maybe_finish_next_locked(r);
}
class SockaddrResolver : public Resolver {
public:
/// Takes ownership of \a addresses.
SockaddrResolver(const ResolverArgs& args, grpc_lb_addresses* addresses);
static void sockaddr_maybe_finish_next_locked(sockaddr_resolver* r) {
if (r->next_completion != nullptr && !r->published) {
r->published = true;
grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
*r->target_result =
grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
r->next_completion = nullptr;
}
}
void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) override;
void RequestReresolutionLocked() override;
static void sockaddr_destroy(grpc_resolver* gr) {
sockaddr_resolver* r = (sockaddr_resolver*)gr;
grpc_lb_addresses_destroy(r->addresses);
grpc_channel_args_destroy(r->channel_args);
gpr_free(r);
void ShutdownLocked() override;
private:
virtual ~SockaddrResolver();
void MaybeFinishNextLocked();
/// the addresses that we've "resolved"
grpc_lb_addresses* addresses_ = nullptr;
/// channel args
grpc_channel_args* channel_args_ = nullptr;
/// have we published?
bool published_ = false;
/// pending next completion, or NULL
grpc_closure* next_completion_ = nullptr;
/// target result address for next completion
grpc_channel_args** target_result_ = nullptr;
};
SockaddrResolver::SockaddrResolver(const ResolverArgs& args,
grpc_lb_addresses* addresses)
: Resolver(args.combiner),
addresses_(addresses),
channel_args_(grpc_channel_args_copy(args.args)) {}
SockaddrResolver::~SockaddrResolver() {
grpc_lb_addresses_destroy(addresses_);
grpc_channel_args_destroy(channel_args_);
}
static char* ip_get_default_authority(grpc_uri* uri) {
const char* path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
void SockaddrResolver::NextLocked(grpc_channel_args** target_result,
grpc_closure* on_complete) {
GPR_ASSERT(!next_completion_);
next_completion_ = on_complete;
target_result_ = target_result;
MaybeFinishNextLocked();
}
static char* ipv4_get_default_authority(grpc_resolver_factory* factory,
grpc_uri* uri) {
return ip_get_default_authority(uri);
void SockaddrResolver::RequestReresolutionLocked() {
published_ = false;
MaybeFinishNextLocked();
}
static char* ipv6_get_default_authority(grpc_resolver_factory* factory,
grpc_uri* uri) {
return ip_get_default_authority(uri);
void SockaddrResolver::ShutdownLocked() {
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Resolver Shutdown"));
next_completion_ = nullptr;
}
}
#ifdef GRPC_HAVE_UNIX_SOCKET
char* unix_get_default_authority(grpc_resolver_factory* factory,
grpc_uri* uri) {
return gpr_strdup("localhost");
void SockaddrResolver::MaybeFinishNextLocked() {
if (next_completion_ != nullptr && !published_) {
published_ = true;
grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses_);
*target_result_ = grpc_channel_args_copy_and_add(channel_args_, &arg, 1);
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
}
}
#endif
static void do_nothing(void* ignored) {}
//
// Factory
//
static grpc_resolver* sockaddr_create(grpc_resolver_args* args,
bool parse(const grpc_uri* uri,
grpc_resolved_address* dst)) {
if (0 != strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
args->uri->scheme);
return nullptr;
void DoNothing(void* ignored) {}
OrphanablePtr<Resolver> CreateSockaddrResolver(
const ResolverArgs& args,
bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
if (0 != strcmp(args.uri->authority, "")) {
gpr_log(GPR_ERROR, "authority-based URIs not supported by the %s scheme",
args.uri->scheme);
return OrphanablePtr<Resolver>(nullptr);
}
/* Construct addresses. */
// Construct addresses.
grpc_slice path_slice =
grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
grpc_slice_new(args.uri->path, strlen(args.uri->path), DoNothing);
grpc_slice_buffer path_parts;
grpc_slice_buffer_init(&path_parts);
grpc_slice_split(path_slice, ",", &path_parts);
@ -153,7 +137,7 @@ static grpc_resolver* sockaddr_create(grpc_resolver_args* args,
path_parts.count, nullptr /* user_data_vtable */);
bool errors_found = false;
for (size_t i = 0; i < addresses->num_addresses; i++) {
grpc_uri ith_uri = *args->uri;
grpc_uri ith_uri = *args.uri;
char* part_str = grpc_slice_to_c_string(path_parts.slices[i]);
ith_uri.path = part_str;
if (!parse(&ith_uri, &addresses->addresses[i].address)) {
@ -166,48 +150,64 @@ static grpc_resolver* sockaddr_create(grpc_resolver_args* args,
grpc_slice_unref_internal(path_slice);
if (errors_found) {
grpc_lb_addresses_destroy(addresses);
return nullptr;
return OrphanablePtr<Resolver>(nullptr);
}
/* Instantiate resolver. */
sockaddr_resolver* r =
(sockaddr_resolver*)gpr_zalloc(sizeof(sockaddr_resolver));
r->addresses = addresses;
r->channel_args = grpc_channel_args_copy(args->args);
grpc_resolver_init(&r->base, &sockaddr_resolver_vtable, args->combiner);
return &r->base;
// Instantiate resolver.
return OrphanablePtr<Resolver>(New<SockaddrResolver>(args, addresses));
}
/*
* FACTORY
*/
class IPv4ResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
return CreateSockaddrResolver(args, grpc_parse_ipv4);
}
static void sockaddr_factory_ref(grpc_resolver_factory* factory) {}
const char* scheme() const override { return "ipv4"; }
};
static void sockaddr_factory_unref(grpc_resolver_factory* factory) {}
class IPv6ResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
return CreateSockaddrResolver(args, grpc_parse_ipv6);
}
#define DECL_FACTORY(name) \
static grpc_resolver* name##_factory_create_resolver( \
grpc_resolver_factory* factory, grpc_resolver_args* args) { \
return sockaddr_create(args, grpc_parse_##name); \
} \
static const grpc_resolver_factory_vtable name##_factory_vtable = { \
sockaddr_factory_ref, sockaddr_factory_unref, \
name##_factory_create_resolver, name##_get_default_authority, #name}; \
static grpc_resolver_factory name##_resolver_factory = { \
&name##_factory_vtable}
const char* scheme() const override { return "ipv6"; }
};
#ifdef GRPC_HAVE_UNIX_SOCKET
DECL_FACTORY(unix);
#endif
DECL_FACTORY(ipv4);
DECL_FACTORY(ipv6);
class UnixResolverFactory : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(
const ResolverArgs& args) const override {
return CreateSockaddrResolver(args, grpc_parse_unix);
}
UniquePtr<char> GetDefaultAuthority(grpc_uri* uri) const override {
return UniquePtr<char>(gpr_strdup("localhost"));
}
const char* scheme() const override { return "unix"; }
};
#endif // GRPC_HAVE_UNIX_SOCKET
} // namespace
} // namespace grpc_core
void grpc_resolver_sockaddr_init(void) {
grpc_register_resolver_type(&ipv4_resolver_factory);
grpc_register_resolver_type(&ipv6_resolver_factory);
void grpc_resolver_sockaddr_init() {
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::IPv4ResolverFactory>()));
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::IPv6ResolverFactory>()));
#ifdef GRPC_HAVE_UNIX_SOCKET
grpc_register_resolver_type(&unix_resolver_factory);
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
grpc_core::New<grpc_core::UnixResolverFactory>()));
#endif
}
void grpc_resolver_sockaddr_shutdown(void) {}
void grpc_resolver_sockaddr_shutdown() {}

@ -1,40 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/ext/filters/client_channel/resolver_factory.h"
void grpc_resolver_factory_ref(grpc_resolver_factory* factory) {
factory->vtable->ref(factory);
}
void grpc_resolver_factory_unref(grpc_resolver_factory* factory) {
factory->vtable->unref(factory);
}
/** Create a resolver instance for a name */
grpc_resolver* grpc_resolver_factory_create_resolver(
grpc_resolver_factory* factory, grpc_resolver_args* args) {
if (factory == nullptr) return nullptr;
return factory->vtable->create_resolver(factory, args);
}
char* grpc_resolver_factory_get_default_authority(
grpc_resolver_factory* factory, grpc_uri* uri) {
if (factory == nullptr) return nullptr;
return factory->vtable->get_default_authority(factory, uri);
}

@ -19,50 +19,51 @@
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
#include "src/core/ext/filters/client_channel/client_channel_factory.h"
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/resolver.h"
#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/pollset_set.h"
typedef struct grpc_resolver_factory grpc_resolver_factory;
typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
namespace grpc_core {
struct grpc_resolver_factory {
const grpc_resolver_factory_vtable* vtable;
struct ResolverArgs {
/// The parsed URI to resolve.
grpc_uri* uri = nullptr;
/// Channel args to be included in resolver results.
const grpc_channel_args* args = nullptr;
/// Used to drive I/O in the name resolution process.
grpc_pollset_set* pollset_set = nullptr;
/// The combiner under which all resolver calls will be run.
grpc_combiner* combiner = nullptr;
};
typedef struct grpc_resolver_args {
grpc_uri* uri;
const grpc_channel_args* args;
grpc_pollset_set* pollset_set;
grpc_combiner* combiner;
} grpc_resolver_args;
class ResolverFactory {
public:
/// Returns a new resolver instance.
virtual OrphanablePtr<Resolver> CreateResolver(const ResolverArgs& args) const
GRPC_ABSTRACT;
struct grpc_resolver_factory_vtable {
void (*ref)(grpc_resolver_factory* factory);
void (*unref)(grpc_resolver_factory* factory);
/// Returns a string representing the default authority to use for this
/// scheme.
virtual UniquePtr<char> GetDefaultAuthority(grpc_uri* uri) const {
const char* path = uri->path;
if (path[0] == '/') ++path;
return UniquePtr<char>(gpr_strdup(path));
}
/** Implementation of grpc_resolver_factory_create_resolver */
grpc_resolver* (*create_resolver)(grpc_resolver_factory* factory,
grpc_resolver_args* args);
/// Returns the URI scheme that this factory implements.
/// Caller does NOT take ownership of result.
virtual const char* scheme() const GRPC_ABSTRACT;
/** Implementation of grpc_resolver_factory_get_default_authority */
char* (*get_default_authority)(grpc_resolver_factory* factory, grpc_uri* uri);
virtual ~ResolverFactory() {}
/** URI scheme that this factory implements */
const char* scheme;
GRPC_ABSTRACT_BASE_CLASS
};
void grpc_resolver_factory_ref(grpc_resolver_factory* resolver);
void grpc_resolver_factory_unref(grpc_resolver_factory* resolver);
/** Create a resolver instance for a name */
grpc_resolver* grpc_resolver_factory_create_resolver(
grpc_resolver_factory* factory, grpc_resolver_args* args);
/** Return a (freshly allocated with gpr_malloc) string representing
the default authority to use for this scheme. */
char* grpc_resolver_factory_get_default_authority(
grpc_resolver_factory* factory, grpc_uri* uri);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H */

@ -24,133 +24,153 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#define MAX_RESOLVERS 10
#define DEFAULT_RESOLVER_PREFIX_MAX_LENGTH 32
namespace grpc_core {
static grpc_resolver_factory* g_all_of_the_resolvers[MAX_RESOLVERS];
static int g_number_of_resolvers = 0;
namespace {
static char g_default_resolver_prefix[DEFAULT_RESOLVER_PREFIX_MAX_LENGTH] =
"dns:///";
class RegistryState {
public:
RegistryState() : default_prefix_(gpr_strdup("dns:///")) {}
void grpc_resolver_registry_init() {}
void grpc_resolver_registry_shutdown(void) {
for (int i = 0; i < g_number_of_resolvers; i++) {
grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
void SetDefaultPrefix(const char* default_resolver_prefix) {
GPR_ASSERT(default_resolver_prefix != nullptr);
GPR_ASSERT(*default_resolver_prefix != '\0');
default_prefix_.reset(gpr_strdup(default_resolver_prefix));
}
// FIXME(ctiller): this should live in grpc_resolver_registry_init,
// however that would have the client_channel plugin call this AFTER we start
// registering resolvers from third party plugins, and so they'd never show
// up.
// We likely need some kind of dependency system for plugins.... what form
// that takes is TBD.
g_number_of_resolvers = 0;
}
void grpc_resolver_registry_set_default_prefix(
const char* default_resolver_prefix) {
const size_t len = strlen(default_resolver_prefix);
GPR_ASSERT(len < DEFAULT_RESOLVER_PREFIX_MAX_LENGTH &&
"default resolver prefix too long");
GPR_ASSERT(len > 0 && "default resolver prefix can't be empty");
// By the previous assert, default_resolver_prefix is safe to be copied with a
// plain strcpy.
strcpy(g_default_resolver_prefix, default_resolver_prefix);
}
void grpc_register_resolver_type(grpc_resolver_factory* factory) {
int i;
for (i = 0; i < g_number_of_resolvers; i++) {
GPR_ASSERT(0 != strcmp(factory->vtable->scheme,
g_all_of_the_resolvers[i]->vtable->scheme));
void RegisterResolverFactory(UniquePtr<ResolverFactory> factory) {
for (size_t i = 0; i < factories_.size(); ++i) {
GPR_ASSERT(strcmp(factories_[i]->scheme(), factory->scheme()) != 0);
}
factories_.push_back(std::move(factory));
}
GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
grpc_resolver_factory_ref(factory);
g_all_of_the_resolvers[g_number_of_resolvers++] = factory;
}
static grpc_resolver_factory* lookup_factory(const char* name) {
int i;
ResolverFactory* LookupResolverFactory(const char* scheme) const {
for (size_t i = 0; i < factories_.size(); ++i) {
if (strcmp(scheme, factories_[i]->scheme()) == 0) {
return factories_[i].get();
}
}
return nullptr;
}
for (i = 0; i < g_number_of_resolvers; i++) {
if (0 == strcmp(name, g_all_of_the_resolvers[i]->vtable->scheme)) {
return g_all_of_the_resolvers[i];
// Returns the factory for the scheme of \a target. If \a target does
// not parse as a URI, prepends \a default_prefix_ and tries again.
// If URI parsing is successful (in either attempt), sets \a uri to
// point to the parsed URI.
// If \a default_prefix_ needs to be prepended, sets \a canonical_target
// to the canonical target string.
ResolverFactory* FindResolverFactory(const char* target, grpc_uri** uri,
char** canonical_target) const {
GPR_ASSERT(uri != nullptr);
*uri = grpc_uri_parse(target, 1);
ResolverFactory* factory =
*uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
if (factory == nullptr) {
grpc_uri_destroy(*uri);
gpr_asprintf(canonical_target, "%s%s", default_prefix_.get(), target);
*uri = grpc_uri_parse(*canonical_target, 1);
factory =
*uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
if (factory == nullptr) {
grpc_uri_destroy(grpc_uri_parse(target, 0));
grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
*canonical_target);
}
}
return factory;
}
return nullptr;
private:
// We currently support 10 factories without doing additional
// allocation. This number could be raised if there is a case where
// more factories are needed and the additional allocations are
// hurting performance (which is unlikely, since these allocations
// only occur at gRPC initialization time).
InlinedVector<UniquePtr<ResolverFactory>, 10> factories_;
UniquePtr<char> default_prefix_;
};
static RegistryState* g_state = nullptr;
} // namespace
//
// ResolverRegistry::Builder
//
void ResolverRegistry::Builder::InitRegistry() {
if (g_state == nullptr) g_state = New<RegistryState>();
}
grpc_resolver_factory* grpc_resolver_factory_lookup(const char* name) {
grpc_resolver_factory* f = lookup_factory(name);
if (f) grpc_resolver_factory_ref(f);
return f;
void ResolverRegistry::Builder::ShutdownRegistry() {
Delete(g_state);
g_state = nullptr;
}
static grpc_resolver_factory* lookup_factory_by_uri(grpc_uri* uri) {
if (!uri) return nullptr;
return lookup_factory(uri->scheme);
void ResolverRegistry::Builder::SetDefaultPrefix(
const char* default_resolver_prefix) {
InitRegistry();
g_state->SetDefaultPrefix(default_resolver_prefix);
}
static grpc_resolver_factory* resolve_factory(const char* target,
grpc_uri** uri,
char** canonical_target) {
grpc_resolver_factory* factory = nullptr;
GPR_ASSERT(uri != nullptr);
*uri = grpc_uri_parse(target, 1);
factory = lookup_factory_by_uri(*uri);
if (factory == nullptr) {
grpc_uri_destroy(*uri);
gpr_asprintf(canonical_target, "%s%s", g_default_resolver_prefix, target);
*uri = grpc_uri_parse(*canonical_target, 1);
factory = lookup_factory_by_uri(*uri);
if (factory == nullptr) {
grpc_uri_destroy(grpc_uri_parse(target, 0));
grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
*canonical_target);
}
}
return factory;
void ResolverRegistry::Builder::RegisterResolverFactory(
UniquePtr<ResolverFactory> factory) {
InitRegistry();
g_state->RegisterResolverFactory(std::move(factory));
}
grpc_resolver* grpc_resolver_create(const char* target,
const grpc_channel_args* args,
grpc_pollset_set* pollset_set,
grpc_combiner* combiner) {
//
// ResolverRegistry
//
ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
GPR_ASSERT(g_state != nullptr);
return g_state->LookupResolverFactory(scheme);
}
OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
const char* target, const grpc_channel_args* args,
grpc_pollset_set* pollset_set, grpc_combiner* combiner) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
grpc_resolver_factory* factory =
resolve_factory(target, &uri, &canonical_target);
grpc_resolver* resolver;
grpc_resolver_args resolver_args;
memset(&resolver_args, 0, sizeof(resolver_args));
ResolverFactory* factory =
g_state->FindResolverFactory(target, &uri, &canonical_target);
ResolverArgs resolver_args;
resolver_args.uri = uri;
resolver_args.args = args;
resolver_args.pollset_set = pollset_set;
resolver_args.combiner = combiner;
resolver = grpc_resolver_factory_create_resolver(factory, &resolver_args);
OrphanablePtr<Resolver> resolver =
factory == nullptr ? nullptr : factory->CreateResolver(resolver_args);
grpc_uri_destroy(uri);
gpr_free(canonical_target);
return resolver;
}
char* grpc_get_default_authority(const char* target) {
UniquePtr<char> ResolverRegistry::GetDefaultAuthority(const char* target) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
grpc_resolver_factory* factory =
resolve_factory(target, &uri, &canonical_target);
char* authority = grpc_resolver_factory_get_default_authority(factory, uri);
ResolverFactory* factory =
g_state->FindResolverFactory(target, &uri, &canonical_target);
UniquePtr<char> authority =
factory == nullptr ? nullptr : factory->GetDefaultAuthority(uri);
grpc_uri_destroy(uri);
gpr_free(canonical_target);
return authority;
}
char* grpc_resolver_factory_add_default_prefix_if_needed(const char* target) {
UniquePtr<char> ResolverRegistry::AddDefaultPrefixIfNeeded(const char* target) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
resolve_factory(target, &uri, &canonical_target);
g_state->FindResolverFactory(target, &uri, &canonical_target);
grpc_uri_destroy(uri);
return canonical_target == nullptr ? gpr_strdup(target) : canonical_target;
return UniquePtr<char>(canonical_target == nullptr ? gpr_strdup(target)
: canonical_target);
}
} // namespace grpc_core

@ -20,49 +20,62 @@
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
#include "src/core/ext/filters/client_channel/resolver_factory.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/pollset_set.h"
void grpc_resolver_registry_init();
void grpc_resolver_registry_shutdown(void);
namespace grpc_core {
/** Set the default URI prefix to \a default_prefix. */
void grpc_resolver_registry_set_default_prefix(const char* default_prefix);
class ResolverRegistry {
public:
/// Methods used to create and populate the ResolverRegistry.
/// NOT THREAD SAFE -- to be used only during global gRPC
/// initialization and shutdown.
class Builder {
public:
/// Global initialization and shutdown hooks.
static void InitRegistry();
static void ShutdownRegistry();
/** Register a resolver type.
URI's of \a scheme will be resolved with the given resolver.
If \a priority is greater than zero, then the resolver will be eligible
to resolve names that are passed in with no scheme. Higher priority
resolvers will be tried before lower priority schemes. */
void grpc_register_resolver_type(grpc_resolver_factory* factory);
/// Sets the default URI prefix to \a default_prefix.
/// Calls InitRegistry() if it has not already been called.
static void SetDefaultPrefix(const char* default_prefix);
/** Create a resolver given \a target.
First tries to parse \a target as a URI. If this succeeds, tries
to locate a registered resolver factory based on the URI scheme.
If parsing or location fails, prefixes default_prefix from
grpc_resolver_registry_init to target, and tries again (if default_prefix
was not NULL).
If a resolver factory was found, use it to instantiate a resolver and
return it.
If a resolver factory was not found, return NULL.
\a args is a set of channel arguments to be included in the result
(typically the set of arguments passed in from the client API).
\a pollset_set is used to drive IO in the name resolution process, it
should not be NULL. */
grpc_resolver* grpc_resolver_create(const char* target,
const grpc_channel_args* args,
grpc_pollset_set* pollset_set,
grpc_combiner* combiner);
/// Registers a resolver factory. The factory will be used to create a
/// resolver for any URI whose scheme matches that of the factory.
/// Calls InitRegistry() if it has not already been called.
static void RegisterResolverFactory(UniquePtr<ResolverFactory> factory);
};
/** Find a resolver factory given a name and return an (owned-by-the-caller)
* reference to it */
grpc_resolver_factory* grpc_resolver_factory_lookup(const char* name);
/// Creates a resolver given \a target.
/// First tries to parse \a target as a URI. If this succeeds, tries
/// to locate a registered resolver factory based on the URI scheme.
/// If parsing fails or there is no factory for the URI's scheme,
/// prepends default_prefix to target and tries again.
/// If a resolver factory is found, uses it to instantiate a resolver and
/// returns it; otherwise, returns nullptr.
/// \a args, \a pollset_set, and \a combiner are passed to the factory's
/// \a CreateResolver() method.
/// \a args are the channel args to be included in resolver results.
/// \a pollset_set is used to drive I/O in the name resolution process.
/// \a combiner is the combiner under which all resolver calls will be run.
static OrphanablePtr<Resolver> CreateResolver(const char* target,
const grpc_channel_args* args,
grpc_pollset_set* pollset_set,
grpc_combiner* combiner);
/** Given a target, return a (freshly allocated with gpr_malloc) string
representing the default authority to pass from a client. */
char* grpc_get_default_authority(const char* target);
/// Returns the default authority to pass from a client for \a target.
static UniquePtr<char> GetDefaultAuthority(const char* target);
/** Returns a newly allocated string containing \a target, adding the
default prefix if needed. */
char* grpc_resolver_factory_add_default_prefix_if_needed(const char* target);
/// Returns \a target with the default prefix prepended, if needed.
static UniquePtr<char> AddDefaultPrefixIfNeeded(const char* target);
/// Returns the resolver factory for \a scheme.
/// Caller does NOT own the return value.
static ResolverFactory* LookupResolverFactory(const char* scheme);
};
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */

@ -52,13 +52,13 @@ static grpc_channel* client_channel_factory_create_channel(
return nullptr;
}
// Add channel arg containing the server URI.
grpc_arg arg = grpc_channel_arg_string_create(
(char*)GRPC_ARG_SERVER_URI,
grpc_resolver_factory_add_default_prefix_if_needed(target));
grpc_core::UniquePtr<char> canonical_target =
grpc_core::ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create((char*)GRPC_ARG_SERVER_URI,
canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
gpr_free(arg.value.string);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);

@ -161,13 +161,13 @@ static grpc_channel* client_channel_factory_create_channel(
return nullptr;
}
// Add channel arg containing the server URI.
grpc_arg arg = grpc_channel_arg_string_create(
(char*)GRPC_ARG_SERVER_URI,
grpc_resolver_factory_add_default_prefix_if_needed(target));
grpc_core::UniquePtr<char> canonical_target =
grpc_core::ResolverRegistry::AddDefaultPrefixIfNeeded(target);
grpc_arg arg = grpc_channel_arg_string_create((char*)GRPC_ARG_SERVER_URI,
canonical_target.get());
const char* to_remove[] = {GRPC_ARG_SERVER_URI};
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
gpr_free(arg.value.string);
grpc_channel* channel =
grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
grpc_channel_args_destroy(new_args);

@ -269,7 +269,6 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_factory.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/subchannel.cc',

@ -79,17 +79,17 @@ static grpc_ares_request* my_dns_lookup_ares(
return nullptr;
}
static grpc_resolver* create_resolver(const char* name) {
grpc_resolver_factory* factory = grpc_resolver_factory_lookup("dns");
static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver(
const char* name) {
grpc_core::ResolverFactory* factory =
grpc_core::ResolverRegistry::LookupResolverFactory("dns");
grpc_uri* uri = grpc_uri_parse(name, 0);
GPR_ASSERT(uri);
grpc_resolver_args args;
memset(&args, 0, sizeof(args));
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
grpc_resolver* resolver =
grpc_resolver_factory_create_resolver(factory, &args);
grpc_resolver_factory_unref(factory);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
grpc_uri_destroy(uri);
return resolver;
}
@ -112,7 +112,7 @@ static bool wait_loop(int deadline_seconds, gpr_event* ev) {
}
typedef struct next_args {
grpc_resolver* resolver;
grpc_core::Resolver* resolver;
grpc_channel_args** result;
grpc_closure* on_complete;
} next_args;
@ -120,21 +120,21 @@ typedef struct next_args {
static void call_resolver_next_now_lock_taken(void* arg,
grpc_error* error_unused) {
next_args* a = static_cast<next_args*>(arg);
grpc_resolver_next_locked(a->resolver, a->result, a->on_complete);
a->resolver->NextLocked(a->result, a->on_complete);
gpr_free(a);
}
static void call_resolver_next_after_locking(grpc_resolver* resolver,
static void call_resolver_next_after_locking(grpc_core::Resolver* resolver,
grpc_channel_args** result,
grpc_closure* on_complete) {
grpc_closure* on_complete,
grpc_combiner* combiner) {
next_args* a = static_cast<next_args*>(gpr_malloc(sizeof(*a)));
a->resolver = resolver;
a->result = result;
a->on_complete = on_complete;
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(call_resolver_next_now_lock_taken, a,
grpc_combiner_scheduler(resolver->combiner)),
GRPC_ERROR_NONE);
GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(call_resolver_next_now_lock_taken, a,
grpc_combiner_scheduler(combiner)),
GRPC_ERROR_NONE);
}
int main(int argc, char** argv) {
@ -149,12 +149,14 @@ int main(int argc, char** argv) {
{
grpc_core::ExecCtx exec_ctx;
grpc_resolver* resolver = create_resolver("dns:test");
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
create_resolver("dns:test");
gpr_event ev1;
gpr_event_init(&ev1);
call_resolver_next_after_locking(
resolver, &result,
GRPC_CLOSURE_CREATE(on_done, &ev1, grpc_schedule_on_exec_ctx));
resolver.get(), &result,
GRPC_CLOSURE_CREATE(on_done, &ev1, grpc_schedule_on_exec_ctx),
g_combiner);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(wait_loop(5, &ev1));
GPR_ASSERT(result == nullptr);
@ -162,14 +164,14 @@ int main(int argc, char** argv) {
gpr_event ev2;
gpr_event_init(&ev2);
call_resolver_next_after_locking(
resolver, &result,
GRPC_CLOSURE_CREATE(on_done, &ev2, grpc_schedule_on_exec_ctx));
resolver.get(), &result,
GRPC_CLOSURE_CREATE(on_done, &ev2, grpc_schedule_on_exec_ctx),
g_combiner);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(wait_loop(30, &ev2));
GPR_ASSERT(result != nullptr);
grpc_channel_args_destroy(result);
GRPC_RESOLVER_UNREF(resolver, "test");
GRPC_COMBINER_UNREF(g_combiner, "test");
}

@ -23,6 +23,7 @@
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "test/core/util/test_config.h"
@ -131,13 +132,13 @@ static void poll_pollset_until_request_done(iomgr_args* args) {
gpr_event_set(&args->ev, (void*)1);
}
typedef struct on_resolution_cb_arg {
const char* uri_str;
grpc_resolver* resolver;
grpc_channel_args* result;
grpc_millis delay_before_second_resolution;
bool using_cares;
} on_resolution_cb_arg;
struct OnResolutionCallbackArg {
const char* uri_str = nullptr;
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
grpc_channel_args* result = nullptr;
grpc_millis delay_before_second_resolution = 0;
bool using_cares = false;
};
// Counter for the number of times a resolution notification callback has been
// invoked.
@ -147,7 +148,7 @@ static int g_on_resolution_invocations_count;
bool g_all_callbacks_invoked;
void on_third_resolution(void* arg, grpc_error* error) {
on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
GPR_ASSERT(error == GRPC_ERROR_NONE);
++g_on_resolution_invocations_count;
grpc_channel_args_destroy(cb_arg->result);
@ -159,8 +160,7 @@ void on_third_resolution(void* arg, grpc_error* error) {
// period.
GPR_ASSERT(g_on_resolution_invocations_count == 3);
GPR_ASSERT(g_resolution_count == 2);
grpc_resolver_shutdown_locked(cb_arg->resolver);
GRPC_RESOLVER_UNREF(cb_arg->resolver, "on_third_resolution");
cb_arg->resolver.reset();
if (cb_arg->using_cares) {
gpr_atm_rel_store(&g_iomgr_args.done_atm, 1);
gpr_mu_lock(g_iomgr_args.mu);
@ -168,12 +168,12 @@ void on_third_resolution(void* arg, grpc_error* error) {
grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
gpr_mu_unlock(g_iomgr_args.mu);
}
gpr_free(cb_arg);
grpc_core::Delete(cb_arg);
g_all_callbacks_invoked = true;
}
void on_second_resolution(void* arg, grpc_error* error) {
on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
++g_on_resolution_invocations_count;
grpc_channel_args_destroy(cb_arg->result);
@ -187,11 +187,11 @@ void on_second_resolution(void* arg, grpc_error* error) {
GPR_ASSERT(g_resolution_count == 1);
grpc_core::ExecCtx::Get()->TestOnlySetNow(
cb_arg->delay_before_second_resolution * 2);
grpc_resolver_next_locked(
cb_arg->resolver, &cb_arg->result,
cb_arg->resolver->NextLocked(
&cb_arg->result,
GRPC_CLOSURE_CREATE(on_third_resolution, arg,
grpc_combiner_scheduler(g_combiner)));
grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
cb_arg->resolver->RequestReresolutionLocked();
if (cb_arg->using_cares) {
gpr_mu_lock(g_iomgr_args.mu);
GRPC_LOG_IF_ERROR("pollset_kick",
@ -201,14 +201,14 @@ void on_second_resolution(void* arg, grpc_error* error) {
}
void on_first_resolution(void* arg, grpc_error* error) {
on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
++g_on_resolution_invocations_count;
grpc_channel_args_destroy(cb_arg->result);
grpc_resolver_next_locked(
cb_arg->resolver, &cb_arg->result,
cb_arg->resolver->NextLocked(
&cb_arg->result,
GRPC_CLOSURE_CREATE(on_second_resolution, arg,
grpc_combiner_scheduler(g_combiner)));
grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
cb_arg->resolver->RequestReresolutionLocked();
gpr_log(GPR_INFO,
"1st: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
g_on_resolution_invocations_count, g_resolution_count);
@ -225,15 +225,16 @@ void on_first_resolution(void* arg, grpc_error* error) {
}
static void start_test_under_combiner(void* arg, grpc_error* error) {
on_resolution_cb_arg* res_cb_arg = static_cast<on_resolution_cb_arg*>(arg);
grpc_resolver* resolver;
grpc_resolver_factory* factory = grpc_resolver_factory_lookup("dns");
OnResolutionCallbackArg* res_cb_arg =
static_cast<OnResolutionCallbackArg*>(arg);
grpc_core::ResolverFactory* factory =
grpc_core::ResolverRegistry::LookupResolverFactory("dns");
grpc_uri* uri = grpc_uri_parse(res_cb_arg->uri_str, 0);
grpc_resolver_args args;
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", res_cb_arg->uri_str,
factory->vtable->scheme);
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
factory->scheme());
GPR_ASSERT(uri != nullptr);
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
g_on_resolution_invocations_count = 0;
@ -248,25 +249,23 @@ static void start_test_under_combiner(void* arg, grpc_error* error) {
auto* cooldown_channel_args =
grpc_channel_args_copy_and_add(nullptr, &cooldown_arg, 1);
args.args = cooldown_channel_args;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
res_cb_arg->resolver = factory->CreateResolver(args);
grpc_channel_args_destroy(cooldown_channel_args);
GPR_ASSERT(resolver != nullptr);
res_cb_arg->resolver = resolver;
GPR_ASSERT(res_cb_arg->resolver != nullptr);
res_cb_arg->delay_before_second_resolution = kMinResolutionPeriodMs;
// First resolution, would incur in system-level resolution.
grpc_resolver_next_locked(
resolver, &res_cb_arg->result,
res_cb_arg->resolver->NextLocked(
&res_cb_arg->result,
GRPC_CLOSURE_CREATE(on_first_resolution, res_cb_arg,
grpc_combiner_scheduler(g_combiner)));
grpc_uri_destroy(uri);
grpc_resolver_factory_unref(factory);
}
static void test_cooldown(bool using_cares) {
grpc_core::ExecCtx exec_ctx;
if (using_cares) iomgr_args_init(&g_iomgr_args);
on_resolution_cb_arg* res_cb_arg =
static_cast<on_resolution_cb_arg*>(gpr_zalloc(sizeof(*res_cb_arg)));
OnResolutionCallbackArg* res_cb_arg =
grpc_core::New<OnResolutionCallbackArg>();
res_cb_arg->uri_str = "dns:127.0.0.1";
res_cb_arg->using_cares = using_cares;

@ -27,47 +27,46 @@
static grpc_combiner* g_combiner;
static void test_succeeds(grpc_resolver_factory* factory, const char* string) {
static void test_succeeds(grpc_core::ResolverFactory* factory,
const char* string) {
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
factory->scheme());
grpc_core::ExecCtx exec_ctx;
grpc_uri* uri = grpc_uri_parse(string, 0);
grpc_resolver_args args;
grpc_resolver* resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
factory->vtable->scheme);
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
GPR_ASSERT(resolver != nullptr);
GRPC_RESOLVER_UNREF(resolver, "test_succeeds");
grpc_uri_destroy(uri);
}
static void test_fails(grpc_resolver_factory* factory, const char* string) {
static void test_fails(grpc_core::ResolverFactory* factory,
const char* string) {
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
factory->scheme());
grpc_core::ExecCtx exec_ctx;
grpc_uri* uri = grpc_uri_parse(string, 0);
grpc_resolver_args args;
grpc_resolver* resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
factory->vtable->scheme);
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
GPR_ASSERT(resolver == nullptr);
grpc_uri_destroy(uri);
}
int main(int argc, char** argv) {
grpc_resolver_factory* dns;
grpc_test_init(argc, argv);
grpc_init();
g_combiner = grpc_combiner_create();
dns = grpc_resolver_factory_lookup("dns");
grpc_core::ResolverFactory* dns =
grpc_core::ResolverRegistry::LookupResolverFactory("dns");
test_succeeds(dns, "dns:10.2.1.1");
test_succeeds(dns, "dns:10.2.1.1:1234");
@ -78,7 +77,6 @@ int main(int argc, char** argv) {
test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
}
grpc_resolver_factory_unref(dns);
{
grpc_core::ExecCtx exec_ctx;
GRPC_COMBINER_UNREF(g_combiner, "test");

@ -27,25 +27,26 @@
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "test/core/util/test_config.h"
static grpc_resolver* build_fake_resolver(
static grpc_core::OrphanablePtr<grpc_core::Resolver> build_fake_resolver(
grpc_combiner* combiner,
grpc_fake_resolver_response_generator* response_generator) {
grpc_resolver_factory* factory = grpc_resolver_factory_lookup("fake");
grpc_core::FakeResolverResponseGenerator* response_generator) {
grpc_core::ResolverFactory* factory =
grpc_core::ResolverRegistry::LookupResolverFactory("fake");
grpc_arg generator_arg =
grpc_fake_resolver_response_generator_arg(response_generator);
grpc_resolver_args args;
memset(&args, 0, sizeof(args));
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator);
grpc_channel_args channel_args = {1, &generator_arg};
grpc_core::ResolverArgs args;
args.args = &channel_args;
args.combiner = combiner;
grpc_resolver* resolver =
grpc_resolver_factory_create_resolver(factory, &args);
grpc_resolver_factory_unref(factory);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
return resolver;
}
@ -57,10 +58,11 @@ typedef struct on_resolution_arg {
// Callback to check the resolution result is as expected.
void on_resolution_cb(void* arg, grpc_error* error) {
if (error != GRPC_ERROR_NONE) return;
on_resolution_arg* res = static_cast<on_resolution_arg*>(arg);
// We only check the addresses channel arg because that's the only one
// explicitly set by the test via
// grpc_fake_resolver_response_generator_set_response.
// FakeResolverResponseGenerator::SetResponse().
const grpc_lb_addresses* actual_lb_addresses =
grpc_lb_addresses_find_channel_arg(res->resolver_result);
const grpc_lb_addresses* expected_lb_addresses =
@ -115,27 +117,27 @@ static void test_fake_resolver() {
grpc_core::ExecCtx exec_ctx;
grpc_combiner* combiner = grpc_combiner_create();
// Create resolver.
grpc_fake_resolver_response_generator* response_generator =
grpc_fake_resolver_response_generator_create();
grpc_resolver* resolver = build_fake_resolver(combiner, response_generator);
GPR_ASSERT(resolver != nullptr);
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
build_fake_resolver(combiner, response_generator.get());
GPR_ASSERT(resolver.get() != nullptr);
// Test 1: normal resolution.
// next_results != NULL, results_upon_error == NULL, last_used_results ==
// next_results != NULL, reresolution_results == NULL, last_used_results ==
// NULL. Expected response is next_results.
grpc_channel_args* results = create_new_resolver_result();
on_resolution_arg on_res_arg = create_on_resolution_arg(results);
grpc_closure* on_resolution = GRPC_CLOSURE_CREATE(
on_resolution_cb, &on_res_arg, grpc_combiner_scheduler(combiner));
// Resolution won't be triggered until next_results is set.
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
grpc_fake_resolver_response_generator_set_response(response_generator,
results);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
response_generator->SetResponse(results);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 2: update resolution.
// next_results != NULL, results_upon_error == NULL, last_used_results !=
// next_results != NULL, reresolution_results == NULL, last_used_results !=
// NULL. Expected response is next_results.
results = create_new_resolver_result();
grpc_channel_args* last_used_results = grpc_channel_args_copy(results);
@ -143,61 +145,55 @@ static void test_fake_resolver() {
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
// Resolution won't be triggered until next_results is set.
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
grpc_fake_resolver_response_generator_set_response(response_generator,
results);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
response_generator->SetResponse(results);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 3: fallback re-resolution.
// next_results == NULL, results_upon_error == NULL, last_used_results !=
// next_results == NULL, reresolution_results == NULL, last_used_results !=
// NULL. Expected response is last_used_results.
on_res_arg = create_on_resolution_arg(last_used_results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
// Trigger a re-resolution.
grpc_resolver_channel_saw_error_locked(resolver);
resolver->RequestReresolutionLocked();
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 4: normal re-resolution.
// next_results == NULL, results_upon_error != NULL, last_used_results !=
// NULL. Expected response is results_upon_error.
grpc_channel_args* results_upon_error = create_new_resolver_result();
// next_results == NULL, reresolution_results != NULL, last_used_results !=
// NULL. Expected response is reresolution_results.
grpc_channel_args* reresolution_results = create_new_resolver_result();
on_res_arg =
create_on_resolution_arg(grpc_channel_args_copy(results_upon_error));
create_on_resolution_arg(grpc_channel_args_copy(reresolution_results));
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
// Set results_upon_error.
grpc_fake_resolver_response_generator_set_response_upon_error(
response_generator, results_upon_error);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
// Set reresolution_results.
response_generator->SetReresolutionResponse(reresolution_results);
// Flush here to guarantee that the response has been set.
grpc_core::ExecCtx::Get()->Flush();
// Trigger a re-resolution.
grpc_resolver_channel_saw_error_locked(resolver);
resolver->RequestReresolutionLocked();
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 5: repeat re-resolution.
// next_results == NULL, results_upon_error != NULL, last_used_results !=
// NULL. Expected response is results_upon_error.
on_res_arg = create_on_resolution_arg(results_upon_error);
// next_results == NULL, reresolution_results != NULL, last_used_results !=
// NULL. Expected response is reresolution_results.
on_res_arg = create_on_resolution_arg(reresolution_results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
// Trigger a re-resolution.
grpc_resolver_channel_saw_error_locked(resolver);
resolver->RequestReresolutionLocked();
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 6: normal resolution.
// next_results != NULL, results_upon_error != NULL, last_used_results !=
// next_results != NULL, reresolution_results != NULL, last_used_results !=
// NULL. Expected response is next_results.
results = create_new_resolver_result();
last_used_results = grpc_channel_args_copy(results);
@ -205,28 +201,24 @@ static void test_fake_resolver() {
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
// Resolution won't be triggered until next_results is set.
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
grpc_fake_resolver_response_generator_set_response(response_generator,
results);
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
response_generator->SetResponse(results);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 7: fallback re-resolution.
// next_results == NULL, results_upon_error == NULL, last_used_results !=
// next_results == NULL, reresolution_results == NULL, last_used_results !=
// NULL. Expected response is last_used_results.
on_res_arg = create_on_resolution_arg(last_used_results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
// Reset results_upon_error.
grpc_fake_resolver_response_generator_set_response_upon_error(
response_generator, nullptr);
// Flush here to guarantee that results_upon_error has been reset.
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
// Reset reresolution_results.
response_generator->SetReresolutionResponse(nullptr);
// Flush here to guarantee that reresolution_results has been reset.
grpc_core::ExecCtx::Get()->Flush();
// Trigger a re-resolution.
grpc_resolver_channel_saw_error_locked(resolver);
resolver->RequestReresolutionLocked();
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
@ -234,16 +226,15 @@ static void test_fake_resolver() {
// Requesting a new resolution without setting the response shouldn't trigger
// the resolution callback.
memset(&on_res_arg, 0, sizeof(on_res_arg));
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_milliseconds_to_deadline(100)) ==
nullptr);
// Clean up.
GRPC_COMBINER_UNREF(combiner, "test_fake_resolver");
GRPC_RESOLVER_UNREF(resolver, "test_fake_resolver");
grpc_fake_resolver_response_generator_unref(response_generator);
}
int main(int argc, char** argv) {

@ -40,18 +40,18 @@ void on_resolution_cb(void* arg, grpc_error* error) {
grpc_channel_args_destroy(res->resolver_result);
}
static void test_succeeds(grpc_resolver_factory* factory, const char* string) {
static void test_succeeds(grpc_core::ResolverFactory* factory,
const char* string) {
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
factory->scheme());
grpc_core::ExecCtx exec_ctx;
grpc_uri* uri = grpc_uri_parse(string, 0);
grpc_resolver_args args;
grpc_resolver* resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
factory->vtable->scheme);
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
GPR_ASSERT(resolver != nullptr);
on_resolution_arg on_res_arg;
@ -60,40 +60,39 @@ static void test_succeeds(grpc_resolver_factory* factory, const char* string) {
grpc_closure* on_resolution = GRPC_CLOSURE_CREATE(
on_resolution_cb, &on_res_arg, grpc_schedule_on_exec_ctx);
grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
on_resolution);
GRPC_RESOLVER_UNREF(resolver, "test_succeeds");
resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
grpc_uri_destroy(uri);
/* Flush ExecCtx to avoid stack-use-after-scope on on_res_arg which is
* accessed in the closure on_resolution_cb */
grpc_core::ExecCtx::Get()->Flush();
}
static void test_fails(grpc_resolver_factory* factory, const char* string) {
static void test_fails(grpc_core::ResolverFactory* factory,
const char* string) {
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
factory->scheme());
grpc_core::ExecCtx exec_ctx;
grpc_uri* uri = grpc_uri_parse(string, 0);
grpc_resolver_args args;
grpc_resolver* resolver;
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
factory->vtable->scheme);
GPR_ASSERT(uri);
memset(&args, 0, sizeof(args));
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory->CreateResolver(args);
GPR_ASSERT(resolver == nullptr);
grpc_uri_destroy(uri);
}
int main(int argc, char** argv) {
grpc_resolver_factory *ipv4, *ipv6;
grpc_test_init(argc, argv);
grpc_init();
g_combiner = grpc_combiner_create();
ipv4 = grpc_resolver_factory_lookup("ipv4");
ipv6 = grpc_resolver_factory_lookup("ipv6");
grpc_core::ResolverFactory* ipv4 =
grpc_core::ResolverRegistry::LookupResolverFactory("ipv4");
grpc_core::ResolverFactory* ipv6 =
grpc_core::ResolverRegistry::LookupResolverFactory("ipv6");
test_fails(ipv4, "ipv4:10.2.1.1");
test_succeeds(ipv4, "ipv4:10.2.1.1:1234");
@ -109,9 +108,6 @@ int main(int argc, char** argv) {
test_fails(ipv6, "ipv6:[::]:123456");
test_fails(ipv6, "ipv6:www.google.com");
grpc_resolver_factory_unref(ipv4);
grpc_resolver_factory_unref(ipv6);
{
grpc_core::ExecCtx exec_ctx;
GRPC_COMBINER_UNREF(g_combiner, "test");

@ -29,8 +29,8 @@
void test_unknown_scheme_target(void) {
grpc_channel* chan;
/* avoid default prefix */
grpc_resolver_registry_shutdown();
grpc_resolver_registry_init();
grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
grpc_core::ResolverRegistry::Builder::InitRegistry();
chan = grpc_insecure_channel_create("blah://blah", nullptr, nullptr);
GPR_ASSERT(chan != nullptr);

@ -28,8 +28,8 @@
#include "test/core/util/test_config.h"
void test_unknown_scheme_target(void) {
grpc_resolver_registry_shutdown();
grpc_resolver_registry_init();
grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
grpc_core::ResolverRegistry::Builder::InitRegistry();
grpc_channel_credentials* creds =
grpc_fake_transport_security_credentials_create();
grpc_channel* chan =

@ -36,6 +36,7 @@
#include <grpc/support/time.h>
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "test/core/util/port.h"
@ -230,8 +231,7 @@ class ClientChannelStressTest {
}
grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args fake_result = {1, &fake_addresses};
grpc_fake_resolver_response_generator_set_response(response_generator_,
&fake_result);
response_generator_->SetResponse(&fake_result);
grpc_lb_addresses_destroy(addresses);
}
@ -253,9 +253,10 @@ class ClientChannelStressTest {
void CreateStub() {
ChannelArguments args;
response_generator_ = grpc_fake_resolver_response_generator_create();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_);
response_generator_.get());
std::ostringstream uri;
uri << "fake:///servername_not_used";
channel_ =
@ -298,7 +299,6 @@ class ClientChannelStressTest {
for (size_t i = 0; i < backends_.size(); ++i) {
backend_servers_[i].Shutdown();
}
grpc_fake_resolver_response_generator_unref(response_generator_);
}
std::atomic_bool shutdown_{false};
@ -310,7 +310,8 @@ class ClientChannelStressTest {
std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_;
std::vector<ServerThread<BackendServiceImpl>> backend_servers_;
std::vector<ServerThread<BalancerServiceImpl>> balancer_servers_;
grpc_fake_resolver_response_generator* response_generator_;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
std::vector<std::thread> client_threads_;
};

@ -40,6 +40,7 @@
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
@ -119,11 +120,11 @@ class ClientLbEnd2endTest : public ::testing::Test {
}
void SetUp() override {
response_generator_ = grpc_fake_resolver_response_generator_create();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
void TearDown() override {
grpc_fake_resolver_response_generator_unref(response_generator_);
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i]->Shutdown();
}
@ -153,13 +154,9 @@ class ClientLbEnd2endTest : public ::testing::Test {
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
const grpc_arg fake_addresses =
grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args* fake_result =
grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1);
grpc_fake_resolver_response_generator_set_response(response_generator_,
fake_result);
grpc_channel_args_destroy(fake_result);
grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args fake_result = {1, &fake_addresses};
response_generator_->SetResponse(&fake_result);
grpc_lb_addresses_destroy(addresses);
}
@ -178,13 +175,9 @@ class ClientLbEnd2endTest : public ::testing::Test {
grpc_uri_destroy(lb_uri);
gpr_free(lb_uri_str);
}
const grpc_arg fake_addresses =
grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args* fake_result =
grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1);
grpc_fake_resolver_response_generator_set_response_upon_error(
response_generator_, fake_result);
grpc_channel_args_destroy(fake_result);
grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args fake_result = {1, &fake_addresses};
response_generator_->SetReresolutionResponse(&fake_result);
grpc_lb_addresses_destroy(addresses);
}
@ -206,7 +199,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
args.SetLoadBalancingPolicyName(lb_policy_name);
} // else, default to pick first
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_);
response_generator_.get());
return CreateCustomChannel("fake:///", InsecureChannelCredentials(), args);
}
@ -323,7 +316,8 @@ class ClientLbEnd2endTest : public ::testing::Test {
const grpc::string server_host_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::vector<std::unique_ptr<ServerData>> servers_;
grpc_fake_resolver_response_generator* response_generator_;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
const grpc::string kRequestMessage_;
};

@ -35,6 +35,7 @@
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "test/core/util/port.h"
@ -339,7 +340,8 @@ class GrpclbEnd2endTest : public ::testing::Test {
}
void SetUp() override {
response_generator_ = grpc_fake_resolver_response_generator_create();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
// Start the backends.
for (size_t i = 0; i < num_backends_; ++i) {
backends_.emplace_back(new BackendServiceImpl());
@ -363,7 +365,6 @@ class GrpclbEnd2endTest : public ::testing::Test {
for (size_t i = 0; i < balancers_.size(); ++i) {
if (balancers_[i]->Shutdown()) balancer_servers_[i].Shutdown();
}
grpc_fake_resolver_response_generator_unref(response_generator_);
}
void SetNextResolutionAllBalancers() {
@ -378,7 +379,7 @@ class GrpclbEnd2endTest : public ::testing::Test {
ChannelArguments args;
args.SetGrpclbFallbackTimeout(fallback_timeout);
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_);
response_generator_.get());
std::ostringstream uri;
uri << "fake:///servername_not_used";
channel_ =
@ -478,20 +479,18 @@ class GrpclbEnd2endTest : public ::testing::Test {
CreateLbAddressesFromAddressDataList(address_data);
grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args fake_result = {1, &fake_addresses};
grpc_fake_resolver_response_generator_set_response(response_generator_,
&fake_result);
response_generator_->SetResponse(&fake_result);
grpc_lb_addresses_destroy(addresses);
}
void SetNextResolutionUponError(
void SetNextReresolutionResponse(
const std::vector<AddressData>& address_data) {
grpc_core::ExecCtx exec_ctx;
grpc_lb_addresses* addresses =
CreateLbAddressesFromAddressDataList(address_data);
grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
grpc_channel_args fake_result = {1, &fake_addresses};
grpc_fake_resolver_response_generator_set_response_upon_error(
response_generator_, &fake_result);
response_generator_->SetReresolutionResponse(&fake_result);
grpc_lb_addresses_destroy(addresses);
}
@ -593,7 +592,8 @@ class GrpclbEnd2endTest : public ::testing::Test {
std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_;
std::vector<ServerThread<BackendService>> backend_servers_;
std::vector<ServerThread<BalancerService>> balancer_servers_;
grpc_fake_resolver_response_generator* response_generator_;
grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
response_generator_;
const grpc::string kRequestMessage_ = "Live long and prosper.";
};

@ -43,6 +43,7 @@
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/tmpfile.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/core/lib/surface/channel.h"
@ -558,8 +559,8 @@ static void setup_client(const server_fixture* lb_server,
const char* backends_name = lb_server->servers_hostport;
gpr_asprintf(&expected_target_names, "%s;%s", backends_name, BALANCERS_NAME);
grpc_fake_resolver_response_generator* response_generator =
grpc_fake_resolver_response_generator_create();
auto response_generator =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
grpc_lb_addresses* addresses = grpc_lb_addresses_create(1, nullptr);
char* lb_uri_str;
@ -578,25 +579,22 @@ static void setup_client(const server_fixture* lb_server,
grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1);
grpc_lb_addresses_destroy(addresses);
const grpc_arg new_args[] = {
grpc_arg new_args[] = {
grpc_fake_transport_expected_targets_arg(expected_target_names),
grpc_fake_resolver_response_generator_arg(response_generator)};
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator.get())};
grpc_channel_args* args = grpc_channel_args_copy_and_add(
nullptr, new_args, GPR_ARRAY_SIZE(new_args));
gpr_free(expected_target_names);
grpc_channel_args args = {GPR_ARRAY_SIZE(new_args), new_args};
cf->cq = grpc_completion_queue_create_for_next(nullptr);
grpc_channel_credentials* fake_creds =
grpc_fake_transport_security_credentials_create();
cf->client =
grpc_secure_channel_create(fake_creds, cf->server_uri, args, nullptr);
grpc_fake_resolver_response_generator_set_response(response_generator,
fake_result);
grpc_secure_channel_create(fake_creds, cf->server_uri, &args, nullptr);
response_generator->SetResponse(fake_result);
grpc_channel_args_destroy(fake_result);
grpc_channel_credentials_unref(fake_creds);
grpc_channel_args_destroy(args);
grpc_fake_resolver_response_generator_unref(response_generator);
gpr_free(expected_target_names);
}
static void teardown_client(client_fixture* cf) {

@ -39,6 +39,7 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
@ -61,11 +62,9 @@ using namespace gflags;
DEFINE_string(target_name, "", "Target name to resolve.");
DEFINE_string(expected_addrs, "",
"Comma-separated list of expected "
"'<ip0:port0>,<is_balancer0>;<ip1:port1>,<is_balancer1>;...' "
"addresses of "
"backend and/or balancers. 'is_balancer' should be bool, i.e. "
"true or false.");
"List of expected backend or balancer addresses in the form "
"'<ip0:port0>,<is_balancer0>;<ip1:port1>,<is_balancer1>;...'. "
"'is_balancer' should be bool, i.e. true or false.");
DEFINE_string(expected_chosen_service_config, "",
"Expected service config json string that gets chosen (no "
"whitespace). Empty for none.");
@ -102,12 +101,10 @@ vector<GrpcLBAddress> ParseExpectedAddrs(std::string expected_addrs) {
// get the next <ip>,<port> (v4 or v6)
size_t next_comma = expected_addrs.find(",");
if (next_comma == std::string::npos) {
gpr_log(
GPR_ERROR,
"Missing ','. Expected_addrs arg should be a semi-colon-separated "
"list of "
"<ip-port>,<bool> pairs. Left-to-be-parsed arg is |%s|",
expected_addrs.c_str());
gpr_log(GPR_ERROR,
"Missing ','. Expected_addrs arg should be a semicolon-separated "
"list of <ip-port>,<bool> pairs. Left-to-be-parsed arg is |%s|",
expected_addrs.c_str());
abort();
}
std::string next_addr = expected_addrs.substr(0, next_comma);
@ -125,7 +122,7 @@ vector<GrpcLBAddress> ParseExpectedAddrs(std::string expected_addrs) {
}
if (out.size() == 0) {
gpr_log(GPR_ERROR,
"expected_addrs arg should be a comma-separated list of "
"expected_addrs arg should be a semicolon-separated list of "
"<ip-port>,<bool> pairs");
abort();
}
@ -287,17 +284,16 @@ TEST(ResolverComponentTest, TestResolvesRelevantRecords) {
FLAGS_local_dns_server_address.c_str(),
FLAGS_target_name.c_str()));
// create resolver and resolve
grpc_resolver* resolver =
grpc_resolver_create(whole_uri, nullptr, args.pollset_set, args.lock);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
grpc_core::ResolverRegistry::CreateResolver(whole_uri, nullptr,
args.pollset_set, args.lock);
gpr_free(whole_uri);
grpc_closure on_resolver_result_changed;
GRPC_CLOSURE_INIT(&on_resolver_result_changed, CheckResolverResultLocked,
(void*)&args, grpc_combiner_scheduler(args.lock));
grpc_resolver_next_locked(resolver, &args.channel_args,
&on_resolver_result_changed);
resolver->NextLocked(&args.channel_args, &on_resolver_result_changed);
grpc_core::ExecCtx::Get()->Flush();
PollPollsetUntilRequestDone(&args);
GRPC_RESOLVER_UNREF(resolver, nullptr);
ArgsFinish(&args);
}

@ -931,7 +931,6 @@ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \
src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver_factory.cc \
src/core/ext/filters/client_channel/resolver_factory.h \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/resolver_registry.h \

@ -8883,7 +8883,6 @@
"src/core/ext/filters/client_channel/proxy_mapper_registry.h",
"src/core/ext/filters/client_channel/resolver.cc",
"src/core/ext/filters/client_channel/resolver.h",
"src/core/ext/filters/client_channel/resolver_factory.cc",
"src/core/ext/filters/client_channel/resolver_factory.h",
"src/core/ext/filters/client_channel/resolver_registry.cc",
"src/core/ext/filters/client_channel/resolver_registry.h",

Loading…
Cancel
Save