2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <boost/noncopyable.hpp>
20 #include <glog/logging.h>
27 #include <type_traits>
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
38 // missing in socket headers
39 #define sa_family_t ADDRESS_FAMILY
42 #include <sys/types.h>
45 #include <folly/Conv.h>
46 #include <folly/Format.h>
48 namespace folly { namespace detail {
50 inline std::string familyNameStr(sa_family_t family) {
61 return folly::format("sa_family_t({})",
62 folly::to<std::string>(family)).str();
66 template<typename IPAddrType>
67 inline bool getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex,
69 if (bitIndex >= ip.bitCount()) {
70 throw std::invalid_argument(folly::to<std::string>("Bit index must be < ",
71 ip.bitCount(), " for addresses of type :", familyNameStr(family)));
73 //Underlying bytes are in n/w byte order
74 return (ip.getNthMSByte(bitIndex / 8) & (0x80 >> (bitIndex % 8))) != 0;
78 * Helper for working with unsigned char* or uint8_t* ByteArray values
80 struct Bytes : private boost::noncopyable {
81 // return true if all values of src are zero
82 static bool isZero(const uint8_t* src, std::size_t len) {
83 for (auto i = 0; i < len; i++) {
91 // mask the values from two byte arrays, returning a new byte array
92 template<std::size_t N>
93 static std::array<uint8_t, N> mask(const std::array<uint8_t, N>& a,
94 const std::array<uint8_t, N>& b) {
95 static_assert(N > 0, "Can't mask an empty ByteArray");
96 std::size_t asize = a.size();
97 std::array<uint8_t, N> ba{{0}};
98 for (int i = 0; i < asize; i++) {
104 template<std::size_t N>
105 static std::pair<std::array<uint8_t, N>, uint8_t>
107 const std::array<uint8_t, N>& one, uint8_t oneMask,
108 const std::array<uint8_t, N>& two, uint8_t twoMask) {
109 static constexpr auto kBitCount = N * 8;
110 static constexpr std::array<uint8_t, 8> kMasks {{
120 if (oneMask > kBitCount || twoMask > kBitCount) {
121 throw std::invalid_argument(folly::to<std::string>("Invalid mask "
122 "length: ", oneMask > twoMask ? oneMask : twoMask,
123 ". Mask length must be <= ", kBitCount));
126 auto mask = std::min(oneMask, twoMask);
127 uint8_t byteIndex = 0;
128 std::array<uint8_t, N> ba{{0}};
129 // Compare a byte at a time. Note - I measured compared this with
130 // going multiple bytes at a time (8, 4, 2 and 1). It turns out
131 // to be 20 - 25% slower for 4 and 16 byte arrays.
132 while (byteIndex * 8 < mask && one[byteIndex] == two[byteIndex]) {
133 ba[byteIndex] = one[byteIndex];
136 auto bitIndex = std::min(mask, (uint8_t)(byteIndex * 8));
137 // Compute the bit up to which the two byte arrays match in the
139 // Here the check is bitIndex < mask since the 0th mask entry in
140 // kMasks array holds the mask for masking the MSb in this byte.
141 // We could instead make it hold so that no 0th entry masks no
142 // bits but thats a useless iteration.
143 while (bitIndex < mask && ((one[bitIndex / 8] & kMasks[bitIndex % 8]) ==
144 (two[bitIndex / 8] & kMasks[bitIndex % 8]))) {
145 ba[bitIndex / 8] = one[bitIndex / 8] & kMasks[bitIndex % 8];
148 return {ba, bitIndex};
151 // create an in_addr from an uint8_t*
152 static inline in_addr mkAddress4(const uint8_t* src) {
157 std::memset(&addr, 0, 4);
158 std::memcpy(addr.bytes, src, 4);
162 // create an in6_addr from an uint8_t*
163 static inline in6_addr mkAddress6(const uint8_t* src) {
165 std::memset(&addr, 0, 16);
166 std::memcpy(addr.s6_addr, src, 16);
170 // convert an uint8_t* to its hex value
171 static std::string toHex(const uint8_t* src, std::size_t len) {
172 static const char* const lut = "0123456789abcdef";
173 std::stringstream ss;
174 for (int i = 0; i < len; i++) {
175 const unsigned char c = src[i];
176 ss << lut[c >> 4] << lut[c & 15];