YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/net/net_util.cc
Line
Count
Source (jump to first uncovered line)
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
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/util/net/net_util.h"
34
35
#include <ifaddrs.h>
36
#include <sys/types.h>
37
38
#include <algorithm>
39
#include <unordered_set>
40
#include <utility>
41
#include <vector>
42
43
#include <boost/algorithm/string.hpp>
44
45
#include "yb/gutil/map-util.h"
46
#include "yb/gutil/strings/join.h"
47
#include "yb/gutil/strings/numbers.h"
48
#include "yb/gutil/strings/split.h"
49
#include "yb/gutil/strings/strip.h"
50
#include "yb/gutil/strings/substitute.h"
51
52
#include "yb/util/debug/trace_event.h"
53
#include "yb/util/env.h"
54
#include "yb/util/env_util.h"
55
#include "yb/util/errno.h"
56
#include "yb/util/faststring.h"
57
#include "yb/util/flag_tags.h"
58
#include "yb/util/net/inetaddress.h"
59
#include "yb/util/net/sockaddr.h"
60
#include "yb/util/net/socket.h"
61
#include "yb/util/random_util.h"
62
#include "yb/util/result.h"
63
#include "yb/util/scope_exit.h"
64
#include "yb/util/status_format.h"
65
#include "yb/util/stopwatch.h"
66
#include "yb/util/subprocess.h"
67
68
// Mac OS 10.9 does not appear to define HOST_NAME_MAX in unistd.h
69
#ifndef HOST_NAME_MAX
70
54.5k
#define HOST_NAME_MAX 64
71
#endif
72
73
using std::unordered_set;
74
using std::vector;
75
using strings::Substitute;
76
77
DEFINE_string(
78
    net_address_filter,
79
    "ipv4_external,ipv4_all,ipv6_external,ipv6_non_link_local,ipv6_all",
80
    "Order in which to select ip addresses returned by the resolver"
81
    "Can be set to something like \"ipv4_all,ipv6_all\" to prefer IPv4 over "
82
    "IPv6 addresses."
83
    "Can be set to something like \"ipv4_external,ipv4_all,ipv6_all\" to "
84
    "prefer external IPv4 "
85
    "addresses first. Other options include ipv6_external,ipv6_non_link_local");
86
87
DEFINE_test_flag(string, fail_to_fast_resolve_address, "",
88
                 "A hostname to fail to fast resolve for tests.");
