Skip to content

Commit

Permalink
Refactor default host name resolution
Browse files Browse the repository at this point in the history
Rephrase API's such that resolvers are constrained to be able to provide a
default host given just the text of the URI channel target.

This avoids needing to rewrite such details in the core library during
retries, and generally makes things much saner to debug.
  • Loading branch information
ctiller committed Aug 24, 2015
1 parent 03d281a commit bc85be1
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 113 deletions.
33 changes: 0 additions & 33 deletions src/core/channel/http_client_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ typedef struct call_data {
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
int sent_initial_metadata;
int sent_authority;

int got_initial_metadata;
grpc_stream_op_buffer *recv_ops;
Expand All @@ -64,7 +63,6 @@ typedef struct channel_data {
grpc_mdelem *scheme;
grpc_mdelem *content_type;
grpc_mdelem *status;
grpc_mdelem *default_authority;
/** complete user agent mdelem */
grpc_mdelem *user_agent;
} channel_data;
Expand Down Expand Up @@ -103,18 +101,13 @@ static void hc_on_recv(void *user_data, int success) {

static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
/* eat the things we'd like to set ourselves */
if (md->key == channeld->method->key) return NULL;
if (md->key == channeld->scheme->key) return NULL;
if (md->key == channeld->te_trailers->key) return NULL;
if (md->key == channeld->content_type->key) return NULL;
if (md->key == channeld->user_agent->key) return NULL;
if (channeld->default_authority &&
channeld->default_authority->key == md->key) {
calld->sent_authority = 1;
}
return md;
}

Expand All @@ -138,11 +131,6 @@ static void hc_mutate_op(grpc_call_element *elem,
GRPC_MDELEM_REF(channeld->method));
grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme,
GRPC_MDELEM_REF(channeld->scheme));
if (channeld->default_authority && !calld->sent_authority) {
grpc_metadata_batch_add_head(
&op->data.metadata, &calld->authority,
GRPC_MDELEM_REF(channeld->default_authority));
}
grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers,
GRPC_MDELEM_REF(channeld->te_trailers));
grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type,
Expand Down Expand Up @@ -175,7 +163,6 @@ static void init_call_elem(grpc_call_element *elem,
call_data *calld = elem->call_data;
calld->sent_initial_metadata = 0;
calld->got_initial_metadata = 0;
calld->sent_authority = 0;
calld->on_done_recv = NULL;
grpc_iomgr_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
if (initial_op) hc_mutate_op(elem, initial_op);
Expand Down Expand Up @@ -257,8 +244,6 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *channel_args,
grpc_mdctx *mdctx, int is_first, int is_last) {
size_t i;

/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;

Expand All @@ -267,21 +252,6 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
path */
GPR_ASSERT(!is_last);

channeld->default_authority = NULL;
if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
if (channel_args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "%s: must be an string",
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
channeld->default_authority = grpc_mdelem_from_strings(
mdctx, ":authority", channel_args->args[i].value.string);
}
}
}
}

/* initialize members */
channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST");
Expand All @@ -306,9 +276,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
GRPC_MDELEM_UNREF(channeld->content_type);
GRPC_MDELEM_UNREF(channeld->status);
GRPC_MDELEM_UNREF(channeld->user_agent);
if (channeld->default_authority) {
GRPC_MDELEM_UNREF(channeld->default_authority);
}
}

const grpc_channel_filter grpc_http_client_filter = {
Expand Down
6 changes: 6 additions & 0 deletions src/core/client_config/resolver_factory.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ grpc_resolver *grpc_resolver_factory_create_resolver(
if (!factory) return NULL;
return factory->vtable->create_resolver(factory, uri, subchannel_factory);
}

char *grpc_resolver_factory_get_default_authority(
grpc_resolver_factory *factory, grpc_uri *uri) {
if (!factory) return NULL;
return factory->vtable->get_default_authority(factory, uri);
}
9 changes: 9 additions & 0 deletions src/core/client_config/resolver_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ struct grpc_resolver_factory_vtable {
grpc_resolver *(*create_resolver)(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory);

char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri);

const char *scheme;
};

void grpc_resolver_factory_ref(grpc_resolver_factory *resolver);
Expand All @@ -64,4 +68,9 @@ grpc_resolver *grpc_resolver_factory_create_resolver(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory);

