Create MacAddress class for MAC address manipulation.

PiperOrigin-RevId: 752503841
This commit is contained in:
Francis Tsui
2025-04-28 17:22:45 -07:00
committed by Copybara-Service
parent 422030f826
commit 83ec6bcece
9 changed files with 237 additions and 70 deletions
+1
View File
@@ -524,6 +524,7 @@ let package = Package(
"internal/platform/bluetooth_utils_test.cc",
"internal/platform/credential_storage_impl_test.cc",
"internal/platform/input_stream_test.cc",
"internal/platform/mac_address_test.cc",
"internal/platform/single_thread_executor_test.cc",
"internal/platform/scheduled_executor_test.cc",
"internal/platform/stream_reader_test.cc",
+25
View File
@@ -347,6 +347,21 @@ cc_library(
],
)
cc_library(
name = "mac_address",
srcs = ["mac_address.cc"],
hdrs = ["mac_address.h"],
compatible_with = ["//buildenv/target:non_prod"],
visibility = [
"//:__subpackages__",
],
deps = [
":logging",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
cc_library(
name = "test_util",
testonly = True,
@@ -570,3 +585,13 @@ cc_test(
],
}),
)
cc_test(
name = "mac_address_test",
srcs = ["mac_address_test.cc"],
deps = [
":mac_address",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
@@ -251,6 +251,7 @@ cc_library(
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//internal/platform:types",
"//internal/platform:uuid",
"//internal/platform/flags:platform_flags",
@@ -13,51 +13,26 @@
// limitations under the License.
#include "internal/platform/implementation/windows/ble_v2_peripheral.h"
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/logging.h"
#include "internal/platform/mac_address.h"
namespace nearby {
namespace windows {
namespace {
constexpr int kMacAddressLength = 17;
}
BleV2Peripheral::BleV2Peripheral(absl::string_view address) {
if (SetAddress(address)) {
unique_id_ = static_cast<UniqueId>(BluetoothUtils::ToNumber(address));
if (!MacAddress::FromString(address, mac_address_)) {
LOG(WARNING) << "Create BleV2Peripheral with invalid MAC: " << address;
}
}
bool BleV2Peripheral::SetAddress(absl::string_view address) {
// The address must be in format "00:B0:D0:63:C2:26".
if (address.size() != kMacAddressLength) {
LOG(ERROR) << ": Invalid MAC address length.";
return false;
std::string BleV2Peripheral::GetAddress() const {
if (mac_address_.IsSet()) {
return mac_address_.ToString();
}
for (int i = 0; i < kMacAddressLength; ++i) {
if ((i % 3) == 0 || (i % 3) == 1) {
if ((address[i] >= '0' && address[i] <= '9') ||
(address[i] >= 'a' && address[i] <= 'f') ||
(address[i] >= 'A' && address[i] <= 'F')) {
continue;
}
} else {
if (address[i] == ':') {
continue;
}
}
LOG(ERROR) << ": Invalid MAC address format.";
return false;
}
address_ = std::string(address);
return true;
return "";
}
} // namespace windows
@@ -19,6 +19,7 @@
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/mac_address.h"
namespace nearby {
namespace windows {
@@ -31,21 +32,17 @@ class BleV2Peripheral : public api::ble_v2::BlePeripheral {
explicit BleV2Peripheral(absl::string_view address);
~BleV2Peripheral() override = default;
// Returns the MAC address of the peripheral. The format is in
// Returns the MAC address of the peripheral or empty string. The format is in
// "00:B0:D0:63:C2:26".
std::string GetAddress() const override { return address_; }
std::string GetAddress() const override;
UniqueId GetUniqueId() const override { return unique_id_; }
// Sets the MAC address of the peripheral. The address format must be in
// pattern of "00:B0:D0:63:C2:26".
bool SetAddress(absl::string_view address);
UniqueId GetUniqueId() const override { return mac_address_.address(); }
bool Ok() const { return unique_id_ != 0; }
bool Ok() const { return mac_address_.IsSet(); }
explicit operator bool() const { return Ok(); }
private:
std::string address_;
UniqueId unique_id_ = 0;
MacAddress mac_address_;
};
} // namespace windows
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/windows/ble_v2_peripheral.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
namespace nearby {
namespace windows {
@@ -26,38 +27,10 @@ TEST(BleV2Peripheral, Constructor) {
EXPECT_TRUE(ble_peripheral);
EXPECT_TRUE(ble_peripheral.Ok());
EXPECT_NE(ble_peripheral.GetUniqueId(), 0);
EXPECT_EQ(ble_peripheral.GetUniqueId(), 0xf1f2f3f4f5f6);
EXPECT_EQ(ble_peripheral.GetAddress(), kAddress);
}
TEST(BleV2Peripheral, SetMacAddress) {
BleV2Peripheral ble_peripheral("F1:F2:F3:F4:F5:F6");
EXPECT_TRUE(ble_peripheral.SetAddress("00:B0:D0:63:C2:26"));
EXPECT_FALSE(ble_peripheral.SetAddress("00:B0:D0:6T:C2:26"));
EXPECT_FALSE(ble_peripheral.SetAddress("00:B0:D0:63:C2:2"));
EXPECT_FALSE(ble_peripheral.SetAddress("0:B0:D0:63:C2:203"));
EXPECT_FALSE(ble_peripheral.SetAddress("0:B0:D0:6P:C2:203"));
}
TEST(BleV2Peripheral, SetAndGetMacAddress) {
constexpr absl::string_view kChangedAddress = "00:B0:D0:63:C2:26";
BleV2Peripheral ble_peripheral("F1:F2:F3:F4:F5:F6");
EXPECT_TRUE(ble_peripheral.SetAddress(kChangedAddress));
EXPECT_EQ(ble_peripheral.GetAddress(), kChangedAddress);
}
TEST(BleV2Peripheral, SetAddressDoesNotChangeUniqueId) {
constexpr absl::string_view kChangedAddress = "00:B0:D0:63:C2:26";
BleV2Peripheral ble_peripheral("F1:F2:F3:F4:F5:F6");
BleV2Peripheral::UniqueId unique_id = ble_peripheral.GetUniqueId();
EXPECT_NE(unique_id, 0);
EXPECT_TRUE(ble_peripheral.SetAddress(kChangedAddress));
EXPECT_EQ(ble_peripheral.GetAddress(), kChangedAddress);
EXPECT_EQ(ble_peripheral.GetUniqueId(), unique_id);
}
TEST(BleV2Peripheral, ConstructFromBadAddress) {
BleV2Peripheral ble_peripheral("G1:F2:F3:F4:F5:F6");
+68
View File
@@ -0,0 +1,68 @@
// Copyright 2025 Google LLC
//
// 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
//
// https://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 "internal/platform/mac_address.h"
#include <cstdint>
#include <string>
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
namespace nearby {
bool MacAddress::FromString(absl::string_view address,
MacAddress& mac_address) {
if (address.length() != 17) {
return false;
}
uint64_t address_int = 0;
for (int i = 0; i < 6; ++i) {
// Check for ":" separator.
if (i < 5 && address[i * 3 + 2] != ':') {
return false;
}
absl::string_view component;
component = address.substr(i * 3, 2);
uint64_t component_int = 0;
if (!absl::SimpleHexAtoi(component, &component_int)) {
return false;
}
address_int = (address_int << 8) | component_int;
}
mac_address.address_ = address_int;
return true;
}
bool MacAddress::FromUint64(uint64_t address, MacAddress& mac_address) {
if ((address & 0xffff000000000000L) != 0) {
return false;
}
mac_address.address_ = address;
return true;
}
std::string MacAddress::ToString() const {
return absl::StrCat(absl::StrFormat("%02X", (address_ >> 40) & 0xff), ":",
absl::StrFormat("%02X", (address_ >> 32) & 0xff), ":",
absl::StrFormat("%02X", (address_ >> 24) & 0xff), ":",
absl::StrFormat("%02X", (address_ >> 16) & 0xff), ":",
absl::StrFormat("%02X", (address_ >> 8) & 0xff), ":",
absl::StrFormat("%02X", address_ & 0xff));
}
} // namespace nearby
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2025 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_MAC_ADDRESS_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_MAC_ADDRESS_H_
#include <cstdint>
#include <string>
#include "absl/strings/string_view.h"
namespace nearby {
// Representation of a 48 bit MAC address.
class MacAddress {
public:
// Creates an empty MAC address with all 0s.
MacAddress() = default;
// Creates a MAC address from a string.
// Returns false if the string is not a valid MAC address.
static bool FromString(absl::string_view address, MacAddress& mac_address);
// Creates a MAC address from a 64-bit integer.
// The upper 16 bits of the address must be 0.
// Returns false if the integer is not a valid MAC address.
static bool FromUint64(uint64_t address, MacAddress& mac_address);
// Packs the MAC address into the lower 48 bits of a 64-bit integer.
uint64_t address() const { return address_; }
// Returns the MAC address in the format of "00:B0:D0:63:C2:26".
std::string ToString() const;
// Returns true if the MAC address is set.
bool IsSet() const { return address_ != 0; }
private:
uint64_t address_ = 0;
};
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_MAC_ADDRESS_H_
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2025 Google LLC
//
// 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
//
// https://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 "internal/platform/mac_address.h"
#include "gtest/gtest.h"
namespace nearby {
namespace {
TEST(MacAddressTest, FromStringSuccess) {
MacAddress mac_address;
EXPECT_TRUE(MacAddress::FromString("00:B0:D0:63:C2:26", mac_address));
EXPECT_EQ(mac_address.address(), 0x00B0D063C226);
EXPECT_EQ(mac_address.ToString(), "00:B0:D0:63:C2:26");
}
TEST(MacAddressTest, FromStringMissingSeparator) {
MacAddress mac_address;
EXPECT_FALSE(MacAddress::FromString("00:B0:D0,63:C2:26", mac_address));
EXPECT_EQ(mac_address.address(), 0);
}
TEST(MacAddressTest, FromStringInvalidHex) {
MacAddress mac_address;
EXPECT_FALSE(MacAddress::FromString("01:BG:D0,63:C2:26", mac_address));
EXPECT_EQ(mac_address.address(), 0);
}
TEST(MacAddressTest, FromStringInvalidLength) {
MacAddress mac_address;
EXPECT_FALSE(MacAddress::FromString("01:BG:D0,63:C2:1", mac_address));
EXPECT_EQ(mac_address.address(), 0);
}
TEST(MacAddressTest, FromUint64Success) {
MacAddress mac_address;
EXPECT_TRUE(MacAddress::FromUint64(0x00B0D063C226, mac_address));
EXPECT_EQ(mac_address.address(), 0x00B0D063C226);
}
TEST(MacAddressTest, FromUint64InvalidAddresss) {
MacAddress mac_address;
EXPECT_FALSE(MacAddress::FromUint64(0x0100B0D063C226, mac_address));
EXPECT_EQ(mac_address.address(), 0);
}
TEST(MacAddressTest, IsSetTrue) {
MacAddress mac_address;
EXPECT_TRUE(MacAddress::FromUint64(0x00B0D063C226, mac_address));
EXPECT_TRUE(mac_address.IsSet());
}
TEST(MacAddressTest, IsSetFalse) {
MacAddress mac_address;
EXPECT_FALSE(mac_address.IsSet());
}
} // namespace
} // namespace nearby