Commit 7b474bc6 authored by Dave Watson's avatar Dave Watson Committed by Anton Likhtarov

Fix SocketAddress AF_UNIX support

Summary: check external_ vs. AF_UNIX.  Also fix reset() to reset storage_.addr

Test Plan: fbconfig folly/test:network_address_test; fbmake runtests

Reviewed By: soren@fb.com

Subscribers: tudorb, trunkagent, doug, njormrod

FB internal diff: D1575098
parent 96be3888
...@@ -112,7 +112,7 @@ bool SocketAddress::isPrivateAddress() const { ...@@ -112,7 +112,7 @@ bool SocketAddress::isPrivateAddress() const {
if (family == AF_INET || family == AF_INET6) { if (family == AF_INET || family == AF_INET6) {
return storage_.addr.isPrivate() || return storage_.addr.isPrivate() ||
(storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal()); (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
} else if (family == AF_UNIX) { } else if (external_) {
// Unix addresses are always local to a host. Return true, // Unix addresses are always local to a host. Return true,
// since this conforms to the semantics of returning true for IP loopback // since this conforms to the semantics of returning true for IP loopback
// addresses. // addresses.
...@@ -125,7 +125,7 @@ bool SocketAddress::isLoopbackAddress() const { ...@@ -125,7 +125,7 @@ bool SocketAddress::isLoopbackAddress() const {
auto family = getFamily(); auto family = getFamily();
if (family == AF_INET || family == AF_INET6) { if (family == AF_INET || family == AF_INET6) {
return storage_.addr.isLoopback(); 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 for UNIX addresses, since they are always local to a host.
return true; return true;
} }
...@@ -172,7 +172,7 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) { ...@@ -172,7 +172,7 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) {
} }
void SocketAddress::setFromPath(const char* path, size_t len) { void SocketAddress::setFromPath(const char* path, size_t len) {
if (getFamily() != AF_UNIX) { if (!external_) {
storage_.un.init(); storage_.un.init();
external_ = true; external_ = true;
} }
...@@ -201,12 +201,12 @@ void SocketAddress::setFromLocalAddress(int socket) { ...@@ -201,12 +201,12 @@ void SocketAddress::setFromLocalAddress(int socket) {
} }
void SocketAddress::setFromSockaddr(const struct sockaddr* address) { void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
uint16_t port;
if (address->sa_family == AF_INET) { 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) { } 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) { } else if (address->sa_family == AF_UNIX) {
// We need an explicitly specified length for AF_UNIX addresses, // We need an explicitly specified length for AF_UNIX addresses,
// to be able to distinguish anonymous addresses from addresses // to be able to distinguish anonymous addresses from addresses
...@@ -220,7 +220,12 @@ void SocketAddress::setFromSockaddr(const struct sockaddr* address) { ...@@ -220,7 +220,12 @@ void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
"SocketAddress::setFromSockaddr() called " "SocketAddress::setFromSockaddr() called "
"with unsupported address type"); "with unsupported address type");
} }
if (external_) {
storage_.un.free();
external_ = false; external_ = false;
}
storage_.addr = folly::IPAddress(address);
port_ = port;
} }
void SocketAddress::setFromSockaddr(const struct sockaddr* address, void SocketAddress::setFromSockaddr(const struct sockaddr* address,
...@@ -296,14 +301,15 @@ const folly::IPAddress& SocketAddress::getIPAddress() const { ...@@ -296,14 +301,15 @@ const folly::IPAddress& SocketAddress::getIPAddress() const {
} }
socklen_t SocketAddress::getActualSize() const { socklen_t SocketAddress::getActualSize() const {
if (external_) {
return storage_.un.len;
}
switch (getFamily()) { switch (getFamily()) {
case AF_UNSPEC: case AF_UNSPEC:
case AF_INET: case AF_INET:
return sizeof(struct sockaddr_in); return sizeof(struct sockaddr_in);
case AF_INET6: case AF_INET6:
return sizeof(struct sockaddr_in6); return sizeof(struct sockaddr_in6);
case AF_UNIX:
return storage_.un.len;
default: default:
throw std::invalid_argument( throw std::invalid_argument(
"SocketAddress::getActualSize() called " "SocketAddress::getActualSize() called "
...@@ -392,7 +398,7 @@ std::string SocketAddress::getHostStr() const { ...@@ -392,7 +398,7 @@ std::string SocketAddress::getHostStr() const {
} }
std::string SocketAddress::getPath() const { std::string SocketAddress::getPath() const {
if (getFamily() != AF_UNIX) { if (!external_) {
throw std::invalid_argument( throw std::invalid_argument(
"SocketAddress: attempting to get path " "SocketAddress: attempting to get path "
"for a non-Unix address"); "for a non-Unix address");
...@@ -413,6 +419,20 @@ std::string SocketAddress::getPath() const { ...@@ -413,6 +419,20 @@ std::string SocketAddress::getPath() const {
} }
std::string SocketAddress::describe() const { 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,
storage_.un.pathLength()));
}
switch (getFamily()) { switch (getFamily()) {
case AF_UNSPEC: case AF_UNSPEC:
return "<uninitialized address>"; return "<uninitialized address>";
...@@ -433,21 +453,6 @@ std::string SocketAddress::describe() const { ...@@ -433,21 +453,6 @@ std::string SocketAddress::describe() const {
snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort()); snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
return buf; 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]; char buf[64];
...@@ -459,17 +464,10 @@ std::string SocketAddress::describe() const { ...@@ -459,17 +464,10 @@ std::string SocketAddress::describe() const {
} }
bool SocketAddress::operator==(const SocketAddress& other) const { bool SocketAddress::operator==(const SocketAddress& other) const {
if (other.getFamily() != getFamily()) { if (external_ != other.external_ || other.getFamily() != getFamily()) {
return false; return false;
} }
if (external_) {
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 // anonymous addresses are never equal to any other addresses
if (storage_.un.pathLength() == 0 || if (storage_.un.pathLength() == 0 ||
other.storage_.un.pathLength() == 0) { other.storage_.un.pathLength() == 0) {
...@@ -484,6 +482,12 @@ bool SocketAddress::operator==(const SocketAddress& other) const { ...@@ -484,6 +482,12 @@ bool SocketAddress::operator==(const SocketAddress& other) const {
storage_.un.pathLength()); storage_.un.pathLength());
return cmp == 0; return cmp == 0;
} }
switch (getFamily()) {
case AF_INET:
case AF_INET6:
return (other.storage_.addr == storage_.addr) &&
(other.port_ == port_);
default: default:
throw std::invalid_argument( throw std::invalid_argument(
"SocketAddress: unsupported address family " "SocketAddress: unsupported address family "
...@@ -517,15 +521,7 @@ bool SocketAddress::prefixMatch(const SocketAddress& other, ...@@ -517,15 +521,7 @@ bool SocketAddress::prefixMatch(const SocketAddress& other,
size_t SocketAddress::hash() const { size_t SocketAddress::hash() const {
size_t seed = folly::hash::twang_mix64(getFamily()); size_t seed = folly::hash::twang_mix64(getFamily());
switch (getFamily()) { if (external_) {
case AF_INET:
case AF_INET6: {
boost::hash_combine(seed, port_);
boost::hash_combine(seed, storage_.addr.hash());
break;
}
case AF_UNIX:
{
enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) }; enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
const char *path = storage_.un.addr->sun_path; const char *path = storage_.un.addr->sun_path;
size_t pathLength = storage_.un.pathLength(); size_t pathLength = storage_.un.pathLength();
...@@ -533,8 +529,18 @@ size_t SocketAddress::hash() const { ...@@ -533,8 +529,18 @@ size_t SocketAddress::hash() const {
for (unsigned int n = 0; n < pathLength; ++n) { for (unsigned int n = 0; n < pathLength; ++n) {
boost::hash_combine(seed, folly::hash::twang_mix64(path[n])); boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
} }
}
switch (getFamily()) {
case AF_INET:
case AF_INET6: {
boost::hash_combine(seed, port_);
boost::hash_combine(seed, storage_.addr.hash());
break; break;
} }
case AF_UNIX:
DCHECK(external_);
break;
case AF_UNSPEC: case AF_UNSPEC:
default: default:
throw std::invalid_argument( throw std::invalid_argument(
...@@ -596,15 +602,6 @@ void SocketAddress::setFromLocalAddr(const struct addrinfo* info) { ...@@ -596,15 +602,6 @@ void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
void SocketAddress::setFromSocket(int socket, void SocketAddress::setFromSocket(int socket,
int (*fn)(int, sockaddr*, socklen_t*)) { 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;
}
// Try to put the address into a local storage buffer. // Try to put the address into a local storage buffer.
sockaddr_storage tmp_sock; sockaddr_storage tmp_sock;
socklen_t addrLen = sizeof(tmp_sock); socklen_t addrLen = sizeof(tmp_sock);
...@@ -670,17 +667,7 @@ bool SocketAddress::operator<(const SocketAddress& other) const { ...@@ -670,17 +667,7 @@ bool SocketAddress::operator<(const SocketAddress& other) const {
return getFamily() < other.getFamily(); return getFamily() < other.getFamily();
} }
switch (getFamily()) { if (external_) {
case AF_INET:
case AF_INET6: {
if (port_ != other.port_) {
return port_ < other.port_;
}
return
storage_.addr < other.storage_.addr;
}
case AF_UNIX: {
// Anonymous addresses can't be compared to anything else. // Anonymous addresses can't be compared to anything else.
// Return that they are never less than anything. // Return that they are never less than anything.
// //
...@@ -704,6 +691,16 @@ bool SocketAddress::operator<(const SocketAddress& other) const { ...@@ -704,6 +691,16 @@ bool SocketAddress::operator<(const SocketAddress& other) const {
thisPathLength); thisPathLength);
return cmp < 0; return cmp < 0;
} }
switch (getFamily()) {
case AF_INET:
case AF_INET6: {
if (port_ != other.port_) {
return port_ < other.port_;
}
return
storage_.addr < other.storage_.addr;
}
case AF_UNSPEC: case AF_UNSPEC:
default: default:
throw std::invalid_argument( throw std::invalid_argument(
......
...@@ -32,9 +32,7 @@ namespace folly { ...@@ -32,9 +32,7 @@ namespace folly {
class SocketAddress { class SocketAddress {
public: public:
SocketAddress() { SocketAddress() {}
storage_.addr = folly::IPAddress();
}
/** /**
* Construct a SocketAddress from a hostname and port. * Construct a SocketAddress from a hostname and port.
...@@ -76,16 +74,17 @@ class SocketAddress { ...@@ -76,16 +74,17 @@ class SocketAddress {
} }
SocketAddress(const SocketAddress& addr) { SocketAddress(const SocketAddress& addr) {
storage_ = addr.storage_;
port_ = addr.port_; port_ = addr.port_;
if (addr.getFamily() == AF_UNIX) { if (addr.getFamily() == AF_UNIX) {
storage_.un.init(addr.storage_.un); storage_.un.init(addr.storage_.un);
} else {
storage_ = addr.storage_;
} }
external_ = addr.external_; external_ = addr.external_;
} }
SocketAddress& operator=(const SocketAddress& addr) { SocketAddress& operator=(const SocketAddress& addr) {
if (getFamily() != AF_UNIX) { if (!external_) {
if (addr.getFamily() != AF_UNIX) { if (addr.getFamily() != AF_UNIX) {
storage_ = addr.storage_; storage_ = addr.storage_;
} else { } else {
...@@ -105,7 +104,7 @@ class SocketAddress { ...@@ -105,7 +104,7 @@ class SocketAddress {
return *this; return *this;
} }
SocketAddress(SocketAddress&& addr) { SocketAddress(SocketAddress&& addr) noexcept {
storage_ = addr.storage_; storage_ = addr.storage_;
port_ = addr.port_; port_ = addr.port_;
external_ = addr.external_; external_ = addr.external_;
...@@ -120,7 +119,7 @@ class SocketAddress { ...@@ -120,7 +119,7 @@ class SocketAddress {
} }
~SocketAddress() { ~SocketAddress() {
if (getFamily() == AF_UNIX) { if (external_) {
storage_.un.free(); storage_.un.free();
} }
} }
...@@ -349,7 +348,7 @@ class SocketAddress { ...@@ -349,7 +348,7 @@ class SocketAddress {
* Returns the actual size of the storage used. * Returns the actual size of the storage used.
*/ */
socklen_t getAddress(sockaddr_storage* addr) const { socklen_t getAddress(sockaddr_storage* addr) const {
if (getFamily() != AF_UNIX) { if (!external_) {
return storage_.addr.toSockaddrStorage(addr, htons(port_)); return storage_.addr.toSockaddrStorage(addr, htons(port_));
} else { } else {
memcpy(addr, storage_.un.addr, sizeof(*storage_.un.addr)); memcpy(addr, storage_.un.addr, sizeof(*storage_.un.addr));
...@@ -363,6 +362,7 @@ class SocketAddress { ...@@ -363,6 +362,7 @@ class SocketAddress {
socklen_t getActualSize() const; socklen_t getActualSize() const;
sa_family_t getFamily() const { sa_family_t getFamily() const {
DCHECK(external_ || AF_UNIX != storage_.addr.family());
return external_ ? AF_UNIX : storage_.addr.family(); return external_ ? AF_UNIX : storage_.addr.family();
} }
...@@ -547,12 +547,13 @@ class SocketAddress { ...@@ -547,12 +547,13 @@ class SocketAddress {
void prepFamilyChange(sa_family_t newFamily) { void prepFamilyChange(sa_family_t newFamily) {
if (newFamily != AF_UNIX) { if (newFamily != AF_UNIX) {
if (getFamily() == AF_UNIX) { if (external_) {
storage_.un.free(); storage_.un.free();
storage_.addr = folly::IPAddress();
} }
external_ = false; external_ = false;
} else { } else {
if (getFamily() != AF_UNIX) { if (!external_) {
storage_.un.init(); storage_.un.init();
} }
external_ = true; external_ = true;
...@@ -569,7 +570,7 @@ class SocketAddress { ...@@ -569,7 +570,7 @@ class SocketAddress {
union { union {
folly::IPAddress addr{}; folly::IPAddress addr{};
ExternalUnixAddr un; ExternalUnixAddr un;
} storage_; } storage_{};
// IPAddress class does nto save zone or port, and must be saved here // IPAddress class does nto save zone or port, and must be saved here
uint16_t port_; uint16_t port_;
......
...@@ -840,3 +840,11 @@ TEST(SocketAddress, SetFromSocketUnixAnonymous) { ...@@ -840,3 +840,11 @@ TEST(SocketAddress, SetFromSocketUnixAnonymous) {
EXPECT_EQ(clientAddr.getPath(), ""); EXPECT_EQ(clientAddr.getPath(), "");
EXPECT_EQ(acceptAddr.getPath(), ""); EXPECT_EQ(acceptAddr.getPath(), "");
} }
TEST(SocketAddress, ResetUnixAddress) {
SocketAddress addy;
addy.setFromPath("/foo");
addy.reset();
EXPECT_EQ(addy.getFamily(), AF_UNSPEC);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment