proxygen
MacAddress.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #include <folly/MacAddress.h>
18 
19 #include <ostream>
20 
21 #include <folly/Exception.h>
22 #include <folly/Format.h>
23 #include <folly/IPAddressV6.h>
24 #include <folly/String.h>
25 
26 using std::invalid_argument;
27 using std::string;
28 
29 namespace folly {
30 
31 const MacAddress MacAddress::BROADCAST{Endian::big(uint64_t(0xffffffffffffU))};
32 const MacAddress MacAddress::ZERO;
33 
35  memset(&bytes_, 0, 8);
36  parse(str);
37 }
38 
40  // This method should only be used for multicast addresses.
41  DCHECK(v6addr.isMulticast());
42 
44  bytes[0] = 0x33;
45  bytes[1] = 0x33;
46  memcpy(bytes + 2, v6addr.bytes() + 12, 4);
47  return fromBinary(ByteRange(bytes, SIZE));
48 }
49 
50 string MacAddress::toString() const {
51  static const char hexValues[] = "0123456789abcdef";
52  string result;
53  result.resize(17);
54  result[0] = hexValues[getByte(0) >> 4];
55  result[1] = hexValues[getByte(0) & 0xf];
56  result[2] = ':';
57  result[3] = hexValues[getByte(1) >> 4];
58  result[4] = hexValues[getByte(1) & 0xf];
59  result[5] = ':';
60  result[6] = hexValues[getByte(2) >> 4];
61  result[7] = hexValues[getByte(2) & 0xf];
62  result[8] = ':';
63  result[9] = hexValues[getByte(3) >> 4];
64  result[10] = hexValues[getByte(3) & 0xf];
65  result[11] = ':';
66  result[12] = hexValues[getByte(4) >> 4];
67  result[13] = hexValues[getByte(4) & 0xf];
68  result[14] = ':';
69  result[15] = hexValues[getByte(5) >> 4];
70  result[16] = hexValues[getByte(5) & 0xf];
71  return result;
72 }
73 
75  // Helper function to convert a single hex char into an integer
76  auto isSeparatorChar = [](char c) { return c == ':' || c == '-'; };
77 
78  uint8_t parsed[SIZE];
79  auto p = str.begin();
80  for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) {
81  if (p == str.end()) {
82  throw invalid_argument(
83  sformat("invalid MAC address '{}': not enough digits", str));
84  }
85 
86  // Skip over ':' or '-' separators between bytes
87  if (byteIndex != 0 && isSeparatorChar(*p)) {
88  ++p;
89  if (p == str.end()) {
90  throw invalid_argument(
91  sformat("invalid MAC address '{}': not enough digits", str));
92  }
93  }
94 
95  // Parse the upper nibble
96  uint8_t upper = detail::hexTable[static_cast<uint8_t>(*p)];
97  if (upper & 0x10) {
98  throw invalid_argument(
99  sformat("invalid MAC address '{}': contains non-hex digit", str));
100  }
101  ++p;
102 
103  // Parse the lower nibble
104  uint8_t lower;
105  if (p == str.end()) {
106  lower = upper;
107  upper = 0;
108  } else {
109  lower = detail::hexTable[static_cast<uint8_t>(*p)];
110  if (lower & 0x10) {
111  // Also accept ':', '-', or '\0', to handle the case where one
112  // of the bytes was represented by just a single digit.
113  if (isSeparatorChar(*p)) {
114  lower = upper;
115  upper = 0;
116  } else {
117  throw invalid_argument(
118  sformat("invalid MAC address '{}': contains non-hex digit", str));
119  }
120  }
121  ++p;
122  }
123 
124  // Update parsed with the newly parsed byte
125  parsed[byteIndex] = (upper << 4) | lower;
126  }
127 
128  if (p != str.end()) {
129  // String is too long to be a MAC address
130  throw invalid_argument(
131  sformat("invalid MAC address '{}': found trailing characters", str));
132  }
133 
134  // Only update now that we have successfully parsed the entire
135  // string. This way we remain unchanged on error.
136  setFromBinary(ByteRange(parsed, SIZE));
137 }
138 
140  if (value.size() != SIZE) {
141  throw invalid_argument(
142  sformat("MAC address must be 6 bytes long, got ", value.size()));
143  }
144  memcpy(bytes_ + 2, value.begin(), SIZE);
145 }
146 
147 std::ostream& operator<<(std::ostream& os, MacAddress address) {
148  os << address.toString();
149  return os;
150 }
151 
152 } // namespace folly
std::string toString() const
Definition: MacAddress.cpp:50
const unsigned char * bytes() const
Definition: IPAddressV6.h:367
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
static constexpr size_t SIZE
Definition: MacAddress.h:33
constexpr size_type size() const
Definition: Range.h:431
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static MacAddress createMulticast(IPAddressV6 addr)
Definition: MacAddress.cpp:39
static const MacAddress ZERO
Definition: MacAddress.h:35
void parse(StringPiece str)
Definition: MacAddress.cpp:74
const std::array< unsigned char, 256 > hexTable
Definition: String.cpp:120
const uint8_t * bytes() const
Definition: MacAddress.h:100
static T big(T x)
Definition: Bits.h:259
static const MacAddress BROADCAST
Definition: MacAddress.h:34
constexpr Iter end() const
Definition: Range.h:455
static MacAddress fromBinary(ByteRange value)
Definition: MacAddress.h:55
constexpr Iter begin() const
Definition: Range.h:452
void setFromBinary(ByteRange value)
Definition: MacAddress.cpp:139
bool isMulticast() const
const char * string
Definition: Conv.cpp:212
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
unsigned char bytes_[8]
Definition: MacAddress.h:210
char c
uint64_t getByte(size_t index) const
Definition: MacAddress.h:212
std::ostream & operator<<(std::ostream &out, dynamic const &d)
Definition: dynamic-inl.h:1158