/** 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);

#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */
79 changes: 42 additions & 37 deletions src/core/client_config/resolver_registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,33 @@

#define MAX_RESOLVERS 10

typedef struct {
char *scheme;
grpc_resolver_factory *factory;
} registered_resolver;

static registered_resolver g_all_of_the_resolvers[MAX_RESOLVERS];
static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS];
static int g_number_of_resolvers = 0;

static char *g_default_resolver_scheme;
static char *g_default_resolver_prefix;

void grpc_resolver_registry_init(const char *default_resolver_scheme) {
void grpc_resolver_registry_init(const char *default_resolver_prefix) {
g_number_of_resolvers = 0;
g_default_resolver_scheme = gpr_strdup(default_resolver_scheme);
g_default_resolver_prefix = gpr_strdup(default_resolver_prefix);
}

void grpc_resolver_registry_shutdown(void) {
int i;
for (i = 0; i < g_number_of_resolvers; i++) {
gpr_free(g_all_of_the_resolvers[i].scheme);
grpc_resolver_factory_unref(g_all_of_the_resolvers[i].factory);
grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
}
gpr_free(g_default_resolver_scheme);
gpr_free(g_default_resolver_prefix);
}

void grpc_register_resolver_type(const char *scheme,
grpc_resolver_factory *factory) {
void grpc_register_resolver_type(grpc_resolver_factory *factory) {
int i;
for (i = 0; i < g_number_of_resolvers; i++) {
GPR_ASSERT(0 != strcmp(scheme, g_all_of_the_resolvers[i].scheme));
GPR_ASSERT(0 != strcmp(factory->vtable->scheme,
g_all_of_the_resolvers[i]->vtable->scheme));
}
GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
g_all_of_the_resolvers[g_number_of_resolvers].scheme = gpr_strdup(scheme);
grpc_resolver_factory_ref(factory);
g_all_of_the_resolvers[g_number_of_resolvers].factory = factory;
g_number_of_resolvers++;
g_all_of_the_resolvers[g_number_of_resolvers++] = factory;
}

static grpc_resolver_factory *lookup_factory(grpc_uri *uri) {
Expand All @@ -85,40 +77,53 @@ static grpc_resolver_factory *lookup_factory(grpc_uri *uri) {
if (!uri) return NULL;

for (i = 0; i < g_number_of_resolvers; i++) {
if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i].scheme)) {
return g_all_of_the_resolvers[i].factory;
if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i]->vtable->scheme)) {
return g_all_of_the_resolvers[i];
}
}

return NULL;
}

