Commit b07e3455 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

MacAddress updaters and factories

Summary: [Folly] `MacAddress` updater and factory suite for parsing string and binary representations and throwing or returning unexpected on parse failures.

Differential Revision: D21273907

fbshipit-source-id: 664cd1980cb12f3352eecf0e25671dca04c4a8a0
parent 35581869
...@@ -72,7 +72,28 @@ string MacAddress::toString() const { ...@@ -72,7 +72,28 @@ string MacAddress::toString() const {
return result; return result;
} }
void MacAddress::parse(StringPiece str) { Expected<Unit, MacAddressFormatError> MacAddress::trySetFromString(
StringPiece value) {
return setFromString(value, [](auto _, auto) { return makeUnexpected(_); });
}
void MacAddress::setFromString(StringPiece value) {
setFromString(value, [](auto, auto _) { return _(), unit; });
}
Expected<Unit, MacAddressFormatError> MacAddress::trySetFromBinary(
ByteRange value) {
return setFromBinary(value, [](auto _, auto) { return makeUnexpected(_); });
}
void MacAddress::setFromBinary(ByteRange value) {
setFromBinary(value, [](auto, auto _) { return _(), unit; });
}
template <typename OnError>
Expected<Unit, MacAddressFormatError> MacAddress::setFromString(
StringPiece str,
OnError err) {
// Helper function to convert a single hex char into an integer // Helper function to convert a single hex char into an integer
auto isSeparatorChar = [](char c) { return c == ':' || c == '-'; }; auto isSeparatorChar = [](char c) { return c == ':' || c == '-'; };
...@@ -80,24 +101,30 @@ void MacAddress::parse(StringPiece str) { ...@@ -80,24 +101,30 @@ void MacAddress::parse(StringPiece str) {
auto p = str.begin(); auto p = str.begin();
for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) { for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) {
if (p == str.end()) { if (p == str.end()) {
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("invalid MAC address '{}': not enough digits", str)); throw invalid_argument(
sformat("invalid MAC address '{}': not enough digits", str));
});
} }
// Skip over ':' or '-' separators between bytes // Skip over ':' or '-' separators between bytes
if (byteIndex != 0 && isSeparatorChar(*p)) { if (byteIndex != 0 && isSeparatorChar(*p)) {
++p; ++p;
if (p == str.end()) { if (p == str.end()) {
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("invalid MAC address '{}': not enough digits", str)); throw invalid_argument(
sformat("invalid MAC address '{}': not enough digits", str));
});
} }
} }
// Parse the upper nibble // Parse the upper nibble
uint8_t upper = detail::hexTable[static_cast<uint8_t>(*p)]; uint8_t upper = detail::hexTable[static_cast<uint8_t>(*p)];
if (upper & 0x10) { if (upper & 0x10) {
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("invalid MAC address '{}': contains non-hex digit", str)); throw invalid_argument(
sformat("invalid MAC address '{}': contains non-hex digit", str));
});
} }
++p; ++p;
...@@ -115,8 +142,10 @@ void MacAddress::parse(StringPiece str) { ...@@ -115,8 +142,10 @@ void MacAddress::parse(StringPiece str) {
lower = upper; lower = upper;
upper = 0; upper = 0;
} else { } else {
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("invalid MAC address '{}': contains non-hex digit", str)); throw invalid_argument(sformat(
"invalid MAC address '{}': contains non-hex digit", str));
});
} }
} }
++p; ++p;
...@@ -128,21 +157,29 @@ void MacAddress::parse(StringPiece str) { ...@@ -128,21 +157,29 @@ void MacAddress::parse(StringPiece str) {
if (p != str.end()) { if (p != str.end()) {
// String is too long to be a MAC address // String is too long to be a MAC address
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("invalid MAC address '{}': found trailing characters", str)); throw invalid_argument(
sformat("invalid MAC address '{}': found trailing characters", str));
});
} }
// Only update now that we have successfully parsed the entire // Only update now that we have successfully parsed the entire
// string. This way we remain unchanged on error. // string. This way we remain unchanged on error.
setFromBinary(ByteRange(parsed, SIZE)); return setFromBinary(ByteRange(parsed, SIZE), err);
} }
void MacAddress::setFromBinary(ByteRange value) { template <typename OnError>
Expected<Unit, MacAddressFormatError> MacAddress::setFromBinary(
ByteRange value,
OnError err) {
if (value.size() != SIZE) { if (value.size() != SIZE) {
throw invalid_argument( return err(MacAddressFormatError::Invalid, [&] {
sformat("MAC address must be 6 bytes long, got ", value.size())); throw invalid_argument(
sformat("MAC address must be 6 bytes long, got ", value.size()));
});
} }
memcpy(bytes_ + 2, value.begin(), SIZE); memcpy(bytes_ + 2, value.begin(), SIZE);
return unit;
} }
std::ostream& operator<<(std::ostream& os, MacAddress address) { std::ostream& operator<<(std::ostream& os, MacAddress address) {
......
...@@ -19,13 +19,19 @@ ...@@ -19,13 +19,19 @@
#include <iosfwd> #include <iosfwd>
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Expected.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/Unit.h>
#include <folly/lang/Bits.h> #include <folly/lang/Bits.h>
namespace folly { namespace folly {
class IPAddressV6; class IPAddressV6;
enum class MacAddressFormatError {
Invalid,
};
/* /*
* MacAddress represents an IEEE 802 MAC address. * MacAddress represents an IEEE 802 MAC address.
*/ */
...@@ -50,9 +56,33 @@ class MacAddress { ...@@ -50,9 +56,33 @@ class MacAddress {
*/ */
explicit MacAddress(StringPiece str); explicit MacAddress(StringPiece str);
static Expected<MacAddress, MacAddressFormatError> tryFromString(
StringPiece value) {
MacAddress ret;
auto ok = ret.trySetFromString(value);
if (!ok) {
return makeUnexpected(ok.error());
}
return ret;
}
static MacAddress fromString(StringPiece value) {
MacAddress ret;
ret.setFromString(value);
return ret;
}
/* /*
* Construct a MAC address from its 6-byte binary value * Construct a MAC address from its 6-byte binary value
*/ */
static Expected<MacAddress, MacAddressFormatError> tryFromBinary(
ByteRange value) {
MacAddress ret;
auto ok = ret.trySetFromBinary(value);
if (!ok) {
return makeUnexpected(ok.error());
}
return ret;
}
static MacAddress fromBinary(ByteRange value) { static MacAddress fromBinary(ByteRange value) {
MacAddress ret; MacAddress ret;
ret.setFromBinary(value); ret.setFromBinary(value);
...@@ -135,11 +165,16 @@ class MacAddress { ...@@ -135,11 +165,16 @@ class MacAddress {
/* /*
* Update the current MacAddress object from a human-readable string. * Update the current MacAddress object from a human-readable string.
*/ */
void parse(StringPiece str); Expected<Unit, MacAddressFormatError> trySetFromString(StringPiece value);
void setFromString(StringPiece value);
void parse(StringPiece str) {
setFromString(str);
}
/* /*
* Update the current MacAddress object from a 6-byte binary representation. * Update the current MacAddress object from a 6-byte binary representation.
*/ */
Expected<Unit, MacAddressFormatError> trySetFromBinary(ByteRange value);
void setFromBinary(ByteRange value); void setFromBinary(ByteRange value);
bool isBroadcast() const { bool isBroadcast() const {
...@@ -204,6 +239,16 @@ class MacAddress { ...@@ -204,6 +239,16 @@ class MacAddress {
bytes_[1] = 0; bytes_[1] = 0;
} }
template <typename OnError>
Expected<Unit, MacAddressFormatError> setFromString(
StringPiece value,
OnError err);
template <typename OnError>
Expected<Unit, MacAddressFormatError> setFromBinary(
ByteRange value,
OnError err);
/* We store the 6 bytes starting at bytes_[2] (most significant) /* We store the 6 bytes starting at bytes_[2] (most significant)
through bytes_[7] (least). through bytes_[7] (least).
bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons. bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons.
......
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