Coverage Report

Created: 2026-08-21 19:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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
#include "util/hash_util.hpp"
42
43
#ifdef __APPLE__
44
#ifndef HOST_NAME_MAX
45
#define HOST_NAME_MAX MAXHOSTNAMELEN
46
#endif
47
#endif
48
49
namespace doris {
50
InetAddress::InetAddress(std::string ip, sa_family_t family, bool is_loopback)
51
156
        : _ip_addr(ip), _family(family), _is_loopback(is_loopback) {}
52
53
10
bool InetAddress::is_loopback() const {
54
10
    return _is_loopback;
55
10
}
56
57
33
std::string InetAddress::get_host_address() const {
58
33
    return _ip_addr;
59
33
}
60
61
20
bool InetAddress::is_ipv6() const {
62
20
    return _family == AF_INET6;
63
20
}
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
1.25M
bool is_valid_ip(const std::string& ip) {
80
1.25M
    unsigned char buf[sizeof(struct in6_addr)];
81
1.26M
    return (inet_pton(AF_INET6, ip.data(), buf) > 0) || (inet_pton(AF_INET, ip.data(), buf) > 0);
82
1.25M
}
83
84
1.06k
bool parse_endpoint(const std::string& endpoint, std::string* host, uint16_t* port) {
85
1.06k
    auto p = endpoint.find_last_of(':');
86
1.06k
    if (p == std::string::npos || p + 1 == endpoint.size()) {
87
0
        return false;
88
0
    }
89
90
1.06k
    const char* port_base = endpoint.c_str() + p + 1;
91
1.06k
    char* end = nullptr;
92
1.06k
    long value = strtol(port_base, &end, 10);
93
1.06k
    if (port_base == end) {
94
0
        return false;
95
1.06k
    } 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
1.06k
    } else if (value < 0 || 65535 < value) {
103
0
        return false;
104
0
    }
105
106
1.06k
    std::string::size_type i = 0;
107
1.06k
    const char* host_base = endpoint.c_str();
108
1.06k
    while (std::isspace(host_base[i])) {
109
0
        i++;
110
0
    }
111
1.06k
    if (i < p && host_base[i] == '[' && host_base[p - 1] == ']') {
112
0
        i += 1;
113
0
        p -= 1;
114
0
    }
115
1.06k
    if (i >= p) {
116
0
        return false;
117
0
    }
118
1.06k
    *host = endpoint.substr(i, p - i);
119
1.06k
    *port = cast_set<uint16_t>(value);
120
1.06k
    return true;
121
1.06k
}
122
123
0
Status hostname_to_ip(const std::string& host, std::string& ip, int* gai_err) {
124
0
    auto start = std::chrono::high_resolution_clock::now();
125
0
    Status status = hostname_to_ipv4(host, ip, gai_err);
126
0
    if (status.ok()) {
127
0
        return status;
128
0
    }
129
0
    status = hostname_to_ipv6(host, ip, gai_err);
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
89
Status hostname_to_ip(const std::string& host, std::string& ip, bool ipv6, int* gai_err) {
141
89
    if (ipv6) {
142
0
        return hostname_to_ipv6(host, ip, gai_err);
143
89
    } else {
144
89
        return hostname_to_ipv4(host, ip, gai_err);
145
89
    }
146
89
}
147
148
89
Status hostname_to_ipv4(const std::string& host, std::string& ip, int* gai_err) {
149
89
    addrinfo hints, *res;
150
89
    in_addr addr;
151
152
89
    memset(&hints, 0, sizeof(addrinfo));
153
89
    hints.ai_socktype = SOCK_STREAM;
154
89
    hints.ai_family = AF_INET;
155
89
    int err = getaddrinfo(host.c_str(), NULL, &hints, &res);
156
89
    if (gai_err != nullptr) {
157
89
        *gai_err = err;
158
89
    }
159
89
    if (err != 0) {
160
1
        LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err);
161
        // No stack trace: the WARNING above already carries the host and the resolver error,
162
        // and this failure is expected often enough (a decommissioned backend, a hostname
163
        // whose DNS record has not propagated yet) that attaching a stack to every
164
        // occurrence floods be.WARNING without adding information.
165
1
        return Status::InternalError<false>("failed to get ip from host: {}, err: {}", host,
166
1
                                            gai_strerror(err));
167
1
    }
168
169
88
    addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
170
88
    ip = inet_ntoa(addr);
171
172
88
    freeaddrinfo(res);
173
88
    return Status::OK();
174
89
}
175
176
0
Status hostname_to_ipv6(const std::string& host, std::string& ip, int* gai_err) {
177
0
    char ipstr2[128];
178
0
    struct sockaddr_in6* sockaddr_ipv6;
179
180
0
    struct addrinfo *answer, hint;
181
0
    bzero(&hint, sizeof(hint));
182
0
    hint.ai_family = AF_INET6;
183
0
    hint.ai_socktype = SOCK_STREAM;
184
185
0
    int err = getaddrinfo(host.c_str(), NULL, &hint, &answer);
186
0
    if (gai_err != nullptr) {
187
0
        *gai_err = err;
188
0
    }
189
0
    if (err != 0) {
190
0
        LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err);
191
        // See hostname_to_ipv4() for why this error carries no stack trace.
192
0
        return Status::InternalError<false>("failed to get ip from host: {}, err: {}", host,
193
0
                                            gai_strerror(err));
194
0
    }
195
196
0
    sockaddr_ipv6 = reinterpret_cast<struct sockaddr_in6*>(answer->ai_addr);
