X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSocketAddress.cpp;h=af6cd77f927ceb70a63cef20d8a6c515c1bf7db7;hb=015306906e2811cc0cf3dab0c4142d45434a2801;hp=4834a134a86307f3411eb4ca0fae3a37f5457dc7;hpb=f760023d339249ca3f6e40ebee69128d9850f925;p=folly.git diff --git a/folly/SocketAddress.cpp b/folly/SocketAddress.cpp index 4834a134..af6cd77f 100644 --- a/folly/SocketAddress.cpp +++ b/folly/SocketAddress.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -15,20 +15,24 @@ */ #ifndef __STDC_FORMAT_MACROS - #define __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS #endif #include -#include - -#include -#include -#include -#include -#include +#include +#include +#include #include #include +#include + +#include + +#include +#include +#include +#include namespace { @@ -36,7 +40,7 @@ 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); } @@ -57,18 +61,15 @@ struct ScopedAddrInfo { */ 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 \":\""); + "expected a host and port string of the " + "form \":\""); } port = str; return; @@ -81,7 +82,7 @@ struct HostAndPort { throw std::bad_alloc(); } - char *allocatedColon = allocated + (colon - str); + char* allocatedColon = allocated + (colon - str); *allocatedColon = '\0'; host = allocated; port = allocatedColon + 1; @@ -103,7 +104,7 @@ struct HostAndPort { char* allocated; }; -} // unnamed namespace +} // namespace namespace folly { @@ -111,8 +112,8 @@ bool SocketAddress::isPrivateAddress() const { 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. @@ -125,7 +126,7 @@ bool SocketAddress::isLoopbackAddress() const { 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; } @@ -142,6 +143,15 @@ void SocketAddress::setFromIpPort(const char* ip, uint16_t port) { 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); @@ -154,8 +164,8 @@ void SocketAddress::setFromLocalPort(const char* port) { 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); } @@ -171,24 +181,62 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) { 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'; } } @@ -201,59 +249,61 @@ void SocketAddress::setFromLocalAddress(int socket) { } void SocketAddress::setFromSockaddr(const struct sockaddr* address) { + uint16_t port; + if (address->sa_family == AF_INET) { - storage_.addr = folly::IPAddress(address); - port_ = ntohs(((sockaddr_in*)address)->sin_port); + port = ntohs(((sockaddr_in*)address)->sin_port); } else if (address->sa_family == AF_INET6) { - storage_.addr = folly::IPAddress(address); - port_ = ntohs(((sockaddr_in6*)address)->sin6_port); + port = ntohs(((sockaddr_in6*)address)->sin6_port); } else if (address->sa_family == AF_UNIX) { // We need an explicitly specified length for AF_UNIX addresses, // 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"); + "SocketAddress::setFromSockaddr() called " + "with unsupported address type"); } - external_ = false; + + 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(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(address)); } else if (address->sa_family == AF_UNIX) { - setFromSockaddr(reinterpret_cast(address), - addrlen); + setFromSockaddr( + reinterpret_cast(address), addrlen); } else { throw std::invalid_argument( - "SocketAddress::setFromSockaddr() called " - "with unsupported address type"); + "SocketAddress::setFromSockaddr() called " + "with unsupported address type"); } } @@ -267,22 +317,26 @@ void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) { 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(storage_.un.addr); + char* p = reinterpret_cast(storage_.un.addr); memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen); } } @@ -296,42 +350,44 @@ const folly::IPAddress& SocketAddress::getIPAddress() const { } 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'; } @@ -343,8 +399,8 @@ uint16_t SocketAddress::getPort() const { return port_; default: throw std::invalid_argument( - "SocketAddress::getPort() called on non-IP " - "address"); + "SocketAddress::getPort() called on non-IP " + "address"); } } @@ -356,16 +412,16 @@ void SocketAddress::setPort(uint16_t port) { 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"); } } @@ -392,10 +448,10 @@ std::string SocketAddress::getHostStr() const { } 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) { @@ -404,28 +460,41 @@ std::string SocketAddress::getPath() const { } 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 ""; + } + + if (storage_.un.addr->sun_path[0] == '\0') { + // Linux supports an abstract namespace for unix socket addresses + return ""; + } + + 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 ""; - 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); @@ -433,79 +502,59 @@ std::string SocketAddress::describe() const { snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort()); return buf; } - case AF_UNIX: - { - if (storage_.un.pathLength() == 0) { - return ""; - } - - if (storage_.un.addr->sun_path[0] == '\0') { - // Linux supports an abstract namespace for unix socket addresses - return ""; - } - - 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), "", - getFamily()); + snprintf(buf, sizeof(buf), "", 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: @@ -513,10 +562,19 @@ bool SocketAddress::prefixMatch(const SocketAddress& other, } } - 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: { @@ -525,29 +583,20 @@ size_t SocketAddress::hash() const { 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); @@ -555,21 +604,22 @@ struct addrinfo* SocketAddress::getAddrInfo(const char* host, 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( - "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); } @@ -577,7 +627,7 @@ struct addrinfo* SocketAddress::getAddrInfo(const char* host, } 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) { @@ -585,26 +635,18 @@ 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); @@ -621,23 +663,27 @@ std::string SocketAddress::getIpString(int flags) const { 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( - "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); } } @@ -645,8 +691,8 @@ void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const { 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; @@ -659,9 +705,10 @@ void SocketAddress::updateUnixAddressLength(socklen_t 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); } } @@ -670,6 +717,31 @@ bool SocketAddress::operator<(const SocketAddress& other) const { 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: { @@ -677,37 +749,12 @@ bool SocketAddress::operator<(const SocketAddress& other) const { 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"); } } @@ -720,4 +767,4 @@ std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) { return os; } -} // folly +} // namespace folly