xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 
36 #include "src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h"
37 #include "src/core/lib/gpr/useful.h"
38 #include "src/core/lib/gprpp/host_port.h"
39 
40 namespace grpc_event_engine {
41 namespace experimental {
42 namespace {
43 
44 absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
LookupHostnameBlocking(absl::string_view name,absl::string_view default_port)45 LookupHostnameBlocking(absl::string_view name, absl::string_view default_port) {
46   struct addrinfo hints;
47   struct addrinfo *result = nullptr, *resp;
48   std::string host;
49   std::string port;
50   // parse name, splitting it into host and port parts
51   grpc_core::SplitHostPort(name, &host, &port);
52   if (host.empty()) {
53     return absl::InvalidArgumentError(absl::StrCat("Unparseable name: ", name));
54   }
55   if (port.empty()) {
56     if (default_port.empty()) {
57       return absl::InvalidArgumentError(
58           absl::StrFormat("No port in name %s or default_port argument", name));
59     }
60     port = std::string(default_port);
61   }
62   // Call getaddrinfo
63   memset(&hints, 0, sizeof(hints));
64   hints.ai_family = AF_UNSPEC;      // ipv4 or ipv6
65   hints.ai_socktype = SOCK_STREAM;  // stream socket
66   hints.ai_flags = AI_PASSIVE;      // for wildcard IP address
67   int s = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
68   if (s != 0) {
69     // Retry if well-known service name is recognized
70     const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
71     for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
72       if (port == svc[i][0]) {
73         s = getaddrinfo(host.c_str(), svc[i][1], &hints, &result);
74         break;
75       }
76     }
77   }
78   if (s != 0) {
79     return absl::UnknownError(absl::StrFormat(
80         "Address lookup failed for %s os_error: %s syscall: getaddrinfo", name,
81         gai_strerror(s)));
82   }
83   // Success path: fill in addrs
84   std::vector<EventEngine::ResolvedAddress> addresses;
85   for (resp = result; resp != nullptr; resp = resp->ai_next) {
86     addresses.emplace_back(resp->ai_addr, resp->ai_addrlen);
87   }
88   if (result) {
89     freeaddrinfo(result);
90   }
91   return addresses;
92 }
93 
94 }  // namespace
95 
NativePosixDNSResolver(std::shared_ptr<EventEngine> event_engine)96 NativePosixDNSResolver::NativePosixDNSResolver(
97     std::shared_ptr<EventEngine> event_engine)
98     : event_engine_(std::move(event_engine)) {}
99 
LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback on_resolved,absl::string_view name,absl::string_view default_port)100 void NativePosixDNSResolver::LookupHostname(
101     EventEngine::DNSResolver::LookupHostnameCallback on_resolved,
102     absl::string_view name, absl::string_view default_port) {
103   event_engine_->Run(
104       [name, default_port, on_resolved = std::move(on_resolved)]() mutable {
105         on_resolved(LookupHostnameBlocking(name, default_port));
106       });
107 }
108 
LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolved,absl::string_view)109 void NativePosixDNSResolver::LookupSRV(
110     EventEngine::DNSResolver::LookupSRVCallback on_resolved,
111     absl::string_view /* name */) {
112   // Not supported
113   event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable {
114     on_resolved(absl::UnimplementedError(
115         "The Native resolver does not support looking up SRV records"));
116   });
117 }
118 
LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolved,absl::string_view)119 void NativePosixDNSResolver::LookupTXT(
120     EventEngine::DNSResolver::LookupTXTCallback on_resolved,
121     absl::string_view /* name */) {
122   // Not supported
123   event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable {
124     on_resolved(absl::UnimplementedError(
125         "The Native resolver does not support looking up TXT records"));
126   });
127 }
128 
129 }  // namespace experimental
130 }  // namespace grpc_event_engine
131 
132 #endif  // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS
133