197
0
    inet_ntop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstr2, sizeof(ipstr2));
198
0
    ip = ipstr2;
199
0
    fflush(NULL);
200
0
    freeaddrinfo(answer);
201
0
    return Status::OK();
202
0
}
203
204
0
bool find_first_non_localhost(const std::vector<std::string>& addresses, std::string* addr) {
205
0
    for (const std::string& candidate : addresses) {
206
0
        if (candidate != LOCALHOST) {
207
0
            *addr = candidate;
208
0
            return true;
209
0
        }
210
0
    }
211
212
0
    return false;
213
0
}
214
215
7
Status get_hosts(std::vector<InetAddress>* hosts) {
216
7
    ifaddrs* if_addrs = nullptr;
217
7
    if (getifaddrs(&if_addrs)) {
218
0
        std::stringstream ss;
219
0
        char buf[64];
220
0
        ss << "getifaddrs failed because " << strerror_r(errno, buf, sizeof(buf));
221
0
        return Status::InternalError(ss.str());
222
0
    }
223
224
248
    for (ifaddrs* if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) {
225
241
        if (!if_addr->ifa_addr) {
226
0
            continue;
227
0
        }
228
241
        auto addr = if_addr->ifa_addr;
229
241
        if (addr->sa_family == AF_INET) {
230
            // check legitimacy of IP4 Address
231
56
            char addr_buf[INET_ADDRSTRLEN];
232
56
            auto tmp_addr = &((struct sockaddr_in*)if_addr->ifa_addr)->sin_addr;
233
56
            inet_ntop(AF_INET, tmp_addr, addr_buf, INET_ADDRSTRLEN);
234
            // check is loopback Address
235
56
            in_addr_t s_addr = ((struct sockaddr_in*)addr)->sin_addr.s_addr;
236
56
            bool is_loopback = (ntohl(s_addr) & 0xFF000000) == 0x7F000000;
237
56
            hosts->emplace_back(std::string(addr_buf), AF_INET, is_loopback);
238
185
        } else if (addr->sa_family == AF_INET6) {
239
            // check legitimacy of IP6 Address
240
86
            auto tmp_addr = &((struct sockaddr_in6*)if_addr->ifa_addr)->sin6_addr;
241
86
            char addr_buf[INET6_ADDRSTRLEN];
242
86
            inet_ntop(AF_INET6, tmp_addr, addr_buf, sizeof(addr_buf));
243
            // check is loopback Address
244
86
            bool is_loopback = IN6_IS_ADDR_LOOPBACK(tmp_addr);
245
86
            hosts->emplace_back(std::string(addr_buf), AF_INET6, is_loopback);
246
99
        } else {
247
99
            continue;
248
99
        }
249
241
    }
250
251
7
    if (if_addrs != nullptr) {
252
7
        freeifaddrs(if_addrs);
253
7
    }
254
255
7
    return Status::OK();
256
7
}
257
258
30.0k
TNetworkAddress make_network_address(const std::string& hostname, int port) {
259
30.0k
    TNetworkAddress ret;
260
30.0k
    ret.__set_hostname(hostname);
261
30.0k
    ret.__set_port(port);
262
30.0k
    return ret;
263
30.0k
}
264
265
0
Status get_inet_interfaces(std::vector<std::string>* interfaces, bool include_ipv6) {
266
0
    ifaddrs* if_addrs = nullptr;
267
0
    if (getifaddrs(&if_addrs)) {
268
0
        std::stringstream ss;
269
0
        char buf[64];
270
0
        ss << "getifaddrs failed, errno:" << errno << ", message"
271
0
           << strerror_r(errno, buf, sizeof(buf));
272
0
        return Status::InternalError(ss.str());
273
0
    }
274
275
0
    for (ifaddrs* if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) {
276
0
        if (if_addr->ifa_addr == nullptr || if_addr->ifa_name == nullptr) {
277
0
            continue;
278
0
        }
279
0
        if (if_addr->ifa_addr->sa_family == AF_INET ||
280
0
            (include_ipv6 && if_addr->ifa_addr->sa_family == AF_INET6)) {
281
0
            interfaces->emplace_back(if_addr->ifa_name);
282
0
        }
283
0
    }
284
0
    if (if_addrs != nullptr) {
285
0
        freeifaddrs(if_addrs);
286
0
    }
287
0
    return Status::OK();
288
0
}
289
290
1.12k
std::string get_host_port(const std::string& host, int port) {
291
1.12k
    std::stringstream ss;
292
1.12k
    if (host.find(':') == std::string::npos) {
293
1.12k
        ss << host << ":" << port;
294
18.4E
    } else {
295
18.4E
        ss << "[" << host << "]"
296
18.4E
           << ":" << port;
297
18.4E
    }
298
1.12k
    return ss.str();
299
1.12k
}
300
301
0
std::string get_brpc_http_url(const std::string& host, int port) {
302
0
    if (host.find(':') != std::string::npos) {
303
0
        return fmt::format("list://[{}]:{}", host, port);
304
0
    } else {
305
0
        return fmt::format("http://{}:{}", host, port);
306
0
    }
307
0
}
308
} // namespace doris
309
310
2.64M
size_t std::hash<doris::TNetworkAddress>::operator()(const doris::TNetworkAddress& address) const {
311
2.64M
    uint32_t seed = 0;
312
2.64M
    seed = doris::HashUtil::hash(address.hostname.data(), (uint32_t)address.hostname.size(), seed);
313
2.64M
    seed = doris::HashUtil::hash(&address.port, 4, seed);
314
2.64M
    return seed;
315
2.64M
}