1 // Copyright 2023 The gRPC Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include "src/core/lib/iomgr/port.h"
18
19 #ifdef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS
20
21 #include <netdb.h>
22 #include <string.h>
23 #include <sys/socket.h>
24
25 #include <string>
26 #include <type_traits>
27 #include <utility>
28 #include <vector>
29
30 #include "absl/functional/any_invocable.h"
31 #include "absl/status/status.h"
32 #include "absl/status/statusor.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/str_format.h"
35 #include "src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h"
36 #include "src/core/util/host_port.h"
37 #include "src/core/util/useful.h"
38
39 namespace grpc_event_engine {
40 namespace experimental {
41 namespace {
42
43 absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
LookupHostnameBlocking(absl::string_view name,absl::string_view default_port)44 LookupHostnameBlocking(absl::string_view name, absl::string_view default_port) {
45 struct addrinfo hints;
46 struct addrinfo *result = nullptr, *resp;
47 std::string host;
48 std::string port;
49 // parse name, splitting it into host and port parts
50 grpc_core::SplitHostPort(name, &host, &port);
51 if (host.empty()) {
52 return absl::InvalidArgumentError(absl::StrCat("Unparsable name: ", name));
53 }
54 if (port.empty()) {
55 if (default_port.empty()) {
56 return absl::InvalidArgumentError(
57 absl::StrFormat("No port in name %s or default_port argument", name));
58 }
59 port = std::string(default_port);
60 }
61 // Call getaddrinfo
62 memset(&hints, 0, sizeof(hints));
63 hints.ai_family = AF_UNSPEC; // ipv4 or ipv6
64 hints.ai_socktype = SOCK_STREAM; // stream socket
65 hints.ai_flags = AI_PASSIVE; // for wildcard IP address
66 int s = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
67 if (s != 0) {
68 // Retry if well-known service name is recognized
69 const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
70 for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
71 if (port == svc[i][0]) {
72 s = getaddrinfo(host.c_str(), svc[i][1], &hints, &result);
73 break;
74 }
75 }
76 }
77 if (s != 0) {
78 return absl::UnknownError(absl::StrFormat(
79 "Address lookup failed for %s os_error: %s syscall: getaddrinfo", name,
80 gai_strerror(s)));
81 }
82 // Success path: fill in addrs
83 std::vector<EventEngine::ResolvedAddress> addresses;
84 for (resp = result; resp != nullptr; resp = resp->ai_next) {
85 addresses.emplace_back(resp->ai_addr, resp->ai_addrlen);
86 }
87 if (result) {
88 freeaddrinfo(result);
89 }
90 return addresses;
91 }
92
93 } // namespace
94
NativePosixDNSResolver(std::shared_ptr<EventEngine> event_engine)95 NativePosixDNSResolver::NativePosixDNSResolver(
96 std::shared_ptr<EventEngine> event_engine)
97 : event_engine_(std::move(event_engine)) {}
98
LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback on_resolved,absl::string_view name,absl::string_view default_port)99 void NativePosixDNSResolver::LookupHostname(
100 EventEngine::DNSResolver::LookupHostnameCallback on_resolved,
101 absl::string_view name, absl::string_view default_port) {
102 event_engine_->Run(
103 [name, default_port, on_resolved = std::move(on_resolved)]() mutable {
104 on_resolved(LookupHostnameBlocking(name, default_port));
105 });
106 }
107
LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolved,absl::string_view)108 void NativePosixDNSResolver::LookupSRV(
109 EventEngine::DNSResolver::LookupSRVCallback on_resolved,
110 absl::string_view /* name */) {
111 // Not supported
112 event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable {
113 on_resolved(absl::UnimplementedError(
114 "The Native resolver does not support looking up SRV records"));
115 });
116 }
117
LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolved,absl::string_view)118 void NativePosixDNSResolver::LookupTXT(
119 EventEngine::DNSResolver::LookupTXTCallback on_resolved,
120 absl::string_view /* name */) {
121 // Not supported
122 event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable {
123 on_resolved(absl::UnimplementedError(
124 "The Native resolver does not support looking up TXT records"));
125 });
126 }
127
128 } // namespace experimental
129 } // namespace grpc_event_engine
130
131 #endif // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS
132