• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/iomgr/port.h"
22 
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/string_util.h>
25 
26 #include <grpc/support/log.h>
27 #include "src/core/lib/gpr/host_port.h"
28 #include "src/core/lib/gpr/string.h"
29 #include "src/core/lib/gpr/useful.h"
30 
31 #include "src/core/lib/iomgr/iomgr_custom.h"
32 #include "src/core/lib/iomgr/resolve_address_custom.h"
33 #include "src/core/lib/iomgr/sockaddr_utils.h"
34 
35 #include <string.h>
36 
37 typedef struct grpc_custom_resolver {
38   grpc_closure* on_done;
39   grpc_resolved_addresses** addresses;
40   char* host;
41   char* port;
42 } grpc_custom_resolver;
43 
44 static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
45 
retry_named_port_failure(grpc_custom_resolver * r,grpc_resolved_addresses ** res)46 static int retry_named_port_failure(grpc_custom_resolver* r,
47                                     grpc_resolved_addresses** res) {
48   // This loop is copied from resolve_address_posix.c
49   const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
50   for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
51     if (strcmp(r->port, svc[i][0]) == 0) {
52       gpr_free(r->port);
53       r->port = gpr_strdup(svc[i][1]);
54       if (res) {
55         grpc_error* error =
56             resolve_address_vtable->resolve(r->host, r->port, res);
57         if (error != GRPC_ERROR_NONE) {
58           GRPC_ERROR_UNREF(error);
59           return 0;
60         }
61       } else {
62         resolve_address_vtable->resolve_async(r, r->host, r->port);
63       }
64       return 1;
65     }
66   }
67   return 0;
68 }
69 
grpc_custom_resolve_callback(grpc_custom_resolver * r,grpc_resolved_addresses * result,grpc_error * error)70 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
71                                   grpc_resolved_addresses* result,
72                                   grpc_error* error) {
73   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
74   grpc_core::ExecCtx exec_ctx;
75   if (error == GRPC_ERROR_NONE) {
76     *r->addresses = result;
77   } else if (retry_named_port_failure(r, nullptr)) {
78     return;
79   }
80   if (r->on_done) {
81     GRPC_CLOSURE_SCHED(r->on_done, error);
82   }
83   gpr_free(r->host);
84   gpr_free(r->port);
85   gpr_free(r);
86 }
87 
try_split_host_port(const char * name,const char * default_port,char ** host,char ** port)88 static grpc_error* try_split_host_port(const char* name,
89                                        const char* default_port, char** host,
90                                        char** port) {
91   /* parse name, splitting it into host and port parts */
92   grpc_error* error;
93   gpr_split_host_port(name, host, port);
94   if (*host == nullptr) {
95     char* msg;
96     gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
97     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
98     gpr_free(msg);
99     return error;
100   }
101   if (*port == nullptr) {
102     // TODO(murgatroid99): add tests for this case
103     if (default_port == nullptr) {
104       char* msg;
105       gpr_asprintf(&msg, "no port in name '%s'", name);
106       error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
107       gpr_free(msg);
108       return error;
109     }
110     *port = gpr_strdup(default_port);
111   }
112   return GRPC_ERROR_NONE;
113 }
114 
blocking_resolve_address_impl(const char * name,const char * default_port,grpc_resolved_addresses ** addresses)115 static grpc_error* blocking_resolve_address_impl(
116     const char* name, const char* default_port,
117     grpc_resolved_addresses** addresses) {
118   char* host;
119   char* port;
120   grpc_error* err;
121 
122   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
123 
124   err = try_split_host_port(name, default_port, &host, &port);
125   if (err != GRPC_ERROR_NONE) {
126     gpr_free(host);
127     gpr_free(port);
128     return err;
129   }
130 
131   /* Call getaddrinfo */
132   grpc_custom_resolver resolver;
133   resolver.host = host;
134   resolver.port = port;
135 
136   grpc_resolved_addresses* addrs;
137   grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
138   grpc_core::ExecCtx::Set(nullptr);
139   err = resolve_address_vtable->resolve(host, port, &addrs);
140   if (err != GRPC_ERROR_NONE) {
141     if (retry_named_port_failure(&resolver, &addrs)) {
142       GRPC_ERROR_UNREF(err);
143       err = GRPC_ERROR_NONE;
144     }
145   }
146   grpc_core::ExecCtx::Set(curr);
147   if (err == GRPC_ERROR_NONE) {
148     *addresses = addrs;
149   }
150   gpr_free(resolver.host);
151   gpr_free(resolver.port);
152   return err;
153 }
154 
resolve_address_impl(const char * name,const char * default_port,grpc_pollset_set * interested_parties,grpc_closure * on_done,grpc_resolved_addresses ** addrs)155 static void resolve_address_impl(const char* name, const char* default_port,
156                                  grpc_pollset_set* interested_parties,
157                                  grpc_closure* on_done,
158                                  grpc_resolved_addresses** addrs) {
159   grpc_custom_resolver* r = nullptr;
160   char* host = nullptr;
161   char* port = nullptr;
162   grpc_error* err;
163   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
164   err = try_split_host_port(name, default_port, &host, &port);
165   if (err != GRPC_ERROR_NONE) {
166     GRPC_CLOSURE_SCHED(on_done, err);
167     gpr_free(host);
168     gpr_free(port);
169     return;
170   }
171   r = (grpc_custom_resolver*)gpr_malloc(sizeof(grpc_custom_resolver));
172   r->on_done = on_done;
173   r->addresses = addrs;
174   r->host = host;
175   r->port = port;
176 
177   /* Call getaddrinfo */
178   resolve_address_vtable->resolve_async(r, r->host, r->port);
179 }
180 
181 static grpc_address_resolver_vtable custom_resolver_vtable = {
182     resolve_address_impl, blocking_resolve_address_impl};
183 
grpc_custom_resolver_init(grpc_custom_resolver_vtable * impl)184 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
185   resolve_address_vtable = impl;
186   grpc_set_resolver_impl(&custom_resolver_vtable);
187 }
188