From c8f4d603e448cdd2749f2850ef70952932962fa1 Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Sat, 9 Jul 2016 02:40:45 -0700 Subject: [PATCH] Move IPAddress definitions to source files Summary: [Folly] Move `IPAddress` definitions to source files. And to internal header files. Keeping headers lightweight can help with build times. Reviewed By: simpkins Differential Revision: D3514455 fbshipit-source-id: de78f4ef9e70e7ddd7fb666348ed705c5228531c --- folly/Conv.h | 8 - folly/IPAddress.cpp | 51 ++++-- folly/IPAddress.h | 40 +++-- folly/IPAddressException.h | 41 ++--- folly/IPAddressV4.cpp | 33 ++-- folly/IPAddressV4.h | 35 ++-- folly/IPAddressV6.cpp | 38 ++-- folly/IPAddressV6.h | 35 ++-- folly/MacAddress.cpp | 2 + folly/MacAddress.h | 27 ++- folly/Makefile.am | 2 + folly/Range.h | 8 + folly/SocketAddress.cpp | 2 + folly/SocketAddress.h | 2 +- folly/detail/IPAddress.cpp | 35 ++++ folly/detail/IPAddress.h | 258 +-------------------------- folly/detail/IPAddressSource.h | 257 ++++++++++++++++++++++++++ folly/io/async/AsyncServerSocket.cpp | 1 + folly/io/async/test/SocketClient.cpp | 2 + folly/test/IPAddressTest.cpp | 3 +- folly/test/MacAddressTest.cpp | 1 + folly/test/SocketAddressTest.cpp | 2 + 22 files changed, 524 insertions(+), 359 deletions(-) create mode 100644 folly/detail/IPAddress.cpp create mode 100644 folly/detail/IPAddressSource.h diff --git a/folly/Conv.h b/folly/Conv.h index 0af04cf6..df34f2fa 100644 --- a/folly/Conv.h +++ b/folly/Conv.h @@ -357,14 +357,6 @@ estimateSpaceNeeded(T) { return 1; } -/** - * Ubiquitous helper template for writing string appenders - */ -template struct IsSomeString { - enum { value = std::is_same::value - || std::is_same::value }; -}; - /** * Everything implicitly convertible to const char* gets appended. */ diff --git a/folly/IPAddress.cpp b/folly/IPAddress.cpp index 9fa6c59d..c4a51007 100644 --- a/folly/IPAddress.cpp +++ b/folly/IPAddress.cpp @@ -21,7 +21,9 @@ #include #include +#include #include +#include using std::ostream; using std::string; @@ -79,9 +81,12 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr, if (elemCount == 0 || // weird invalid string elemCount > 2) { // invalid string (IP/CIDR/extras) - throw IPAddressFormatException("Invalid ipSlashCidr specified. ", - "Expected IP/CIDR format, got ", - "'", ipSlashCidr, "'"); + throw IPAddressFormatException(to( + "Invalid ipSlashCidr specified. ", + "Expected IP/CIDR format, got ", + "'", + ipSlashCidr, + "'")); } IPAddress subnet(vec.at(0)); uint8_t cidr = (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128); @@ -90,18 +95,28 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr, try { cidr = to(vec.at(1)); } catch (...) { - throw IPAddressFormatException("Mask value ", - "'", vec.at(1), "' not a valid mask"); + throw IPAddressFormatException( + to("Mask value ", "'", vec.at(1), "' not a valid mask")); } } if (cidr > subnet.bitCount()) { - throw IPAddressFormatException("CIDR value '", cidr, "' ", - "is > network bit count ", - "'", subnet.bitCount(), "'"); + throw IPAddressFormatException(to( + "CIDR value '", + cidr, + "' ", + "is > network bit count ", + "'", + subnet.bitCount(), + "'")); } return std::make_pair(applyMask ? subnet.mask(cidr) : subnet, cidr); } +// public static +std::string IPAddress::networkToString(const CIDRNetwork& network) { + return network.first.str() + "/" + folly::to(network.second); +} + // public static IPAddress IPAddress::fromBinary(ByteRange bytes) { if (bytes.size() == 4) { @@ -110,8 +125,8 @@ IPAddress IPAddress::fromBinary(ByteRange bytes) { return IPAddress(IPAddressV6::fromBinary(bytes)); } else { string hexval = detail::Bytes::toHex(bytes.data(), bytes.size()); - throw IPAddressFormatException("Invalid address with hex value ", - "'", hexval, "'"); + throw IPAddressFormatException( + to("Invalid address with hex value ", "'", hexval, "'")); } } @@ -137,7 +152,8 @@ IPAddress::IPAddress(StringPiece addr) { string ip = addr.str(); // inet_pton() needs NUL-terminated string auto throwFormatException = [&](const string& msg) { - throw IPAddressFormatException("Invalid IP '", ip, "': ", msg); + throw IPAddressFormatException( + to("Invalid IP '", ip, "': ", msg)); }; if (ip.size() < 2) { @@ -406,4 +422,17 @@ IPAddress::longestCommonPrefix(const CIDRNetwork& one, const CIDRNetwork& two) { return {IPAddress(0), 0}; } +[[noreturn]] void IPAddress::asV4Throw() const { + auto fam = detail::familyNameStr(family()); + throw InvalidAddressFamilyException(to( + "Can't convert address with family ", fam, " to AF_INET address")); +} + +[[noreturn]] void IPAddress::asV6Throw() const { + auto fam = detail::familyNameStr(family()); + throw InvalidAddressFamilyException(to( + "Can't convert address with family ", fam, " to AF_INET6 address")); +} + + } // folly diff --git a/folly/IPAddress.h b/folly/IPAddress.h index c5f31c77..df21342e 100644 --- a/folly/IPAddress.h +++ b/folly/IPAddress.h @@ -17,15 +17,11 @@ #pragma once #include -#include +#include #include #include #include // std::pair -#include - -#include -#include #include #include #include @@ -68,7 +64,7 @@ typedef std::pair CIDRNetwork; * CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6()); * @encode */ -class IPAddress : boost::totally_ordered { +class IPAddress { public: // returns true iff the input string can be parsed as an ip-address static bool validate(StringPiece ip); @@ -101,9 +97,7 @@ class IPAddress : boost::totally_ordered { * * @return string representing the netblock */ - static std::string networkToString(const CIDRNetwork& network) { - return network.first.str() + "/" + folly::to(network.second); - } + static std::string networkToString(const CIDRNetwork& network); /** * Create a new IPAddress instance from the provided binary data @@ -170,10 +164,8 @@ class IPAddress : boost::totally_ordered { * @throws IPAddressFormatException is not a V4 instance */ const IPAddressV4& asV4() const { - if (!isV4()) { - auto familyName = detail::familyNameStr(family()); - throw InvalidAddressFamilyException("Can't convert address with family ", - familyName, " to AF_INET address"); + if (UNLIKELY(!isV4())) { + asV4Throw(); } return addr_.ipV4Addr; } @@ -183,10 +175,8 @@ class IPAddress : boost::totally_ordered { * @throws InvalidAddressFamilyException is not a V6 instance */ const IPAddressV6& asV6() const { - if (!isV6()) { - auto familyName = detail::familyNameStr(family()); - throw InvalidAddressFamilyException("Can't convert address with family ", - familyName, " to AF_INET6 address"); + if (UNLIKELY(!isV6())) { + asV6Throw(); } return addr_.ipV6Addr; } @@ -411,6 +401,9 @@ class IPAddress : boost::totally_ordered { } private: + [[noreturn]] void asV4Throw() const; + [[noreturn]] void asV6Throw() const; + typedef union IPAddressV46 { IPAddressV4 ipV4Addr; IPAddressV6 ipV6Addr; @@ -444,6 +437,19 @@ void toAppend(IPAddress addr, fbstring* result); bool operator==(const IPAddress& addr1, const IPAddress& addr2); // Return true if addr1 < addr2 bool operator<(const IPAddress& addr1, const IPAddress& addr2); +// Derived operators +inline bool operator!=(const IPAddress& a, const IPAddress& b) { + return !(a == b); +} +inline bool operator>(const IPAddress& a, const IPAddress& b) { + return b < a; +} +inline bool operator<=(const IPAddress& a, const IPAddress& b) { + return !(a > b); +} +inline bool operator>=(const IPAddress& a, const IPAddress& b) { + return !(a < b); +} } // folly diff --git a/folly/IPAddressException.h b/folly/IPAddressException.h index 9ef8ca85..1b5253ea 100644 --- a/folly/IPAddressException.h +++ b/folly/IPAddressException.h @@ -18,8 +18,8 @@ #include #include +#include -#include #include namespace folly { @@ -29,13 +29,13 @@ namespace folly { */ class IPAddressFormatException : public std::exception { public: - explicit IPAddressFormatException(const std::string& msg) - : msg_(msg) {} - IPAddressFormatException( - const IPAddressFormatException&) = default; - template - explicit IPAddressFormatException(Args&&... args) - : msg_(to(std::forward(args)...)) {} + explicit IPAddressFormatException(std::string msg) noexcept + : msg_(std::move(msg)) {} + IPAddressFormatException(const IPAddressFormatException&) = default; + IPAddressFormatException(IPAddressFormatException&&) = default; + IPAddressFormatException& operator=(const IPAddressFormatException&) = + default; + IPAddressFormatException& operator=(IPAddressFormatException&&) = default; virtual ~IPAddressFormatException() noexcept {} virtual const char *what(void) const noexcept { @@ -43,22 +43,23 @@ class IPAddressFormatException : public std::exception { } private: - const std::string msg_; + std::string msg_; }; class InvalidAddressFamilyException : public IPAddressFormatException { public: - explicit InvalidAddressFamilyException(const std::string& msg) - : IPAddressFormatException(msg) {} - InvalidAddressFamilyException( - const InvalidAddressFamilyException&) = default; - explicit InvalidAddressFamilyException(sa_family_t family) - : IPAddressFormatException("Address family " + - detail::familyNameStr(family) + - " is not AF_INET or AF_INET6") {} - template - explicit InvalidAddressFamilyException(Args&&... args) - : IPAddressFormatException(std::forward(args)...) {} + explicit InvalidAddressFamilyException(std::string msg) noexcept + : IPAddressFormatException(std::move(msg)) {} + explicit InvalidAddressFamilyException(sa_family_t family) noexcept + : InvalidAddressFamilyException( + "Address family " + detail::familyNameStr(family) + + " is not AF_INET or AF_INET6") {} + InvalidAddressFamilyException(const InvalidAddressFamilyException&) = default; + InvalidAddressFamilyException(InvalidAddressFamilyException&&) = default; + InvalidAddressFamilyException& operator=( + const InvalidAddressFamilyException&) = default; + InvalidAddressFamilyException& operator=(InvalidAddressFamilyException&&) = + default; }; } // folly diff --git a/folly/IPAddressV4.cpp b/folly/IPAddressV4.cpp index ff44cee8..b8a0e0e2 100644 --- a/folly/IPAddressV4.cpp +++ b/folly/IPAddressV4.cpp @@ -22,6 +22,7 @@ #include #include #include +#include using std::ostream; using std::string; @@ -72,8 +73,8 @@ uint32_t IPAddressV4::toLong(StringPiece ip) { auto str = ip.str(); in_addr addr; if (inet_pton(AF_INET, str.c_str(), &addr) != 1) { - throw IPAddressFormatException("Can't convert invalid IP '", ip, "' ", - "to long"); + throw IPAddressFormatException( + to("Can't convert invalid IP '", ip, "' ", "to long")); } return addr.s_addr; } @@ -99,7 +100,8 @@ IPAddressV4::IPAddressV4(StringPiece addr) { auto ip = addr.str(); if (inet_pton(AF_INET, ip.c_str(), &addr_.inAddr_) != 1) { - throw IPAddressFormatException("Invalid IPv4 address '", addr, "'"); + throw IPAddressFormatException( + to("Invalid IPv4 address '", addr, "'")); } } @@ -112,8 +114,10 @@ IPAddressV4::IPAddressV4(const in_addr src) // public void IPAddressV4::setFromBinary(ByteRange bytes) { if (bytes.size() != 4) { - throw IPAddressFormatException("Invalid IPv4 binary data: length must " - "be 4 bytes, got ", bytes.size()); + throw IPAddressFormatException(to( + "Invalid IPv4 binary data: length must ", + "be 4 bytes, got ", + bytes.size())); } memcpy(&addr_.inAddr_.s_addr, bytes.data(), sizeof(in_addr)); } @@ -147,8 +151,8 @@ bool IPAddressV4::inSubnet(StringPiece cidrNetwork) const { auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto addr = subnetInfo.first; if (!addr.isV4()) { - throw IPAddressFormatException("Address '", addr.toJson(), "' ", - "is not a V4 address"); + throw IPAddressFormatException(to( + "Address '", addr.toJson(), "' ", "is not a V4 address")); } return inSubnetWithMask(addr.asV4(), fetchMask(subnetInfo.second)); } @@ -207,8 +211,8 @@ bool IPAddressV4::isMulticast() const { IPAddressV4 IPAddressV4::mask(size_t numBits) const { static const auto bits = bitCount(); if (numBits > bits) { - throw IPAddressFormatException("numBits(", numBits, - ") > bitsCount(", bits, ")"); + throw IPAddressFormatException( + to("numBits(", numBits, ") > bitsCount(", bits, ")")); } ByteArray4 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); @@ -234,11 +238,20 @@ uint8_t IPAddressV4::getNthMSByte(size_t byteIndex) const { const ByteArray4 IPAddressV4::fetchMask(size_t numBits) { static const uint8_t bits = bitCount(); if (numBits > bits) { - throw IPAddressFormatException("IPv4 addresses are 32 bits"); + throw IPAddressFormatException( + to("IPv4 addresses are 32 bits")); } // masks_ is backed by an array so is zero indexed return masks_[numBits]; } +// public static +CIDRNetworkV4 IPAddressV4::longestCommonPrefix( + const CIDRNetworkV4& one, + const CIDRNetworkV4& two) { + auto prefix = detail::Bytes::longestCommonPrefix( + one.first.addr_.bytes_, one.second, two.first.addr_.bytes_, two.second); + return {IPAddressV4(prefix.first), prefix.second}; +} // static private const std::array IPAddressV4::masks_ = {{ diff --git a/folly/IPAddressV4.h b/folly/IPAddressV4.h index fa4d46d2..7d310668 100644 --- a/folly/IPAddressV4.h +++ b/folly/IPAddressV4.h @@ -16,10 +16,11 @@ #pragma once -#include -#include +#include -#include +#include +#include +#include #include #include @@ -51,7 +52,7 @@ typedef std::array ByteArray4; * * @see IPAddress */ -class IPAddressV4 : boost::totally_ordered { +class IPAddressV4 { public: // returns true iff the input string can be parsed as an ipv4-address static bool validate(StringPiece ip); @@ -168,7 +169,8 @@ class IPAddressV4 : boost::totally_ordered { // @see IPAddress#isZero bool isZero() const { - return detail::Bytes::isZero(bytes(), 4); + constexpr auto zero = ByteArray4{{}}; + return 0 == std::memcmp(bytes(), zero.data(), zero.size()); } bool isLinkLocalBroadcast() const { @@ -214,15 +216,11 @@ class IPAddressV4 : boost::totally_ordered { */ static const ByteArray4 fetchMask(size_t numBits); - // Given 2 IPAddressV4,mask pairs extract the longest common IPAddress, + // Given 2 IPAddressV4, mask pairs extract the longest common IPAddress, // mask pair static CIDRNetworkV4 longestCommonPrefix( - const CIDRNetworkV4& one, const CIDRNetworkV4& two) { - auto prefix = - detail::Bytes::longestCommonPrefix(one.first.addr_.bytes_, one.second, - two.first.addr_.bytes_, two.second); - return {IPAddressV4(prefix.first), prefix.second}; - } + const CIDRNetworkV4& one, + const CIDRNetworkV4& two); // Number of bytes in the address representation. static size_t byteCount() { return 4; } //get nth most significant bit - 0 indexed @@ -282,6 +280,19 @@ inline bool operator==(const IPAddressV4& addr1, const IPAddressV4& addr2) { inline bool operator<(const IPAddressV4& addr1, const IPAddressV4& addr2) { return (addr1.toLongHBO() < addr2.toLongHBO()); } +// Derived operators +inline bool operator!=(const IPAddressV4& a, const IPAddressV4& b) { + return !(a == b); +} +inline bool operator>(const IPAddressV4& a, const IPAddressV4& b) { + return b < a; +} +inline bool operator<=(const IPAddressV4& a, const IPAddressV4& b) { + return !(a > b); +} +inline bool operator>=(const IPAddressV4& a, const IPAddressV4& b) { + return !(a < b); +} } // folly diff --git a/folly/IPAddressV6.cpp b/folly/IPAddressV6.cpp index d0927882..9904c406 100644 --- a/folly/IPAddressV6.cpp +++ b/folly/IPAddressV6.cpp @@ -23,6 +23,7 @@ #include #include #include +#include using std::ostream; using std::string; @@ -72,8 +73,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) { // Allow addresses surrounded in brackets if (ip.size() < 2) { - throw IPAddressFormatException("Invalid IPv6 address '", ip, - "': address too short"); + throw IPAddressFormatException( + to("Invalid IPv6 address '", ip, "': address too short")); } if (ip.front() == '[' && ip.back() == ']') { ip = ip.substr(1, ip.size() - 2); @@ -91,7 +92,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) { scope_ = ipAddr->sin6_scope_id; freeaddrinfo(result); } else { - throw IPAddressFormatException("Invalid IPv6 address '", ip, "'"); + throw IPAddressFormatException( + to("Invalid IPv6 address '", ip, "'")); } } @@ -136,8 +138,10 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { void IPAddressV6::setFromBinary(ByteRange bytes) { if (bytes.size() != 16) { - throw IPAddressFormatException("Invalid IPv6 binary data: length must " - "be 16 bytes, got ", bytes.size()); + throw IPAddressFormatException(to( + "Invalid IPv6 binary data: length must ", + "be 16 bytes, got ", + bytes.size())); } memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr)); scope_ = 0; @@ -252,8 +256,8 @@ bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const { auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto addr = subnetInfo.first; if (!addr.isV6()) { - throw IPAddressFormatException("Address '", addr.toJson(), "' ", - "is not a V6 address"); + throw IPAddressFormatException(to( + "Address '", addr.toJson(), "' ", "is not a V6 address")); } return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second)); } @@ -336,8 +340,8 @@ IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const { IPAddressV6 IPAddressV6::mask(size_t numBits) const { static const auto bits = bitCount(); if (numBits > bits) { - throw IPAddressFormatException("numBits(", numBits, ") > bitCount(", - bits, ")"); + throw IPAddressFormatException( + to("numBits(", numBits, ") > bitCount(", bits, ")")); } ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); return IPAddressV6(ba); @@ -354,8 +358,11 @@ string IPAddressV6::str() const { string ip(buffer); return ip; } else { - throw IPAddressFormatException("Invalid address with hex ", - "'", detail::Bytes::toHex(bytes(), 16), "'"); + throw IPAddressFormatException(to( + "Invalid address with hex ", + "'", + detail::Bytes::toHex(bytes(), 16), + "'")); } } @@ -385,6 +392,15 @@ const ByteArray16 IPAddressV6::fetchMask(size_t numBits) { return masks_[numBits]; } +// public static +CIDRNetworkV6 IPAddressV6::longestCommonPrefix( + const CIDRNetworkV6& one, + const CIDRNetworkV6& two) { + auto prefix = detail::Bytes::longestCommonPrefix( + one.first.addr_.bytes_, one.second, two.first.addr_.bytes_, two.second); + return {IPAddressV6(prefix.first), prefix.second}; +} + // protected bool IPAddressV6::inBinarySubnet(const std::array addr, size_t numBits) const { diff --git a/folly/IPAddressV6.h b/folly/IPAddressV6.h index 703f9da7..db70d093 100644 --- a/folly/IPAddressV6.h +++ b/folly/IPAddressV6.h @@ -16,13 +16,14 @@ #pragma once +#include + +#include #include -#include +#include #include #include -#include - #include #include #include @@ -63,7 +64,7 @@ typedef std::array ByteArray16; * Serializing / Deserializing IPAddressB6's on different hosts * that use link-local scoping probably won't work. */ -class IPAddressV6 : boost::totally_ordered { +class IPAddressV6 { public: // V6 Address Type enum Type { @@ -227,7 +228,8 @@ class IPAddressV6 : boost::totally_ordered { // @see IPAddress#isZero bool isZero() const { - return detail::Bytes::isZero(bytes(), 16); + constexpr auto zero = ByteArray16{{}}; + return 0 == std::memcmp(bytes(), zero.data(), zero.size()); } bool isLinkLocalBroadcast() const; @@ -283,13 +285,9 @@ class IPAddressV6 : boost::totally_ordered { static const ByteArray16 fetchMask(size_t numBits); // Given 2 IPAddressV6,mask pairs extract the longest common IPAddress, // mask pair - static CIDRNetworkV6 longestCommonPrefix(const CIDRNetworkV6& one, - const CIDRNetworkV6& two) { - auto prefix = detail::Bytes::longestCommonPrefix( - one.first.addr_.bytes_, one.second, - two.first.addr_.bytes_, two.second); - return {IPAddressV6(prefix.first), prefix.second}; - } + static CIDRNetworkV6 longestCommonPrefix( + const CIDRNetworkV6& one, + const CIDRNetworkV6& two); // Number of bytes in the address representation. static constexpr size_t byteCount() { return 16; } @@ -367,6 +365,19 @@ inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) { return cmp; } } +// Derived operators +inline bool operator!=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a == b); +} +inline bool operator>(const IPAddressV6& a, const IPAddressV6& b) { + return b < a; +} +inline bool operator<=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a > b); +} +inline bool operator>=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a < b); +} } // folly diff --git a/folly/MacAddress.cpp b/folly/MacAddress.cpp index f458138f..bdc54a3a 100644 --- a/folly/MacAddress.cpp +++ b/folly/MacAddress.cpp @@ -16,6 +16,8 @@ #include +#include + #include #include diff --git a/folly/MacAddress.h b/folly/MacAddress.h index 49852edb..309a427b 100644 --- a/folly/MacAddress.h +++ b/folly/MacAddress.h @@ -16,12 +16,10 @@ #pragma once -#include - -#include +#include #include -#include +#include namespace folly { @@ -30,7 +28,7 @@ class IPAddressV6; /* * MacAddress represents an IEEE 802 MAC address. */ -class MacAddress : private boost::totally_ordered { +class MacAddress { public: static constexpr size_t SIZE = 6; static const MacAddress BROADCAST; @@ -167,8 +165,7 @@ class MacAddress : private boost::totally_ordered { return getByte(0) & 0x2; } - // Equality and less-than operators. - // boost::totally_ordered provides the other comparison operators. + // Comparison operators. bool operator==(const MacAddress& other) const { // All constructors and modifying methods make sure padding is 0, @@ -180,6 +177,22 @@ class MacAddress : private boost::totally_ordered { return u64HBO() < other.u64HBO(); } + bool operator!=(const MacAddress& other) const { + return !(*this == other); + } + + bool operator>(const MacAddress& other) const { + return other < *this; + } + + bool operator>=(const MacAddress& other) const { + return !(*this < other); + } + + bool operator<=(const MacAddress& other) const { + return !(*this > other); + } + private: explicit MacAddress(uint64_t valueNBO) { memcpy(&bytes_, &valueNBO, 8); diff --git a/folly/Makefile.am b/folly/Makefile.am index 381bd1bb..69559225 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -63,6 +63,7 @@ nobase_follyinclude_HEADERS = \ detail/Futex.h \ detail/GroupVarintDetail.h \ detail/IPAddress.h \ + detail/IPAddressSource.h \ detail/Malloc.h \ detail/MemoryIdler.h \ detail/MPMCPipelineDetail.h \ @@ -363,6 +364,7 @@ libfolly_la_SOURCES = \ Bits.cpp \ Checksum.cpp \ detail/CacheLocality.cpp \ + detail/IPAddress.cpp \ dynamic.cpp \ File.cpp \ FileUtil.cpp \ diff --git a/folly/Range.h b/folly/Range.h index e4be2b06..0b63f457 100644 --- a/folly/Range.h +++ b/folly/Range.h @@ -1162,6 +1162,14 @@ struct hasher, } }; +/** + * Ubiquitous helper template for knowing what's a string + */ +template struct IsSomeString { + enum { value = std::is_same::value + || std::is_same::value }; +}; + } // !namespace folly #pragma GCC diagnostic pop diff --git a/folly/SocketAddress.cpp b/folly/SocketAddress.cpp index dbeff61b..6a13554a 100644 --- a/folly/SocketAddress.cpp +++ b/folly/SocketAddress.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include namespace { diff --git a/folly/SocketAddress.h b/folly/SocketAddress.h index d48f3ccc..688dcf92 100644 --- a/folly/SocketAddress.h +++ b/folly/SocketAddress.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/folly/detail/IPAddress.cpp b/folly/detail/IPAddress.cpp new file mode 100644 index 00000000..85fa0930 --- /dev/null +++ b/folly/detail/IPAddress.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace folly { namespace detail { + +std::string familyNameStrDefault(sa_family_t family) { + return folly::sformat("sa_family_t({})", folly::to(family)); +} + +[[noreturn]] void getNthMSBitImplThrow(size_t bitCount, sa_family_t family) { + throw std::invalid_argument(folly::to( + "Bit index must be < ", + bitCount, + " for addresses of type :", + familyNameStr(family))); +} + +}} diff --git a/folly/detail/IPAddress.h b/folly/detail/IPAddress.h index b92ce657..3abaefc3 100644 --- a/folly/detail/IPAddress.h +++ b/folly/detail/IPAddress.h @@ -16,32 +16,14 @@ #pragma once -#include -#include - -#include -#include -#include #include -#include -#include -#include #include - -#include -#include #include -// BSDish platforms don't provide standard access to s6_addr16 -#ifndef s6_addr16 -# if defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) -# define s6_addr16 __u6_addr.__u6_addr16 -# endif -#endif - namespace folly { namespace detail { +std::string familyNameStrDefault(sa_family_t family); + inline std::string familyNameStr(sa_family_t family) { switch (family) { case AF_INET: @@ -53,242 +35,20 @@ inline std::string familyNameStr(sa_family_t family) { case AF_UNIX: return "AF_UNIX"; default: - return folly::format("sa_family_t({})", - folly::to(family)).str(); + return familyNameStrDefault(family); } } -template -inline bool getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex, - sa_family_t family) { +[[noreturn]] void getNthMSBitImplThrow(size_t bitCount, sa_family_t family); + +template +inline bool +getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex, sa_family_t family) { if (bitIndex >= ip.bitCount()) { - throw std::invalid_argument(folly::to("Bit index must be < ", - ip.bitCount(), " for addresses of type :", familyNameStr(family))); + getNthMSBitImplThrow(ip.bitCount(), family); } //Underlying bytes are in n/w byte order return (ip.getNthMSByte(bitIndex / 8) & (0x80 >> (bitIndex % 8))) != 0; } -/** - * Helper for working with unsigned char* or uint8_t* ByteArray values - */ -struct Bytes : private boost::noncopyable { - // return true if all values of src are zero - static bool isZero(const uint8_t* src, std::size_t len) { - for (std::size_t i = 0; i < len; i++) { - if (src[i] != 0x00) { - return false; - } - } - return true; - } - - // mask the values from two byte arrays, returning a new byte array - template - static std::array mask(const std::array& a, - const std::array& b) { - static_assert(N > 0, "Can't mask an empty ByteArray"); - std::size_t asize = a.size(); - std::array ba{{0}}; - for (std::size_t i = 0; i < asize; i++) { - ba[i] = a[i] & b[i]; - } - return ba; - } - - template - static std::pair, uint8_t> - longestCommonPrefix( - const std::array& one, uint8_t oneMask, - const std::array& two, uint8_t twoMask) { - static constexpr auto kBitCount = N * 8; - static constexpr std::array kMasks {{ - 0x80, // /1 - 0xc0, // /2 - 0xe0, // /3 - 0xf0, // /4 - 0xf8, // /5 - 0xfc, // /6 - 0xfe, // /7 - 0xff // /8 - }}; - if (oneMask > kBitCount || twoMask > kBitCount) { - throw std::invalid_argument(folly::to("Invalid mask " - "length: ", oneMask > twoMask ? oneMask : twoMask, - ". Mask length must be <= ", kBitCount)); - } - - auto mask = std::min(oneMask, twoMask); - uint8_t byteIndex = 0; - std::array ba{{0}}; - // Compare a byte at a time. Note - I measured compared this with - // going multiple bytes at a time (8, 4, 2 and 1). It turns out - // to be 20 - 25% slower for 4 and 16 byte arrays. - while (byteIndex * 8 < mask && one[byteIndex] == two[byteIndex]) { - ba[byteIndex] = one[byteIndex]; - ++byteIndex; - } - auto bitIndex = std::min(mask, (uint8_t)(byteIndex * 8)); - // Compute the bit up to which the two byte arrays match in the - // unmatched byte. - // Here the check is bitIndex < mask since the 0th mask entry in - // kMasks array holds the mask for masking the MSb in this byte. - // We could instead make it hold so that no 0th entry masks no - // bits but thats a useless iteration. - while (bitIndex < mask && ((one[bitIndex / 8] & kMasks[bitIndex % 8]) == - (two[bitIndex / 8] & kMasks[bitIndex % 8]))) { - ba[bitIndex / 8] = one[bitIndex / 8] & kMasks[bitIndex % 8]; - ++bitIndex; - } - return {ba, bitIndex}; - } - - // create an in_addr from an uint8_t* - static inline in_addr mkAddress4(const uint8_t* src) { - union { - in_addr addr; - uint8_t bytes[4]; - } addr; - std::memset(&addr, 0, 4); - std::memcpy(addr.bytes, src, 4); - return addr.addr; - } - - // create an in6_addr from an uint8_t* - static inline in6_addr mkAddress6(const uint8_t* src) { - in6_addr addr; - std::memset(&addr, 0, 16); - std::memcpy(addr.s6_addr, src, 16); - return addr; - } - - // convert an uint8_t* to its hex value - static std::string toHex(const uint8_t* src, std::size_t len) { - static const char* const lut = "0123456789abcdef"; - std::stringstream ss; - for (std::size_t i = 0; i < len; i++) { - const unsigned char c = src[i]; - ss << lut[c >> 4] << lut[c & 15]; - } - return ss.str(); - } - - private: - Bytes() = delete; - ~Bytes() = delete; -}; - -// -// Write a maximum amount of base-converted character digits, of a -// given base, from an unsigned integral type into a byte buffer of -// sufficient size. -// -// This function does not append null terminators. -// -// Output buffer size must be guaranteed by caller (indirectly -// controlled by DigitCount template parameter). -// -// Having these parameters at compile time allows compiler to -// precompute several of the values, use smaller instructions, and -// better optimize surrounding code. -// -// IntegralType: -// - Something like uint8_t, uint16_t, etc -// -// DigitCount is the maximum number of digits to be printed -// - This is tied to IntegralType and Base. For example: -// - uint8_t in base 10 will print at most 3 digits ("255") -// - uint16_t in base 16 will print at most 4 hex digits ("FFFF") -// -// Base is the desired output base of the string -// - Base 10 will print [0-9], base 16 will print [0-9a-f] -// -// PrintAllDigits: -// - Whether or not leading zeros should be printed -// -template::value && - std::is_unsigned::value, - bool>::type> - inline void writeIntegerString( - IntegralType val, - char** buffer) { - char* buf = *buffer; - - if (!PrintAllDigits && val == 0) { - *(buf++) = '0'; - *buffer = buf; - return; - } - - IntegralType powerToPrint = 1; - for (int i = 1; i < DigitCount; ++i) { - powerToPrint *= Base; - } - - bool found = PrintAllDigits; - while (powerToPrint) { - - if (found || powerToPrint <= val) { - IntegralType value = val/powerToPrint; - if (Base == 10 || value < 10) { - value += '0'; - } else { - value += ('a'-10); - } - *(buf++) = value; - val %= powerToPrint; - found = true; - } - - powerToPrint /= Base; - } - - *buffer = buf; -} - -inline std::string fastIpv4ToString( - const in_addr& inAddr) { - const uint8_t* octets = reinterpret_cast(&inAddr.s_addr); - char str[sizeof("255.255.255.255")]; - char* buf = str; - - writeIntegerString(octets[0], &buf); - *(buf++) = '.'; - writeIntegerString(octets[1], &buf); - *(buf++) = '.'; - writeIntegerString(octets[2], &buf); - *(buf++) = '.'; - writeIntegerString(octets[3], &buf); - - return std::string(str, buf-str); -} - -inline std::string fastIpv6ToString(const in6_addr& in6Addr) { -#ifdef _MSC_VER - const uint16_t* bytes = reinterpret_cast(&in6Addr.u.Word); -#else - const uint16_t* bytes = reinterpret_cast(&in6Addr.s6_addr16); -#endif - char str[sizeof("2001:0db8:0000:0000:0000:ff00:0042:8329")]; - char* buf = str; - - for (int i = 0; i < 8; ++i) { - writeIntegerString(htons(bytes[i]), &buf); - - if(i != 7) { - *(buf++) = ':'; - } - } - - return std::string(str, buf-str); -} - }} // folly::detail diff --git a/folly/detail/IPAddressSource.h b/folly/detail/IPAddressSource.h new file mode 100644 index 00000000..e8a18110 --- /dev/null +++ b/folly/detail/IPAddressSource.h @@ -0,0 +1,257 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// BSDish platforms don't provide standard access to s6_addr16 +#ifndef s6_addr16 +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#endif + +namespace folly { +namespace detail { + +/** + * Helper for working with unsigned char* or uint8_t* ByteArray values + */ +struct Bytes { + // mask the values from two byte arrays, returning a new byte array + template + static std::array mask( + const std::array& a, + const std::array& b) { + static_assert(N > 0, "Can't mask an empty ByteArray"); + std::size_t asize = a.size(); + std::array ba{{0}}; + for (std::size_t i = 0; i < asize; i++) { + ba[i] = a[i] & b[i]; + } + return ba; + } + + template + static std::pair, uint8_t> longestCommonPrefix( + const std::array& one, + uint8_t oneMask, + const std::array& two, + uint8_t twoMask) { + static constexpr auto kBitCount = N * 8; + static constexpr std::array kMasks{{ + 0x80, // /1 + 0xc0, // /2 + 0xe0, // /3 + 0xf0, // /4 + 0xf8, // /5 + 0xfc, // /6 + 0xfe, // /7 + 0xff // /8 + }}; + if (oneMask > kBitCount || twoMask > kBitCount) { + throw std::invalid_argument(folly::to( + "Invalid mask " + "length: ", + oneMask > twoMask ? oneMask : twoMask, + ". Mask length must be <= ", + kBitCount)); + } + + auto mask = std::min(oneMask, twoMask); + uint8_t byteIndex = 0; + std::array ba{{0}}; + // Compare a byte at a time. Note - I measured compared this with + // going multiple bytes at a time (8, 4, 2 and 1). It turns out + // to be 20 - 25% slower for 4 and 16 byte arrays. + while (byteIndex * 8 < mask && one[byteIndex] == two[byteIndex]) { + ba[byteIndex] = one[byteIndex]; + ++byteIndex; + } + auto bitIndex = std::min(mask, (uint8_t)(byteIndex * 8)); + // Compute the bit up to which the two byte arrays match in the + // unmatched byte. + // Here the check is bitIndex < mask since the 0th mask entry in + // kMasks array holds the mask for masking the MSb in this byte. + // We could instead make it hold so that no 0th entry masks no + // bits but thats a useless iteration. + while (bitIndex < mask && ((one[bitIndex / 8] & kMasks[bitIndex % 8]) == + (two[bitIndex / 8] & kMasks[bitIndex % 8]))) { + ba[bitIndex / 8] = one[bitIndex / 8] & kMasks[bitIndex % 8]; + ++bitIndex; + } + return {ba, bitIndex}; + } + + // create an in_addr from an uint8_t* + static inline in_addr mkAddress4(const uint8_t* src) { + union { + in_addr addr; + uint8_t bytes[4]; + } addr; + std::memset(&addr, 0, 4); + std::memcpy(addr.bytes, src, 4); + return addr.addr; + } + + // create an in6_addr from an uint8_t* + static inline in6_addr mkAddress6(const uint8_t* src) { + in6_addr addr; + std::memset(&addr, 0, 16); + std::memcpy(addr.s6_addr, src, 16); + return addr; + } + + // convert an uint8_t* to its hex value + static std::string toHex(const uint8_t* src, std::size_t len) { + static const char* const lut = "0123456789abcdef"; + std::string out(len * 2, 0); + for (std::size_t i = 0; i < len; i++) { + const unsigned char c = src[i]; + out[i * 2 + 0] = lut[c >> 4]; + out[i + 2 + 1] = lut[c & 15]; + } + return out; + } + + private: + Bytes() = delete; + ~Bytes() = delete; +}; + +// +// Write a maximum amount of base-converted character digits, of a +// given base, from an unsigned integral type into a byte buffer of +// sufficient size. +// +// This function does not append null terminators. +// +// Output buffer size must be guaranteed by caller (indirectly +// controlled by DigitCount template parameter). +// +// Having these parameters at compile time allows compiler to +// precompute several of the values, use smaller instructions, and +// better optimize surrounding code. +// +// IntegralType: +// - Something like uint8_t, uint16_t, etc +// +// DigitCount is the maximum number of digits to be printed +// - This is tied to IntegralType and Base. For example: +// - uint8_t in base 10 will print at most 3 digits ("255") +// - uint16_t in base 16 will print at most 4 hex digits ("FFFF") +// +// Base is the desired output base of the string +// - Base 10 will print [0-9], base 16 will print [0-9a-f] +// +// PrintAllDigits: +// - Whether or not leading zeros should be printed +// +template < + class IntegralType, + IntegralType DigitCount, + IntegralType Base = 10, + bool PrintAllDigits = false, + class = typename std::enable_if< + std::is_integral::value && + std::is_unsigned::value, + bool>::type> +inline void writeIntegerString(IntegralType val, char** buffer) { + char* buf = *buffer; + + if (!PrintAllDigits && val == 0) { + *(buf++) = '0'; + *buffer = buf; + return; + } + + IntegralType powerToPrint = 1; + for (int i = 1; i < DigitCount; ++i) { + powerToPrint *= Base; + } + + bool found = PrintAllDigits; + while (powerToPrint) { + if (found || powerToPrint <= val) { + IntegralType value = val / powerToPrint; + if (Base == 10 || value < 10) { + value += '0'; + } else { + value += ('a' - 10); + } + *(buf++) = value; + val %= powerToPrint; + found = true; + } + + powerToPrint /= Base; + } + + *buffer = buf; +} + +inline std::string fastIpv4ToString(const in_addr& inAddr) { + const uint8_t* octets = reinterpret_cast(&inAddr.s_addr); + char str[sizeof("255.255.255.255")]; + char* buf = str; + + writeIntegerString(octets[0], &buf); + *(buf++) = '.'; + writeIntegerString(octets[1], &buf); + *(buf++) = '.'; + writeIntegerString(octets[2], &buf); + *(buf++) = '.'; + writeIntegerString(octets[3], &buf); + + return std::string(str, buf - str); +} + +inline std::string fastIpv6ToString(const in6_addr& in6Addr) { +#ifdef _MSC_VER + const uint16_t* bytes = reinterpret_cast(&in6Addr.u.Word); +#else + const uint16_t* bytes = reinterpret_cast(&in6Addr.s6_addr16); +#endif + char str[sizeof("2001:0db8:0000:0000:0000:ff00:0042:8329")]; + char* buf = str; + + for (int i = 0; i < 8; ++i) { + writeIntegerString< + uint16_t, + 4, // at most 4 hex digits per ushort + 16, // base 16 (hex) + true>(htons(bytes[i]), &buf); + + if (i != 7) { + *(buf++) = ':'; + } + } + + return std::string(str, buf - str); +} +} +} diff --git a/folly/io/async/AsyncServerSocket.cpp b/folly/io/async/AsyncServerSocket.cpp index bc68a309..f740c2de 100644 --- a/folly/io/async/AsyncServerSocket.cpp +++ b/folly/io/async/AsyncServerSocket.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/folly/io/async/test/SocketClient.cpp b/folly/io/async/test/SocketClient.cpp index 23bef722..957ec9d0 100644 --- a/folly/io/async/test/SocketClient.cpp +++ b/folly/io/async/test/SocketClient.cpp @@ -15,6 +15,8 @@ */ #include +#include + #include #include diff --git a/folly/test/IPAddressTest.cpp b/folly/test/IPAddressTest.cpp index 566a73cf..a8b5e752 100644 --- a/folly/test/IPAddressTest.cpp +++ b/folly/test/IPAddressTest.cpp @@ -20,8 +20,9 @@ #include #include -#include #include +#include +#include using namespace folly; using namespace std; diff --git a/folly/test/MacAddressTest.cpp b/folly/test/MacAddressTest.cpp index d4b833e5..b97ea211 100644 --- a/folly/test/MacAddressTest.cpp +++ b/folly/test/MacAddressTest.cpp @@ -16,6 +16,7 @@ #include +#include #include #include diff --git a/folly/test/SocketAddressTest.cpp b/folly/test/SocketAddressTest.cpp index 07a140ea..20a4fc0f 100644 --- a/folly/test/SocketAddressTest.cpp +++ b/folly/test/SocketAddressTest.cpp @@ -19,6 +19,8 @@ #include #include #include +#include + #include using namespace boost; -- 2.34.1