grpc_resolver *grpc_resolver_create(
const char *name, grpc_subchannel_factory *subchannel_factory) {
grpc_uri *uri;
static grpc_resolver_factory *resolve_factory(const char *target,
grpc_uri **uri) {
char *tmp;
grpc_resolver_factory *factory = NULL;
grpc_resolver *resolver;

uri = grpc_uri_parse(name, 1);
factory = lookup_factory(uri);
if (factory == NULL && g_default_resolver_scheme != NULL) {
grpc_uri_destroy(uri);
gpr_asprintf(&tmp, "%s%s", g_default_resolver_scheme, name);
uri = grpc_uri_parse(tmp, 1);
factory = lookup_factory(uri);

*uri = grpc_uri_parse(target, 1);
factory = lookup_factory(*uri);
if (factory == NULL && g_default_resolver_prefix != NULL) {
grpc_uri_destroy(*uri);
gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target);
*uri = grpc_uri_parse(tmp, 1);
factory = lookup_factory(*uri);
if (factory == NULL) {
grpc_uri_destroy(grpc_uri_parse(name, 0));
grpc_uri_destroy(grpc_uri_parse(target, 0));
grpc_uri_destroy(grpc_uri_parse(tmp, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", name, tmp);
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, tmp);
}
gpr_free(tmp);
} else if (factory == NULL) {
grpc_uri_destroy(grpc_uri_parse(name, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s'", name);
grpc_uri_destroy(grpc_uri_parse(target, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target);
}
resolver =
return factory;
}

grpc_resolver *grpc_resolver_create(
const char *target, grpc_subchannel_factory *subchannel_factory) {
grpc_uri *uri = NULL;
grpc_resolver_factory *factory = resolve_factory(target, &uri);
grpc_resolver *resolver =
grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory);
grpc_uri_destroy(uri);
return resolver;
}

char *grpc_get_default_authority(const char *target) {
grpc_uri *uri = NULL;
grpc_resolver_factory *factory = resolve_factory(target, &uri);
char *authority = grpc_resolver_factory_get_default_authority(factory, uri);
grpc_uri_destroy(uri);
return authority;
}
15 changes: 9 additions & 6 deletions src/core/client_config/resolver_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,22 @@ void grpc_resolver_registry_shutdown(void);
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(const char *scheme,
grpc_resolver_factory *factory);
void grpc_register_resolver_type(grpc_resolver_factory *factory);

/** Create a resolver given \a name.
First tries to parse \a name as a URI. If this succeeds, tries
/** 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 name, and tries again (if default_prefix
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. */
grpc_resolver *grpc_resolver_create(
const char *name, grpc_subchannel_factory *subchannel_factory);
const char *target, grpc_subchannel_factory *subchannel_factory);

/** 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);

#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */
25 changes: 10 additions & 15 deletions src/core/client_config/resolvers/dns_resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,6 @@ static grpc_resolver *dns_create(
grpc_subchannel_factory *subchannel_factory) {
dns_resolver *r;
const char *path = uri->path;
grpc_arg default_host_arg;
char *host;
char *port;

if (0 != strcmp(uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported");
Expand All @@ -214,17 +211,6 @@ static grpc_resolver *dns_create(

if (path[0] == '/') ++path;

gpr_split_host_port(path, &host, &port);

default_host_arg.type = GRPC_ARG_STRING;
default_host_arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
default_host_arg.value.string = host;
subchannel_factory = grpc_subchannel_factory_add_channel_arg(
subchannel_factory, &default_host_arg);

gpr_free(host);
gpr_free(port);

r = gpr_malloc(sizeof(dns_resolver));
memset(r, 0, sizeof(*r));
gpr_ref_init(&r->refs, 1);
Expand All @@ -233,6 +219,7 @@ static grpc_resolver *dns_create(
r->name = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
r->subchannel_factory = subchannel_factory;
grpc_subchannel_factory_ref(subchannel_factory);
r->lb_policy_factory = lb_policy_factory;
return &r->base;
}
Expand All @@ -252,8 +239,16 @@ static grpc_resolver *dns_factory_create_resolver(
subchannel_factory);
}

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_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};

grpc_resolver_factory *grpc_dns_resolver_factory_create() {
Expand Down
49 changes: 35 additions & 14 deletions src/core/client_config/resolvers/sockaddr_resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,29 @@ static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, int *len) {

return 1;
}

static char *unix_get_default_authority(grpc_resolver_factory *factory,
grpc_uri *uri) {
return gpr_strdup("localhost");
}
#endif

static char *ip_get_default_authority(grpc_uri *uri) {
const char *path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
}

static char *ipv4_get_default_authority(grpc_resolver_factory *factory,
grpc_uri *uri) {
return ip_get_default_authority(uri);
}

static char *ipv6_get_default_authority(grpc_resolver_factory *factory,
grpc_uri *uri) {
return ip_get_default_authority(uri);
}

static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, int *len) {
const char *host_port = uri->path;
char *host;
Expand Down Expand Up @@ -276,20 +297,20 @@ static void sockaddr_factory_ref(grpc_resolver_factory *factory) {}

static void sockaddr_factory_unref(grpc_resolver_factory *factory) {}

#define DECL_FACTORY(name) \
static grpc_resolver *name##_factory_create_resolver( \
grpc_resolver_factory *factory, grpc_uri *uri, \
grpc_subchannel_factory *subchannel_factory) { \
return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \
subchannel_factory, parse_##name); \
} \
static const grpc_resolver_factory_vtable name##_factory_vtable = { \
sockaddr_factory_ref, sockaddr_factory_unref, \
name##_factory_create_resolver}; \
static grpc_resolver_factory name##_resolver_factory = { \
&name##_factory_vtable}; \
grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \
return &name##_resolver_factory; \
#define DECL_FACTORY(name) \
static grpc_resolver *name##_factory_create_resolver( \
grpc_resolver_factory *factory, grpc_uri *uri, \
grpc_subchannel_factory *subchannel_factory) { \
return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \
subchannel_factory, 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}; \
grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \
return &name##_resolver_factory; \
}

#ifdef GPR_POSIX_SOCKET
Expand Down
Loading

0 comments on commit bc85be1

Please sign in to comment.