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) {
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.
*/
......
......@@ -21,7 +21,9 @@
#include <string>
#include <vector>
#include <folly/Conv.h>
#include <folly/String.h>
#include <folly/detail/IPAddressSource.h>
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. ",
throw IPAddressFormatException(to<std::string>(
"Invalid ipSlashCidr specified. ",
"Expected IP/CIDR format, got ",
"'", ipSlashCidr, "'");
"'",
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<uint8_t>(vec.at(1));
} catch (...) {
throw IPAddressFormatException("Mask value ",
"'", vec.at(1), "' not a valid mask");
throw IPAddressFormatException(
to<std::string>("Mask value ", "'", vec.at(1), "' not a valid mask"));
}
}
if (cidr > subnet.bitCount()) {
throw IPAddressFormatException("CIDR value '", cidr, "' ",
throw IPAddressFormatException(to<std::string>(
"CIDR value '",
cidr,
"' ",
"is > network bit count ",
"'", subnet.bitCount(), "'");
"'",
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<std::string>(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<std::string>("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<std::string>("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<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
......@@ -17,15 +17,11 @@
#pragma once
#include <functional>
#include <iostream>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility> // std::pair
#include <boost/operators.hpp>
#include <folly/Conv.h>
#include <folly/Format.h>
#include <folly/Range.h>
#include <folly/IPAddressException.h>
#include <folly/IPAddressV4.h>
......@@ -68,7 +64,7 @@ typedef std::pair<IPAddress, uint8_t> CIDRNetwork;
* CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6());
* @encode
*/
class IPAddress : boost::totally_ordered<IPAddress> {
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<IPAddress> {
*
* @return string representing the netblock
*/
static std::string networkToString(const CIDRNetwork& network) {
return network.first.str() + "/" + folly::to<std::string>(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<IPAddress> {
* @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<IPAddress> {
* @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<IPAddress> {
}
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
......
......@@ -18,8 +18,8 @@
#include <exception>
#include <string>
#include <utility>
#include <folly/Conv.h>
#include <folly/detail/IPAddress.h>
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<typename... Args>
explicit IPAddressFormatException(Args&&... args)
: msg_(to<std::string>(std::forward<Args>(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) +
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") {}
template<typename... Args>
explicit InvalidAddressFamilyException(Args&&... args)
: IPAddressFormatException(std::forward<Args>(args)...) {}
InvalidAddressFamilyException(const InvalidAddressFamilyException&) = default;
InvalidAddressFamilyException(InvalidAddressFamilyException&&) = default;
InvalidAddressFamilyException& operator=(
const InvalidAddressFamilyException&) = default;
InvalidAddressFamilyException& operator=(InvalidAddressFamilyException&&) =
default;
};
} // folly
......@@ -22,6 +22,7 @@
#include <folly/Format.h>
#include <folly/IPAddress.h>
#include <folly/IPAddressV6.h>
#include <folly/detail/IPAddressSource.h>
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<std::string>("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<std::string>("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<std::string>(
"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<std::string>(
"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<std::string>("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<std::string>("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<ByteArray4, 33> IPAddressV4::masks_ = {{
......
......@@ -16,10 +16,11 @@
#pragma once
#include <functional>
#include <iostream>
#include <cstring>
#include <boost/operators.hpp>
#include <array>
#include <functional>
#include <iosfwd>
#include <folly/Hash.h>
#include <folly/Range.h>
......@@ -51,7 +52,7 @@ typedef std::array<uint8_t, 4> ByteArray4;
*
* @see IPAddress
*/
class IPAddressV4 : boost::totally_ordered<IPAddressV4> {
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<IPAddressV4> {
// @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<IPAddressV4> {
*/
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
......
......@@ -23,6 +23,7 @@
#include <folly/IPAddress.h>
#include <folly/IPAddressV4.h>
#include <folly/MacAddress.h>
#include <folly/detail/IPAddressSource.h>
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<std::string>("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<std::string>("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<std::string>(
"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<std::string>(
"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<std::string>("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<std::string>(
"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<uint8_t, 2> addr,
size_t numBits) const {
......
......@@ -16,13 +16,14 @@
#pragma once
#include <cstring>
#include <array>
#include <functional>
#include <iostream>
#include <iosfwd>
#include <map>
#include <stdexcept>
#include <boost/operators.hpp>
#include <folly/Hash.h>
#include <folly/Range.h>
#include <folly/detail/IPAddress.h>
......@@ -63,7 +64,7 @@ typedef std::array<uint8_t, 16> ByteArray16;
* Serializing / Deserializing IPAddressB6's on different hosts
* that use link-local scoping probably won't work.
*/
class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
class IPAddressV6 {
public:
// V6 Address Type
enum Type {
......@@ -227,7 +228,8 @@ class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
// @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<IPAddressV6> {
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
......
......@@ -16,6 +16,8 @@
#include <folly/MacAddress.h>
#include <iostream>
#include <folly/Exception.h>
#include <folly/IPAddressV6.h>
......
......@@ -16,12 +16,10 @@
#pragma once
#include <iostream>
#include <boost/operators.hpp>
#include <iosfwd>
#include <folly/Bits.h>
#include <folly/Conv.h>
#include <folly/Range.h>
namespace folly {
......@@ -30,7 +28,7 @@ class IPAddressV6;
/*
* MacAddress represents an IEEE 802 MAC address.
*/
class MacAddress : private boost::totally_ordered<MacAddress> {
class MacAddress {
public:
static constexpr size_t SIZE = 6;
static const MacAddress BROADCAST;
......@@ -167,8 +165,7 @@ class MacAddress : private boost::totally_ordered<MacAddress> {
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<MacAddress> {
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);
......
......@@ -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 \
......
......@@ -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
#pragma GCC diagnostic pop
......
......@@ -20,6 +20,7 @@
#include <folly/SocketAddress.h>
#include <folly/Exception.h>
#include <folly/Hash.h>
#include <boost/functional/hash.hpp>
......@@ -28,6 +29,7 @@
#include <errno.h>
#include <sstream>
#include <string>
#include <system_error>
namespace {
......
......@@ -18,7 +18,7 @@
#include <sys/types.h>
#include <cstddef>
#include <iostream>
#include <iosfwd>
#include <string>
#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 @@
#pragma once
#include <boost/noncopyable.hpp>
#include <glog/logging.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <string>
#include <sstream>
#include <type_traits>
#include <vector>
#include <sys/types.h>
#include <folly/Conv.h>
#include <folly/Format.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 {
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<std::string>(family)).str();
return familyNameStrDefault(family);
}
}
template<typename IPAddrType>
inline bool getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex,
sa_family_t family) {
[[noreturn]] void getNthMSBitImplThrow(size_t bitCount, sa_family_t family);
template <typename IPAddrType>
inline bool
getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex, sa_family_t family) {
if (bitIndex >= ip.bitCount()) {
throw std::invalid_argument(folly::to<std::string>("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<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
/*
* 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 @@
#include <folly/FileUtil.h>
#include <folly/SocketAddress.h>
#include <folly/String.h>
#include <folly/detail/SocketFastOpen.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/NotificationQueue.h>
......
......@@ -15,6 +15,8 @@
*/
#include <folly/io/async/test/BlockingSocket.h>
#include <iostream>
#include <folly/ExceptionWrapper.h>
#include <gflags/gflags.h>
......
......@@ -20,8 +20,9 @@
#include <folly/Bits.h>
#include <folly/Format.h>
#include <folly/String.h>
#include <folly/MacAddress.h>
#include <folly/String.h>
#include <folly/detail/IPAddressSource.h>
using namespace folly;
using namespace std;
......
......@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
#include <folly/Conv.h>
#include <folly/IPAddressV6.h>
#include <folly/MacAddress.h>
......
......@@ -19,6 +19,8 @@
#include <gtest/gtest.h>
#include <iostream>
#include <sstream>
#include <system_error>
#include <folly/test/SocketAddressTestHelper.h>
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