Implementation work for client_config

- uri parsing
- dns resolution
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 187ff26..95f38ec 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -33,4 +33,229 @@
 
 #include "src/core/client_config/resolvers/dns_resolver.h"
 
- 
\ No newline at end of file
+#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;
+}