Files
nearby/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc
T
Guogang Li a2bcb2db27 Fix asan/msan bug
PiperOrigin-RevId: 780237506
2025-07-07 13:30:50 -07:00

180 lines
6.7 KiB
C++

// Copyright 2020-2023 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 "connections/implementation/mediums/ble_v2/ble_advertisement_header.h"
#include <string>
#include <utility>
#include "absl/strings/str_cat.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/logging.h"
#include "internal/platform/stream_reader.h"
namespace nearby {
namespace connections {
namespace mediums {
// These definitions are necessary before C++17.
constexpr int BleAdvertisementHeader::kAdvertisementHashByteLength;
constexpr int BleAdvertisementHeader::kServiceIdBloomFilterByteLength;
constexpr int BleAdvertisementHeader::kDefaultPsmValue;
constexpr int BleAdvertisementHeader::kPsmValueByteLength;
BleAdvertisementHeader::BleAdvertisementHeader(
Version version, bool support_extended_advertisement, int num_slots,
const ByteArray &service_id_bloom_filter,
const ByteArray &advertisement_hash, int psm) {
if (version != Version::kV2 || num_slots < 0 ||
service_id_bloom_filter.size() != kServiceIdBloomFilterByteLength ||
advertisement_hash.size() != kAdvertisementHashByteLength) {
return;
}
version_ = version;
support_extended_advertisement_ = support_extended_advertisement;
num_slots_ = num_slots;
service_id_bloom_filter_ = service_id_bloom_filter;
advertisement_hash_ = advertisement_hash;
psm_ = psm;
}
BleAdvertisementHeader::BleAdvertisementHeader(
const ByteArray &ble_advertisement_header_bytes) {
ByteArray advertisement_header_bytes =
Base64Utils::Decode(ble_advertisement_header_bytes.AsStringView());
if (advertisement_header_bytes.Empty()) {
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableBleV2)) {
// The BLE advertisement header is not encoded in base64, but still try to
// parse it as raw bytes.
if (ble_advertisement_header_bytes.size() ==
kMinAdvertisementHeaderLength ||
ble_advertisement_header_bytes.size() ==
kMinAdvertisementHeaderLength + 2) {
advertisement_header_bytes = ble_advertisement_header_bytes;
} else {
NEARBY_VLOG(1) << "Cannot deserialize BLEAdvertisementHeader. "
"Invalid advertising data.";
return;
}
} else {
LOG(INFO) << "Cannot deserialize BLEAdvertisementHeader: failed "
"Base64 decoding";
return;
}
}
if (advertisement_header_bytes.size() < kMinAdvertisementHeaderLength) {
LOG(INFO) << "Cannot deserialize BleAdvertisementHeader: expecting min "
<< kMinAdvertisementHeaderLength << "raw bytes, got "
<< advertisement_header_bytes.size();
return;
}
StreamReader stream_reader(&advertisement_header_bytes);
// The first 1 byte is supposed to be the version and number of slots.
auto version_and_num_slots_byte = stream_reader.ReadUint8();
if (!version_and_num_slots_byte.has_value()) {
LOG(INFO) << "Cannot deserialize BleAdvertisementHeader: version_and_num.";
return;
}
// The upper 3 bits are supposed to be the version.
version_ = static_cast<Version>(
(*version_and_num_slots_byte & kVersionBitmask) >> 5);
if (version_ != Version::kV2) {
LOG(INFO)
<< "Cannot deserialize BleAdvertisementHeader: unsupported Version "
<< static_cast<int>(version_);
return;
}
// The next 1 bit is supposed to be the extended advertisement flag.
support_extended_advertisement_ =
((*version_and_num_slots_byte & kExtendedAdvertismentBitMask) >> 4) == 1;
// The lower 4 bits are supposed to be the number of slots.
num_slots_ = static_cast<int>(*version_and_num_slots_byte & kNumSlotsBitmask);
if (num_slots_ < 0) {
version_ = Version::kUndefined;
return;
}
// The next 10 bytes are supposed to be the service_id_bloom_filter.
service_id_bloom_filter_ =
stream_reader.ReadBytes(kServiceIdBloomFilterByteLength)
.value_or(ByteArray());
// The next 4 bytes are supposed to be the advertisement_hash.
advertisement_hash_ = stream_reader.ReadBytes(kAdvertisementHashByteLength)
.value_or(ByteArray());
// The next 2 bytes are PSM value.
if (stream_reader.IsAvailable(kPsmValueByteLength)) {
psm_ = stream_reader.ReadInt16().value_or(0);
}
}
BleAdvertisementHeader::operator ByteArray() const {
if (!IsValid()) {
return ByteArray();
}
// The first 3 bits are the Version.
char version_and_num_slots_byte =
(static_cast<char>(version_) << 5) & kVersionBitmask;
// The next 1 bit is extended advertisement flag.
version_and_num_slots_byte |=
(static_cast<char>(support_extended_advertisement_) << 4) &
kExtendedAdvertismentBitMask;
// The next 5 bits are the number of slots.
version_and_num_slots_byte |=
static_cast<char>(num_slots_) & kNumSlotsBitmask;
// Convert psm_ value to 2-bytes.
ByteArray psm_bytes{kPsmValueByteLength};
char *data = psm_bytes.data();
data[0] = (psm_ & 0xFF00) >> 8;
data[1] = psm_ & 0x00FF;
// clang-format off
std::string out = absl::StrCat(std::string(1, version_and_num_slots_byte),
std::string(service_id_bloom_filter_),
std::string(advertisement_hash_),
std::string(psm_bytes));
// clang-format on
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableBleV2)) {
return ByteArray(std::move(out));
} else {
return ByteArray(Base64Utils::Encode(ByteArray(std::move(out))));
}
}
bool BleAdvertisementHeader::operator==(
const BleAdvertisementHeader &rhs) const {
return GetVersion() == rhs.GetVersion() &&
IsSupportExtendedAdvertisement() ==
rhs.IsSupportExtendedAdvertisement() &&
GetNumSlots() == rhs.GetNumSlots() &&
GetServiceIdBloomFilter() == rhs.GetServiceIdBloomFilter() &&
GetAdvertisementHash() == rhs.GetAdvertisementHash() &&
GetPsm() == rhs.GetPsm();
}
} // namespace mediums
} // namespace connections
} // namespace nearby