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