X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSocketAddress.cpp;h=2425a7e54a0b05ca6e549f5e6eba29b85ea6a559;hb=8281c7faafe4b6ad2b92436e133d21eb0c219ab4;hp=6c83e033fe3b8178535aa70bd24e0255404085e8;hpb=cae6c97a3e46d3e58f1b28eadc097fb14391f559;p=folly.git diff --git a/folly/SocketAddress.cpp b/folly/SocketAddress.cpp index 6c83e033..2425a7e5 100644 --- a/folly/SocketAddress.cpp +++ b/folly/SocketAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,7 +112,7 @@ bool SocketAddress::isPrivateAddress() const { if (family == AF_INET || family == AF_INET6) { return storage_.addr.isPrivate() || (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, // since this conforms to the semantics of returning true for IP loopback // addresses. @@ -125,7 +125,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 +142,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); @@ -172,7 +181,7 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) { } void SocketAddress::setFromPath(const char* path, size_t len) { - if (getFamily() != AF_UNIX) { + if (!external_) { storage_.un.init(); external_ = true; } @@ -192,16 +201,17 @@ void SocketAddress::setFromPath(const char* path, size_t len) { } } -void SocketAddress::setFromPeerAddress(int socket) { +void SocketAddress::setFromPeerAddress(SocketDesc socket) { setFromSocket(socket, getpeername); } -void SocketAddress::setFromLocalAddress(int socket) { +void SocketAddress::setFromLocalAddress(SocketDesc socket) { setFromSocket(socket, getsockname); } 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) { @@ -219,12 +229,8 @@ void SocketAddress::setFromSockaddr(const struct sockaddr* address) { "SocketAddress::setFromSockaddr() called " "with unsupported address type"); } - if (getFamily() == AF_UNIX) { - storage_.un.free(); - external_ = false; - } - storage_.addr = folly::IPAddress(address); - port_ = port; + + setFromIpAddrPort(folly::IPAddress(address), port); } void SocketAddress::setFromSockaddr(const struct sockaddr* address, @@ -300,14 +306,15 @@ 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 " @@ -396,7 +403,7 @@ 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"); @@ -417,6 +424,20 @@ std::string SocketAddress::getPath() const { } 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, + storage_.un.pathLength())); + } switch (getFamily()) { case AF_UNSPEC: return ""; @@ -437,21 +458,6 @@ 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: { char buf[64]; @@ -463,31 +469,30 @@ std::string SocketAddress::describe() const { } 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, + 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; - } default: throw std::invalid_argument( "SocketAddress: unsupported address family " @@ -521,6 +526,16 @@ 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; + 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])); + } + } + switch (getFamily()) { case AF_INET: case AF_INET6: { @@ -529,16 +544,8 @@ 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( @@ -598,17 +605,7 @@ void SocketAddress::setFromLocalAddr(const struct addrinfo* info) { setFromSockaddr(info->ai_addr, 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(SocketDesc socket, GetPeerNameFunc fn) { // Try to put the address into a local storage buffer. sockaddr_storage tmp_sock; socklen_t addrLen = sizeof(tmp_sock); @@ -674,6 +671,30 @@ 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. + 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; + } switch (getFamily()) { case AF_INET: case AF_INET6: { @@ -684,30 +705,6 @@ bool SocketAddress::operator<(const SocketAddress& other) const { 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; - } case AF_UNSPEC: default: throw std::invalid_argument(