f89eab0591c31615fff10dec4c9eddbdb3d63666
[platform/upstream/grpc.git] / src / core / lib / iomgr / resolve_address_custom.cc
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/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"
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
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_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);
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
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)) {
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
89 static grpc_error_handle try_split_host_port(const char* name,
90                                              const char* default_port,
91                                              std::string* host,
92                                              std::string* port) {
93   /* parse name, splitting it into host and port parts */
94   grpc_core::SplitHostPort(name, host, port);
95   if (host->empty()) {
96     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
97         absl::StrFormat("unparseable host:port: '%s'", name).c_str());
98   }
99   if (port->empty()) {
100     // TODO(murgatroid99): add tests for this case
101     if (default_port == nullptr) {
102       return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
103           absl::StrFormat("no port in name '%s'", name).c_str());
104     }
105     *port = default_port;
106   }
107   return GRPC_ERROR_NONE;
108 }
109
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();
114
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) {
119     return err;
120   }
121
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;
132     }
133   }
134   grpc_core::ExecCtx::Set(curr);
135   if (err == GRPC_ERROR_NONE) {
136     *addresses = addrs;
137   }
138   return err;
139 }
140
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();
146   std::string host;
147   std::string port;
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);
151     return;
152   }
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);
158
159   /* Call getaddrinfo */
160   resolve_address_vtable->resolve_async(r, r->host.c_str(), r->port.c_str());
161 }
162
163 static grpc_address_resolver_vtable custom_resolver_vtable = {
164     resolve_address_impl, blocking_resolve_address_impl};
165
166 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
167   resolve_address_vtable = impl;
168   grpc_set_resolver_impl(&custom_resolver_vtable);
169 }