X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FSocketAddress.cpp;h=2d12d787e74ae2d4c630b716063a29f9935ad039;hb=55791684950381d92cef305d1e9124120b178ad5;hp=292ba056fca8d6d3336bb39fe62c8e50189aa183;hpb=275ca94d04e44f28cfa411668eb1c1dd8db90b80;p=folly.git diff --git a/folly/SocketAddress.cpp b/folly/SocketAddress.cpp index 292ba056..2d12d787 100644 --- a/folly/SocketAddress.cpp +++ b/folly/SocketAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 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. @@ -20,15 +20,17 @@ #include +#include +#include #include #include -#include #include #include #include #include #include +#include namespace { @@ -36,7 +38,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); } @@ -142,6 +144,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); @@ -171,24 +182,62 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) { setFromAddrInfo(results.info); } -void SocketAddress::setFromPath(const char* path, size_t len) { +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'; } } @@ -220,12 +269,8 @@ void SocketAddress::setFromSockaddr(const struct sockaddr* address) { "SocketAddress::setFromSockaddr() called " "with unsupported address type"); } - if (external_) { - storage_.un.free(); - external_ = false; - } - storage_.addr = folly::IPAddress(address); - port_ = port; + + setFromIpAddrPort(folly::IPAddress(address), port); } void SocketAddress::setFromSockaddr(const struct sockaddr* address, @@ -281,8 +326,11 @@ void SocketAddress::setFromSockaddr(const struct sockaddr_un* address, "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 @@ -318,26 +366,27 @@ socklen_t SocketAddress::getActualSize() const { } 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'; } @@ -410,12 +459,13 @@ 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 { @@ -429,9 +479,9 @@ std::string SocketAddress::describe() const { return ""; } - 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()))); } switch (getFamily()) { case AF_UNSPEC: @@ -477,9 +527,10 @@ bool SocketAddress::operator==(const SocketAddress& other) const { 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()); + int cmp = memcmp( + storage_.un.addr->sun_path, + other.storage_.un.addr->sun_path, + size_t(storage_.un.pathLength())); return cmp == 0; } @@ -500,11 +551,11 @@ bool SocketAddress::prefixMatch(const SocketAddress& other, if (other.getFamily() != getFamily()) { return false; } - int mask_length = 128; + uint8_t mask_length = 128; switch (getFamily()) { case AF_INET: mask_length = 32; - // fallthrough + FOLLY_FALLTHROUGH; case AF_INET6: { auto prefix = folly::IPAddress::longestCommonPrefix( @@ -524,10 +575,10 @@ size_t SocketAddress::hash() const { if (external_) { enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) }; const char *path = storage_.un.addr->sun_path; - size_t pathLength = storage_.un.pathLength(); + auto 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])); + for (off_t n = 0; n < pathLength; ++n) { + boost::hash_combine(seed, folly::hash::twang_mix64(uint64_t(path[n]))); } } @@ -583,7 +634,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) { @@ -591,17 +642,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*)) { +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); @@ -656,9 +708,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); } } @@ -673,11 +726,11 @@ bool SocketAddress::operator<(const SocketAddress& other) const { // // 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(); + auto thisPathLength = storage_.un.pathLength(); if (thisPathLength == 0) { return false; } - size_t otherPathLength = other.storage_.un.pathLength(); + auto otherPathLength = other.storage_.un.pathLength(); if (otherPathLength == 0) { return true; } @@ -686,9 +739,10 @@ bool SocketAddress::operator<(const SocketAddress& other) const { if (thisPathLength != otherPathLength) { return thisPathLength < otherPathLength; } - int cmp = memcmp(storage_.un.addr->sun_path, - other.storage_.un.addr->sun_path, - thisPathLength); + int cmp = memcmp( + storage_.un.addr->sun_path, + other.storage_.un.addr->sun_path, + size_t(thisPathLength)); return cmp < 0; } switch (getFamily()) {