proxygen
SocketAddress.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS
19 #endif
20 
21 #include <folly/SocketAddress.h>
22 
23 #include <cerrno>
24 #include <cstdio>
25 #include <cstring>
26 #include <sstream>
27 #include <string>
28 #include <system_error>
29 
30 #include <boost/functional/hash.hpp>
31 
32 #include <folly/CppAttributes.h>
33 #include <folly/Exception.h>
34 #include <folly/Format.h>
35 #include <folly/hash/Hash.h>
36 #include <folly/net/NetOps.h>
38 
39 namespace {
40 
44 struct ScopedAddrInfo {
45  explicit ScopedAddrInfo(struct addrinfo* addrinfo) : info(addrinfo) {}
46  ~ScopedAddrInfo() {
47  freeaddrinfo(info);
48  }
49 
50  struct addrinfo* info;
51 };
52 
64 struct HostAndPort {
65  HostAndPort(const char* str, bool hostRequired)
66  : host(nullptr), port(nullptr), allocated(nullptr) {
67  // Look for the last colon
68  const char* colon = strrchr(str, ':');
69  if (colon == nullptr) {
70  // No colon, just a port number.
71  if (hostRequired) {
72  throw std::invalid_argument(
73  "expected a host and port string of the "
74  "form \"<host>:<port>\"");
75  }
76  port = str;
77  return;
78  }
79 
80  // We have to make a copy of the string so we can modify it
81  // and change the colon to a NUL terminator.
82  allocated = strdup(str);
83  if (!allocated) {
84  throw std::bad_alloc();
85  }
86 
87  char* allocatedColon = allocated + (colon - str);
88  *allocatedColon = '\0';
89  host = allocated;
90  port = allocatedColon + 1;
91  // bracketed IPv6 address, remove the brackets
92  // allocatedColon[-1] is fine, as allocatedColon >= host and
93  // *allocatedColon != *host therefore allocatedColon > host
94  if (*host == '[' && allocatedColon[-1] == ']') {
95  allocatedColon[-1] = '\0';
96  ++host;
97  }
98  }
99 
100  ~HostAndPort() {
101  free(allocated);
102  }
103 
104  const char* host;
105  const char* port;
106  char* allocated;
107 };
108 
109 } // namespace
110 
111 namespace folly {
112 
113 bool SocketAddress::isPrivateAddress() const {
114  auto family = getFamily();
115  if (family == AF_INET || family == AF_INET6) {
116  return storage_.addr.isPrivate() ||
117  (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
118  } else if (external_) {
119  // Unix addresses are always local to a host. Return true,
120  // since this conforms to the semantics of returning true for IP loopback
121  // addresses.
122  return true;
123  }
124  return false;
125 }
126 
127 bool SocketAddress::isLoopbackAddress() const {
128  auto family = getFamily();
129  if (family == AF_INET || family == AF_INET6) {
130  return storage_.addr.isLoopback();
131  } else if (external_) {
132  // Return true for UNIX addresses, since they are always local to a host.
133  return true;
134  }
135  return false;
136 }
137 
138 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
139  ScopedAddrInfo results(getAddrInfo(host, port, 0));
140  setFromAddrInfo(results.info);
141 }
142 
143 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
144  ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
145  setFromAddrInfo(results.info);
146 }
147 
148 void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) {
149  if (external_) {
150  storage_.un.free();
151  external_ = false;
152  }
153  storage_.addr = ipAddr;
154  port_ = port;
155 }
156 
157 void SocketAddress::setFromLocalPort(uint16_t port) {
158  ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
159  setFromLocalAddr(results.info);
160 }
161 
162 void SocketAddress::setFromLocalPort(const char* port) {
163  ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
164  setFromLocalAddr(results.info);
165 }
166 
167 void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
168  HostAndPort hp(addressAndPort, false);
169  ScopedAddrInfo results(
170  getAddrInfo(hp.host, hp.port, AI_NUMERICHOST | AI_ADDRCONFIG));
171  setFromLocalAddr(results.info);
172 }
173 
174 void SocketAddress::setFromIpPort(const char* addressAndPort) {
175  HostAndPort hp(addressAndPort, true);
176  ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST));
177  setFromAddrInfo(results.info);
178 }
179 
180 void SocketAddress::setFromHostPort(const char* hostAndPort) {
181  HostAndPort hp(hostAndPort, true);
182  ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0));
183  setFromAddrInfo(results.info);
184 }
185 
186 int SocketAddress::getPortFrom(const struct sockaddr* address) {
187  switch (address->sa_family) {
188  case AF_INET:
189  return ntohs(((sockaddr_in*)address)->sin_port);
190 
191  case AF_INET6:
192  return ntohs(((sockaddr_in6*)address)->sin6_port);
193 
194  default:
195  return -1;
196  }
197 }
198 
199 const char* SocketAddress::getFamilyNameFrom(
200  const struct sockaddr* address,
201  const char* defaultResult) {
202 #define GETFAMILYNAMEFROM_IMPL(Family) \
203  case Family: \
204  return #Family
205 
206  switch (address->sa_family) {
207  GETFAMILYNAMEFROM_IMPL(AF_INET);
208  GETFAMILYNAMEFROM_IMPL(AF_INET6);
209  GETFAMILYNAMEFROM_IMPL(AF_UNIX);
210  GETFAMILYNAMEFROM_IMPL(AF_UNSPEC);
211 
212  default:
213  return defaultResult;
214  }
215 
216 #undef GETFAMILYNAMEFROM_IMPL
217 }
218 
219 void SocketAddress::setFromPath(StringPiece path) {
220  // Before we touch storage_, check to see if the length is too big.
221  // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
222  // but sizeof() just uses its type, and does't evaluate it.
223  if (path.size() > sizeof(storage_.un.addr->sun_path)) {
224  throw std::invalid_argument(
225  "socket path too large to fit into sockaddr_un");
226  }
227 
228  if (!external_) {
229  storage_.un.init();
230  external_ = true;
231  }
232 
233  size_t len = path.size();
234  storage_.un.len = socklen_t(offsetof(struct sockaddr_un, sun_path) + len);
235  memcpy(storage_.un.addr->sun_path, path.data(), len);
236  // If there is room, put a terminating NUL byte in sun_path. In general the
237  // path should be NUL terminated, although getsockname() and getpeername()
238  // may return Unix socket addresses with paths that fit exactly in sun_path
239  // with no terminating NUL.
240  if (len < sizeof(storage_.un.addr->sun_path)) {
241  storage_.un.addr->sun_path[len] = '\0';
242  }
243 }
244 
245 void SocketAddress::setFromPeerAddress(int socket) {
246  setFromPeerAddress(NetworkSocket::fromFd(socket));
247 }
248 
249 void SocketAddress::setFromPeerAddress(NetworkSocket socket) {
250  setFromSocket(socket, netops::getpeername);
251 }
252 
253 void SocketAddress::setFromLocalAddress(int socket) {
254  setFromLocalAddress(NetworkSocket::fromFd(socket));
255 }
256 
257 void SocketAddress::setFromLocalAddress(NetworkSocket socket) {
258  setFromSocket(socket, netops::getsockname);
259 }
260 
261 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
262  uint16_t port;
263 
264  if (address->sa_family == AF_INET) {
265  port = ntohs(((sockaddr_in*)address)->sin_port);
266  } else if (address->sa_family == AF_INET6) {
267  port = ntohs(((sockaddr_in6*)address)->sin6_port);
268  } else if (address->sa_family == AF_UNIX) {
269  // We need an explicitly specified length for AF_UNIX addresses,
270  // to be able to distinguish anonymous addresses from addresses
271  // in Linux's abstract namespace.
272  throw std::invalid_argument(
273  "SocketAddress::setFromSockaddr(): the address "
274  "length must be explicitly specified when "
275  "setting AF_UNIX addresses");
276  } else {
277  throw std::invalid_argument(
278  "SocketAddress::setFromSockaddr() called "
279  "with unsupported address type");
280  }
281 
282  setFromIpAddrPort(folly::IPAddress(address), port);
283 }
284 
285 void SocketAddress::setFromSockaddr(
286  const struct sockaddr* address,
287  socklen_t addrlen) {
288  // Check the length to make sure we can access address->sa_family
289  if (addrlen <
290  (offsetof(struct sockaddr, sa_family) + sizeof(address->sa_family))) {
291  throw std::invalid_argument(
292  "SocketAddress::setFromSockaddr() called "
293  "with length too short for a sockaddr");
294  }
295 
296  if (address->sa_family == AF_INET) {
297  if (addrlen < sizeof(struct sockaddr_in)) {
298  throw std::invalid_argument(
299  "SocketAddress::setFromSockaddr() called "
300  "with length too short for a sockaddr_in");
301  }
302  setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
303  } else if (address->sa_family == AF_INET6) {
304  if (addrlen < sizeof(struct sockaddr_in6)) {
305  throw std::invalid_argument(
306  "SocketAddress::setFromSockaddr() called "
307  "with length too short for a sockaddr_in6");
308  }
309  setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
310  } else if (address->sa_family == AF_UNIX) {
311  setFromSockaddr(
312  reinterpret_cast<const struct sockaddr_un*>(address), addrlen);
313  } else {
314  throw std::invalid_argument(
315  "SocketAddress::setFromSockaddr() called "
316  "with unsupported address type");
317  }
318 }
319 
320 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
321  assert(address->sin_family == AF_INET);
322  setFromSockaddr((sockaddr*)address);
323 }
324 
325 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
326  assert(address->sin6_family == AF_INET6);
327  setFromSockaddr((sockaddr*)address);
328 }
329 
330 void SocketAddress::setFromSockaddr(
331  const struct sockaddr_un* address,
332  socklen_t addrlen) {
333  assert(address->sun_family == AF_UNIX);
334  if (addrlen > sizeof(struct sockaddr_un)) {
335  throw std::invalid_argument(
336  "SocketAddress::setFromSockaddr() called "
337  "with length too long for a sockaddr_un");
338  }
339 
340  if (!external_) {
341  storage_.un.init();
342  }
343  external_ = true;
344  memcpy(storage_.un.addr, address, size_t(addrlen));
345  updateUnixAddressLength(addrlen);
346 
347  // Fill the rest with 0s, just for safety
348  if (addrlen < sizeof(struct sockaddr_un)) {
349  char* p = reinterpret_cast<char*>(storage_.un.addr);
350  memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
351  }
352 }
353 
354 const folly::IPAddress& SocketAddress::getIPAddress() const {
355  auto family = getFamily();
356  if (family != AF_INET && family != AF_INET6) {
357  throw InvalidAddressFamilyException(family);
358  }
359  return storage_.addr;
360 }
361 
362 socklen_t SocketAddress::getActualSize() const {
363  if (external_) {
364  return storage_.un.len;
365  }
366  switch (getFamily()) {
367  case AF_UNSPEC:
368  case AF_INET:
369  return sizeof(struct sockaddr_in);
370  case AF_INET6:
371  return sizeof(struct sockaddr_in6);
372  default:
373  throw std::invalid_argument(
374  "SocketAddress::getActualSize() called "
375  "with unrecognized address family");
376  }
377 }
378 
379 std::string SocketAddress::getFullyQualified() const {
380  if (!isFamilyInet()) {
381  throw std::invalid_argument("Can't get address str for non ip address");
382  }
383  return storage_.addr.toFullyQualified();
384 }
385 
386 std::string SocketAddress::getAddressStr() const {
387  if (!isFamilyInet()) {
388  throw std::invalid_argument("Can't get address str for non ip address");
389  }
390  return storage_.addr.str();
391 }
392 
393 bool SocketAddress::isFamilyInet() const {
394  auto family = getFamily();
395  return family == AF_INET || family == AF_INET6;
396 }
397 
398 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
399  auto ret = getAddressStr();
400  size_t len = std::min(buflen - 1, ret.size());
401  memcpy(buf, ret.data(), len);
402  buf[len] = '\0';
403 }
404 
405 uint16_t SocketAddress::getPort() const {
406  switch (getFamily()) {
407  case AF_INET:
408  case AF_INET6:
409  return port_;
410  default:
411  throw std::invalid_argument(
412  "SocketAddress::getPort() called on non-IP "
413  "address");
414  }
415 }
416 
417 void SocketAddress::setPort(uint16_t port) {
418  switch (getFamily()) {
419  case AF_INET:
420  case AF_INET6:
421  port_ = port;
422  return;
423  default:
424  throw std::invalid_argument(
425  "SocketAddress::setPort() called on non-IP "
426  "address");
427  }
428 }
429 
430 void SocketAddress::convertToIPv4() {
431  if (!tryConvertToIPv4()) {
432  throw std::invalid_argument(
433  "convertToIPv4() called on an addresse that is "
434  "not an IPv4-mapped address");
435  }
436 }
437 
438 bool SocketAddress::tryConvertToIPv4() {
439  if (!isIPv4Mapped()) {
440  return false;
441  }
442 
443  storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
444  return true;
445 }
446 
447 bool SocketAddress::mapToIPv6() {
448  if (getFamily() != AF_INET) {
449  return false;
450  }
451 
452  storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
453  return true;
454 }
455 
456 std::string SocketAddress::getHostStr() const {
457  return getIpString(0);
458 }
459 
460 std::string SocketAddress::getPath() const {
461  if (!external_) {
462  throw std::invalid_argument(
463  "SocketAddress: attempting to get path "
464  "for a non-Unix address");
465  }
466 
467  if (storage_.un.pathLength() == 0) {
468  // anonymous address
469  return std::string();
470  }
471  if (storage_.un.addr->sun_path[0] == '\0') {
472  // abstract namespace
473  return std::string(
474  storage_.un.addr->sun_path, size_t(storage_.un.pathLength()));
475  }
476 
477  return std::string(
478  storage_.un.addr->sun_path,
479  strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
480 }
481 
482 std::string SocketAddress::describe() const {
483  if (external_) {
484  if (storage_.un.pathLength() == 0) {
485  return "<anonymous unix address>";
486  }
487 
488  if (storage_.un.addr->sun_path[0] == '\0') {
489  // Linux supports an abstract namespace for unix socket addresses
490  return "<abstract unix address>";
491  }
492 
493  return std::string(
494  storage_.un.addr->sun_path,
495  strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
496  }
497  switch (getFamily()) {
498  case AF_UNSPEC:
499  return "<uninitialized address>";
500  case AF_INET: {
501  char buf[NI_MAXHOST + 16];
502  getAddressStr(buf, sizeof(buf));
503  size_t iplen = strlen(buf);
504  snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
505  return buf;
506  }
507  case AF_INET6: {
508  char buf[NI_MAXHOST + 18];
509  buf[0] = '[';
510  getAddressStr(buf + 1, sizeof(buf) - 1);
511  size_t iplen = strlen(buf);
512  snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
513  return buf;
514  }
515  default: {
516  char buf[64];
517  snprintf(buf, sizeof(buf), "<unknown address family %d>", getFamily());
518  return buf;
519  }
520  }
521 }
522 
523 bool SocketAddress::operator==(const SocketAddress& other) const {
524  if (external_ != other.external_ || other.getFamily() != getFamily()) {
525  return false;
526  }
527  if (external_) {
528  // anonymous addresses are never equal to any other addresses
529  if (storage_.un.pathLength() == 0 || other.storage_.un.pathLength() == 0) {
530  return false;
531  }
532 
533  if (storage_.un.len != other.storage_.un.len) {
534  return false;
535  }
536  int cmp = memcmp(
537  storage_.un.addr->sun_path,
538  other.storage_.un.addr->sun_path,
539  size_t(storage_.un.pathLength()));
540  return cmp == 0;
541  }
542 
543  switch (getFamily()) {
544  case AF_INET:
545  case AF_INET6:
546  return (other.storage_.addr == storage_.addr) && (other.port_ == port_);
547  default:
548  throw std::invalid_argument(
549  "SocketAddress: unsupported address family "
550  "for comparison");
551  }
552 }
553 
554 bool SocketAddress::prefixMatch(
555  const SocketAddress& other,
556  unsigned prefixLength) const {
557  if (other.getFamily() != getFamily()) {
558  return false;
559  }
560  uint8_t mask_length = 128;
561  switch (getFamily()) {
562  case AF_INET:
563  mask_length = 32;
565  case AF_INET6: {
566  auto prefix = folly::IPAddress::longestCommonPrefix(
567  {storage_.addr, mask_length}, {other.storage_.addr, mask_length});
568  return prefix.second >= prefixLength;
569  }
570  default:
571  return false;
572  }
573 }
574 
575 size_t SocketAddress::hash() const {
576  size_t seed = folly::hash::twang_mix64(getFamily());
577 
578  if (external_) {
579  enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
580  const char* path = storage_.un.addr->sun_path;
581  auto pathLength = storage_.un.pathLength();
582  // TODO: this probably could be made more efficient
583  for (off_t n = 0; n < pathLength; ++n) {
585  }
586  }
587 
588  switch (getFamily()) {
589  case AF_INET:
590  case AF_INET6: {
591  boost::hash_combine(seed, port_);
592  boost::hash_combine(seed, storage_.addr.hash());
593  break;
594  }
595  case AF_UNIX:
596  DCHECK(external_);
597  break;
598  case AF_UNSPEC:
599  default:
600  throw std::invalid_argument(
601  "SocketAddress: unsupported address family "
602  "for hashing");
603  }
604 
605  return seed;
606 }
607 
608 struct addrinfo*
609 SocketAddress::getAddrInfo(const char* host, uint16_t port, int flags) {
610  // getaddrinfo() requires the port number as a string
611  char portString[sizeof("65535")];
612  snprintf(portString, sizeof(portString), "%" PRIu16, port);
613 
614  return getAddrInfo(host, portString, flags);
615 }
616 
617 struct addrinfo*
618 SocketAddress::getAddrInfo(const char* host, const char* port, int flags) {
619  struct addrinfo hints;
620  memset(&hints, 0, sizeof(hints));
621  hints.ai_family = AF_UNSPEC;
622  hints.ai_socktype = SOCK_STREAM;
623  hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
624 
625  struct addrinfo* results;
626  int error = getaddrinfo(host, port, &hints, &results);
627  if (error != 0) {
628  auto os = folly::sformat(
629  "Failed to resolve address for '{}': {} (error={})",
630  host,
631  gai_strerror(error),
632  error);
633  throw std::system_error(error, std::generic_category(), os);
634  }
635 
636  return results;
637 }
638 
639 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
640  setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
641 }
642 
643 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
644  // If an IPv6 address is present, prefer to use it, since IPv4 addresses
645  // can be mapped into IPv6 space.
646  for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
647  if (ai->ai_family == AF_INET6) {
648  setFromSockaddr(ai->ai_addr, socklen_t(ai->ai_addrlen));
649  return;
650  }
651  }
652 
653  // Otherwise, just use the first address in the list.
654  setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
655 }
656 
657 void SocketAddress::setFromSocket(
659  int (*fn)(NetworkSocket, struct sockaddr*, socklen_t*)) {
660  // Try to put the address into a local storage buffer.
661  sockaddr_storage tmp_sock;
662  socklen_t addrLen = sizeof(tmp_sock);
663  if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
664  folly::throwSystemError("setFromSocket() failed");
665  }
666 
667  setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
668 }
669 
670 std::string SocketAddress::getIpString(int flags) const {
671  char addrString[NI_MAXHOST];
672  getIpString(addrString, sizeof(addrString), flags);
673  return std::string(addrString);
674 }
675 
676 void SocketAddress::getIpString(char* buf, size_t buflen, int flags) const {
677  auto family = getFamily();
678  if (family != AF_INET && family != AF_INET6) {
679  throw std::invalid_argument(
680  "SocketAddress: attempting to get IP address "
681  "for a non-IP address");
682  }
683 
684  sockaddr_storage tmp_sock;
685  storage_.addr.toSockaddrStorage(&tmp_sock, port_);
686  int rc = getnameinfo(
687  (sockaddr*)&tmp_sock,
688  sizeof(sockaddr_storage),
689  buf,
690  buflen,
691  nullptr,
692  0,
693  flags);
694  if (rc != 0) {
695  auto os = sformat(
696  "getnameinfo() failed in getIpString() error = {}", gai_strerror(rc));
697  throw std::system_error(rc, std::generic_category(), os);
698  }
699 }
700 
701 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
702  if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
703  throw std::invalid_argument(
704  "SocketAddress: attempted to set a Unix socket "
705  "with a length too short for a sockaddr_un");
706  }
707 
708  storage_.un.len = addrlen;
709  if (storage_.un.pathLength() == 0) {
710  // anonymous address
711  return;
712  }
713 
714  if (storage_.un.addr->sun_path[0] == '\0') {
715  // abstract namespace. honor the specified length
716  } else {
717  // Call strnlen(), just in case the length was overspecified.
718  size_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
719  size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
720  storage_.un.len =
721  socklen_t(offsetof(struct sockaddr_un, sun_path) + pathLength);
722  }
723 }
724 
725 bool SocketAddress::operator<(const SocketAddress& other) const {
726  if (getFamily() != other.getFamily()) {
727  return getFamily() < other.getFamily();
728  }
729 
730  if (external_) {
731  // Anonymous addresses can't be compared to anything else.
732  // Return that they are never less than anything.
733  //
734  // Note that this still meets the requirements for a strict weak
735  // ordering, so we can use this operator<() with standard C++ containers.
736  auto thisPathLength = storage_.un.pathLength();
737  if (thisPathLength == 0) {
738  return false;
739  }
740  auto otherPathLength = other.storage_.un.pathLength();
741  if (otherPathLength == 0) {
742  return true;
743  }
744 
745  // Compare based on path length first, for efficiency
746  if (thisPathLength != otherPathLength) {
747  return thisPathLength < otherPathLength;
748  }
749  int cmp = memcmp(
750  storage_.un.addr->sun_path,
751  other.storage_.un.addr->sun_path,
752  size_t(thisPathLength));
753  return cmp < 0;
754  }
755  switch (getFamily()) {
756  case AF_INET:
757  case AF_INET6: {
758  if (port_ != other.port_) {
759  return port_ < other.port_;
760  }
761 
762  return storage_.addr < other.storage_.addr;
763  }
764  case AF_UNSPEC:
765  default:
766  throw std::invalid_argument(
767  "SocketAddress: unsupported address family for comparing");
768  }
769 }
770 
771 size_t hash_value(const SocketAddress& address) {
772  return address.hash();
773 }
774 
775 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
776  os << addr.describe();
777  return os;
778 }
779 
780 } // namespace folly
bool operator==(const char *c, CStringRange::Sentinel)
def info()
Definition: deadlock.py:447
flags
Definition: http_parser.h:127
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
static const int seed
constexpr size_type size() const
Definition: Range.h:431
#define GETFAMILYNAMEFROM_IMPL(Family)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::string describe() const
bool prefix(Cursor &c, uint32_t expected)
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
std::ostream & operator<<(std::ostream &os, const SocketAddress &addr)
int getsockname(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:108
LogLevel min
Definition: LogLevel.cpp:30
sa_family_t getFamily() const
size_t hash_combine(const T &t, const Ts &...ts) noexcept(noexcept(hash_combine_generic(StdHasher{}, t, ts...)))
Definition: Hash.h:669
constexpr Iter data() const
Definition: Range.h:446
NetworkSocket socket(int af, int type, int protocol)
Definition: NetOps.cpp:412
void free()
size_t hash() const
union folly::SocketAddress::AddrStorage storage_
uint64_t twang_mix64(uint64_t key) noexcept
Definition: Hash.h:49
const char * string
Definition: Conv.cpp:212
int getpeername(NetworkSocket s, sockaddr *name, socklen_t *namelen)
Definition: NetOps.cpp:104
static unsigned long long allocated
size_t hash_value(const SocketAddress &address)
void throwSystemError(Args &&...args)
Definition: Exception.h:76
ThreadPoolListHook * addr
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321