89
90
namespace yb {
91
92
namespace {
93
struct AddrinfoDeleter {
94
23.1k
  void operator()(struct addrinfo* info) {
95
23.1k
    freeaddrinfo(info);
96
23.1k
  }
97
};
98
}
99
100
HostPort::HostPort()
101
1.69M
    : port_(0) {
102
1.69M
}
103
104
HostPort::HostPort(Slice host, uint16_t port)
105
162
    : host_(host.cdata(), host.size()), port_(port) {}
106
107
HostPort::HostPort(std::string host, uint16_t port)
108
47.0k
    : host_(std::move(host)), port_(port) {}
109
110
HostPort::HostPort(const Endpoint& endpoint)
111
2.61k
    : host_(endpoint.address().to_string()), port_(endpoint.port()) {
112
2.61k
}
113
114
HostPort::HostPort(const char* host, uint16_t port)
115
162
    : HostPort(Slice(host), port) {
116
162
}
Unexecuted instantiation: _ZN2yb8HostPortC2EPKct
_ZN2yb8HostPortC1EPKct
Line
Count
Source
115
162
    : HostPort(Slice(host), port) {
116
162
}
117
118
Status HostPort::RemoveAndGetHostPortList(
119
    const Endpoint& remove,
120
    const std::vector<std::string>& multiple_server_addresses,
121
    uint16_t default_port,
122
0
    std::vector<HostPort> *res) {
123
0
  bool found = false;
124
  // Note that this outer loop is over a vector of comma-separated strings.
125
0
  for (const string& master_server_addr : multiple_server_addresses) {
126
0
    std::vector<std::string> addr_strings =
127
0
        strings::Split(master_server_addr, ",", strings::SkipEmpty());
128
0
    for (const auto& single_addr : addr_strings) {
129
0
      HostPort host_port;
130
0
      RETURN_NOT_OK(host_port.ParseString(single_addr, default_port));
131
0
      if (host_port.equals(remove)) {
132
0
        found = true;
133
0
        continue;
134
0
      } else {
135
0
        res->push_back(host_port);
136
0
      }
137
0
    }
138
0
  }
139
140
0
  if (!found) {
141
0
    std::ostringstream out;
142
0
    out.str("Current list of master addresses: ");
143
0
    for (const string& master_server_addr : multiple_server_addresses) {
144
0
      out.str(master_server_addr);
145
0
      out.str(" ");
146
0
    }
147
0
    LOG(ERROR) << out.str();
148
149
0
    return STATUS_SUBSTITUTE(NotFound,
150
0
                             "Cannot find $0 in addresses: $1",
151
0
                             yb::ToString(remove),
152
0
                             out.str());
153
0
  }
154
155
0
  return Status::OK();
156
0
}
157
158
// Accepts entries like: [::1], 127.0.0.1, [::1]:7100, 0.0.0.0:7100,
159
// f.q.d.n:7100
160
237k
Status HostPort::ParseString(const string &str_in, uint16_t default_port) {
161
237k
  uint32_t port;
162
237k
  string host;
163
164
237k
  string str(str_in);
165
237k
  StripWhiteSpace(&str);
166
237k
  size_t pos = str.rfind(':');
167
237k
  if (str[0] == '[' && str[str.length() - 1] == ']' && str.length() > 2) {
168
    // The whole thing is an IPv6 address.
169
3
    host = str.substr(1, str.length() - 2);
170
3
    port = default_port;
171
237k
  } else if (pos == string::npos) {
172
    // No port was specified, the whole thing must be a host.
173
1.81k
    host = str;
174
1.81k
    port = default_port;
175
235k
  } else if (pos > 1 && pos + 1 < str.length() &&
176
235k
             SimpleAtoi(str.substr(pos + 1), &port)) {
177
178
235k
    if (port > numeric_limits<uint16_t>::max()) {
179
1
      return STATUS(InvalidArgument, "Invalid port", str);
180
1
    }
181
182
    // Got a host:port
183
235k
    host = str.substr(0, pos);
184
235k
    if (host[0] == '[' && host[host.length() - 1] == ']' && host.length() > 2) {
185
      // Remove brackets if we have an IPv6 address
186
5
      host = host.substr(1, host.length() - 2);
187
5
    }
188
18.4E
  } else {
189
18.4E
    return STATUS(InvalidArgument,
190
18.4E
                  Format(
191
18.4E
                      "Invalid port: expected port after ':' "
192
18.4E
                      "at position $0 in $1",
193
18.4E
                      pos, str));
194
18.4E
  }
195
196
237k
  host_ = host;
197
237k
  port_ = port;
198
237k
  return Status::OK();
199
237k
}
200
201
36.2k
Result<HostPort> HostPort::FromString(const std::string& str, uint16_t default_port) {
202
36.2k
  HostPort result;
203
36.2k
  RETURN_NOT_OK(result.ParseString(str, default_port));
204
36.2k
  return result;
205
36.2k
}
206
207
Result<std::vector<HostPort>> HostPort::ParseStrings(
208
    const std::string& comma_sep_addrs, uint16_t default_port,
209
1.80k
    const char* separator) {
210
1.80k
  std::vector<HostPort> result;
211
1.80k
  RETURN_NOT_OK(ParseStrings(comma_sep_addrs, default_port, &result, separator));
212
1.80k
  return result;
213
1.80k
}
214
215
5.66M
size_t HostPortHash::operator()(const HostPort& hostPort) const {
216
5.66M
  return GStringPiece(std::to_string(hostPort.port()) + hostPort.host()).hash();
217
5.66M
}
218
219
namespace {
220
133
const string getaddrinfo_rc_to_string(int rc) {
221
133
  const char* s = nullptr;
222
133
  switch (rc) {
223
0
    case EAI_ADDRFAMILY: s = "EAI_ADDRFAMILY"; break;
224
0
    case EAI_AGAIN: s = "EAI_AGAIN"; break;
225
0
    case EAI_BADFLAGS: s = "EAI_BADFLAGS"; break;
226
0
    case EAI_FAIL: s = "EAI_FAIL"; break;
227
0
    case EAI_FAMILY: s = "EAI_FAMILY"; break;
228
0
    case EAI_MEMORY: s = "EAI_MEMORY"; break;
229
0
    case EAI_NODATA: s = "EAI_NODATA"; break;
230
133
    case EAI_NONAME: s = "EAI_NONAME"; break;
231
0
    case EAI_SERVICE: s = "EAI_SERVICE"; break;
232
0
    case EAI_SOCKTYPE: s = "EAI_SOCKTYPE"; break;
233
0
    case EAI_SYSTEM: s = "EAI_SYSTEM"; break;
234
0
    default: s = "UNKNOWN";
235
133
  }
236
133
  return Substitute("$0 ($1)", rc, s);
237
133
}
238
239
23.0k
Result<std::unique_ptr<addrinfo, AddrinfoDeleter>> HostToInetAddrInfo(const std::string& host) {
240
23.0k
  struct addrinfo hints;
241
23.0k
  memset(&hints, 0, sizeof(hints));
242
23.0k
  hints.ai_family = AF_UNSPEC;
243
23.0k
  hints.ai_socktype = SOCK_STREAM;
244
23.0k
  struct addrinfo* res = nullptr;
245
23.0k
  int rc = 0;
246
23.0k
  LOG_SLOW_EXECUTION(WARNING, 200,
247
23.1k
                     Substitute("resolving address for $0", host)) {
248
23.1k
    rc = getaddrinfo(host.c_str(), nullptr, &hints, &res);
249
23.1k
  }
250
23.0k
  if (rc != 0) {
251
29
    return STATUS_FORMAT(NetworkError, "Unable to resolve address $0, getaddrinfo returned $1: $2",
252
29
                         host.c_str(), getaddrinfo_rc_to_string(rc).c_str(), gai_strerror(rc));
253
22.9k
  } else {
254
22.9k
    return std::unique_ptr<addrinfo, AddrinfoDeleter>(res);
255
22.9k
  }
256
23.0k
}
257
258
template <typename F>
259
90.5k
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
260
90.5k
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
261
90.5k
  if (fast_resolve) {
262
67.4k
    func(*fast_resolve);
263
2
    VLOG(4) << "Fast resolved " << host << " to " << fast_resolve->to_string();
264
67.4k
    return Status::OK();
265
67.4k
  }
266
267
23.1k
  auto addrinfo_holder = VERIFY_RESULT(HostToInetAddrInfo(host));
268
23.0k
  struct addrinfo* addrinfo = addrinfo_holder.get();
269
69.3k
  for (; addrinfo != nullptr; addrinfo = addrinfo->ai_next) {
270
46.2k
    if (addrinfo->ai_family == AF_INET) {
271
45.8k
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
272
45.8k
      Endpoint endpoint;
273
45.8k
      memcpy(endpoint.data(), addr, sizeof(*addr));
274
45.8k
      func(endpoint.address());
275
337
    } else if (addrinfo->ai_family == AF_INET6) {
276
337
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
277
337
      Endpoint endpoint;
278
337
      memcpy(endpoint.data(), addr, sizeof(*addr));
279
337
      func(endpoint.address());
280
0
    } else {
281
0
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
282
0
    }
283
46.2k
  }
284
23.0k
  return Status::OK();
285
23.0k
}
net_util.cc:_ZN2yb12_GLOBAL__N_120ResolveInetAddressesIZNKS_8HostPort16ResolveAddressesEPNSt3__16vectorIN5boost4asio2ip14basic_endpointINS7_3tcpEEENS3_9allocatorISA_EEEEE3$_0EENS_6StatusERKNS3_12basic_stringIcNS3_11char_traitsIcEENSB_IcEEEET_
Line
Count
Source
259
90.2k
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
260
90.2k
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
261
90.2k
  if (fast_resolve) {
262
67.1k
    func(*fast_resolve);
263
0
    VLOG(4) << "Fast resolved " << host << " to " << fast_resolve->to_string();
264
67.1k
    return Status::OK();
265
67.1k
  }
266
267
23.1k
  auto addrinfo_holder = VERIFY_RESULT(HostToInetAddrInfo(host));
268
23.0k
  struct addrinfo* addrinfo = addrinfo_holder.get();
269
69.2k
  for (; addrinfo != nullptr; addrinfo = addrinfo->ai_next) {
270
46.2k
    if (addrinfo->ai_family == AF_INET) {
271
45.8k
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
272
45.8k
      Endpoint endpoint;
273
45.8k
      memcpy(endpoint.data(), addr, sizeof(*addr));
274
45.8k
      func(endpoint.address());
275
337
    } else if (addrinfo->ai_family == AF_INET6) {
276
337
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
277
337
      Endpoint endpoint;
278
337
      memcpy(endpoint.data(), addr, sizeof(*addr));
279
337
      func(endpoint.address());
280
0
    } else {
281
0
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
282
0
    }
283
46.2k
  }
284
23.0k
  return Status::OK();
285
23.0k
}
net_util.cc:_ZN2yb12_GLOBAL__N_120ResolveInetAddressesIZNS_15HostToAddressesERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPN5boost9container17small_vector_baseINSB_4asio2ip7addressEvvEEE3$_2EENS_6StatusESA_T_
Line
Count
Source
259
351
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
260
351
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
261
351
  if (fast_resolve) {
262
341
    func(*fast_resolve);
263
2
    VLOG(4) << "Fast resolved " << host << " to " << fast_resolve->to_string();
264
341
    return Status::OK();
265
341
  }
