3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/lib/iomgr/port.h"
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/string_util.h>
26 #include <grpc/support/log.h>
27 #include "src/core/lib/gpr/string.h"
28 #include "src/core/lib/gpr/useful.h"
29 #include "src/core/lib/gprpp/host_port.h"
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"
37 typedef struct grpc_custom_resolver {
38 grpc_closure* on_done;
39 grpc_resolved_addresses** addresses;
42 } grpc_custom_resolver;
44 static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
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) {
53 r->port = gpr_strdup(svc[i][1]);
56 resolve_address_vtable->resolve(r->host, r->port, res);
57 if (error != GRPC_ERROR_NONE) {
58 GRPC_ERROR_UNREF(error);
62 resolve_address_vtable->resolve_async(r, r->host, r->port);
70 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
71 grpc_resolved_addresses* result,
73 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
74 grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
75 grpc_core::ExecCtx exec_ctx;
76 if (error == GRPC_ERROR_NONE) {
77 *r->addresses = result;
78 } else if (retry_named_port_failure(r, nullptr)) {
82 GRPC_CLOSURE_SCHED(r->on_done, error);
89 static grpc_error* try_split_host_port(const char* name,
90 const char* default_port,
91 grpc_core::UniquePtr<char>* host,
92 grpc_core::UniquePtr<char>* port) {
93 /* parse name, splitting it into host and port parts */
95 SplitHostPort(name, host, port);
96 if (*host == nullptr) {
98 gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
99 error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
103 if (*port == nullptr) {
104 // TODO(murgatroid99): add tests for this case
105 if (default_port == nullptr) {
107 gpr_asprintf(&msg, "no port in name '%s'", name);
108 error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
112 port->reset(gpr_strdup(default_port));
114 return GRPC_ERROR_NONE;
117 static grpc_error* blocking_resolve_address_impl(
118 const char* name, const char* default_port,
119 grpc_resolved_addresses** addresses) {
120 grpc_core::UniquePtr<char> host;
121 grpc_core::UniquePtr<char> port;
124 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
126 err = try_split_host_port(name, default_port, &host, &port);
127 if (err != GRPC_ERROR_NONE) {
131 /* Call getaddrinfo */
132 grpc_custom_resolver resolver;
133 resolver.host = host.get();
134 resolver.port = port.get();
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.get(), port.get(), &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;
146 grpc_core::ExecCtx::Set(curr);
147 if (err == GRPC_ERROR_NONE) {
153 static void resolve_address_impl(const char* name, const char* default_port,
154 grpc_pollset_set* interested_parties,
155 grpc_closure* on_done,
156 grpc_resolved_addresses** addrs) {
157 grpc_custom_resolver* r = nullptr;
158 grpc_core::UniquePtr<char> host;
159 grpc_core::UniquePtr<char> port;
161 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
162 err = try_split_host_port(name, default_port, &host, &port);
163 if (err != GRPC_ERROR_NONE) {
164 GRPC_CLOSURE_SCHED(on_done, err);
167 r = (grpc_custom_resolver*)gpr_malloc(sizeof(grpc_custom_resolver));
168 r->on_done = on_done;
169 r->addresses = addrs;
170 r->host = host.release();
171 r->port = port.release();
173 /* Call getaddrinfo */
174 resolve_address_vtable->resolve_async(r, r->host, r->port);
177 static grpc_address_resolver_vtable custom_resolver_vtable = {
178 resolve_address_impl, blocking_resolve_address_impl};
180 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
181 resolve_address_vtable = impl;
182 grpc_set_resolver_impl(&custom_resolver_vtable);