/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#ifndef __STDC_FORMAT_MACROS
- #define __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
#endif
#include <folly/SocketAddress.h>
-#include <folly/Hash.h>
-
-#include <boost/functional/hash.hpp>
-#include <boost/static_assert.hpp>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
#include <sstream>
#include <string>
+#include <system_error>
+
+#include <boost/functional/hash.hpp>
+
+#include <folly/CppAttributes.h>
+#include <folly/Exception.h>
+#include <folly/Format.h>
+#include <folly/hash/Hash.h>
namespace {
* A structure to free a struct addrinfo when it goes out of scope.
*/
struct ScopedAddrInfo {
- explicit ScopedAddrInfo(struct addrinfo* info) : info(info) {}
+ explicit ScopedAddrInfo(struct addrinfo* addrinfo) : info(addrinfo) {}
~ScopedAddrInfo() {
freeaddrinfo(info);
}
*/
struct HostAndPort {
HostAndPort(const char* str, bool hostRequired)
- : host(nullptr),
- port(nullptr),
- allocated(nullptr) {
-
+ : host(nullptr), port(nullptr), allocated(nullptr) {
// Look for the last colon
const char* colon = strrchr(str, ':');
if (colon == nullptr) {
// No colon, just a port number.
if (hostRequired) {
throw std::invalid_argument(
- "expected a host and port string of the "
- "form \"<host>:<port>\"");
+ "expected a host and port string of the "
+ "form \"<host>:<port>\"");
}
port = str;
return;
throw std::bad_alloc();
}
- char *allocatedColon = allocated + (colon - str);
+ char* allocatedColon = allocated + (colon - str);
*allocatedColon = '\0';
host = allocated;
port = allocatedColon + 1;
char* allocated;
};
-} // unnamed namespace
+} // namespace
namespace folly {
auto family = getFamily();
if (family == AF_INET || family == AF_INET6) {
return storage_.addr.isPrivate() ||
- (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
- } else if (family == AF_UNIX) {
+ (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
+ } else if (external_) {
// Unix addresses are always local to a host. Return true,
// since this conforms to the semantics of returning true for IP loopback
// addresses.
auto family = getFamily();
if (family == AF_INET || family == AF_INET6) {
return storage_.addr.isLoopback();
- } else if (family == AF_UNIX) {
+ } else if (external_) {
// Return true for UNIX addresses, since they are always local to a host.
return true;
}
setFromAddrInfo(results.info);
}
+void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) {
+ if (external_) {
+ storage_.un.free();
+ external_ = false;
+ }
+ storage_.addr = ipAddr;
+ port_ = port;
+}
+
void SocketAddress::setFromLocalPort(uint16_t port) {
ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
setFromLocalAddr(results.info);
void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
HostAndPort hp(addressAndPort, false);
- ScopedAddrInfo results(getAddrInfo(hp.host, hp.port,
- AI_NUMERICHOST | AI_ADDRCONFIG));
+ ScopedAddrInfo results(
+ getAddrInfo(hp.host, hp.port, AI_NUMERICHOST | AI_ADDRCONFIG));
setFromLocalAddr(results.info);
}
setFromAddrInfo(results.info);
}
-void SocketAddress::setFromPath(const char* path, size_t len) {
- if (getFamily() != AF_UNIX) {
+int SocketAddress::getPortFrom(const struct sockaddr* address) {
+ switch (address->sa_family) {
+ case AF_INET:
+ return ntohs(((sockaddr_in*)address)->sin_port);
+
+ case AF_INET6:
+ return ntohs(((sockaddr_in6*)address)->sin6_port);
+
+ default:
+ return -1;
+ }
+}
+
+const char* SocketAddress::getFamilyNameFrom(
+ const struct sockaddr* address,
+ const char* defaultResult) {
+#define GETFAMILYNAMEFROM_IMPL(Family) \
+ case Family: \
+ return #Family
+
+ switch (address->sa_family) {
+ GETFAMILYNAMEFROM_IMPL(AF_INET);
+ GETFAMILYNAMEFROM_IMPL(AF_INET6);
+ GETFAMILYNAMEFROM_IMPL(AF_UNIX);
+ GETFAMILYNAMEFROM_IMPL(AF_UNSPEC);
+
+ default:
+ return defaultResult;
+ }
+
+#undef GETFAMILYNAMEFROM_IMPL
+}
+
+void SocketAddress::setFromPath(StringPiece path) {
+ // Before we touch storage_, check to see if the length is too big.
+ // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
+ // but sizeof() just uses its type, and does't evaluate it.
+ if (path.size() > sizeof(storage_.un.addr->sun_path)) {
+ throw std::invalid_argument(
+ "socket path too large to fit into sockaddr_un");
+ }
+
+ if (!external_) {
storage_.un.init();
external_ = true;
}
- storage_.un.len = offsetof(struct sockaddr_un, sun_path) + len;
- if (len > sizeof(storage_.un.addr->sun_path)) {
- throw std::invalid_argument(
- "socket path too large to fit into sockaddr_un");
- } else if (len == sizeof(storage_.un.addr->sun_path)) {
- // Note that there will be no terminating NUL in this case.
- // We allow this since getsockname() and getpeername() may return
- // Unix socket addresses with paths that fit exactly in sun_path with no
- // terminating NUL.
- memcpy(storage_.un.addr->sun_path, path, len);
- } else {
- memcpy(storage_.un.addr->sun_path, path, len + 1);
+ size_t len = path.size();
+ storage_.un.len = socklen_t(offsetof(struct sockaddr_un, sun_path) + len);
+ memcpy(storage_.un.addr->sun_path, path.data(), len);
+ // If there is room, put a terminating NUL byte in sun_path. In general the
+ // path should be NUL terminated, although getsockname() and getpeername()
+ // may return Unix socket addresses with paths that fit exactly in sun_path
+ // with no terminating NUL.
+ if (len < sizeof(storage_.un.addr->sun_path)) {
+ storage_.un.addr->sun_path[len] = '\0';
}
}
void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
uint16_t port;
+
if (address->sa_family == AF_INET) {
port = ntohs(((sockaddr_in*)address)->sin_port);
} else if (address->sa_family == AF_INET6) {
// to be able to distinguish anonymous addresses from addresses
// in Linux's abstract namespace.
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr(): the address "
- "length must be explicitly specified when "
- "setting AF_UNIX addresses");
+ "SocketAddress::setFromSockaddr(): the address "
+ "length must be explicitly specified when "
+ "setting AF_UNIX addresses");
} else {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with unsupported address type");
- }
- if (getFamily() == AF_UNIX) {
- storage_.un.free();
- external_ = false;
+ "SocketAddress::setFromSockaddr() called "
+ "with unsupported address type");
}
- storage_.addr = folly::IPAddress(address);
- port_ = port;
+
+ setFromIpAddrPort(folly::IPAddress(address), port);
}
-void SocketAddress::setFromSockaddr(const struct sockaddr* address,
- socklen_t addrlen) {
+void SocketAddress::setFromSockaddr(
+ const struct sockaddr* address,
+ socklen_t addrlen) {
// Check the length to make sure we can access address->sa_family
- if (addrlen < (offsetof(struct sockaddr, sa_family) +
- sizeof(address->sa_family))) {
+ if (addrlen <
+ (offsetof(struct sockaddr, sa_family) + sizeof(address->sa_family))) {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with length too short for a sockaddr");
+ "SocketAddress::setFromSockaddr() called "
+ "with length too short for a sockaddr");
}
if (address->sa_family == AF_INET) {
if (addrlen < sizeof(struct sockaddr_in)) {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with length too short for a sockaddr_in");
+ "SocketAddress::setFromSockaddr() called "
+ "with length too short for a sockaddr_in");
}
setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
} else if (address->sa_family == AF_INET6) {
if (addrlen < sizeof(struct sockaddr_in6)) {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with length too short for a sockaddr_in6");
+ "SocketAddress::setFromSockaddr() called "
+ "with length too short for a sockaddr_in6");
}
setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
} else if (address->sa_family == AF_UNIX) {
- setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
- addrlen);
+ setFromSockaddr(
+ reinterpret_cast<const struct sockaddr_un*>(address), addrlen);
} else {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with unsupported address type");
+ "SocketAddress::setFromSockaddr() called "
+ "with unsupported address type");
}
}
setFromSockaddr((sockaddr*)address);
}
-void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
- socklen_t addrlen) {
+void SocketAddress::setFromSockaddr(
+ const struct sockaddr_un* address,
+ socklen_t addrlen) {
assert(address->sun_family == AF_UNIX);
if (addrlen > sizeof(struct sockaddr_un)) {
throw std::invalid_argument(
- "SocketAddress::setFromSockaddr() called "
- "with length too long for a sockaddr_un");
+ "SocketAddress::setFromSockaddr() called "
+ "with length too long for a sockaddr_un");
}
- prepFamilyChange(AF_UNIX);
- memcpy(storage_.un.addr, address, addrlen);
+ if (!external_) {
+ storage_.un.init();
+ }
+ external_ = true;
+ memcpy(storage_.un.addr, address, size_t(addrlen));
updateUnixAddressLength(addrlen);
// Fill the rest with 0s, just for safety
if (addrlen < sizeof(struct sockaddr_un)) {
- char *p = reinterpret_cast<char*>(storage_.un.addr);
+ char* p = reinterpret_cast<char*>(storage_.un.addr);
memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
}
}
}
socklen_t SocketAddress::getActualSize() const {
+ if (external_) {
+ return storage_.un.len;
+ }
switch (getFamily()) {
case AF_UNSPEC:
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
- case AF_UNIX:
- return storage_.un.len;
default:
throw std::invalid_argument(
- "SocketAddress::getActualSize() called "
- "with unrecognized address family");
+ "SocketAddress::getActualSize() called "
+ "with unrecognized address family");
}
}
std::string SocketAddress::getFullyQualified() const {
- auto family = getFamily();
- if (family != AF_INET && family != AF_INET6) {
+ if (!isFamilyInet()) {
throw std::invalid_argument("Can't get address str for non ip address");
}
return storage_.addr.toFullyQualified();
}
std::string SocketAddress::getAddressStr() const {
- char buf[INET6_ADDRSTRLEN];
- getAddressStr(buf, sizeof(buf));
- return buf;
+ if (!isFamilyInet()) {
+ throw std::invalid_argument("Can't get address str for non ip address");
+ }
+ return storage_.addr.str();
}
-void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
+bool SocketAddress::isFamilyInet() const {
auto family = getFamily();
- if (family != AF_INET && family != AF_INET6) {
- throw std::invalid_argument("Can't get address str for non ip address");
- }
- std::string ret = storage_.addr.str();
- size_t len = std::min(buflen, ret.size());
+ return family == AF_INET || family == AF_INET6;
+}
+
+void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
+ auto ret = getAddressStr();
+ size_t len = std::min(buflen - 1, ret.size());
memcpy(buf, ret.data(), len);
buf[len] = '\0';
}
return port_;
default:
throw std::invalid_argument(
- "SocketAddress::getPort() called on non-IP "
- "address");
+ "SocketAddress::getPort() called on non-IP "
+ "address");
}
}
return;
default:
throw std::invalid_argument(
- "SocketAddress::setPort() called on non-IP "
- "address");
+ "SocketAddress::setPort() called on non-IP "
+ "address");
}
}
void SocketAddress::convertToIPv4() {
if (!tryConvertToIPv4()) {
throw std::invalid_argument(
- "convertToIPv4() called on an addresse that is "
- "not an IPv4-mapped address");
+ "convertToIPv4() called on an addresse that is "
+ "not an IPv4-mapped address");
}
}
}
std::string SocketAddress::getPath() const {
- if (getFamily() != AF_UNIX) {
+ if (!external_) {
throw std::invalid_argument(
- "SocketAddress: attempting to get path "
- "for a non-Unix address");
+ "SocketAddress: attempting to get path "
+ "for a non-Unix address");
}
if (storage_.un.pathLength() == 0) {
}
if (storage_.un.addr->sun_path[0] == '\0') {
// abstract namespace
- return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
+ return std::string(
+ storage_.un.addr->sun_path, size_t(storage_.un.pathLength()));
}
- return std::string(storage_.un.addr->sun_path,
- strnlen(storage_.un.addr->sun_path,
- storage_.un.pathLength()));
+ return std::string(
+ storage_.un.addr->sun_path,
+ strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
}
std::string SocketAddress::describe() const {
+ if (external_) {
+ if (storage_.un.pathLength() == 0) {
+ return "<anonymous unix address>";
+ }
+
+ if (storage_.un.addr->sun_path[0] == '\0') {
+ // Linux supports an abstract namespace for unix socket addresses
+ return "<abstract unix address>";
+ }
+
+ return std::string(
+ storage_.un.addr->sun_path,
+ strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
+ }
switch (getFamily()) {
case AF_UNSPEC:
return "<uninitialized address>";
- case AF_INET:
- {
+ case AF_INET: {
char buf[NI_MAXHOST + 16];
getAddressStr(buf, sizeof(buf));
size_t iplen = strlen(buf);
snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
return buf;
}
- case AF_INET6:
- {
+ case AF_INET6: {
char buf[NI_MAXHOST + 18];
buf[0] = '[';
getAddressStr(buf + 1, sizeof(buf) - 1);
snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
return buf;
}
- case AF_UNIX:
- {
- if (storage_.un.pathLength() == 0) {
- return "<anonymous unix address>";
- }
-
- if (storage_.un.addr->sun_path[0] == '\0') {
- // Linux supports an abstract namespace for unix socket addresses
- return "<abstract unix address>";
- }
-
- return std::string(storage_.un.addr->sun_path,
- strnlen(storage_.un.addr->sun_path,
- storage_.un.pathLength()));
- }
- default:
- {
+ default: {
char buf[64];
- snprintf(buf, sizeof(buf), "<unknown address family %d>",
- getFamily());
+ snprintf(buf, sizeof(buf), "<unknown address family %d>", getFamily());
return buf;
}
}
}
bool SocketAddress::operator==(const SocketAddress& other) const {
- if (other.getFamily() != getFamily()) {
+ if (external_ != other.external_ || other.getFamily() != getFamily()) {
return false;
}
+ if (external_) {
+ // anonymous addresses are never equal to any other addresses
+ if (storage_.un.pathLength() == 0 || other.storage_.un.pathLength() == 0) {
+ return false;
+ }
+
+ if (storage_.un.len != other.storage_.un.len) {
+ return false;
+ }
+ int cmp = memcmp(
+ storage_.un.addr->sun_path,
+ other.storage_.un.addr->sun_path,
+ size_t(storage_.un.pathLength()));
+ return cmp == 0;
+ }
switch (getFamily()) {
case AF_INET:
case AF_INET6:
- return (other.storage_.addr == storage_.addr) &&
- (other.port_ == port_);
- case AF_UNIX:
- {
- // anonymous addresses are never equal to any other addresses
- if (storage_.un.pathLength() == 0 ||
- other.storage_.un.pathLength() == 0) {
- return false;
- }
-
- if (storage_.un.len != other.storage_.un.len) {
- return false;
- }
- int cmp = memcmp(storage_.un.addr->sun_path,
- other.storage_.un.addr->sun_path,
- storage_.un.pathLength());
- return cmp == 0;
- }
+ return (other.storage_.addr == storage_.addr) && (other.port_ == port_);
default:
throw std::invalid_argument(
- "SocketAddress: unsupported address family "
- "for comparison");
+ "SocketAddress: unsupported address family "
+ "for comparison");
}
}
-bool SocketAddress::prefixMatch(const SocketAddress& other,
+bool SocketAddress::prefixMatch(
+ const SocketAddress& other,
unsigned prefixLength) const {
if (other.getFamily() != getFamily()) {
return false;
}
- int mask_length = 128;
+ uint8_t mask_length = 128;
switch (getFamily()) {
case AF_INET:
mask_length = 32;
- // fallthrough
- case AF_INET6:
- {
+ FOLLY_FALLTHROUGH;
+ case AF_INET6: {
auto prefix = folly::IPAddress::longestCommonPrefix(
- {storage_.addr, mask_length},
- {other.storage_.addr, mask_length});
+ {storage_.addr, mask_length}, {other.storage_.addr, mask_length});
return prefix.second >= prefixLength;
}
default:
}
}
-
size_t SocketAddress::hash() const {
size_t seed = folly::hash::twang_mix64(getFamily());
+ if (external_) {
+ enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
+ const char* path = storage_.un.addr->sun_path;
+ auto pathLength = storage_.un.pathLength();
+ // TODO: this probably could be made more efficient
+ for (off_t n = 0; n < pathLength; ++n) {
+ boost::hash_combine(seed, folly::hash::twang_mix64(uint64_t(path[n])));
+ }
+ }
+
switch (getFamily()) {
case AF_INET:
case AF_INET6: {
break;
}
case AF_UNIX:
- {
- enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
- const char *path = storage_.un.addr->sun_path;
- size_t pathLength = storage_.un.pathLength();
- // TODO: this probably could be made more efficient
- for (unsigned int n = 0; n < pathLength; ++n) {
- boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
- }
+ DCHECK(external_);
break;
- }
case AF_UNSPEC:
default:
throw std::invalid_argument(
- "SocketAddress: unsupported address family "
- "for hashing");
+ "SocketAddress: unsupported address family "
+ "for hashing");
}
return seed;
}
-struct addrinfo* SocketAddress::getAddrInfo(const char* host,
- uint16_t port,
- int flags) {
+struct addrinfo*
+SocketAddress::getAddrInfo(const char* host, uint16_t port, int flags) {
// getaddrinfo() requires the port number as a string
char portString[sizeof("65535")];
snprintf(portString, sizeof(portString), "%" PRIu16, port);
return getAddrInfo(host, portString, flags);
}
-struct addrinfo* SocketAddress::getAddrInfo(const char* host,
- const char* port,
- int flags) {
+struct addrinfo*
+SocketAddress::getAddrInfo(const char* host, const char* port, int flags) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
- struct addrinfo *results;
+ struct addrinfo* results;
int error = getaddrinfo(host, port, &hints, &results);
if (error != 0) {
- auto os = folly::to<std::string>(
- "Failed to resolve address for \"", host, "\": ",
- gai_strerror(error), " (error=", error, ")");
+ auto os = folly::sformat(
+ "Failed to resolve address for '{}': {} (error={})",
+ host,
+ gai_strerror(error),
+ error);
throw std::system_error(error, std::generic_category(), os);
}
}
void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
- setFromSockaddr(info->ai_addr, info->ai_addrlen);
+ setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
}
void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
// can be mapped into IPv6 space.
for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
if (ai->ai_family == AF_INET6) {
- setFromSockaddr(ai->ai_addr, ai->ai_addrlen);
+ setFromSockaddr(ai->ai_addr, socklen_t(ai->ai_addrlen));
return;
}
}
// Otherwise, just use the first address in the list.
- setFromSockaddr(info->ai_addr, info->ai_addrlen);
+ setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
}
-void SocketAddress::setFromSocket(int socket,
- int (*fn)(int, sockaddr*, socklen_t*)) {
- // If this was previously an AF_UNIX socket, free the external buffer.
- // TODO: It would be smarter to just remember the external buffer, and then
- // re-use it or free it depending on if the new address is also a unix
- // socket.
- if (getFamily() == AF_UNIX) {
- storage_.un.free();
- external_ = false;
- }
-
+void SocketAddress::setFromSocket(
+ int socket,
+ int (*fn)(int, struct sockaddr*, socklen_t*)) {
// Try to put the address into a local storage buffer.
sockaddr_storage tmp_sock;
socklen_t addrLen = sizeof(tmp_sock);
return std::string(addrString);
}
-void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
+void SocketAddress::getIpString(char* buf, size_t buflen, int flags) const {
auto family = getFamily();
- if (family != AF_INET &&
- family != AF_INET6) {
+ if (family != AF_INET && family != AF_INET6) {
throw std::invalid_argument(
- "SocketAddress: attempting to get IP address "
- "for a non-IP address");
+ "SocketAddress: attempting to get IP address "
+ "for a non-IP address");
}
sockaddr_storage tmp_sock;
storage_.addr.toSockaddrStorage(&tmp_sock, port_);
- int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
- buf, buflen, nullptr, 0, flags);
+ int rc = getnameinfo(
+ (sockaddr*)&tmp_sock,
+ sizeof(sockaddr_storage),
+ buf,
+ buflen,
+ nullptr,
+ 0,
+ flags);
if (rc != 0) {
- auto os = folly::to<std::string>(
- "getnameinfo() failed in getIpString() error = ",
- gai_strerror(rc));
+ auto os = sformat(
+ "getnameinfo() failed in getIpString() error = {}", gai_strerror(rc));
throw std::system_error(rc, std::generic_category(), os);
}
}
void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
throw std::invalid_argument(
- "SocketAddress: attempted to set a Unix socket "
- "with a length too short for a sockaddr_un");
+ "SocketAddress: attempted to set a Unix socket "
+ "with a length too short for a sockaddr_un");
}
storage_.un.len = addrlen;
// abstract namespace. honor the specified length
} else {
// Call strnlen(), just in case the length was overspecified.
- socklen_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
+ size_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
- storage_.un.len = offsetof(struct sockaddr_un, sun_path) + pathLength;
+ storage_.un.len =
+ socklen_t(offsetof(struct sockaddr_un, sun_path) + pathLength);
}
}
return getFamily() < other.getFamily();
}
+ if (external_) {
+ // Anonymous addresses can't be compared to anything else.
+ // Return that they are never less than anything.
+ //
+ // Note that this still meets the requirements for a strict weak
+ // ordering, so we can use this operator<() with standard C++ containers.
+ auto thisPathLength = storage_.un.pathLength();
+ if (thisPathLength == 0) {
+ return false;
+ }
+ auto otherPathLength = other.storage_.un.pathLength();
+ if (otherPathLength == 0) {
+ return true;
+ }
+
+ // Compare based on path length first, for efficiency
+ if (thisPathLength != otherPathLength) {
+ return thisPathLength < otherPathLength;
+ }
+ int cmp = memcmp(
+ storage_.un.addr->sun_path,
+ other.storage_.un.addr->sun_path,
+ size_t(thisPathLength));
+ return cmp < 0;
+ }
switch (getFamily()) {
case AF_INET:
case AF_INET6: {
return port_ < other.port_;
}
- return
- storage_.addr < other.storage_.addr;
- }
- case AF_UNIX: {
- // Anonymous addresses can't be compared to anything else.
- // Return that they are never less than anything.
- //
- // Note that this still meets the requirements for a strict weak
- // ordering, so we can use this operator<() with standard C++ containers.
- size_t thisPathLength = storage_.un.pathLength();
- if (thisPathLength == 0) {
- return false;
- }
- size_t otherPathLength = other.storage_.un.pathLength();
- if (otherPathLength == 0) {
- return true;
- }
-
- // Compare based on path length first, for efficiency
- if (thisPathLength != otherPathLength) {
- return thisPathLength < otherPathLength;
- }
- int cmp = memcmp(storage_.un.addr->sun_path,
- other.storage_.un.addr->sun_path,
- thisPathLength);
- return cmp < 0;
+ return storage_.addr < other.storage_.addr;
}
case AF_UNSPEC:
default:
throw std::invalid_argument(
- "SocketAddress: unsupported address family for comparing");
+ "SocketAddress: unsupported address family for comparing");
}
}
return os;
}
-} // folly
+} // namespace folly