• 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/resolve_address_custom.h"
22 
23 #include <string.h>
24 
25 #include <string>
26 
27 #include "absl/strings/str_format.h"
28 
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31 
32 #include "src/core/lib/gpr/string.h"
33 #include "src/core/lib/gpr/useful.h"
34 #include "src/core/lib/gprpp/host_port.h"
35 #include "src/core/lib/iomgr/iomgr_custom.h"
36 #include "src/core/lib/iomgr/port.h"
37 #include "src/core/lib/iomgr/sockaddr_utils.h"
38 
39 struct grpc_custom_resolver {
40   grpc_closure* on_done = nullptr;
41   grpc_resolved_addresses** addresses = nullptr;
42   std::string host;
43   std::string port;
44 };
45 
46 static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
47 
retry_named_port_failure(grpc_custom_resolver * r,grpc_resolved_addresses ** res)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]) {
54       r->port = svc[i][1];
55       if (res) {
56         grpc_error* 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);
60           return 0;
61         }
62       } else {
63         resolve_address_vtable->resolve_async(r, r->host.c_str(),
64                                               r->port.c_str());
65       }
66       return 1;
67     }
68   }
69   return 0;
70 }
71 
grpc_custom_resolve_callback(grpc_custom_resolver * r,grpc_resolved_addresses * result,grpc_error * error)72 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
73                                   grpc_resolved_addresses* result,
74                                   grpc_error* 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)) {
81     return;
82   }
83   if (r->on_done) {
84     grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_done, error);
85   }
86   delete r;
87 }
88 
try_split_host_port(const char * name,const char * default_port,std::string * host,std::string * port)89 static grpc_error* try_split_host_port(const char* name,
90                                        const char* default_port,
91                                        std::string* host, std::string* port) {
92   /* parse name, splitting it into host and port parts */
93   grpc_core::SplitHostPort(name, host, port);
94   if (host->empty()) {
95     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
96         absl::StrFormat("unparseable host:port: '%s'", name).c_str());
97   }
98   if (port->empty()) {
99     // TODO(murgatroid99): add tests for this case
100     if (default_port == nullptr) {
101       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
102           absl::StrFormat("no port in name '%s'", name).c_str());
103     }
104     *port = default_port;
105   }
106   return GRPC_ERROR_NONE;
107 }
108 
blocking_resolve_address_impl(const char * name,const char * default_port,grpc_resolved_addresses ** addresses)109 static grpc_error* blocking_resolve_address_impl(
110     const char* name, const char* default_port,
111     grpc_resolved_addresses** addresses) {
112   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
113 
114   grpc_custom_resolver resolver;
115   grpc_error* err =
116       try_split_host_port(name, default_port, &resolver.host, &resolver.port);
117   if (err != GRPC_ERROR_NONE) {
118     return err;
119   }
120 
121   /* Call getaddrinfo */
122   grpc_resolved_addresses* addrs;
123   grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
124   grpc_core::ExecCtx::Set(nullptr);
125   err = resolve_address_vtable->resolve(resolver.host.c_str(),
126                                         resolver.port.c_str(), &addrs);
127   if (err != GRPC_ERROR_NONE) {
128     if (retry_named_port_failure(&resolver, &addrs)) {
129       GRPC_ERROR_UNREF(err);
130       err = GRPC_ERROR_NONE;
131     }
132   }
133   grpc_core::ExecCtx::Set(curr);
134   if (err == GRPC_ERROR_NONE) {
135     *addresses = addrs;
136   }
137   return err;
138 }
139 
resolve_address_impl(const char * name,const char * default_port,grpc_pollset_set *,grpc_closure * on_done,grpc_resolved_addresses ** addrs)140 static void resolve_address_impl(const char* name, const char* default_port,
141                                  grpc_pollset_set* /*interested_parties*/,
142                                  grpc_closure* on_done,
143                                  grpc_resolved_addresses** addrs) {
144   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
145   std::string host;
146   std::string port;
147   grpc_error* err = try_split_host_port(name, default_port, &host, &port);
148   if (err != GRPC_ERROR_NONE) {
149     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, err);
150     return;
151   }
152   grpc_custom_resolver* r = new grpc_custom_resolver();
153   r->on_done = on_done;
154   r->addresses = addrs;
155   r->host = std::move(host);
156   r->port = std::move(port);
157 
158   /* Call getaddrinfo */
159   resolve_address_vtable->resolve_async(r, r->host.c_str(), r->port.c_str());
160 }
161 
162 static grpc_address_resolver_vtable custom_resolver_vtable = {
163     resolve_address_impl, blocking_resolve_address_impl};
164 
grpc_custom_resolver_init(grpc_custom_resolver_vtable * impl)165 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
166   resolve_address_vtable = impl;
167   grpc_set_resolver_impl(&custom_resolver_vtable);
168 }
169