be/src/util/network_util.cpp
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. 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, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // This file is copied from |
18 | | // https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/network-util.cc |
19 | | // and modified by Doris |
20 | | |
21 | | #include "util/network_util.h" |
22 | | |
23 | | #include <arpa/inet.h> |
24 | | // IWYU pragma: no_include <bits/local_lim.h> |
25 | | // IWYU pragma: no_include <bthread/errno.h> |
26 | | #include <errno.h> // IWYU pragma: keep |
27 | | #include <fmt/format.h> |
28 | | #include <gen_cpp/Types_types.h> |
29 | | #include <ifaddrs.h> |
30 | | #include <netdb.h> |
31 | | #include <netinet/in.h> |
32 | | #include <string.h> |
33 | | #include <sys/socket.h> |
34 | | #include <unistd.h> |
35 | | |
36 | | #include <chrono> |
37 | | #include <cstdint> |
38 | | #include <sstream> |
39 | | |
40 | | #include "common/cast_set.h" |
41 | | |
42 | | #ifdef __APPLE__ |
43 | | #ifndef HOST_NAME_MAX |
44 | | #define HOST_NAME_MAX MAXHOSTNAMELEN |
45 | | #endif |
46 | | #endif |
47 | | |
48 | | namespace doris { |
49 | | #include "common/compile_check_begin.h" |
50 | | InetAddress::InetAddress(std::string ip, sa_family_t family, bool is_loopback) |
51 | 123 | : _ip_addr(ip), _family(family), _is_loopback(is_loopback) {} |
52 | | |
53 | 8 | bool InetAddress::is_loopback() const { |
54 | 8 | return _is_loopback; |
55 | 8 | } |
56 | | |
57 | 27 | std::string InetAddress::get_host_address() const { |
58 | 27 | return _ip_addr; |
59 | 27 | } |
60 | | |
61 | 17 | bool InetAddress::is_ipv6() const { |
62 | 17 | return _family == AF_INET6; |
63 | 17 | } |
64 | | |
65 | | static const std::string LOCALHOST("127.0.0.1"); |
66 | | |
67 | 0 | Status get_hostname(std::string* hostname) { |
68 | 0 | char name[HOST_NAME_MAX]; |
69 | 0 | int ret = gethostname(name, HOST_NAME_MAX); |
70 | |
|
71 | 0 | if (ret != 0) { |
72 | 0 | return Status::InternalError("Could not get hostname: errno: {}", errno); |
73 | 0 | } |
74 | | |
75 | 0 | *hostname = std::string(name); |
76 | 0 | return Status::OK(); |
77 | 0 | } |
78 | | |
79 | 6.94k | bool is_valid_ip(const std::string& ip) { |
80 | 6.94k | unsigned char buf[sizeof(struct in6_addr)]; |
81 | 6.94k | return (inet_pton(AF_INET6, ip.data(), buf) > 0) || (inet_pton(AF_INET, ip.data(), buf) > 0); |
82 | 6.94k | } |
83 | | |
84 | 0 | bool parse_endpoint(const std::string& endpoint, std::string* host, uint16_t* port) { |
85 | 0 | auto p = endpoint.find_last_of(':'); |
86 | 0 | if (p == std::string::npos || p + 1 == endpoint.size()) { |
87 | 0 | return false; |
88 | 0 | } |
89 | | |
90 | 0 | const char* port_base = endpoint.c_str() + p + 1; |
91 | 0 | char* end = nullptr; |
92 | 0 | long value = strtol(port_base, &end, 10); |
93 | 0 | if (port_base == end) { |
94 | 0 | return false; |
95 | 0 | } else if (*end) { |
96 | 0 | while (std::isspace(*end)) { |
97 | 0 | end++; |
98 | 0 | } |
99 | 0 | if (*end) { |
100 | 0 | return false; |
101 | 0 | } |
102 | 0 | } else if (value < 0 || 65535 < value) { |
103 | 0 | return false; |
104 | 0 | } |
105 | | |
106 | 0 | std::string::size_type i = 0; |
107 | 0 | const char* host_base = endpoint.c_str(); |
108 | 0 | while (std::isspace(host_base[i])) { |
109 | 0 | i++; |
110 | 0 | } |
111 | 0 | if (i < p && host_base[i] == '[' && host_base[p - 1] == ']') { |
112 | 0 | i += 1; |
113 | 0 | p -= 1; |
114 | 0 | } |
115 | 0 | if (i >= p) { |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 | *host = endpoint.substr(i, p - i); |
119 | 0 | *port = cast_set<uint16_t>(value); |
120 | 0 | return true; |
121 | 0 | } |
122 | | |
123 | 0 | Status hostname_to_ip(const std::string& host, std::string& ip) { |
124 | 0 | auto start = std::chrono::high_resolution_clock::now(); |
125 | 0 | Status status = hostname_to_ipv4(host, ip); |
126 | 0 | if (status.ok()) { |
127 | 0 | return status; |
128 | 0 | } |
129 | 0 | status = hostname_to_ipv6(host, ip); |
130 | |
|
131 | 0 | auto current = std::chrono::high_resolution_clock::now(); |
132 | 0 | auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - start); |
133 | 0 | if (duration.count() >= 500) { |
134 | 0 | LOG(WARNING) << "hostname_to_ip cost to mush time, cost_time:" << duration.count() |
135 | 0 | << "ms hostname:" << host << " ip:" << ip; |
136 | 0 | } |
137 | 0 | return status; |
138 | 0 | } |
139 | | |
140 | 224 | Status hostname_to_ip(const std::string& host, std::string& ip, bool ipv6) { |
141 | 224 | if (ipv6) { |
142 | 0 | return hostname_to_ipv6(host, ip); |
143 | 224 | } else { |
144 | 224 | return hostname_to_ipv4(host, ip); |
145 | 224 | } |
146 | 224 | } |
147 | | |
148 | 224 | Status hostname_to_ipv4(const std::string& host, std::string& ip) { |
149 | 224 | addrinfo hints, *res; |
150 | 224 | in_addr addr; |
151 | | |
152 | 224 | memset(&hints, 0, sizeof(addrinfo)); |
153 | 224 | hints.ai_socktype = SOCK_STREAM; |
154 | 224 | hints.ai_family = AF_INET; |
155 | 224 | int err = getaddrinfo(host.c_str(), NULL, &hints, &res); |
156 | 224 | if (err != 0) { |
157 | 0 | LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err); |
158 | 0 | return Status::InternalError("failed to get ip from host: {}, err: {}", host, |
159 | 0 | gai_strerror(err)); |
160 | 0 | } |
161 | | |
162 | 224 | addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr; |
163 | 224 | ip = inet_ntoa(addr); |
164 | | |
165 | 224 | freeaddrinfo(res); |
166 | 224 | return Status::OK(); |
167 | 224 | } |
168 | | |
169 | 0 | Status hostname_to_ipv6(const std::string& host, std::string& ip) { |
170 | 0 | char ipstr2[128]; |
171 | 0 | struct sockaddr_in6* sockaddr_ipv6; |
172 | |
|
173 | 0 | struct addrinfo *answer, hint; |
174 | 0 | bzero(&hint, sizeof(hint)); |
175 | 0 | hint.ai_family = AF_INET6; |
176 | 0 | hint.ai_socktype = SOCK_STREAM; |
177 | |
|
178 | 0 | int err = getaddrinfo(host.c_str(), NULL, &hint, &answer); |
179 | 0 | if (err != 0) { |
180 | 0 | LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err); |
181 | 0 | return Status::InternalError("failed to get ip from host: {}, err: {}", host, |
182 | 0 | gai_strerror(err)); |
183 | 0 | } |
184 | | |
185 | 0 | sockaddr_ipv6 = reinterpret_cast<struct sockaddr_in6*>(answer->ai_addr); |
186 | 0 | inet_ntop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstr2, sizeof(ipstr2)); |
187 | 0 | ip = ipstr2; |
188 | 0 | fflush(NULL); |
189 | 0 | freeaddrinfo(answer); |
190 | 0 | return Status::OK(); |
191 | 0 | } |
192 | | |
193 | 0 | bool find_first_non_localhost(const std::vector<std::string>& addresses, std::string* addr) { |
194 | 0 | for (const std::string& candidate : addresses) { |
195 | 0 | if (candidate != LOCALHOST) { |
196 | 0 | *addr = candidate; |
197 | 0 | return true; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 0 | return false; |
202 | 0 | } |
203 | | |
204 | 6 | Status get_hosts(std::vector<InetAddress>* hosts) { |
205 | 6 | ifaddrs* if_addrs = nullptr; |
206 | 6 | if (getifaddrs(&if_addrs)) { |
207 | 0 | std::stringstream ss; |
208 | 0 | char buf[64]; |
209 | 0 | ss << "getifaddrs failed because " << strerror_r(errno, buf, sizeof(buf)); |
210 | 0 | return Status::InternalError(ss.str()); |
211 | 0 | } |
212 | | |
213 | 182 | for (ifaddrs* if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) { |
214 | 176 | if (!if_addr->ifa_addr) { |
215 | 0 | continue; |
216 | 0 | } |
217 | 176 | auto addr = if_addr->ifa_addr; |
218 | 176 | if (addr->sa_family == AF_INET) { |
219 | | // check legitimacy of IP4 Address |
220 | 58 | char addr_buf[INET_ADDRSTRLEN]; |
221 | 58 | auto tmp_addr = &((struct sockaddr_in*)if_addr->ifa_addr)->sin_addr; |
222 | 58 | inet_ntop(AF_INET, tmp_addr, addr_buf, INET_ADDRSTRLEN); |
223 | | // check is loopback Address |
224 | 58 | in_addr_t s_addr = ((struct sockaddr_in*)addr)->sin_addr.s_addr; |
225 | 58 | bool is_loopback = (ntohl(s_addr) & 0xFF000000) == 0x7F000000; |
226 | 58 | hosts->emplace_back(std::string(addr_buf), AF_INET, is_loopback); |
227 | 118 | } else if (addr->sa_family == AF_INET6) { |
228 | | // check legitimacy of IP6 Address |
229 | 52 | auto tmp_addr = &((struct sockaddr_in6*)if_addr->ifa_addr)->sin6_addr; |
230 | 52 | char addr_buf[INET6_ADDRSTRLEN]; |
231 | 52 | inet_ntop(AF_INET6, tmp_addr, addr_buf, sizeof(addr_buf)); |
232 | | // check is loopback Address |
233 | 52 | bool is_loopback = IN6_IS_ADDR_LOOPBACK(tmp_addr); |
234 | 52 | hosts->emplace_back(std::string(addr_buf), AF_INET6, is_loopback); |
235 | 66 | } else { |
236 | 66 | continue; |
237 | 66 | } |
238 | 176 | } |
239 | | |
240 | 6 | if (if_addrs != nullptr) { |
241 | 6 | freeifaddrs(if_addrs); |
242 | 6 | } |
243 | | |
244 | 6 | return Status::OK(); |
245 | 6 | } |
246 | | |
247 | 3.23k | TNetworkAddress make_network_address(const std::string& hostname, int port) { |
248 | 3.23k | TNetworkAddress ret; |
249 | 3.23k | ret.__set_hostname(hostname); |
250 | 3.23k | ret.__set_port(port); |
251 | 3.23k | return ret; |
252 | 3.23k | } |
253 | | |
254 | 4 | Status get_inet_interfaces(std::vector<std::string>* interfaces, bool include_ipv6) { |
255 | 4 | ifaddrs* if_addrs = nullptr; |
256 | 4 | if (getifaddrs(&if_addrs)) { |
257 | 0 | std::stringstream ss; |
258 | 0 | char buf[64]; |
259 | 0 | ss << "getifaddrs failed, errno:" << errno << ", message" |
260 | 0 | << strerror_r(errno, buf, sizeof(buf)); |
261 | 0 | return Status::InternalError(ss.str()); |
262 | 0 | } |
263 | | |
264 | 142 | for (ifaddrs* if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) { |
265 | 138 | if (if_addr->ifa_addr == nullptr || if_addr->ifa_name == nullptr) { |
266 | 0 | continue; |
267 | 0 | } |
268 | 138 | if (if_addr->ifa_addr->sa_family == AF_INET || |
269 | 138 | (include_ipv6 && if_addr->ifa_addr->sa_family == AF_INET6)) { |
270 | 46 | interfaces->emplace_back(if_addr->ifa_name); |
271 | 46 | } |
272 | 138 | } |
273 | 4 | if (if_addrs != nullptr) { |
274 | 4 | freeifaddrs(if_addrs); |
275 | 4 | } |
276 | 4 | return Status::OK(); |
277 | 4 | } |
278 | | |
279 | 44 | std::string get_host_port(const std::string& host, int port) { |
280 | 44 | std::stringstream ss; |
281 | 44 | if (host.find(':') == std::string::npos) { |
282 | 44 | ss << host << ":" << port; |
283 | 44 | } else { |
284 | 0 | ss << "[" << host << "]" |
285 | 0 | << ":" << port; |
286 | 0 | } |
287 | 44 | return ss.str(); |
288 | 44 | } |
289 | | |
290 | 0 | std::string get_brpc_http_url(const std::string& host, int port) { |
291 | 0 | if (host.find(':') != std::string::npos) { |
292 | 0 | return fmt::format("list://[{}]:{}", host, port); |
293 | 0 | } else { |
294 | 0 | return fmt::format("http://{}:{}", host, port); |
295 | 0 | } |
296 | 0 | } |
297 | | #include "common/compile_check_end.h" |
298 | | } // namespace doris |