266
267
10
  auto addrinfo_holder = VERIFY_RESULT(HostToInetAddrInfo(host));
268
8
  struct addrinfo* addrinfo = addrinfo_holder.get();
269
13
  for (; addrinfo != nullptr; addrinfo = addrinfo->ai_next) {
270
5
    if (addrinfo->ai_family == AF_INET) {
271
5
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
272
5
      Endpoint endpoint;
273
5
      memcpy(endpoint.data(), addr, sizeof(*addr));
274
5
      func(endpoint.address());
275
0
    } else if (addrinfo->ai_family == AF_INET6) {
276
0
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
277
0
      Endpoint endpoint;
278
0
      memcpy(endpoint.data(), addr, sizeof(*addr));
279
0
      func(endpoint.address());
280
0
    } else {
281
0
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
282
0
    }
283
5
  }
284
8
  return Status::OK();
285
8
}
286
287
}  // namespace
288
289
90.2k
Status HostPort::ResolveAddresses(std::vector<Endpoint>* addresses) const {
290
90.2k
  TRACE_EVENT1("net", "HostPort::ResolveAddresses",
291
90.2k
               "host", host_);
292
90.2k
  if (!addresses) {
293
1
    return Status::OK();
294
1
  }
295
90.2k
  vector<IpAddress> ip_addresses;
296
90.2k
  RETURN_NOT_OK(ResolveInetAddresses(
297
90.2k
      host_, [this, &ip_addresses](const IpAddress &ip_address) {
298
90.2k
        ip_addresses.push_back(ip_address);
299
90.2k
        VLOG(3) << "Resolved address " << ip_address.to_string() << " for host "
300
90.2k
                << host_;
301
90.2k
      }));
302
303
90.2k
  FilterAddresses(FLAGS_net_address_filter, &ip_addresses);
304
305
13
  VLOG(2) << "Returned " << ip_addresses.size() << " addresses for host "
306
13
          << host_;
307
113k
  for (const auto &ip_addr : ip_addresses) {
308
15
    VLOG(2) << "Returned address " << ip_addr.to_string() << " for host "
309
15
            << host_;
310
113k
    addresses->push_back(Endpoint(ip_addr, port_));
311
113k
  }
312
90.2k
  return Status::OK();
313
90.2k
}
314
315
Status HostPort::ParseStrings(const string& comma_sep_addrs,
316
                              uint16_t default_port,
317
                              std::vector<HostPort>* res,
318
138k
                              const char* separator) {
319
138k
  std::vector<string> addr_strings = strings::Split(
320
138k
      comma_sep_addrs, separator, strings::SkipEmpty());
321
138k
  std::vector<HostPort> host_ports;
322
193k
  for (string& addr_string : addr_strings) {
323
193k
    HostPort host_port;
324
193k
    RETURN_NOT_OK(host_port.ParseString(addr_string, default_port));
325
193k
    host_ports.push_back(host_port);
326
193k
  }
327
138k
  *res = host_ports;
328
138k
  return Status::OK();
329
138k
}
330
331
14.7M
string HostPort::ToString() const { return HostPortToString(host_, port_); }
332
333
4.44k
string HostPort::ToCommaSeparatedString(const std::vector<HostPort>& hostports) {
334
4.44k
  vector<string> hostport_strs;
335
4.61k
  for (const HostPort& hostport : hostports) {
336
4.61k
    hostport_strs.push_back(hostport.ToString());
337
4.61k
  }
338
4.44k
  return JoinStrings(hostport_strs, ",");
339
4.44k
}
340
341
17.2k
bool IsPrivilegedPort(uint16_t port) { return port < 1024 && port != 0; }
342
343
Status ParseAddressList(const std::string& addr_list,
344
                        uint16_t default_port,
345
35.2k
                        std::vector<Endpoint>* addresses) {
346
35.2k
  std::vector<HostPort> host_ports;
347
35.2k
  RETURN_NOT_OK(HostPort::ParseStrings(addr_list, default_port, &host_ports));
348
35.2k
  std::unordered_set<Endpoint, EndpointHash> uniqued;
349
350
35.2k
  for (const HostPort& host_port : host_ports) {
351
35.2k
    std::vector<Endpoint> this_addresses;
352
35.2k
    RETURN_NOT_OK(host_port.ResolveAddresses(&this_addresses));
353
354
    // Only add the unique ones -- the user may have specified
355
    // some IP addresses in multiple ways
356
35.6k
    for (const auto& addr : this_addresses) {
357
35.6k
      if (InsertIfNotPresent(&uniqued, addr)) {
358
35.6k
        addresses->push_back(addr);
359
0
      } else {
360
0
        LOG(INFO) << "Address " << addr << " for " << host_port.ToString()
361
0
                  << " duplicates an earlier resolved entry.";
362
0
      }
363
35.6k
    }
364
35.2k
  }
365
35.2k
  return Status::OK();
366
35.2k
}
367
368
54.5k
Status GetHostname(string* hostname) {
369
54.5k
  TRACE_EVENT0("net", "GetHostname");
370
54.5k
  char name[HOST_NAME_MAX];
371
54.5k
  int ret = gethostname(name, HOST_NAME_MAX);
372
54.5k
  if (ret != 0) {
373
0
    return STATUS(NetworkError, "Unable to determine local hostname", Errno(errno));
374
0
  }
375
54.5k
  *hostname = name;
376
54.5k
  return Status::OK();
377
54.5k
}
378
379
8.33k
Result<string> GetHostname() {
380
8.33k
  std::string result;
381
8.33k
  RETURN_NOT_OK(GetHostname(&result));
382
8.33k
  return result;
383
8.33k
}
384
385
Status GetLocalAddresses(const string &filter_spec,
386
0
                         std::vector<IpAddress> *result) {
387
0
  RETURN_NOT_OK(GetLocalAddresses(result, AddressFilter::ANY));
388
0
  FilterAddresses(filter_spec, result);
389
0
  return Status::OK();
390
0
}
391
392
22.9k
Status GetLocalAddresses(std::vector<IpAddress>* result, AddressFilter filter) {
393
22.9k
  ifaddrs* addresses;
394
22.9k
  if (getifaddrs(&addresses)) {
395
0
    return STATUS(NetworkError, "Failed to list network interfaces", Errno(errno));
396
0
  }
397
398
22.9k
  auto se = ScopeExit([addresses] {
399
22.9k
    freeifaddrs(addresses);
400
22.9k
  });
401
402
24.1M
  for (auto address = addresses; address; address = address->ifa_next) {
403
24.0M
    if (address->ifa_addr != nullptr) {
404
24.0M
      Endpoint temp;
405
24.0M
      auto family = address->ifa_addr->sa_family;
406
24.0M
      size_t size;
407
24.0M
      if (family == AF_INET) {
408
23.2M
        size = sizeof(sockaddr_in);
409
823k
      } else if (family == AF_INET6) {
410
229k
        size = sizeof(sockaddr_in6);
411
594k
      } else {
412
594k
        continue;
413
594k
      }
414
23.4M
      memcpy(temp.data(), address->ifa_addr, size);
415
23.4M
      switch (filter) {
416
2.05k
        case AddressFilter::ANY:
417
2.05k
          result->push_back(temp.address());
418
2.05k
          break;
419
23.4M
        case AddressFilter::EXTERNAL:
420
23.4M
          if (!temp.address().is_unspecified() && !temp.address().is_loopback()) {
421
297k
            result->push_back(temp.address());
422
297k
          }
423
23.4M
          break;
424
23.4M
      }
425
23.4M
    }
426
24.0M
  }
427
24.5k
  return Status::OK();
428
22.9k
}
429
430
23.8k
Status GetFQDN(string* hostname) {
431
23.8k
  TRACE_EVENT0("net", "GetFQDN");
432
  // Start with the non-qualified hostname
433
23.8k
  RETURN_NOT_OK(GetHostname(hostname));
434
435
23.8k
  struct addrinfo hints;
436
23.8k
  memset(&hints, 0, sizeof(hints));
437
23.8k
  hints.ai_socktype = SOCK_DGRAM;
438
23.8k
  hints.ai_flags = AI_CANONNAME;
439
440
23.8k
  struct addrinfo* result;
441
23.8k
  LOG_SLOW_EXECUTION(WARNING, 200,
442
23.8k
                     Substitute("looking up canonical hostname for localhost $0", *hostname)) {
443
23.8k
    TRACE_EVENT0("net", "getaddrinfo");
444
23.8k
    const int rc = getaddrinfo(hostname->c_str(), nullptr, &hints, &result);
445
23.8k
    if (rc != 0) {
446
104
      return STATUS(NetworkError,
447
104
                    Substitute("Unable to lookup FQDN ($0), getaddrinfo returned $1",
448
104
                               *hostname, getaddrinfo_rc_to_string(rc)),
449
104
                    Errno(errno));
450
104
    }
451
23.8k
  }
452
453
23.7k
  if (!result->ai_canonname) {
454
0
    return STATUS(NetworkError, "Canonical name not specified");
455
0
  }
456
457
23.7k
  *hostname = result->ai_canonname;
458
23.7k
  freeaddrinfo(result);
459
23.7k
  return Status::OK();
460
23.7k
}
461
462
0
Status EndpointFromHostPort(const HostPort& host_port, Endpoint* endpoint) {
463
0
  vector<Endpoint> addrs;
464
0
  RETURN_NOT_OK(host_port.ResolveAddresses(&addrs));
465
0
  if (addrs.empty()) {
466
0
    return STATUS(NetworkError, "Unable to resolve address", host_port.ToString());
467
0
  }
468
0
  *endpoint = addrs[0];
469
0
  if (addrs.size() > 1) {
470
0
    VLOG(1) << "Hostname " << host_port.host() << " resolved to more than one address. "
471
0
            << "Using address: " << *endpoint;
472
0
  }
473
0
  return Status::OK();
474
0
}
475
476
2
Status HostPortFromEndpointReplaceWildcard(const Endpoint& addr, HostPort* hp) {
477
2
  string host;
478
2
  if (addr.address().is_unspecified()) {
479
1
    auto status = GetFQDN(&host);
480
1
    if (!status.ok()) {
481
0
      std::vector<IpAddress> locals;
482
0
      if (GetLocalAddresses(&locals, AddressFilter::EXTERNAL).ok() && !locals.empty()) {
483
0
        hp->set_host(locals.front().to_string());
484
0
        hp->set_port(addr.port());
485
0
        return Status::OK();
486
0
      }
487
0
      return status;
488
0
    }
489
1
  } else {
490
1
    host = addr.address().to_string();
491
1
  }
492
2
  hp->set_host(host);
493
2
  hp->set_port(addr.port());
494
2
  return Status::OK();
495
2
}
496
497
4
void TryRunLsof(const Endpoint& addr, vector<string>* log) {
498
4
#if defined(__APPLE__)
499
4
  string cmd = strings::Substitute(
500
4
      "lsof -n -i 'TCP:$0' -sTCP:LISTEN ; "
501
4
      "for pid in $$(lsof -F p -n -i 'TCP:$0' -sTCP:LISTEN | cut -f 2 -dp) ; do"
502
4
      "  pstree $$pid || ps h -p $$pid;"
503
4
      "done",
504
4
      addr.port());
505
#else
506
  // Little inline bash script prints the full ancestry of any pid listening
507
  // on the same port as 'addr'. We could use 'pstree -s', but that option
508
  // doesn't exist on el6.
509
  //
510
  // Note the sed command to check for the process name wrapped in ().
511
  // Example prefix of /proc/$pid/stat output, with a process with spaces in the name:
512
  // 3917 (tmux: server) S 1
513
  string cmd = strings::Substitute(
514
      "export PATH=$$PATH:/usr/sbin ; "
515
      "lsof -n -i 'TCP:$0' -sTCP:LISTEN ; "
516
      "for pid in $$(lsof -F p -n -i 'TCP:$0' -sTCP:LISTEN | cut -f 2 -dp) ; do"
517
      "  while [ $$pid -gt 1 ] ; do"
518
      "    ps h -fp $$pid ;"
519
      "    pid=$$(sed 's/.* (.*) [^ ] \\([0-9]*\\).*/\\1/g' /proc/$$pid/stat);"
520
      "  done ; "
521
      "done",
522
      addr.port());
523
#endif // defined(__APPLE__)
524
525
4
  LOG_STRING(WARNING, log) << "Failed to bind to " << addr << ". "
526
4
                           << "Trying to use lsof to find any processes listening "
527
4
                           << "on the same port:";
528
4
  LOG_STRING(INFO, log) << "$ " << cmd;
529
4
  vector<string> argv = { "bash", "-c", cmd };
530
4
  string results;
531
4
  Status s = Subprocess::Call(argv, &results);
532
4
  if (PREDICT_FALSE(!s.ok())) {
533
3
    LOG_STRING(WARNING, log) << s.ToString();
534
3
  }
535
4
  LOG_STRING(WARNING, log) << results;
536
4
}
537
538
8.45k
uint16_t GetFreePort(std::unique_ptr<FileLock>* file_lock) {
539
  // To avoid a race condition where the free port returned to the caller gets used by another
540
  // process before this caller can use it, we will lock the port using a file level lock.
541
  // First create the directory, if it doesn't already exist, where these lock files will live.
542
8.45k
  Env* env = Env::Default();
543
8.45k
  bool created = false;
544
8.45k
  const string lock_file_dir = "/tmp/yb-port-locks";
545
8.45k
  Status status = env_util::CreateDirIfMissing(env, lock_file_dir, &created);
546
8.45k
  if (!status.ok()) {
547
0
    LOG(FATAL) << "Could not create " << lock_file_dir << " directory: "
548
0
               << status.ToString();
549
0
  }
550
551
  // Now, find a unused port in the [kMinPort..kMaxPort] range.
552
8.45k
  constexpr uint16_t kMinPort = 15000;
553
8.45k
  constexpr uint16_t kMaxPort = 30000;
554
8.45k
  Status s;
555
12.7k
  for (int i = 0; i < 1000; ++i) {
556
12.7k
    const uint16_t random_port = RandomUniformInt(kMinPort, kMaxPort);
557
0
    VLOG(1) << "Trying to bind to port " << random_port;
558
559
12.7k
    Endpoint sock_addr(boost::asio::ip::address_v4::loopback(), random_port);
560
12.7k
    Socket sock;
561
12.7k
    s = sock.Init(0);
562
12.7k
    if (!s.ok()) {
563
0
      VLOG(1) << "Failed to call Init() on socket ith address " << sock_addr;
564
0
      continue;
565
0
    }
566
567
12.7k
    s = sock.Bind(sock_addr, /* explain_addr_in_use */ false);
568
12.7k
    if (s.ok()) {
569
      // We found an unused port.
570
571
      // Now, lock this "port" for use by the current process before 'sock' goes out of scope.
572
      // This will ensure that no other process can get this port while this process is still
573
      // running. LockFile() returns immediately if we can't get the lock. That's the behavior
574
      // we want. In that case, we'll just try another port.
575
12.2k
      const string lock_file = lock_file_dir + "/" + std::to_string(random_port) + ".lck";
576
12.2k
      FileLock *lock = nullptr;
577
12.2k
      s = env->LockFile(lock_file, &lock, false /* recursive_lock_ok */);
578
12.2k
      if (s.ok()) {
579
0
        CHECK(lock) << "Lock should not be NULL";
580
8.45k
        file_lock->reset(lock);
581
8.45k
        LOG(INFO) << "Selected random free RPC port " << random_port;
582
8.45k
        return random_port;
583
3.77k
      } else {
584
0
        VLOG(1) << "Could not lock file " << lock_file << ": " << s.ToString();
585
3.77k
      }
586
520
    } else {
587
0
      VLOG(1) << "Failed to bind to port " << random_port << ": " << s.ToString();
588
520
    }
589
12.7k
  }
590
591
4
  LOG(FATAL) << "Could not find a free random port between " <<  kMinPort << " and "
592
4
             << kMaxPort << " inclusively" << ": " << s.ToString();
593
4
  return 0;  // never reached
594
8.45k
}
595
596
0
bool HostPort::equals(const Endpoint& endpoint) const {
597
0
  return endpoint.address().to_string() == host() && endpoint.port() == port();
598
0
}
599
600
1.03k
HostPort HostPort::FromBoundEndpoint(const Endpoint& endpoint) {
601
1.03k
  if (endpoint.address().is_unspecified()) {
602
84
    return HostPort(endpoint.address().is_v4() ? "127.0.0.1" : "::1", endpoint.port());
603
955
  } else {
604
955
    return HostPort(endpoint);
605
955
  }
606
1.03k
}
607
608
14.7M
std::string HostPortToString(const std::string& host, int port) {
609
14.7M
  DCHECK_GE(port, 0);
610
14.7M
  DCHECK_LE(port, 65535);
611
14.7M
  if (host.find(':') != string::npos) {
612
0
    return Format("[$0]:$1", host, port);
613
14.7M
  } else {
614
14.7M
    return Format("$0:$1", host, port);
615
14.7M
  }
616
14.7M
}
617
618
Status HostToAddresses(
619
    const std::string& host,
620
351
    boost::container::small_vector_base<IpAddress>* addresses) {
621
349
  return ResolveInetAddresses(host, [&addresses](const IpAddress& address) {
622
349
    addresses->push_back(address);
623
349
  });
624
351
}
625
626
39.0k
Result<IpAddress> HostToAddress(const std::string& host) {
627
39.0k
  boost::container::small_vector<IpAddress, 1> addrs;
628
39.0k
  RETURN_NOT_OK(HostToAddresses(host, &addrs));
629
39.0k
  if (addrs.empty()) {
630
0
    return STATUS(NetworkError, "Unable to resolve address", host);
631
0
  }
632
39.0k
  auto addr = addrs.front();
633
39.0k
  if (addrs.size() > 1) {
634
0
    VLOG(1) << "Hostname " << host << " resolved to more than one address. "
635
0
            << "Using address: " << addr;
636
0
  }
637
39.0k
  return addr;
638
39.0k
}
639
640
59.6k
bool IsWildcardAddress(const std::string& host_str) {
641
59.6k
  boost::system::error_code ec;
642
59.6k
  auto addr = IpAddress::from_string(host_str, ec);
643
59.6k
  return !ec && addr.is_unspecified();
644
59.6k
}
645
646
382k
Result<IpAddress> ParseIpAddress(const std::string& host) {
647
382k
  boost::system::error_code ec;
648
382k
  auto addr = IpAddress::from_string(host, ec);
649
382k
  if (ec) {
650
46.7k
    return STATUS_FORMAT(InvalidArgument, "Failed to parse $0: $1", host, ec.message());
651
46.7k
  }
652
653
1.03k
  VLOG(4) << "Resolving ip address to itself for input: " << host;
654
335k
  return addr;
655
335k
}
656
657
382k
boost::optional<IpAddress> TryFastResolve(const std::string& host) {
658
382k
  auto result = ParseIpAddress(host);
659
382k
  if (result.ok()) {
660
334k
    return *result;
661
334k
  }
662
663
  // For testing purpose we resolve A.B.C.D.ip.yugabyte to A.B.C.D.
664
48.5k
  static const std::string kYbIpSuffix = ".ip.yugabyte";
665
48.5k
  if (boost::ends_with(host, kYbIpSuffix)) {
666
23.7k
    if (PREDICT_FALSE(host == FLAGS_TEST_fail_to_fast_resolve_address)) {
667
0
      return boost::none;
668
0
    }
669
23.7k
    boost::system::error_code ec;
670
23.7k
    auto address = IpAddress::from_string(
671
23.7k
        host.substr(0, host.length() - kYbIpSuffix.length()), ec);
672
23.7k
    if (!ec) {
673
23.7k
      return address;
674
23.7k
    }
675
24.8k
  }
676
677
24.8k
  return boost::none;
678
24.8k
}
679
680
} // namespace yb