MacAddress.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. #include <folly/MacAddress.h>
  17. #include <ostream>
  18. #include <folly/Exception.h>
  19. #include <folly/Format.h>
  20. #include <folly/IPAddressV6.h>
  21. #include <folly/String.h>
  22. using std::invalid_argument;
  23. using std::string;
  24. namespace folly {
  25. const MacAddress MacAddress::BROADCAST{Endian::big(uint64_t(0xffffffffffffU))};
  26. const MacAddress MacAddress::ZERO;
  27. MacAddress::MacAddress(StringPiece str) {
  28. memset(&bytes_, 0, 8);
  29. parse(str);
  30. }
  31. MacAddress MacAddress::createMulticast(IPAddressV6 v6addr) {
  32. // This method should only be used for multicast addresses.
  33. DCHECK(v6addr.isMulticast());
  34. uint8_t bytes[SIZE];
  35. bytes[0] = 0x33;
  36. bytes[1] = 0x33;
  37. memcpy(bytes + 2, v6addr.bytes() + 12, 4);
  38. return fromBinary(ByteRange(bytes, SIZE));
  39. }
  40. string MacAddress::toString() const {
  41. static const char hexValues[] = "0123456789abcdef";
  42. string result;
  43. result.resize(17);
  44. result[0] = hexValues[getByte(0) >> 4];
  45. result[1] = hexValues[getByte(0) & 0xf];
  46. result[2] = ':';
  47. result[3] = hexValues[getByte(1) >> 4];
  48. result[4] = hexValues[getByte(1) & 0xf];
  49. result[5] = ':';
  50. result[6] = hexValues[getByte(2) >> 4];
  51. result[7] = hexValues[getByte(2) & 0xf];
  52. result[8] = ':';
  53. result[9] = hexValues[getByte(3) >> 4];
  54. result[10] = hexValues[getByte(3) & 0xf];
  55. result[11] = ':';
  56. result[12] = hexValues[getByte(4) >> 4];
  57. result[13] = hexValues[getByte(4) & 0xf];
  58. result[14] = ':';
  59. result[15] = hexValues[getByte(5) >> 4];
  60. result[16] = hexValues[getByte(5) & 0xf];
  61. return result;
  62. }
  63. void MacAddress::parse(StringPiece str) {
  64. // Helper function to convert a single hex char into an integer
  65. auto isSeparatorChar = [](char c) { return c == ':' || c == '-'; };
  66. uint8_t parsed[SIZE];
  67. auto p = str.begin();
  68. for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) {
  69. if (p == str.end()) {
  70. throw invalid_argument(
  71. sformat("invalid MAC address '{}': not enough digits", str));
  72. }
  73. // Skip over ':' or '-' separators between bytes
  74. if (byteIndex != 0 && isSeparatorChar(*p)) {
  75. ++p;
  76. if (p == str.end()) {
  77. throw invalid_argument(
  78. sformat("invalid MAC address '{}': not enough digits", str));
  79. }
  80. }
  81. // Parse the upper nibble
  82. uint8_t upper = detail::hexTable[static_cast<uint8_t>(*p)];
  83. if (upper & 0x10) {
  84. throw invalid_argument(
  85. sformat("invalid MAC address '{}': contains non-hex digit", str));
  86. }
  87. ++p;
  88. // Parse the lower nibble
  89. uint8_t lower;
  90. if (p == str.end()) {
  91. lower = upper;
  92. upper = 0;
  93. } else {
  94. lower = detail::hexTable[static_cast<uint8_t>(*p)];
  95. if (lower & 0x10) {
  96. // Also accept ':', '-', or '\0', to handle the case where one
  97. // of the bytes was represented by just a single digit.
  98. if (isSeparatorChar(*p)) {
  99. lower = upper;
  100. upper = 0;
  101. } else {
  102. throw invalid_argument(
  103. sformat("invalid MAC address '{}': contains non-hex digit", str));
  104. }
  105. }
  106. ++p;
  107. }
  108. // Update parsed with the newly parsed byte
  109. parsed[byteIndex] = (upper << 4) | lower;
  110. }
  111. if (p != str.end()) {
  112. // String is too long to be a MAC address
  113. throw invalid_argument(
  114. sformat("invalid MAC address '{}': found trailing characters", str));
  115. }
  116. // Only update now that we have successfully parsed the entire
  117. // string. This way we remain unchanged on error.
  118. setFromBinary(ByteRange(parsed, SIZE));
  119. }
  120. void MacAddress::setFromBinary(ByteRange value) {
  121. if (value.size() != SIZE) {
  122. throw invalid_argument(
  123. sformat("MAC address must be 6 bytes long, got ", value.size()));
  124. }
  125. memcpy(bytes_ + 2, value.begin(), SIZE);
  126. }
  127. std::ostream& operator<<(std::ostream& os, MacAddress address) {
  128. os << address.toString();
  129. return os;
  130. }
  131. } // namespace folly