|  | @@ -33,4 +33,229 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include "src/core/client_config/resolvers/dns_resolver.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | +#include <string.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <grpc/support/alloc.h>
 | 
	
		
			
				|  |  | +#include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "src/core/iomgr/resolve_address.h"
 | 
	
		
			
				|  |  | +#include "src/core/support/string.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +  /** base class: must be first */
 | 
	
		
			
				|  |  | +  grpc_resolver base;
 | 
	
		
			
				|  |  | +  /** refcount */
 | 
	
		
			
				|  |  | +  gpr_refcount refs;
 | 
	
		
			
				|  |  | +  /** name to resolve */
 | 
	
		
			
				|  |  | +  char *name;
 | 
	
		
			
				|  |  | +  /** default port to use */
 | 
	
		
			
				|  |  | +  char *default_port;
 | 
	
		
			
				|  |  | +  /** subchannel factory */
 | 
	
		
			
				|  |  | +  grpc_subchannel_factory *subchannel_factory;
 | 
	
		
			
				|  |  | +  /** load balancing policy factory */
 | 
	
		
			
				|  |  | +  grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
 | 
	
		
			
				|  |  | +                                       size_t num_subchannels);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /** mutex guarding the rest of the state */
 | 
	
		
			
				|  |  | +  gpr_mu mu;
 | 
	
		
			
				|  |  | +  /** are we currently resolving? */
 | 
	
		
			
				|  |  | +  int resolving;
 | 
	
		
			
				|  |  | +  /** which version of resolved_config have we published? */
 | 
	
		
			
				|  |  | +  int published_version;
 | 
	
		
			
				|  |  | +  /** which version of resolved_config is current? */
 | 
	
		
			
				|  |  | +  int resolved_version;
 | 
	
		
			
				|  |  | +  /** pending next completion, or NULL */
 | 
	
		
			
				|  |  | +  grpc_iomgr_closure *next_completion;
 | 
	
		
			
				|  |  | +  /** target config address for next completion */
 | 
	
		
			
				|  |  | +  grpc_client_config **target_config;
 | 
	
		
			
				|  |  | +  /** current (fully resolved) config */
 | 
	
		
			
				|  |  | +  grpc_client_config *resolved_config;
 | 
	
		
			
				|  |  | +} dns_resolver;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_destroy(dns_resolver *r);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_start_resolving_locked(dns_resolver *r);
 | 
	
		
			
				|  |  | +static void dns_maybe_finish_next_locked(dns_resolver *r);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_ref(grpc_resolver *r);
 | 
	
		
			
				|  |  | +static void dns_unref(grpc_resolver *r);
 | 
	
		
			
				|  |  | +static void dns_shutdown(grpc_resolver *r);
 | 
	
		
			
				|  |  | +static void dns_channel_saw_error(grpc_resolver *r,
 | 
	
		
			
				|  |  | +                                  struct sockaddr *failing_address,
 | 
	
		
			
				|  |  | +                                  int failing_address_len);
 | 
	
		
			
				|  |  | +static void dns_next(grpc_resolver *r, grpc_client_config **target_config,
 | 
	
		
			
				|  |  | +                     grpc_iomgr_closure *on_complete);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const grpc_resolver_vtable dns_resolver_vtable = {
 | 
	
		
			
				|  |  | +    dns_ref, dns_unref, dns_shutdown, dns_channel_saw_error, dns_next};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_ref(grpc_resolver *resolver) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = (dns_resolver *)resolver;
 | 
	
		
			
				|  |  | +  gpr_ref(&r->refs);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_unref(grpc_resolver *resolver) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = (dns_resolver *)resolver;
 | 
	
		
			
				|  |  | +  if (gpr_unref(&r->refs)) {
 | 
	
		
			
				|  |  | +    dns_destroy(r);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_shutdown(grpc_resolver *resolver) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = (dns_resolver *)resolver;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&r->mu);
 | 
	
		
			
				|  |  | +  if (r->next_completion != NULL) {
 | 
	
		
			
				|  |  | +    *r->target_config = NULL;
 | 
	
		
			
				|  |  | +    /* TODO(ctiller): add delayed callback */
 | 
	
		
			
				|  |  | +    grpc_iomgr_add_callback(r->next_completion);
 | 
	
		
			
				|  |  | +    r->next_completion = NULL;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&r->mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
 | 
	
		
			
				|  |  | +                                  int len) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = (dns_resolver *)resolver;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&r->mu);
 | 
	
		
			
				|  |  | +  if (!r->resolving) {
 | 
	
		
			
				|  |  | +    dns_start_resolving_locked(r);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&r->mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_next(grpc_resolver *resolver,
 | 
	
		
			
				|  |  | +                     grpc_client_config **target_config,
 | 
	
		
			
				|  |  | +                     grpc_iomgr_closure *on_complete) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = (dns_resolver *)resolver;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&r->mu);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(!r->next_completion);
 | 
	
		
			
				|  |  | +  r->next_completion = on_complete;
 | 
	
		
			
				|  |  | +  r->target_config = target_config;
 | 
	
		
			
				|  |  | +  if (r->resolved_version == 0 && !r->resolving) {
 | 
	
		
			
				|  |  | +    dns_start_resolving_locked(r);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    dns_maybe_finish_next_locked(r);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&r->mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) {
 | 
	
		
			
				|  |  | +  dns_resolver *r = arg;
 | 
	
		
			
				|  |  | +  grpc_client_config *config = NULL;
 | 
	
		
			
				|  |  | +  grpc_subchannel **subchannels;
 | 
	
		
			
				|  |  | +  grpc_subchannel_args args;
 | 
	
		
			
				|  |  | +  size_t i;
 | 
	
		
			
				|  |  | +  if (addresses) {
 | 
	
		
			
				|  |  | +    config = grpc_client_config_create();
 | 
	
		
			
				|  |  | +    subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
 | 
	
		
			
				|  |  | +    for (i = 0; i < addresses->naddrs; i++) {
 | 
	
		
			
				|  |  | +      memset(&args, 0, sizeof(args));
 | 
	
		
			
				|  |  | +      args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
 | 
	
		
			
				|  |  | +      args.addr_len = addresses->addrs[i].len;
 | 
	
		
			
				|  |  | +      subchannels[i] = grpc_subchannel_factory_create_subchannel(
 | 
	
		
			
				|  |  | +          r->subchannel_factory, &args);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    grpc_client_config_set_lb_policy(
 | 
	
		
			
				|  |  | +        config, r->lb_policy_factory(subchannels, addresses->naddrs));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&r->mu);
 | 
	
		
			
				|  |  | +  if (r->resolved_config) {
 | 
	
		
			
				|  |  | +    grpc_client_config_unref(r->resolved_config);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  r->resolved_config = config;
 | 
	
		
			
				|  |  | +  r->resolved_version++;
 | 
	
		
			
				|  |  | +  dns_maybe_finish_next_locked(r);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&r->mu);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_start_resolving_locked(dns_resolver *r) {
 | 
	
		
			
				|  |  | +  dns_ref(&r->base);
 | 
	
		
			
				|  |  | +  r->resolving = 1;
 | 
	
		
			
				|  |  | +  grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_maybe_finish_next_locked(dns_resolver *r) {
 | 
	
		
			
				|  |  | +  if (r->next_completion != NULL &&
 | 
	
		
			
				|  |  | +      r->resolved_version != r->published_version) {
 | 
	
		
			
				|  |  | +    grpc_iomgr_add_callback(r->next_completion);
 | 
	
		
			
				|  |  | +    r->next_completion = NULL;
 | 
	
		
			
				|  |  | +    r->published_version = r->resolved_version;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_destroy(dns_resolver *r) {
 | 
	
		
			
				|  |  | +  gpr_mu_destroy(&r->mu);
 | 
	
		
			
				|  |  | +  grpc_subchannel_factory_unref(r->subchannel_factory);
 | 
	
		
			
				|  |  | +  gpr_free(r->name);
 | 
	
		
			
				|  |  | +  gpr_free(r->default_port);
 | 
	
		
			
				|  |  | +  gpr_free(r);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static grpc_resolver *dns_create(grpc_uri *uri, const char *default_port,
 | 
	
		
			
				|  |  | +                                 grpc_subchannel_factory *subchannel_factory) {
 | 
	
		
			
				|  |  | +  dns_resolver *r;
 | 
	
		
			
				|  |  | +  const char *path = uri->path;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (0 != strcmp(uri->authority, "")) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_ERROR, "authority based uri's not supported");
 | 
	
		
			
				|  |  | +    return NULL;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (path[0] == '/') ++path;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  r = gpr_malloc(sizeof(dns_resolver));
 | 
	
		
			
				|  |  | +  memset(r, 0, sizeof(*r));
 | 
	
		
			
				|  |  | +  gpr_ref_init(&r->refs, 1);
 | 
	
		
			
				|  |  | +  gpr_mu_init(&r->mu);
 | 
	
		
			
				|  |  | +  r->base.vtable = &dns_resolver_vtable;
 | 
	
		
			
				|  |  | +  r->name = gpr_strdup(path);
 | 
	
		
			
				|  |  | +  r->default_port = gpr_strdup(default_port);
 | 
	
		
			
				|  |  | +  r->subchannel_factory = subchannel_factory;
 | 
	
		
			
				|  |  | +  grpc_subchannel_factory_ref(subchannel_factory);
 | 
	
		
			
				|  |  | +  return &r->base;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * FACTORY
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef struct {
 | 
	
		
			
				|  |  | +  /** base: must be first */
 | 
	
		
			
				|  |  | +  grpc_resolver_factory base;
 | 
	
		
			
				|  |  | +  /** ref count */
 | 
	
		
			
				|  |  | +  gpr_refcount refs;
 | 
	
		
			
				|  |  | +  /** default port */
 | 
	
		
			
				|  |  | +  char *default_port;
 | 
	
		
			
				|  |  | +} dns_resolver_factory;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_factory_ref(grpc_resolver_factory *factory) {
 | 
	
		
			
				|  |  | +  dns_resolver_factory *f = (dns_resolver_factory *)factory;
 | 
	
		
			
				|  |  | +  gpr_ref(&f->refs);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dns_factory_unref(grpc_resolver_factory *factory) {
 | 
	
		
			
				|  |  | +  dns_resolver_factory *f = (dns_resolver_factory *)factory;
 | 
	
		
			
				|  |  | +  if (gpr_unref(&f->refs)) {
 | 
	
		
			
				|  |  | +    gpr_free(f->default_port);
 | 
	
		
			
				|  |  | +    gpr_free(f);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static grpc_resolver *dns_factory_create_resolver(
 | 
	
		
			
				|  |  | +    grpc_resolver_factory *factory, grpc_uri *uri,
 | 
	
		
			
				|  |  | +    grpc_subchannel_factory *subchannel_factory) {
 | 
	
		
			
				|  |  | +  dns_resolver_factory *f = (dns_resolver_factory *)factory;
 | 
	
		
			
				|  |  | +  return dns_create(uri, f->default_port, subchannel_factory);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const grpc_resolver_factory_vtable dns_factory_vtable = {
 | 
	
		
			
				|  |  | +    dns_factory_ref, dns_factory_unref, dns_factory_create_resolver};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +grpc_resolver_factory *grpc_dns_resolver_factory_create(
 | 
	
		
			
				|  |  | +    const char *default_port) {
 | 
	
		
			
				|  |  | +  dns_resolver_factory *f = gpr_malloc(sizeof(*f));
 | 
	
		
			
				|  |  | +  memset(f, 0, sizeof(*f));
 | 
	
		
			
				|  |  | +  f->base.vtable = &dns_factory_vtable;
 | 
	
		
			
				|  |  | +  f->default_port = gpr_strdup(default_port);
 | 
	
		
			
				|  |  | +  return &f->base;
 | 
	
		
			
				|  |  | +}
 |