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/resolve_address_custom.h"
27 #include "absl/strings/str_format.h"
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
32 #include "src/core/lib/address_utils/sockaddr_utils.h"
33 #include "src/core/lib/gpr/string.h"
34 #include "src/core/lib/gpr/useful.h"
35 #include "src/core/lib/gprpp/host_port.h"
36 #include "src/core/lib/iomgr/iomgr_custom.h"
37 #include "src/core/lib/iomgr/port.h"
39 struct grpc_custom_resolver {
40 grpc_closure* on_done = nullptr;
41 grpc_resolved_addresses** addresses = nullptr;
46 static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
48 static int retry_named_port_failure(grpc_custom_resolver* r,
49 grpc_resolved_addresses** res) {
50 // This loop is copied from resolve_address_posix.c
51 const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
52 for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
53 if (r->port == svc[i][0]) {
56 grpc_error_handle error = resolve_address_vtable->resolve(
57 r->host.c_str(), r->port.c_str(), res);
58 if (error != GRPC_ERROR_NONE) {
59 GRPC_ERROR_UNREF(error);
63 resolve_address_vtable->resolve_async(r, r->host.c_str(),
72 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
73 grpc_resolved_addresses* result,
74 grpc_error_handle error) {
75 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
76 grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
77 grpc_core::ExecCtx exec_ctx;
78 if (error == GRPC_ERROR_NONE) {
79 *r->addresses = result;
80 } else if (retry_named_port_failure(r, nullptr)) {
84 grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
89 static grpc_error_handle try_split_host_port(const char* name,
90 const char* default_port,
93 /* parse name, splitting it into host and port parts */
94 grpc_core::SplitHostPort(name, host, port);
96 return GRPC_ERROR_CREATE_FROM_CPP_STRING(
97 absl::StrFormat("unparseable host:port: '%s'", name));
100 // TODO(murgatroid99): add tests for this case
101 if (default_port == nullptr) {
102 return GRPC_ERROR_CREATE_FROM_CPP_STRING(
103 absl::StrFormat("no port in name '%s'", name));
105 *port = default_port;
107 return GRPC_ERROR_NONE;
110 static grpc_error_handle blocking_resolve_address_impl(
111 const char* name, const char* default_port,
112 grpc_resolved_addresses** addresses) {
113 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
115 grpc_custom_resolver resolver;
116 grpc_error_handle err =
117 try_split_host_port(name, default_port, &resolver.host, &resolver.port);
118 if (err != GRPC_ERROR_NONE) {
122 /* Call getaddrinfo */
123 grpc_resolved_addresses* addrs;
124 grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
125 grpc_core::ExecCtx::Set(nullptr);
126 err = resolve_address_vtable->resolve(resolver.host.c_str(),
127 resolver.port.c_str(), &addrs);
128 if (err != GRPC_ERROR_NONE) {
129 if (retry_named_port_failure(&resolver, &addrs)) {
130 GRPC_ERROR_UNREF(err);
131 err = GRPC_ERROR_NONE;
134 grpc_core::ExecCtx::Set(curr);
135 if (err == GRPC_ERROR_NONE) {
141 static void resolve_address_impl(const char* name, const char* default_port,
142 grpc_pollset_set* /*interested_parties*/,
143 grpc_closure* on_done,
144 grpc_resolved_addresses** addrs) {
145 GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
148 grpc_error_handle err = try_split_host_port(name, default_port, &host, &port);
149 if (err != GRPC_ERROR_NONE) {
150 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, err);
153 grpc_custom_resolver* r = new grpc_custom_resolver();
154 r->on_done = on_done;
155 r->addresses = addrs;
156 r->host = std::move(host);
157 r->port = std::move(port);
159 /* Call getaddrinfo */
160 resolve_address_vtable->resolve_async(r, r->host.c_str(), r->port.c_str());
163 static grpc_address_resolver_vtable custom_resolver_vtable = {
164 resolve_address_impl, blocking_resolve_address_impl};
166 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
167 resolve_address_vtable = impl;
168 grpc_set_resolver_impl(&custom_resolver_vtable);