Commit c8f4d603 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot 2

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
parent 2f9865aa
...@@ -357,14 +357,6 @@ estimateSpaceNeeded(T) { ...@@ -357,14 +357,6 @@ estimateSpaceNeeded(T) {
return 1; return 1;
} }
/**
* Ubiquitous helper template for writing string appenders
*/
template <class T> struct IsSomeString {
enum { value = std::is_same<T, std::string>::value
|| std::is_same<T, fbstring>::value };
};
/** /**
* Everything implicitly convertible to const char* gets appended. * Everything implicitly convertible to const char* gets appended.
*/ */
......
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <folly/Conv.h>
#include <folly/String.h> #include <folly/String.h>
#include <folly/detail/IPAddressSource.h>
using std::ostream; using std::ostream;
using std::string; using std::string;
...@@ -79,9 +81,12 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr, ...@@ -79,9 +81,12 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr,
if (elemCount == 0 || // weird invalid string if (elemCount == 0 || // weird invalid string
elemCount > 2) { // invalid string (IP/CIDR/extras) elemCount > 2) { // invalid string (IP/CIDR/extras)
throw IPAddressFormatException("Invalid ipSlashCidr specified. ", throw IPAddressFormatException(to<std::string>(
"Expected IP/CIDR format, got ", "Invalid ipSlashCidr specified. ",
"'", ipSlashCidr, "'"); "Expected IP/CIDR format, got ",
"'",
ipSlashCidr,
"'"));
} }
IPAddress subnet(vec.at(0)); IPAddress subnet(vec.at(0));
uint8_t cidr = (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128); uint8_t cidr = (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128);
...@@ -90,18 +95,28 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr, ...@@ -90,18 +95,28 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr,
try { try {
cidr = to<uint8_t>(vec.at(1)); cidr = to<uint8_t>(vec.at(1));
} catch (...) { } catch (...) {
throw IPAddressFormatException("Mask value ", throw IPAddressFormatException(
"'", vec.at(1), "' not a valid mask"); to<std::string>("Mask value ", "'", vec.at(1), "' not a valid mask"));
} }
} }
if (cidr > subnet.bitCount()) { if (cidr > subnet.bitCount()) {
throw IPAddressFormatException("CIDR value '", cidr, "' ", throw IPAddressFormatException(to<std::string>(
"is > network bit count ", "CIDR value '",
"'", subnet.bitCount(), "'"); cidr,
"' ",
"is > network bit count ",
"'",
subnet.bitCount(),
"'"));
} }
return std::make_pair(applyMask ? subnet.mask(cidr) : subnet, cidr); 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<std::string>(network.second);
}
// public static // public static
IPAddress IPAddress::fromBinary(ByteRange bytes) { IPAddress IPAddress::fromBinary(ByteRange bytes) {
if (bytes.size() == 4) { if (bytes.size() == 4) {
...@@ -110,8 +125,8 @@ IPAddress IPAddress::fromBinary(ByteRange bytes) { ...@@ -110,8 +125,8 @@ IPAddress IPAddress::fromBinary(ByteRange bytes) {
return IPAddress(IPAddressV6::fromBinary(bytes)); return IPAddress(IPAddressV6::fromBinary(bytes));
} else { } else {
string hexval = detail::Bytes::toHex(bytes.data(), bytes.size()); string hexval = detail::Bytes::toHex(bytes.data(), bytes.size());
throw IPAddressFormatException("Invalid address with hex value ", throw IPAddressFormatException(
"'", hexval, "'"); to<std::string>("Invalid address with hex value ", "'", hexval, "'"));
} }
} }
...@@ -137,7 +152,8 @@ IPAddress::IPAddress(StringPiece addr) ...@@ -137,7 +152,8 @@ IPAddress::IPAddress(StringPiece addr)
{ {
string ip = addr.str(); // inet_pton() needs NUL-terminated string string ip = addr.str(); // inet_pton() needs NUL-terminated string
auto throwFormatException = [&](const string& msg) { auto throwFormatException = [&](const string& msg) {
throw IPAddressFormatException("Invalid IP '", ip, "': ", msg); throw IPAddressFormatException(
to<std::string>("Invalid IP '", ip, "': ", msg));
}; };
if (ip.size() < 2) { if (ip.size() < 2) {
...@@ -406,4 +422,17 @@ IPAddress::longestCommonPrefix(const CIDRNetwork& one, const CIDRNetwork& two) { ...@@ -406,4 +422,17 @@ IPAddress::longestCommonPrefix(const CIDRNetwork& one, const CIDRNetwork& two) {
return {IPAddress(0), 0}; return {IPAddress(0), 0};
} }
[[noreturn]] void IPAddress::asV4Throw() const {
auto fam = detail::familyNameStr(family());
throw InvalidAddressFamilyException(to<std::string>(
"Can't convert address with family ", fam, " to AF_INET address"));
}
[[noreturn]] void IPAddress::asV6Throw() const {
auto fam = detail::familyNameStr(family());
throw InvalidAddressFamilyException(to<std::string>(
"Can't convert address with family ", fam, " to AF_INET6 address"));
}
} // folly } // folly
...@@ -17,15 +17,11 @@ ...@@ -17,15 +17,11 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <iostream> #include <iosfwd>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> // std::pair #include <utility> // std::pair
#include <boost/operators.hpp>
#include <folly/Conv.h>
#include <folly/Format.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/IPAddressException.h> #include <folly/IPAddressException.h>
#include <folly/IPAddressV4.h> #include <folly/IPAddressV4.h>
...@@ -68,7 +64,7 @@ typedef std::pair<IPAddress, uint8_t> CIDRNetwork; ...@@ -68,7 +64,7 @@ typedef std::pair<IPAddress, uint8_t> CIDRNetwork;
* CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6()); * CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6());
* @encode * @encode
*/ */
class IPAddress : boost::totally_ordered<IPAddress> { class IPAddress {
public: public:
// returns true iff the input string can be parsed as an ip-address // returns true iff the input string can be parsed as an ip-address
static bool validate(StringPiece ip); static bool validate(StringPiece ip);
...@@ -101,9 +97,7 @@ class IPAddress : boost::totally_ordered<IPAddress> { ...@@ -101,9 +97,7 @@ class IPAddress : boost::totally_ordered<IPAddress> {
* *
* @return string representing the netblock * @return string representing the netblock
*/ */
static std::string networkToString(const CIDRNetwork& network) { static std::string networkToString(const CIDRNetwork& network);
return network.first.str() + "/" + folly::to<std::string>(network.second);
}
/** /**
* Create a new IPAddress instance from the provided binary data * Create a new IPAddress instance from the provided binary data
...@@ -170,10 +164,8 @@ class IPAddress : boost::totally_ordered<IPAddress> { ...@@ -170,10 +164,8 @@ class IPAddress : boost::totally_ordered<IPAddress> {
* @throws IPAddressFormatException is not a V4 instance * @throws IPAddressFormatException is not a V4 instance
*/ */
const IPAddressV4& asV4() const { const IPAddressV4& asV4() const {
if (!isV4()) { if (UNLIKELY(!isV4())) {
auto familyName = detail::familyNameStr(family()); asV4Throw();
throw InvalidAddressFamilyException("Can't convert address with family ",
familyName, " to AF_INET address");
} }
return addr_.ipV4Addr; return addr_.ipV4Addr;
} }
...@@ -183,10 +175,8 @@ class IPAddress : boost::totally_ordered<IPAddress> { ...@@ -183,10 +175,8 @@ class IPAddress : boost::totally_ordered<IPAddress> {
* @throws InvalidAddressFamilyException is not a V6 instance * @throws InvalidAddressFamilyException is not a V6 instance
*/ */
const IPAddressV6& asV6() const { const IPAddressV6& asV6() const {
if (!isV6()) { if (UNLIKELY(!isV6())) {
auto familyName = detail::familyNameStr(family()); asV6Throw();
throw InvalidAddressFamilyException("Can't convert address with family ",
familyName, " to AF_INET6 address");
} }
return addr_.ipV6Addr; return addr_.ipV6Addr;
} }
...@@ -411,6 +401,9 @@ class IPAddress : boost::totally_ordered<IPAddress> { ...@@ -411,6 +401,9 @@ class IPAddress : boost::totally_ordered<IPAddress> {
} }
private: private:
[[noreturn]] void asV4Throw() const;
[[noreturn]] void asV6Throw() const;
typedef union IPAddressV46 { typedef union IPAddressV46 {
IPAddressV4 ipV4Addr; IPAddressV4 ipV4Addr;
IPAddressV6 ipV6Addr; IPAddressV6 ipV6Addr;
...@@ -444,6 +437,19 @@ void toAppend(IPAddress addr, fbstring* result); ...@@ -444,6 +437,19 @@ void toAppend(IPAddress addr, fbstring* result);
bool operator==(const IPAddress& addr1, const IPAddress& addr2); bool operator==(const IPAddress& addr1, const IPAddress& addr2);
// Return true if addr1 < addr2 // Return true if addr1 < addr2
bool operator<(const IPAddress& addr1, const IPAddress& 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 } // folly
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
#include <exception> #include <exception>
#include <string> #include <string>
#include <utility>
#include <folly/Conv.h>
#include <folly/detail/IPAddress.h> #include <folly/detail/IPAddress.h>
namespace folly { namespace folly {
...@@ -29,13 +29,13 @@ namespace folly { ...@@ -29,13 +29,13 @@ namespace folly {
*/ */
class IPAddressFormatException : public std::exception { class IPAddressFormatException : public std::exception {
public: public:
explicit IPAddressFormatException(const std::string& msg) explicit IPAddressFormatException(std::string msg) noexcept
: msg_(msg) {} : msg_(std::move(msg)) {}
IPAddressFormatException( IPAddressFormatException(const IPAddressFormatException&) = default;
const IPAddressFormatException&) = default; IPAddressFormatException(IPAddressFormatException&&) = default;
template<typename... Args> IPAddressFormatException& operator=(const IPAddressFormatException&) =
explicit IPAddressFormatException(Args&&... args) default;
: msg_(to<std::string>(std::forward<Args>(args)...)) {} IPAddressFormatException& operator=(IPAddressFormatException&&) = default;
virtual ~IPAddressFormatException() noexcept {} virtual ~IPAddressFormatException() noexcept {}
virtual const char *what(void) const noexcept { virtual const char *what(void) const noexcept {
...@@ -43,22 +43,23 @@ class IPAddressFormatException : public std::exception { ...@@ -43,22 +43,23 @@ class IPAddressFormatException : public std::exception {
} }
private: private:
const std::string msg_; std::string msg_;
}; };
class InvalidAddressFamilyException : public IPAddressFormatException { class InvalidAddressFamilyException : public IPAddressFormatException {
public: public:
explicit InvalidAddressFamilyException(const std::string& msg) explicit InvalidAddressFamilyException(std::string msg) noexcept
: IPAddressFormatException(msg) {} : IPAddressFormatException(std::move(msg)) {}
InvalidAddressFamilyException( explicit InvalidAddressFamilyException(sa_family_t family) noexcept
const InvalidAddressFamilyException&) = default; : InvalidAddressFamilyException(
explicit InvalidAddressFamilyException(sa_family_t family) "Address family " + detail::familyNameStr(family) +
: IPAddressFormatException("Address family " + " is not AF_INET or AF_INET6") {}
detail::familyNameStr(family) + InvalidAddressFamilyException(const InvalidAddressFamilyException&) = default;
" is not AF_INET or AF_INET6") {} InvalidAddressFamilyException(InvalidAddressFamilyException&&) = default;
template<typename... Args> InvalidAddressFamilyException& operator=(
explicit InvalidAddressFamilyException(Args&&... args) const InvalidAddressFamilyException&) = default;
: IPAddressFormatException(std::forward<Args>(args)...) {} InvalidAddressFamilyException& operator=(InvalidAddressFamilyException&&) =
default;
}; };
} // folly } // folly
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <folly/Format.h> #include <folly/Format.h>
#include <folly/IPAddress.h> #include <folly/IPAddress.h>
#include <folly/IPAddressV6.h> #include <folly/IPAddressV6.h>
#include <folly/detail/IPAddressSource.h>
using std::ostream; using std::ostream;
using std::string; using std::string;
...@@ -72,8 +73,8 @@ uint32_t IPAddressV4::toLong(StringPiece ip) { ...@@ -72,8 +73,8 @@ uint32_t IPAddressV4::toLong(StringPiece ip) {
auto str = ip.str(); auto str = ip.str();
in_addr addr; in_addr addr;
if (inet_pton(AF_INET, str.c_str(), &addr) != 1) { if (inet_pton(AF_INET, str.c_str(), &addr) != 1) {
throw IPAddressFormatException("Can't convert invalid IP '", ip, "' ", throw IPAddressFormatException(
"to long"); to<std::string>("Can't convert invalid IP '", ip, "' ", "to long"));
} }
return addr.s_addr; return addr.s_addr;
} }
...@@ -99,7 +100,8 @@ IPAddressV4::IPAddressV4(StringPiece addr) ...@@ -99,7 +100,8 @@ IPAddressV4::IPAddressV4(StringPiece addr)
{ {
auto ip = addr.str(); auto ip = addr.str();
if (inet_pton(AF_INET, ip.c_str(), &addr_.inAddr_) != 1) { if (inet_pton(AF_INET, ip.c_str(), &addr_.inAddr_) != 1) {
throw IPAddressFormatException("Invalid IPv4 address '", addr, "'"); throw IPAddressFormatException(
to<std::string>("Invalid IPv4 address '", addr, "'"));
} }
} }
...@@ -112,8 +114,10 @@ IPAddressV4::IPAddressV4(const in_addr src) ...@@ -112,8 +114,10 @@ IPAddressV4::IPAddressV4(const in_addr src)
// public // public
void IPAddressV4::setFromBinary(ByteRange bytes) { void IPAddressV4::setFromBinary(ByteRange bytes) {
if (bytes.size() != 4) { if (bytes.size() != 4) {
throw IPAddressFormatException("Invalid IPv4 binary data: length must " throw IPAddressFormatException(to<std::string>(
"be 4 bytes, got ", bytes.size()); "Invalid IPv4 binary data: length must ",
"be 4 bytes, got ",
bytes.size()));
} }
memcpy(&addr_.inAddr_.s_addr, bytes.data(), sizeof(in_addr)); memcpy(&addr_.inAddr_.s_addr, bytes.data(), sizeof(in_addr));
} }
...@@ -147,8 +151,8 @@ bool IPAddressV4::inSubnet(StringPiece cidrNetwork) const { ...@@ -147,8 +151,8 @@ bool IPAddressV4::inSubnet(StringPiece cidrNetwork) const {
auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
auto addr = subnetInfo.first; auto addr = subnetInfo.first;
if (!addr.isV4()) { if (!addr.isV4()) {
throw IPAddressFormatException("Address '", addr.toJson(), "' ", throw IPAddressFormatException(to<std::string>(
"is not a V4 address"); "Address '", addr.toJson(), "' ", "is not a V4 address"));
} }
return inSubnetWithMask(addr.asV4(), fetchMask(subnetInfo.second)); return inSubnetWithMask(addr.asV4(), fetchMask(subnetInfo.second));
} }
...@@ -207,8 +211,8 @@ bool IPAddressV4::isMulticast() const { ...@@ -207,8 +211,8 @@ bool IPAddressV4::isMulticast() const {
IPAddressV4 IPAddressV4::mask(size_t numBits) const { IPAddressV4 IPAddressV4::mask(size_t numBits) const {
static const auto bits = bitCount(); static const auto bits = bitCount();
if (numBits > bits) { if (numBits > bits) {
throw IPAddressFormatException("numBits(", numBits, throw IPAddressFormatException(
") > bitsCount(", bits, ")"); to<std::string>("numBits(", numBits, ") > bitsCount(", bits, ")"));
} }
ByteArray4 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); ByteArray4 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
...@@ -234,11 +238,20 @@ uint8_t IPAddressV4::getNthMSByte(size_t byteIndex) const { ...@@ -234,11 +238,20 @@ uint8_t IPAddressV4::getNthMSByte(size_t byteIndex) const {
const ByteArray4 IPAddressV4::fetchMask(size_t numBits) { const ByteArray4 IPAddressV4::fetchMask(size_t numBits) {
static const uint8_t bits = bitCount(); static const uint8_t bits = bitCount();
if (numBits > bits) { if (numBits > bits) {
throw IPAddressFormatException("IPv4 addresses are 32 bits"); throw IPAddressFormatException(
to<std::string>("IPv4 addresses are 32 bits"));
} }
// masks_ is backed by an array so is zero indexed // masks_ is backed by an array so is zero indexed
return masks_[numBits]; 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 // static private
const std::array<ByteArray4, 33> IPAddressV4::masks_ = {{ const std::array<ByteArray4, 33> IPAddressV4::masks_ = {{
......
...@@ -16,10 +16,11 @@ ...@@ -16,10 +16,11 @@
#pragma once #pragma once
#include <functional> #include <cstring>
#include <iostream>
#include <boost/operators.hpp> #include <array>
#include <functional>
#include <iosfwd>
#include <folly/Hash.h> #include <folly/Hash.h>
#include <folly/Range.h> #include <folly/Range.h>
...@@ -51,7 +52,7 @@ typedef std::array<uint8_t, 4> ByteArray4; ...@@ -51,7 +52,7 @@ typedef std::array<uint8_t, 4> ByteArray4;
* *
* @see IPAddress * @see IPAddress
*/ */
class IPAddressV4 : boost::totally_ordered<IPAddressV4> { class IPAddressV4 {
public: public:
// returns true iff the input string can be parsed as an ipv4-address // returns true iff the input string can be parsed as an ipv4-address
static bool validate(StringPiece ip); static bool validate(StringPiece ip);
...@@ -168,7 +169,8 @@ class IPAddressV4 : boost::totally_ordered<IPAddressV4> { ...@@ -168,7 +169,8 @@ class IPAddressV4 : boost::totally_ordered<IPAddressV4> {
// @see IPAddress#isZero // @see IPAddress#isZero
bool isZero() const { 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 { bool isLinkLocalBroadcast() const {
...@@ -214,15 +216,11 @@ class IPAddressV4 : boost::totally_ordered<IPAddressV4> { ...@@ -214,15 +216,11 @@ class IPAddressV4 : boost::totally_ordered<IPAddressV4> {
*/ */
static const ByteArray4 fetchMask(size_t numBits); 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 // mask pair
static CIDRNetworkV4 longestCommonPrefix( static CIDRNetworkV4 longestCommonPrefix(
const CIDRNetworkV4& one, const CIDRNetworkV4& two) { const CIDRNetworkV4& one,
auto prefix = const CIDRNetworkV4& two);
detail::Bytes::longestCommonPrefix(one.first.addr_.bytes_, one.second,
two.first.addr_.bytes_, two.second);
return {IPAddressV4(prefix.first), prefix.second};
}
// Number of bytes in the address representation. // Number of bytes in the address representation.
static size_t byteCount() { return 4; } static size_t byteCount() { return 4; }
//get nth most significant bit - 0 indexed //get nth most significant bit - 0 indexed
...@@ -282,6 +280,19 @@ inline bool operator==(const IPAddressV4& addr1, const IPAddressV4& addr2) { ...@@ -282,6 +280,19 @@ inline bool operator==(const IPAddressV4& addr1, const IPAddressV4& addr2) {
inline bool operator<(const IPAddressV4& addr1, const IPAddressV4& addr2) { inline bool operator<(const IPAddressV4& addr1, const IPAddressV4& addr2) {
return (addr1.toLongHBO() < addr2.toLongHBO()); 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 } // folly
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <folly/IPAddress.h> #include <folly/IPAddress.h>
#include <folly/IPAddressV4.h> #include <folly/IPAddressV4.h>
#include <folly/MacAddress.h> #include <folly/MacAddress.h>
#include <folly/detail/IPAddressSource.h>
using std::ostream; using std::ostream;
using std::string; using std::string;
...@@ -72,8 +73,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) { ...@@ -72,8 +73,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) {
// Allow addresses surrounded in brackets // Allow addresses surrounded in brackets
if (ip.size() < 2) { if (ip.size() < 2) {
throw IPAddressFormatException("Invalid IPv6 address '", ip, throw IPAddressFormatException(
"': address too short"); to<std::string>("Invalid IPv6 address '", ip, "': address too short"));
} }
if (ip.front() == '[' && ip.back() == ']') { if (ip.front() == '[' && ip.back() == ']') {
ip = ip.substr(1, ip.size() - 2); ip = ip.substr(1, ip.size() - 2);
...@@ -91,7 +92,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) { ...@@ -91,7 +92,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) {
scope_ = ipAddr->sin6_scope_id; scope_ = ipAddr->sin6_scope_id;
freeaddrinfo(result); freeaddrinfo(result);
} else { } else {
throw IPAddressFormatException("Invalid IPv6 address '", ip, "'"); throw IPAddressFormatException(
to<std::string>("Invalid IPv6 address '", ip, "'"));
} }
} }
...@@ -136,8 +138,10 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { ...@@ -136,8 +138,10 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) {
void IPAddressV6::setFromBinary(ByteRange bytes) { void IPAddressV6::setFromBinary(ByteRange bytes) {
if (bytes.size() != 16) { if (bytes.size() != 16) {
throw IPAddressFormatException("Invalid IPv6 binary data: length must " throw IPAddressFormatException(to<std::string>(
"be 16 bytes, got ", bytes.size()); "Invalid IPv6 binary data: length must ",
"be 16 bytes, got ",
bytes.size()));
} }
memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr)); memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr));
scope_ = 0; scope_ = 0;
...@@ -252,8 +256,8 @@ bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const { ...@@ -252,8 +256,8 @@ bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const {
auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
auto addr = subnetInfo.first; auto addr = subnetInfo.first;
if (!addr.isV6()) { if (!addr.isV6()) {
throw IPAddressFormatException("Address '", addr.toJson(), "' ", throw IPAddressFormatException(to<std::string>(
"is not a V6 address"); "Address '", addr.toJson(), "' ", "is not a V6 address"));
} }
return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second)); return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second));
} }
...@@ -336,8 +340,8 @@ IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const { ...@@ -336,8 +340,8 @@ IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const {
IPAddressV6 IPAddressV6::mask(size_t numBits) const { IPAddressV6 IPAddressV6::mask(size_t numBits) const {
static const auto bits = bitCount(); static const auto bits = bitCount();
if (numBits > bits) { if (numBits > bits) {
throw IPAddressFormatException("numBits(", numBits, ") > bitCount(", throw IPAddressFormatException(
bits, ")"); to<std::string>("numBits(", numBits, ") > bitCount(", bits, ")"));
} }
ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
return IPAddressV6(ba); return IPAddressV6(ba);
...@@ -354,8 +358,11 @@ string IPAddressV6::str() const { ...@@ -354,8 +358,11 @@ string IPAddressV6::str() const {
string ip(buffer); string ip(buffer);
return ip; return ip;
} else { } else {
throw IPAddressFormatException("Invalid address with hex ", throw IPAddressFormatException(to<std::string>(
"'", detail::Bytes::toHex(bytes(), 16), "'"); "Invalid address with hex ",
"'",
detail::Bytes::toHex(bytes(), 16),
"'"));
} }
} }
...@@ -385,6 +392,15 @@ const ByteArray16 IPAddressV6::fetchMask(size_t numBits) { ...@@ -385,6 +392,15 @@ const ByteArray16 IPAddressV6::fetchMask(size_t numBits) {
return masks_[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 // protected
bool IPAddressV6::inBinarySubnet(const std::array<uint8_t, 2> addr, bool IPAddressV6::inBinarySubnet(const std::array<uint8_t, 2> addr,
size_t numBits) const { size_t numBits) const {
......
...@@ -16,13 +16,14 @@ ...@@ -16,13 +16,14 @@
#pragma once #pragma once
#include <cstring>
#include <array>
#include <functional> #include <functional>
#include <iostream> #include <iosfwd>
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <boost/operators.hpp>
#include <folly/Hash.h> #include <folly/Hash.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/detail/IPAddress.h> #include <folly/detail/IPAddress.h>
...@@ -63,7 +64,7 @@ typedef std::array<uint8_t, 16> ByteArray16; ...@@ -63,7 +64,7 @@ typedef std::array<uint8_t, 16> ByteArray16;
* Serializing / Deserializing IPAddressB6's on different hosts * Serializing / Deserializing IPAddressB6's on different hosts
* that use link-local scoping probably won't work. * that use link-local scoping probably won't work.
*/ */
class IPAddressV6 : boost::totally_ordered<IPAddressV6> { class IPAddressV6 {
public: public:
// V6 Address Type // V6 Address Type
enum Type { enum Type {
...@@ -227,7 +228,8 @@ class IPAddressV6 : boost::totally_ordered<IPAddressV6> { ...@@ -227,7 +228,8 @@ class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
// @see IPAddress#isZero // @see IPAddress#isZero
bool isZero() const { 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; bool isLinkLocalBroadcast() const;
...@@ -283,13 +285,9 @@ class IPAddressV6 : boost::totally_ordered<IPAddressV6> { ...@@ -283,13 +285,9 @@ class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
static const ByteArray16 fetchMask(size_t numBits); static const ByteArray16 fetchMask(size_t numBits);
// Given 2 IPAddressV6,mask pairs extract the longest common IPAddress, // Given 2 IPAddressV6,mask pairs extract the longest common IPAddress,
// mask pair // mask pair
static CIDRNetworkV6 longestCommonPrefix(const CIDRNetworkV6& one, static CIDRNetworkV6 longestCommonPrefix(
const CIDRNetworkV6& two) { const CIDRNetworkV6& one,
auto prefix = detail::Bytes::longestCommonPrefix( const CIDRNetworkV6& two);
one.first.addr_.bytes_, one.second,
two.first.addr_.bytes_, two.second);
return {IPAddressV6(prefix.first), prefix.second};
}
// Number of bytes in the address representation. // Number of bytes in the address representation.
static constexpr size_t byteCount() { return 16; } static constexpr size_t byteCount() { return 16; }
...@@ -367,6 +365,19 @@ inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) { ...@@ -367,6 +365,19 @@ inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) {
return cmp; 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 } // folly
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <folly/MacAddress.h> #include <folly/MacAddress.h>
#include <iostream>
#include <folly/Exception.h> #include <folly/Exception.h>
#include <folly/IPAddressV6.h> #include <folly/IPAddressV6.h>
......
...@@ -16,12 +16,10 @@ ...@@ -16,12 +16,10 @@
#pragma once #pragma once
#include <iostream> #include <iosfwd>
#include <boost/operators.hpp>
#include <folly/Bits.h> #include <folly/Bits.h>
#include <folly/Conv.h> #include <folly/Range.h>
namespace folly { namespace folly {
...@@ -30,7 +28,7 @@ class IPAddressV6; ...@@ -30,7 +28,7 @@ class IPAddressV6;
/* /*
* MacAddress represents an IEEE 802 MAC address. * MacAddress represents an IEEE 802 MAC address.
*/ */
class MacAddress : private boost::totally_ordered<MacAddress> { class MacAddress {
public: public:
static constexpr size_t SIZE = 6; static constexpr size_t SIZE = 6;
static const MacAddress BROADCAST; static const MacAddress BROADCAST;
...@@ -167,8 +165,7 @@ class MacAddress : private boost::totally_ordered<MacAddress> { ...@@ -167,8 +165,7 @@ class MacAddress : private boost::totally_ordered<MacAddress> {
return getByte(0) & 0x2; return getByte(0) & 0x2;
} }
// Equality and less-than operators. // Comparison operators.
// boost::totally_ordered provides the other comparison operators.
bool operator==(const MacAddress& other) const { bool operator==(const MacAddress& other) const {
// All constructors and modifying methods make sure padding is 0, // All constructors and modifying methods make sure padding is 0,
...@@ -180,6 +177,22 @@ class MacAddress : private boost::totally_ordered<MacAddress> { ...@@ -180,6 +177,22 @@ class MacAddress : private boost::totally_ordered<MacAddress> {
return u64HBO() < other.u64HBO(); 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: private:
explicit MacAddress(uint64_t valueNBO) { explicit MacAddress(uint64_t valueNBO) {
memcpy(&bytes_, &valueNBO, 8); memcpy(&bytes_, &valueNBO, 8);
......
...@@ -63,6 +63,7 @@ nobase_follyinclude_HEADERS = \ ...@@ -63,6 +63,7 @@ nobase_follyinclude_HEADERS = \
detail/Futex.h \ detail/Futex.h \
detail/GroupVarintDetail.h \ detail/GroupVarintDetail.h \
detail/IPAddress.h \ detail/IPAddress.h \
detail/IPAddressSource.h \
detail/Malloc.h \ detail/Malloc.h \
detail/MemoryIdler.h \ detail/MemoryIdler.h \
detail/MPMCPipelineDetail.h \ detail/MPMCPipelineDetail.h \
...@@ -363,6 +364,7 @@ libfolly_la_SOURCES = \ ...@@ -363,6 +364,7 @@ libfolly_la_SOURCES = \
Bits.cpp \ Bits.cpp \
Checksum.cpp \ Checksum.cpp \
detail/CacheLocality.cpp \ detail/CacheLocality.cpp \
detail/IPAddress.cpp \
dynamic.cpp \ dynamic.cpp \
File.cpp \ File.cpp \
FileUtil.cpp \ FileUtil.cpp \
......
...@@ -1162,6 +1162,14 @@ struct hasher<folly::Range<T*>, ...@@ -1162,6 +1162,14 @@ struct hasher<folly::Range<T*>,
} }
}; };
/**
* Ubiquitous helper template for knowing what's a string
*/
template <class T> struct IsSomeString {
enum { value = std::is_same<T, std::string>::value
|| std::is_same<T, fbstring>::value };
};
} // !namespace folly } // !namespace folly
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <folly/SocketAddress.h> #include <folly/SocketAddress.h>
#include <folly/Exception.h>
#include <folly/Hash.h> #include <folly/Hash.h>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#include <errno.h> #include <errno.h>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <system_error>
namespace { namespace {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <cstddef> #include <cstddef>
#include <iostream> #include <iosfwd>
#include <string> #include <string>
#include <folly/IPAddress.h> #include <folly/IPAddress.h>
......
/*
* 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 <folly/detail/IPAddress.h>
#include <folly/Format.h>
namespace folly { namespace detail {
std::string familyNameStrDefault(sa_family_t family) {
return folly::sformat("sa_family_t({})", folly::to<std::string>(family));
}
[[noreturn]] void getNthMSBitImplThrow(size_t bitCount, sa_family_t family) {
throw std::invalid_argument(folly::to<std::string>(
"Bit index must be < ",
bitCount,
" for addresses of type :",
familyNameStr(family)));
}
}}
...@@ -16,32 +16,14 @@ ...@@ -16,32 +16,14 @@
#pragma once #pragma once
#include <boost/noncopyable.hpp>
#include <glog/logging.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <string> #include <string>
#include <sstream>
#include <type_traits>
#include <vector>
#include <sys/types.h> #include <sys/types.h>
#include <folly/Conv.h>
#include <folly/Format.h>
#include <folly/portability/Sockets.h> #include <folly/portability/Sockets.h>
// 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 { namespace folly { namespace detail {
std::string familyNameStrDefault(sa_family_t family);
inline std::string familyNameStr(sa_family_t family) { inline std::string familyNameStr(sa_family_t family) {
switch (family) { switch (family) {
case AF_INET: case AF_INET:
...@@ -53,242 +35,20 @@ inline std::string familyNameStr(sa_family_t family) { ...@@ -53,242 +35,20 @@ inline std::string familyNameStr(sa_family_t family) {
case AF_UNIX: case AF_UNIX:
return "AF_UNIX"; return "AF_UNIX";
default: default:
return folly::format("sa_family_t({})", return familyNameStrDefault(family);
folly::to<std::string>(family)).str();
} }
} }
template<typename IPAddrType> [[noreturn]] void getNthMSBitImplThrow(size_t bitCount, sa_family_t family);
inline bool getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex,
sa_family_t family) { template <typename IPAddrType>
inline bool
getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex, sa_family_t family) {
if (bitIndex >= ip.bitCount()) { if (bitIndex >= ip.bitCount()) {
throw std::invalid_argument(folly::to<std::string>("Bit index must be < ", getNthMSBitImplThrow(ip.bitCount(), family);
ip.bitCount(), " for addresses of type :", familyNameStr(family)));
} }
//Underlying bytes are in n/w byte order //Underlying bytes are in n/w byte order
return (ip.getNthMSByte(bitIndex / 8) & (0x80 >> (bitIndex % 8))) != 0; 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<std::size_t N>
static std::array<uint8_t, N> mask(const std::array<uint8_t, N>& a,
const std::array<uint8_t, N>& b) {
static_assert(N > 0, "Can't mask an empty ByteArray");
std::size_t asize = a.size();
std::array<uint8_t, N> ba{{0}};
for (std::size_t i = 0; i < asize; i++) {
ba[i] = a[i] & b[i];
}
return ba;
}
template<std::size_t N>
static std::pair<std::array<uint8_t, N>, uint8_t>
longestCommonPrefix(
const std::array<uint8_t, N>& one, uint8_t oneMask,
const std::array<uint8_t, N>& two, uint8_t twoMask) {
static constexpr auto kBitCount = N * 8;
static constexpr std::array<uint8_t, 8> 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<std::string>("Invalid mask "
"length: ", oneMask > twoMask ? oneMask : twoMask,
". Mask length must be <= ", kBitCount));
}
auto mask = std::min(oneMask, twoMask);
uint8_t byteIndex = 0;
std::array<uint8_t, N> 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<class IntegralType,
IntegralType DigitCount,
IntegralType Base = 10,
bool PrintAllDigits = false,
class = typename std::enable_if<
std::is_integral<IntegralType>::value &&
std::is_unsigned<IntegralType>::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<const uint8_t*>(&inAddr.s_addr);
char str[sizeof("255.255.255.255")];
char* buf = str;
writeIntegerString<uint8_t, 3>(octets[0], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(octets[1], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(octets[2], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(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<const uint16_t*>(&in6Addr.u.Word);
#else
const uint16_t* bytes = reinterpret_cast<const uint16_t*>(&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);
}
}} // folly::detail }} // folly::detail
/*
* 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 <glog/logging.h>
#include <sys/types.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <string>
#include <type_traits>
#include <folly/Conv.h>
#include <folly/detail/IPAddress.h>
// 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 <std::size_t N>
static std::array<uint8_t, N> mask(
const std::array<uint8_t, N>& a,
const std::array<uint8_t, N>& b) {
static_assert(N > 0, "Can't mask an empty ByteArray");
std::size_t asize = a.size();
std::array<uint8_t, N> ba{{0}};
for (std::size_t i = 0; i < asize; i++) {
ba[i] = a[i] & b[i];
}
return ba;
}
template <std::size_t N>
static std::pair<std::array<uint8_t, N>, uint8_t> longestCommonPrefix(
const std::array<uint8_t, N>& one,
uint8_t oneMask,
const std::array<uint8_t, N>& two,
uint8_t twoMask) {
static constexpr auto kBitCount = N * 8;
static constexpr std::array<uint8_t, 8> 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<std::string>(
"Invalid mask "
"length: ",
oneMask > twoMask ? oneMask : twoMask,
". Mask length must be <= ",
kBitCount));
}
auto mask = std::min(oneMask, twoMask);
uint8_t byteIndex = 0;
std::array<uint8_t, N> 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<IntegralType>::value &&
std::is_unsigned<IntegralType>::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<const uint8_t*>(&inAddr.s_addr);
char str[sizeof("255.255.255.255")];
char* buf = str;
writeIntegerString<uint8_t, 3>(octets[0], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(octets[1], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(octets[2], &buf);
*(buf++) = '.';
writeIntegerString<uint8_t, 3>(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<const uint16_t*>(&in6Addr.u.Word);
#else
const uint16_t* bytes = reinterpret_cast<const uint16_t*>(&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);
}
}
}
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <folly/FileUtil.h> #include <folly/FileUtil.h>
#include <folly/SocketAddress.h> #include <folly/SocketAddress.h>
#include <folly/String.h>
#include <folly/detail/SocketFastOpen.h> #include <folly/detail/SocketFastOpen.h>
#include <folly/io/async/EventBase.h> #include <folly/io/async/EventBase.h>
#include <folly/io/async/NotificationQueue.h> #include <folly/io/async/NotificationQueue.h>
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
#include <folly/io/async/test/BlockingSocket.h> #include <folly/io/async/test/BlockingSocket.h>
#include <iostream>
#include <folly/ExceptionWrapper.h> #include <folly/ExceptionWrapper.h>
#include <gflags/gflags.h> #include <gflags/gflags.h>
......
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
#include <folly/Bits.h> #include <folly/Bits.h>
#include <folly/Format.h> #include <folly/Format.h>
#include <folly/String.h>
#include <folly/MacAddress.h> #include <folly/MacAddress.h>
#include <folly/String.h>
#include <folly/detail/IPAddressSource.h>
using namespace folly; using namespace folly;
using namespace std; using namespace std;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <folly/Conv.h>
#include <folly/IPAddressV6.h> #include <folly/IPAddressV6.h>
#include <folly/MacAddress.h> #include <folly/MacAddress.h>
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <system_error>
#include <folly/test/SocketAddressTestHelper.h> #include <folly/test/SocketAddressTestHelper.h>
using namespace boost; using namespace boost;
......
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