diff options
author | Nicolas Noble <nnoble@google.com> | 2015-01-26 11:41:12 -0800 |
---|---|---|
committer | Nicolas Noble <nnoble@google.com> | 2015-01-26 11:41:12 -0800 |
commit | fee065c1c7f01207c0e484c92681cea184b1983a (patch) | |
tree | 11baf429fdee72a169bdb0b1d17f16154ab5186a /src/core/iomgr/resolve_address.c | |
parent | 614c2bf99b1865761e5a05a56faf1ad8f26138ff (diff) | |
parent | c41704bada0dc8974e7063f84dae934931813811 (diff) |
Merge branch 'master' of github.com:google/grpc into json
Conflicts:
src/core/security/credentials.c
Diffstat (limited to 'src/core/iomgr/resolve_address.c')
-rw-r--r-- | src/core/iomgr/resolve_address.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/core/iomgr/resolve_address.c b/src/core/iomgr/resolve_address.c new file mode 100644 index 0000000000..01681168ce --- /dev/null +++ b/src/core/iomgr/resolve_address.c @@ -0,0 +1,219 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define _POSIX_SOURCE + +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/resolve_address.h" + +#include <sys/types.h> +#include <string.h> + +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/support/string.h" +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/thd.h> +#include <grpc/support/time.h> + +typedef struct { + char *name; + char *default_port; + grpc_resolve_cb cb; + void *arg; +} request; + +static void split_host_port(const char *name, char **host, char **port) { + const char *host_start; + size_t host_len; + const char *port_start; + + *host = NULL; + *port = NULL; + + if (name[0] == '[') { + /* Parse a bracketed host, typically an IPv6 literal. */ + const char *rbracket = strchr(name, ']'); + if (rbracket == NULL) { + /* Unmatched [ */ + return; + } + if (rbracket[1] == '\0') { + /* ]<end> */ + port_start = NULL; + } else if (rbracket[1] == ':') { + /* ]:<port?> */ + port_start = rbracket + 2; + } else { + /* ]<invalid> */ + return; + } + host_start = name + 1; + host_len = rbracket - host_start; + if (memchr(host_start, ':', host_len) == NULL) { + /* Require all bracketed hosts to contain a colon, because a hostname or + IPv4 address should never use brackets. */ + return; + } + } else { + const char *colon = strchr(name, ':'); + if (colon != NULL && strchr(colon + 1, ':') == NULL) { + /* Exactly 1 colon. Split into host:port. */ + host_start = name; + host_len = colon - name; + port_start = colon + 1; + } else { + /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ + host_start = name; + host_len = strlen(name); + port_start = NULL; + } + } + + /* Allocate return values. */ + *host = gpr_malloc(host_len + 1); + memcpy(*host, host_start, host_len); + (*host)[host_len] = '\0'; + + if (port_start != NULL) { + *port = gpr_strdup(port_start); + } +} + +grpc_resolved_addresses *grpc_blocking_resolve_address( + const char *name, const char *default_port) { + struct addrinfo hints; + struct addrinfo *result = NULL, *resp; + char *host; + char *port; + int s; + size_t i; + grpc_resolved_addresses *addrs = NULL; + const gpr_timespec start_time = gpr_now(); + + /* parse name, splitting it into host and port parts */ + split_host_port(name, &host, &port); + if (host == NULL) { + gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); + goto done; + } + if (port == NULL) { + if (default_port == NULL) { + gpr_log(GPR_ERROR, "no port in name '%s'", name); + goto done; + } + port = gpr_strdup(default_port); + } + + /* Call getaddrinfo */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ + + s = getaddrinfo(host, port, &hints, &result); + if (s != 0) { + gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); + goto done; + } + + /* Success path: set addrs non-NULL, fill it in */ + addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + addrs->naddrs++; + } + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); + i = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); + addrs->addrs[i].len = resp->ai_addrlen; + i++; + } + + /* Temporary logging, to help identify flakiness in dualstack_socket_test. */ + { + const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time); + const int delay_ms = + delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_MS; + gpr_log(GPR_INFO, "logspam: getaddrinfo(%s, %s) resolved %d addrs in %dms:", + host, port, addrs->naddrs, delay_ms); + for (i = 0; i < addrs->naddrs; i++) { + char *buf; + grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, + 0); + gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf); + gpr_free(buf); + } + } + +done: + gpr_free(host); + gpr_free(port); + if (result) { + freeaddrinfo(result); + } + return addrs; +} + +/* Thread function to asynch-ify grpc_blocking_resolve_address */ +static void do_request(void *rp) { + request *r = rp; + grpc_resolved_addresses *resolved = + grpc_blocking_resolve_address(r->name, r->default_port); + void *arg = r->arg; + grpc_resolve_cb cb = r->cb; + gpr_free(r->name); + gpr_free(r->default_port); + gpr_free(r); + cb(arg, resolved); + grpc_iomgr_unref(); +} + +void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { + gpr_free(addrs->addrs); + gpr_free(addrs); +} + +void grpc_resolve_address(const char *name, const char *default_port, + grpc_resolve_cb cb, void *arg) { + request *r = gpr_malloc(sizeof(request)); + gpr_thd_id id; + grpc_iomgr_ref(); + r->name = gpr_strdup(name); + r->default_port = gpr_strdup(default_port); + r->cb = cb; + r->arg = arg; + gpr_thd_new(&id, do_request, r, NULL); +} |