Merge branch 'master' into release

Change-Id: I89401ad2264e728c6a9e5feadf00f92ce60c7248
This commit is contained in:
Alexey Polyudov
2020-09-03 02:23:32 -07:00
39 changed files with 1266 additions and 650 deletions
-4
View File
@@ -101,7 +101,6 @@ cc_test(
deps = [
":mediums",
"//platform:utils",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
@@ -112,7 +111,6 @@ cc_test(
srcs = ["ble_advertisement_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
@@ -123,7 +121,6 @@ cc_test(
srcs = ["ble_packet_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
@@ -134,7 +131,6 @@ cc_test(
srcs = ["bloom_filter_test.cc"],
deps = [
":mediums",
"//platform/api",
"//platform/impl/g3",
"//testing/base/public:gunit_main",
],
+1
View File
@@ -75,6 +75,7 @@ cc_library(
"//core/internal:message_lite",
"//core_v2:core_types",
"//core_v2/internal/mediums",
"//core_v2/internal/mediums:utils",
"//core_v2/internal/mediums/webrtc",
"//proto/connections:offline_wire_formats_portable_proto",
"//platform_v2/base",
+1 -16
View File
@@ -15,11 +15,7 @@
cc_library(
name = "mediums",
srcs = [
"advertisement_read_result.cc",
"ble.cc",
"ble_advertisement.cc",
"ble_advertisement_header.cc",
"ble_packet.cc",
"bloom_filter.cc",
"bluetooth_classic.cc",
"bluetooth_radio.cc",
@@ -29,12 +25,7 @@ cc_library(
"wifi_lan.cc",
],
hdrs = [
"advertisement_read_result.h",
"ble.h",
"ble_advertisement.h",
"ble_advertisement_header.h",
"ble_packet.h",
"ble_peripheral.h",
"bloom_filter.h",
"bluetooth_classic.h",
"bluetooth_radio.h",
@@ -51,7 +42,6 @@ cc_library(
"//core_v2:core_types",
"//core_v2/internal/mediums/webrtc",
"//platform_v2/base",
"//platform_v2/base:util",
"//platform_v2/public:comm",
"//platform_v2/public:logging",
"//platform_v2/public:types",
@@ -73,11 +63,11 @@ cc_library(
hdrs = ["utils.h"],
visibility = [
"//core_v2/internal:__pkg__",
"//core_v2/internal/mediums/ble_v2:__pkg__",
"//core_v2/internal/mediums/webrtc:__pkg__",
],
deps = [
"//platform_v2/base",
"//platform_v2/public:comm",
"//platform_v2/public:types",
],
)
@@ -86,11 +76,6 @@ cc_test(
name = "core_v2_internal_mediums_test",
size = "small",
srcs = [
"advertisement_read_result_test.cc",
"ble_advertisement_header_test.cc",
"ble_advertisement_test.cc",
"ble_packet_test.cc",
"ble_peripheral_test.cc",
"ble_test.cc",
"bloom_filter_test.cc",
"bluetooth_classic_test.cc",
@@ -1,187 +0,0 @@
// Copyright 2020 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 "core_v2/internal/mediums/ble_advertisement.h"
#include <inttypes.h>
#include "platform_v2/base/base_input_stream.h"
#include "platform_v2/public/logging.h"
#include "absl/strings/str_cat.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
BleAdvertisement::BleAdvertisement(Version version,
SocketVersion socket_version,
const ByteArray &service_id_hash,
const ByteArray &data) {
// Check that the given input is valid.
if (!IsSupportedVersion(version) ||
!IsSupportedSocketVersion(socket_version) ||
service_id_hash.size() != kServiceIdHashLength ||
data.size() > kMaxDataSize) {
return;
}
version_ = version;
socket_version_ = socket_version;
service_id_hash_ = service_id_hash;
data_ = data;
}
BleAdvertisement::BleAdvertisement(const ByteArray &ble_advertisement_bytes) {
if (ble_advertisement_bytes.Empty()) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: null bytes passed in.");
return;
}
if (ble_advertisement_bytes.size() < kMinAdvertisementLength) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: expecting min %d raw "
"bytes, got %" PRIu64,
kMinAdvertisementLength, ble_advertisement_bytes.size());
return;
}
ByteArray advertisement_bytes{ble_advertisement_bytes};
BaseInputStream base_input_stream{advertisement_bytes};
// The first 1 byte is supposed to be the version and socket version.
auto version_and_socket_version_byte =
static_cast<char>(base_input_stream.ReadUint8());
// Version.
version_ = static_cast<Version>(
(version_and_socket_version_byte & kVersionBitmask) >> 5);
if (!IsSupportedVersion(version_)) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: unsupported Version %u",
version_);
return;
}
// Socket version.
socket_version_ = static_cast<SocketVersion>(
(version_and_socket_version_byte & kSocketVersionBitmask) >> 2);
if (!IsSupportedSocketVersion(socket_version_)) {
NEARBY_LOG(
INFO,
"Cannot deserialize BleAdvertisement: unsupported SocketVersion %u",
socket_version_);
version_ = Version::kUndefined;
return;
}
// The next 3 bytes are supposed to be the service_id_hash.
service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength);
// The next 4 bytes are supposed to be the length of the data.
std::uint32_t expected_data_size = base_input_stream.ReadUint32();
if (expected_data_size < 0) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: negative data size %d",
expected_data_size);
version_ = Version::kUndefined;
return;
}
// The rest bytes are supposed to be the data.
// Check that the stated data size is the same as what we received.
data_ = base_input_stream.ReadBytes(expected_data_size);
if (data_.size() != expected_data_size) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: expected data to be %u "
"bytes, got %" PRIu64 " bytes ",
expected_data_size, data_.size());
version_ = Version::kUndefined;
return;
}
}
BleAdvertisement::operator ByteArray() const {
if (!IsValid()) {
return ByteArray{};
}
// The first 3 bits are the Version.
char version_and_socket_version_byte =
(static_cast<char>(version_) << 5) & kVersionBitmask;
// The next 3 bits are the Socket version. 2 bits left are reserved.
version_and_socket_version_byte |=
(static_cast<char>(socket_version_) << 2) & kSocketVersionBitmask;
// Serialize Data size bytes(4).
ByteArray data_size_bytes{kDataSizeLength};
auto *data_size_bytes_write_ptr = data_size_bytes.data();
SerializeDataSize(data_size_bytes_write_ptr, data_.size());
// clang-format off
std::string out =
absl::StrCat(std::string(1, version_and_socket_version_byte),
std::string(service_id_hash_),
std::string(data_size_bytes),
std::string(data_));
// clang-format on
return ByteArray{std::move(out)};
}
bool BleAdvertisement::operator==(const BleAdvertisement &rhs) const {
return this->GetVersion() == rhs.GetVersion() &&
this->GetSocketVersion() == rhs.GetSocketVersion() &&
this->GetServiceIdHash() == rhs.GetServiceIdHash() &&
this->GetData() == rhs.GetData();
}
bool BleAdvertisement::operator<(const BleAdvertisement &rhs) const {
if (this->GetVersion() != rhs.GetVersion()) {
return this->GetVersion() < rhs.GetVersion();
}
if (this->GetSocketVersion() != rhs.GetSocketVersion()) {
return this->GetSocketVersion() < rhs.GetSocketVersion();
}
if (this->GetServiceIdHash() != rhs.GetServiceIdHash()) {
return this->GetServiceIdHash() < rhs.GetServiceIdHash();
}
return this->GetData() < rhs.GetData();
}
bool BleAdvertisement::IsSupportedVersion(Version version) const {
return version >= Version::kV1 && version <= Version::kV2;
}
bool BleAdvertisement::IsSupportedSocketVersion(
SocketVersion socket_version) const {
return socket_version >= SocketVersion::kV1 &&
socket_version <= SocketVersion::kV2;
}
void BleAdvertisement::SerializeDataSize(char *data_size_bytes_write_ptr,
size_t data_size) const {
// Get a raw representation of the data size bytes in memory.
char *data_size_bytes = reinterpret_cast<char *>(&data_size);
// Append these raw bytes to advertisement bytes, keeping in mind that we need
// to convert from Little Endian to Big Endian in the process.
for (int i = 0; i < kDataSizeLength; ++i) {
data_size_bytes_write_ptr[i] = data_size_bytes[kDataSizeLength - i - 1];
}
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -1,233 +0,0 @@
// Copyright 2020 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 "core_v2/internal/mediums/ble_advertisement.h"
#include <algorithm>
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
constexpr BleAdvertisement::Version kVersion = BleAdvertisement::Version::kV2;
constexpr BleAdvertisement::SocketVersion kSocketVersion =
BleAdvertisement::SocketVersion::kV2;
constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"};
constexpr absl::string_view kData{
"How much wood can a woodchuck chuck if a wood chuck would chuck wood?"};
// This corresponds to the length of a specific BleAdvertisement packed with the
// kData given above. Be sure to update this if kData ever changes.
constexpr size_t kAdvertisementLength = 77;
constexpr size_t kLongAdvertisementLength = kAdvertisementLength + 1000;
TEST(BleAdvertisementTest, ConstructionWorksV1) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{BleAdvertisement::Version::kV1,
BleAdvertisement::SocketVersion::kV1,
service_id_hash, data};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_EQ(BleAdvertisement::Version::kV1, ble_advertisement.GetVersion());
EXPECT_EQ(BleAdvertisement::SocketVersion::kV1,
ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(data, ble_advertisement.GetData());
}
TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) {
BleAdvertisement::Version bad_version =
static_cast<BleAdvertisement::Version>(666);
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{bad_version, kSocketVersion,
service_id_hash, data};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithBadSocketVersion) {
BleAdvertisement::SocketVersion bad_socket_version =
static_cast<BleAdvertisement::SocketVersion>(666);
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{kVersion, bad_socket_version,
service_id_hash, data};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithShortServiceIdHash) {
char short_service_id_hash_bytes[] = "\x0a\x0b";
ByteArray bad_service_id_hash{short_service_id_hash_bytes};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{kVersion, kSocketVersion,
bad_service_id_hash, data};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithLongServiceIdHash) {
char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d";
ByteArray bad_service_id_hash{long_service_id_hash_bytes};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{kVersion, kSocketVersion,
bad_service_id_hash, data};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithLongData) {
// BleAdvertisement shouldn't be able to support data with the max GATT
// attribute length because it needs some room for the preceding fields.
char long_data[512]{};
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray bad_data{long_data, 512};
BleAdvertisement ble_advertisement{kVersion, kSocketVersion, service_id_hash,
bad_data};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFromSerializedBytesWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement org_ble_advertisement{kVersion, kSocketVersion,
service_id_hash, data};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(data, ble_advertisement.GetData());
}
TEST(BleAdvertisementTest, ConstructionFromSerializedBytesWithEmptyDataWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
BleAdvertisement org_ble_advertisement{kVersion, kSocketVersion,
service_id_hash, ByteArray()};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_TRUE(ble_advertisement.GetData().Empty());
}
TEST(BleAdvertisementTest, ConstructionFromExtraSerializedBytesWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement org_ble_advertisement{kVersion, kSocketVersion,
service_id_hash, data};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Copy the bytes into a new array with extra bytes. We must explicitly
// define how long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kLongAdvertisementLength]{};
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
std::min(sizeof(raw_ble_advertisement_bytes),
org_ble_advertisement_bytes.size()));
// Re-parse the Ble advertisement using our extra long advertisement bytes.
ByteArray long_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kLongAdvertisementLength};
BleAdvertisement long_ble_advertisement{long_ble_advertisement_bytes};
EXPECT_TRUE(long_ble_advertisement.IsValid());
EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, long_ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, long_ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), long_ble_advertisement.GetData().size());
EXPECT_EQ(data, long_ble_advertisement.GetData());
}
TEST(BleAdvertisementTest, ConstructionFromNullBytesFails) {
BleAdvertisement ble_advertisement{ByteArray{}};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFromShortLengthSerializedBytesFails) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement org_ble_advertisement{kVersion, kSocketVersion,
service_id_hash, data};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Cut off the advertisement so that it's too short.
ByteArray short_ble_advertisement_bytes{org_ble_advertisement_bytes.data(),
7};
BleAdvertisement short_ble_advertisement{short_ble_advertisement_bytes};
EXPECT_FALSE(short_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest,
ConstructionFromSerializedBytesWithInvalidDataLengthFails) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement org_ble_advertisement{kVersion, kSocketVersion,
service_id_hash, data};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Corrupt the DATA_SIZE bits. Start by making a raw copy of the Ble
// advertisement bytes so we can modify it. We must explicitly define how
// long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kAdvertisementLength];
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
kAdvertisementLength);
// The data size field lives in indices 4-7. Corrupt it.
memset(raw_ble_advertisement_bytes + 4, 0xFF, 4);
// Try to parse the Ble advertisement using our corrupted advertisement bytes.
ByteArray corrupted_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kAdvertisementLength};
BleAdvertisement corrupted_ble_advertisement{
corrupted_ble_advertisement_bytes};
EXPECT_FALSE(corrupted_ble_advertisement.IsValid());
}
} // namespace
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
+26 -23
View File
@@ -71,14 +71,14 @@ TEST_F(BleTest, CanStartAdvertising) {
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
CountDownLatch found_latch(1);
ble_b.StartScanning(service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](BlePeripheral& peripheral,
const std::string& service_id) {
found_latch.CountDown();
},
});
ble_b.StartScanning(
service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { found_latch.CountDown(); },
});
EXPECT_TRUE(ble_a.StartAdvertising(service_id, advertisement_bytes));
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
@@ -103,18 +103,18 @@ TEST_F(BleTest, CanStartDiscovery) {
ble_b.StartAdvertising(service_id, advertisement_bytes);
EXPECT_TRUE(ble_a.StartScanning(
service_id, DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&accept_latch](BlePeripheral& peripheral,
const std::string& service_id) {
accept_latch.CountDown();
},
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
}));
service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&accept_latch](
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { accept_latch.CountDown(); },
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
}));
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
ble_b.StopAdvertising(service_id);
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
@@ -149,10 +149,13 @@ TEST_F(BleTest, CanStartAcceptingConnectionsAndConnect) {
{
.peripheral_discovered_cb =
[&found_latch, &discovered_peripheral](
BlePeripheral& peripheral, const std::string& service_id) {
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) {
discovered_peripheral = peripheral;
NEARBY_LOG(INFO, "Discovered peripheral=%p [impl=%p]",
&peripheral, &peripheral.GetImpl());
NEARBY_LOG(
INFO,
"Discovered peripheral=%p [impl=%p], fast advertisement=%d",
&peripheral, &peripheral.GetImpl(), fast_advertisement);
found_latch.CountDown();
},
});
+63
View File
@@ -0,0 +1,63 @@
# Copyright 2020 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.
cc_library(
name = "ble_v2",
srcs = [
"advertisement_read_result.cc",
"ble_advertisement.cc",
"ble_advertisement_header.cc",
"ble_packet.cc",
],
hdrs = [
"advertisement_read_result.h",
"ble_advertisement.h",
"ble_advertisement_header.h",
"ble_packet.h",
"ble_peripheral.h",
"discovered_peripheral_callback.h",
],
visibility = [
"//core_v2/internal:__subpackages__",
],
deps = [
"//core_v2:core_types",
"//platform_v2/base",
"//platform_v2/base:util",
"//platform_v2/public:logging",
"//platform_v2/public:types",
"//absl/container:flat_hash_map",
"//absl/container:flat_hash_set",
"//absl/strings",
"//absl/time",
],
)
cc_test(
name = "ble_v2_test",
srcs = [
"advertisement_read_result_test.cc",
"ble_advertisement_header_test.cc",
"ble_advertisement_test.cc",
"ble_packet_test.cc",
"ble_peripheral_test.cc",
],
deps = [
":ble_v2",
"//platform_v2/base",
"//platform_v2/impl/g3", # buildcleaner: keep
"//testing/base/public:gunit_main",
"//absl/time",
],
)
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/advertisement_read_result.h"
#include "core_v2/internal/mediums/ble_v2/advertisement_read_result.h"
#include <algorithm>
#include <vector>
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_
#define CORE_V2_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_
#include <cstdint>
#include <vector>
@@ -101,4 +101,4 @@ class AdvertisementReadResult {
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_ADVERTISEMENT_READ_RESULT_H_
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_ADVERTISEMENT_READ_RESULT_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/advertisement_read_result.h"
#include "core_v2/internal/mediums/ble_v2/advertisement_read_result.h"
#include "gtest/gtest.h"
#include "absl/time/clock.h"
@@ -0,0 +1,258 @@
// Copyright 2020 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 "core_v2/internal/mediums/ble_v2/ble_advertisement.h"
#include <inttypes.h>
#include "platform_v2/base/base_input_stream.h"
#include "platform_v2/public/logging.h"
#include "absl/strings/str_cat.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
BleAdvertisement::BleAdvertisement(Version version,
SocketVersion socket_version,
const ByteArray &service_id_hash,
const ByteArray &data,
const ByteArray &device_token) {
DoInitialize(/*fast_advertisement=*/false, version, socket_version,
service_id_hash, data, device_token);
}
BleAdvertisement::BleAdvertisement(Version version,
SocketVersion socket_version,
const ByteArray &data,
const ByteArray &device_token) {
DoInitialize(/*fast_advertisement=*/true, version, socket_version,
{}, data, device_token);
}
void BleAdvertisement::DoInitialize(bool fast_advertisement, Version version,
SocketVersion socket_version,
const ByteArray &service_id_hash,
const ByteArray &data,
const ByteArray &device_token) {
// Check that the given input is valid.
fast_advertisement_ = fast_advertisement;
if (!fast_advertisement_) {
if (service_id_hash.size() != kServiceIdHashLength) return;
}
if (!IsSupportedVersion(version) ||
!IsSupportedSocketVersion(socket_version) ||
(!device_token.Empty() && device_token.size() != kDeviceTokenLength)) {
return;
}
int advertisement_Length = ComputeAdvertisementLength(
data.size(), device_token.size(), fast_advertisement_);
int max_advertisement_length = fast_advertisement
? kMaxFastAdvertisementLength
: kMaxAdvertisementLength;
if (advertisement_Length > max_advertisement_length) {
return;
}
version_ = version;
socket_version_ = socket_version;
if (!fast_advertisement_) service_id_hash_ = service_id_hash;
data_ = data;
device_token_ = device_token;
}
BleAdvertisement::BleAdvertisement(const ByteArray &ble_advertisement_bytes) {
if (ble_advertisement_bytes.Empty()) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: null bytes passed in.");
return;
}
if (ble_advertisement_bytes.size() < kVersionLength) {
NEARBY_LOG(
INFO,
"Cannot deserialize BleAdvertisement: expecting min %d raw bytes to "
"parse the version, got %" PRIu64,
kVersionLength, ble_advertisement_bytes.size());
return;
}
ByteArray advertisement_bytes{ble_advertisement_bytes};
BaseInputStream base_input_stream{advertisement_bytes};
// The first 1 byte is supposed to be the version, socket version and the fast
// advertisement flag.
auto version_byte =
static_cast<char>(base_input_stream.ReadUint8());
// Version.
version_ = static_cast<Version>((version_byte & kVersionBitmask) >> 5);
if (!IsSupportedVersion(version_)) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: unsupported Version %u",
version_);
return;
}
// Socket version.
socket_version_ =
static_cast<SocketVersion>((version_byte & kSocketVersionBitmask) >> 2);
if (!IsSupportedSocketVersion(socket_version_)) {
NEARBY_LOG(
INFO,
"Cannot deserialize BleAdvertisement: unsupported SocketVersion %u",
socket_version_);
version_ = Version::kUndefined;
return;
}
// Fast advertisement flag.
fast_advertisement_ =
static_cast<bool>((version_byte & kFastAdvertisementFlagBitmask) >> 1);
// The next 3 bytes are supposed to be the service_id_hash if not fast
// advertisement.
if (!fast_advertisement_) {
service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength);
}
// Data length.
int expected_data_size =
fast_advertisement_
? static_cast<int>(
base_input_stream.ReadBytes(kFastDataSizeLength).data()[0])
: static_cast<int>(base_input_stream.ReadUint32());
if (expected_data_size < 0) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: negative data size %d",
expected_data_size);
version_ = Version::kUndefined;
return;
}
// Data.
// Check that the stated data size is the same as what we received.
data_ = base_input_stream.ReadBytes(expected_data_size);
if (data_.size() != expected_data_size) {
NEARBY_LOG(INFO,
"Cannot deserialize BleAdvertisement: expected data to be %u "
"bytes, got %" PRIu64 " bytes ",
expected_data_size, data_.size());
version_ = Version::kUndefined;
return;
}
// Device token. If the number of remaining bytes are valid for device token,
// then read it.
if (base_input_stream.IsAvailable(kDeviceTokenLength)) {
device_token_ = base_input_stream.ReadBytes(kDeviceTokenLength);
}
}
BleAdvertisement::operator ByteArray() const {
if (!IsValid()) {
return ByteArray{};
}
// The first 3 bits are the Version.
char version_byte = (static_cast<char>(version_) << 5) & kVersionBitmask;
// The next 3 bits are the Socket version. 2 bits left are reserved.
version_byte |=
(static_cast<char>(socket_version_) << 2) & kSocketVersionBitmask;
// The next 1 bit is the fast advertisement flag. 1 bit left is reserved.
version_byte |= (static_cast<char>(fast_advertisement_ ? 1 : 0) << 1) &
kFastAdvertisementFlagBitmask;
// Serialize Data size bytes
ByteArray data_size_bytes{static_cast<size_t>(
fast_advertisement_ ? kFastDataSizeLength : kDataSizeLength)};
auto *data_size_bytes_write_ptr = data_size_bytes.data();
SerializeDataSize(fast_advertisement_, data_size_bytes_write_ptr,
data_.size());
// clang-format on
if (fast_advertisement_) {
std::string out =
absl::StrCat(std::string(1, version_byte),
std::string(data_size_bytes),
std::string(data_),
std::string(device_token_));
return ByteArray{std::move(out)};
} else {
std::string out =
absl::StrCat(std::string(1, version_byte),
std::string(service_id_hash_),
std::string(data_size_bytes),
std::string(data_),
std::string(device_token_));
return ByteArray{std::move(out)};
}
// clang-format on
}
bool BleAdvertisement::operator==(const BleAdvertisement &rhs) const {
return this->GetVersion() == rhs.GetVersion() &&
this->GetSocketVersion() == rhs.GetSocketVersion() &&
this->GetServiceIdHash() == rhs.GetServiceIdHash() &&
this->GetData() == rhs.GetData() &&
this->GetDeviceToken() == rhs.GetDeviceToken();
}
bool BleAdvertisement::operator<(const BleAdvertisement &rhs) const {
if (this->GetVersion() != rhs.GetVersion()) {
return this->GetVersion() < rhs.GetVersion();
}
if (this->GetSocketVersion() != rhs.GetSocketVersion()) {
return this->GetSocketVersion() < rhs.GetSocketVersion();
}
if (this->GetServiceIdHash() != rhs.GetServiceIdHash()) {
return this->GetServiceIdHash() < rhs.GetServiceIdHash();
}
if (this->GetDeviceToken() != rhs.GetDeviceToken()) {
return this->GetDeviceToken() < rhs.GetDeviceToken();
}
return this->GetData() < rhs.GetData();
}
bool BleAdvertisement::IsSupportedVersion(Version version) const {
return version >= Version::kV1 && version <= Version::kV2;
}
bool BleAdvertisement::IsSupportedSocketVersion(
SocketVersion socket_version) const {
return socket_version >= SocketVersion::kV1 &&
socket_version <= SocketVersion::kV2;
}
void BleAdvertisement::SerializeDataSize(bool fast_advertisement,
char *data_size_bytes_write_ptr,
size_t data_size) const {
// Get a raw representation of the data size bytes in memory.
char *data_size_bytes = reinterpret_cast<char *>(&data_size);
const int data_size_length =
fast_advertisement ? kFastDataSizeLength : kDataSizeLength;
// Append these raw bytes to advertisement bytes, keeping in mind that we need
// to convert from Little Endian to Big Endian in the process.
for (int i = 0; i < data_size_length; ++i) {
data_size_bytes_write_ptr[i] = data_size_bytes[data_size_length - i - 1];
}
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_
#include <utility>
@@ -24,10 +24,14 @@ namespace nearby {
namespace connections {
namespace mediums {
// Represents the format of the Mediums Ble Advertisement used in advertising
// and discovery.
// Represents the format of the Mediums BLE Advertisement used in Advertising +
// Discovery.
//
// [VERSION][SOCKET_VERSION][2_RESERVED_BITS][SERVICE_ID_HASH][DATA_SIZE][DATA]
// [VERSION][SOCKET_VERSION][FAST_ADVERTISEMENT_FLAG][1_RESERVED_BIT][SERVICE_ID_HASH][DATA_SIZE][DATA][DEVICE_TOKEN]
//
// For fast advertisement, we remove SERVICE_ID_HASH since we already have one
// copy in Nearby Connections(b/138447288)
// [VERSION][SOCKET_VERSION][FAST_ADVERTISEMENT_FLAG][1_RESERVED_BIT][DATA_SIZE][DATA][DEVICE_TOKEN]
//
// See go/nearby-ble-design for more information.
class BleAdvertisement {
@@ -51,10 +55,14 @@ class BleAdvertisement {
};
static constexpr int kServiceIdHashLength = 3;
static constexpr int kDeviceTokenLength = 2;
BleAdvertisement() = default;
BleAdvertisement(Version version, SocketVersion socket_version,
const ByteArray &service_id_hash, const ByteArray &data);
const ByteArray &service_id_hash, const ByteArray &data,
const ByteArray &device_token);
BleAdvertisement(Version version, SocketVersion socket_version,
const ByteArray &data, const ByteArray &device_token);
explicit BleAdvertisement(const ByteArray &ble_advertisement_bytes);
BleAdvertisement(const BleAdvertisement &) = default;
BleAdvertisement &operator=(const BleAdvertisement &) = default;
@@ -70,37 +78,59 @@ class BleAdvertisement {
bool IsValid() const { return IsSupportedVersion(version_); }
Version GetVersion() const { return version_; }
SocketVersion GetSocketVersion() const { return socket_version_; }
bool IsFastAdvertisement() const { return fast_advertisement_; }
ByteArray GetServiceIdHash() const { return service_id_hash_; }
ByteArray &GetData() & { return data_; }
const ByteArray &GetData() const & { return data_; }
ByteArray &&GetData() && { return std::move(data_); }
const ByteArray &&GetData() const && { return std::move(data_); }
ByteArray GetDeviceToken() const { return device_token_; }
private:
void DoInitialize(bool fast_advertisement, Version version,
SocketVersion socket_version,
const ByteArray &service_id_hash, const ByteArray &data,
const ByteArray &device_token);
bool IsSupportedVersion(Version version) const;
bool IsSupportedSocketVersion(SocketVersion socket_version) const;
void SerializeDataSize(char *data_size_bytes_write_ptr,
void SerializeDataSize(bool fast_advertisement,
char *data_size_bytes_write_ptr,
size_t data_size) const;
int ComputeAdvertisementLength(int data_length, int total_optional_length,
bool fast_advertisement) const {
// The advertisement length is the minimum length + the length of the data +
// the length of in-use optional fields.
return fast_advertisement ? (kMinFastAdvertisementLegth + data_length +
total_optional_length)
: (kMinAdvertisementLength + data_length +
total_optional_length);
}
static constexpr int kVersionLength = 1;
// Length of one int. Be sure to re-evaluate how we compute data size in this
// class if this constant ever changes!
static constexpr int kDataSizeLength = 4;
static constexpr int kVersionBitmask = 0x0E0;
static constexpr int kSocketVersionBitmask = 0x01C;
static constexpr int kFastAdvertisementFlagBitmask = 0x002;
static constexpr int kDataSizeLength = 4; // Length of one int.
static constexpr int kFastDataSizeLength = 1; // Length of one byte.
static constexpr int kMinAdvertisementLength =
kVersionLength + kServiceIdHashLength + kDataSizeLength;
// The maximum length for a Gatt characteristic value is 512 bytes, so make
// sure the entire advertisement is less than that. The data can take up
// whatever space is remaining after the bytes preceding it.
static constexpr int kMaxGattCharacteristicValueSize = 512;
static constexpr int kMaxDataSize =
kMaxGattCharacteristicValueSize - kMinAdvertisementLength;
static constexpr int kVersionBitmask = 0x0E0;
static constexpr int kSocketVersionBitmask = 0x01C;
static constexpr int kMaxAdvertisementLength = 512;
static constexpr int kMinFastAdvertisementLegth =
kVersionLength + kFastDataSizeLength;
// The maximum length for the scan response is 31 bytes. However, with the
// required header that comes before the service data, this leaves the
// advertiser with 27 leftover bytes.
static constexpr int kMaxFastAdvertisementLength = 27;
Version version_{Version::kUndefined};
SocketVersion socket_version_{SocketVersion::kUndefined};
bool fast_advertisement_ = false;
ByteArray service_id_hash_;
ByteArray data_;
ByteArray device_token_;
};
} // namespace mediums
@@ -108,4 +138,4 @@ class BleAdvertisement {
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_H_
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/ble_advertisement_header.h"
#include "core_v2/internal/mediums/ble_v2/ble_advertisement_header.h"
#include <inttypes.h>
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
#include <string>
@@ -94,4 +94,4 @@ class BleAdvertisementHeader {
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_ADVERTISEMENT_HEADER_H_
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/ble_advertisement_header.h"
#include "core_v2/internal/mediums/ble_v2/ble_advertisement_header.h"
#include "platform_v2/base/base64_utils.h"
#include "gtest/gtest.h"
@@ -0,0 +1,519 @@
// Copyright 2020 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 "core_v2/internal/mediums/ble_v2/ble_advertisement.h"
#include <algorithm>
#include "gtest/gtest.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
constexpr BleAdvertisement::Version kVersion = BleAdvertisement::Version::kV2;
constexpr BleAdvertisement::SocketVersion kSocketVersion =
BleAdvertisement::SocketVersion::kV2;
constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"};
constexpr absl::string_view kData{
"How much wood can a woodchuck chuck if a wood chuck would chuck wood?"};
constexpr absl::string_view kFastData{"Fast Advertise"};
constexpr absl::string_view kDeviceToken{"\x04\x20"};
// kAdvertisementLength/kFastAdvertisementLength corresponds to the length of a
// specific BleAdvertisement packed with the kData/kFastData given above. Be
// sure to update this if kData/kFastData ever changes.
constexpr size_t kAdvertisementLength = 77;
constexpr size_t kFastAdvertisementLength = 16;
constexpr size_t kLongAdvertisementLength = kAdvertisementLength + 1000;
TEST(BleAdvertisementTest, ConstructionWorksV1) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{BleAdvertisement::Version::kV1,
BleAdvertisement::SocketVersion::kV1,
service_id_hash,
data,
device_token};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(BleAdvertisement::Version::kV1, ble_advertisement.GetVersion());
EXPECT_EQ(BleAdvertisement::SocketVersion::kV1,
ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(data, ble_advertisement.GetData());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest, ConstructionWorksV1ForFastAdvertisement) {
ByteArray fast_data{std::string(kFastData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{BleAdvertisement::Version::kV1,
BleAdvertisement::SocketVersion::kV1,
fast_data,
device_token};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(BleAdvertisement::Version::kV1, ble_advertisement.GetVersion());
EXPECT_EQ(BleAdvertisement::SocketVersion::kV1,
ble_advertisement.GetSocketVersion());
EXPECT_EQ(fast_data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(fast_data, ble_advertisement.GetData());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) {
BleAdvertisement::Version bad_version =
static_cast<BleAdvertisement::Version>(666);
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{bad_version,
kSocketVersion,
service_id_hash,
data,
device_token};
EXPECT_FALSE(ble_advertisement.IsValid());
BleAdvertisement fast_ble_advertisement{bad_version,
kSocketVersion,
data,
device_token};
EXPECT_FALSE(fast_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithBadSocketVersion) {
BleAdvertisement::SocketVersion bad_socket_version =
static_cast<BleAdvertisement::SocketVersion>(666);
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{kVersion,
bad_socket_version,
service_id_hash,
data,
device_token};
EXPECT_FALSE(ble_advertisement.IsValid());
BleAdvertisement fast_ble_advertisement{kVersion,
bad_socket_version,
data,
device_token};
EXPECT_FALSE(fast_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithShortServiceIdHash) {
char short_service_id_hash_bytes[] = "\x0a\x0b";
ByteArray bad_service_id_hash{short_service_id_hash_bytes};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{kVersion,
kSocketVersion,
bad_service_id_hash,
data,
device_token};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithLongServiceIdHash) {
char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d";
ByteArray bad_service_id_hash{long_service_id_hash_bytes};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{kVersion,
kSocketVersion,
bad_service_id_hash,
data,
device_token};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFailsWithLongData) {
// BleAdvertisement shouldn't be able to support data with the max GATT
// attribute length because it needs some room for the preceding fields.
char long_data[512]{};
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray bad_data{long_data, 512};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
bad_data,
device_token};
EXPECT_FALSE(ble_advertisement.IsValid());
BleAdvertisement fast_ble_advertisement{kVersion,
kSocketVersion,
bad_data,
device_token};
EXPECT_FALSE(fast_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionWorksWithEmptyDeviceToken) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
BleAdvertisement ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
data,
ByteArray{}};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(data, ble_advertisement.GetData());
EXPECT_TRUE(ble_advertisement.GetDeviceToken().Empty());
}
TEST(BleAdvertisementTest,
ConstructionWorksWithEmptyDeviceTokenForFastAdvertisement) {
ByteArray fast_data{std::string(kFastData)};
BleAdvertisement ble_advertisement{kVersion,
kSocketVersion,
fast_data,
ByteArray{}};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(fast_data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(fast_data, ble_advertisement.GetData());
EXPECT_TRUE(ble_advertisement.GetDeviceToken().Empty());
}
TEST(BleAdvertisementTest, ConstructionFailsWithWrongSizeofDeviceToken) {
char wrong_device_token_bytes_1[] = "\x04\x2\x10"; // over 2 bytes
char wrong_device_token_bytes_2[] = "\x04"; // 1 byte
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray bad_device_token_1{wrong_device_token_bytes_1};
ByteArray bad_device_token_2{wrong_device_token_bytes_2};
BleAdvertisement ble_advertisement_1{kVersion,
kSocketVersion,
service_id_hash,
data,
bad_device_token_1};
EXPECT_FALSE(ble_advertisement_1.IsValid());
BleAdvertisement ble_advertisement_2{kVersion,
kSocketVersion,
service_id_hash,
data,
bad_device_token_2};
EXPECT_FALSE(ble_advertisement_2.IsValid());
BleAdvertisement fast_ble_advertisement_1{kVersion,
kSocketVersion,
data,
bad_device_token_1};
EXPECT_FALSE(fast_ble_advertisement_1.IsValid());
BleAdvertisement fast_ble_advertisement_2{kVersion,
kSocketVersion,
data,
bad_device_token_2};
EXPECT_FALSE(fast_ble_advertisement_2.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFromSerializedBytesWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
data,
device_token};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(data, ble_advertisement.GetData());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest,
ConstructionFromSerializedBytesWorksForAdvertisement) {
ByteArray fast_data{std::string(kFastData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
fast_data,
device_token};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(fast_data.size(), ble_advertisement.GetData().size());
EXPECT_EQ(fast_data, ble_advertisement.GetData());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest, ConstructionFromSerializedBytesWithEmptyDataWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
ByteArray(),
device_token};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
EXPECT_TRUE(ble_advertisement.GetData().Empty());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest,
ConstructionFromSerializedBytesWithEmptyDataWorksForFastAdvertisement) {
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
ByteArray(),
device_token};
ByteArray ble_advertisement_bytes{org_ble_advertisement};
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
EXPECT_TRUE(ble_advertisement.IsValid());
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, ble_advertisement.GetSocketVersion());
EXPECT_TRUE(ble_advertisement.GetData().Empty());
EXPECT_EQ(device_token, ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest, ConstructionFromExtraSerializedBytesWorks) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Copy the bytes into a new array with extra bytes. We must explicitly
// define how long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kLongAdvertisementLength]{};
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
std::min(sizeof(raw_ble_advertisement_bytes),
org_ble_advertisement_bytes.size()));
// Re-parse the Ble advertisement using our extra long advertisement bytes.
ByteArray long_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kLongAdvertisementLength};
BleAdvertisement long_ble_advertisement{long_ble_advertisement_bytes};
EXPECT_TRUE(long_ble_advertisement.IsValid());
EXPECT_FALSE(long_ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, long_ble_advertisement.GetSocketVersion());
EXPECT_EQ(service_id_hash, long_ble_advertisement.GetServiceIdHash());
EXPECT_EQ(data.size(), long_ble_advertisement.GetData().size());
EXPECT_EQ(data, long_ble_advertisement.GetData());
EXPECT_EQ(device_token, long_ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest,
ConstructionFromExtraSerializedBytesWorksForFastAdvertisement) {
ByteArray fast_data{std::string(kFastData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
fast_data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Copy the bytes into a new array with extra bytes. We must explicitly
// define how long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kLongAdvertisementLength]{};
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
std::min(sizeof(raw_ble_advertisement_bytes),
org_ble_advertisement_bytes.size()));
// Re-parse the Ble advertisement using our extra long advertisement bytes.
ByteArray long_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kLongAdvertisementLength};
BleAdvertisement long_ble_advertisement{long_ble_advertisement_bytes};
EXPECT_TRUE(long_ble_advertisement.IsValid());
EXPECT_TRUE(long_ble_advertisement.IsFastAdvertisement());
EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion());
EXPECT_EQ(kSocketVersion, long_ble_advertisement.GetSocketVersion());
EXPECT_EQ(fast_data.size(), long_ble_advertisement.GetData().size());
EXPECT_EQ(fast_data, long_ble_advertisement.GetData());
EXPECT_EQ(device_token, long_ble_advertisement.GetDeviceToken());
}
TEST(BleAdvertisementTest, ConstructionFromNullBytesFails) {
BleAdvertisement ble_advertisement{ByteArray{}};
EXPECT_FALSE(ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest, ConstructionFromShortLengthSerializedBytesFails) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Cut off the advertisement so that it's too short.
ByteArray short_ble_advertisement_bytes{org_ble_advertisement_bytes.data(),
7};
BleAdvertisement short_ble_advertisement{short_ble_advertisement_bytes};
EXPECT_FALSE(short_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest,
ConstructionFromShortLengthSerializedBytesFailsForFastAdvertisement) {
ByteArray fast_data{std::string(kFastData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
fast_data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Cut off the advertisement so that it's too short.
ByteArray short_ble_advertisement_bytes{org_ble_advertisement_bytes.data(),
2};
BleAdvertisement short_ble_advertisement{short_ble_advertisement_bytes};
EXPECT_FALSE(short_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest,
ConstructionFromSerializedBytesWithInvalidDataLengthFails) {
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
ByteArray data{std::string(kData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
service_id_hash,
data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Corrupt the DATA_SIZE bits. Start by making a raw copy of the Ble
// advertisement bytes so we can modify it. We must explicitly define how
// long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kAdvertisementLength];
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
kAdvertisementLength);
// The data size field lives in indices 4-7. Corrupt it.
memset(raw_ble_advertisement_bytes + 4, 0xFF, 4);
// Try to parse the Ble advertisement using our corrupted advertisement bytes.
ByteArray corrupted_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kAdvertisementLength};
BleAdvertisement corrupted_ble_advertisement{
corrupted_ble_advertisement_bytes};
EXPECT_FALSE(corrupted_ble_advertisement.IsValid());
}
TEST(BleAdvertisementTest,
ConstructionFromSerializedBytesWithInvalidDataLengthFails2) {
ByteArray fast_data{std::string(kFastData)};
ByteArray device_token{std::string(kDeviceToken)};
BleAdvertisement org_ble_advertisement{kVersion,
kSocketVersion,
fast_data,
device_token};
ByteArray org_ble_advertisement_bytes{org_ble_advertisement};
// Corrupt the DATA_SIZE bits. Start by making a raw copy of the Ble
// advertisement bytes so we can modify it. We must explicitly define how
// long our array is because we can't use variable length arrays.
char raw_ble_advertisement_bytes[kFastAdvertisementLength];
memcpy(raw_ble_advertisement_bytes, org_ble_advertisement_bytes.data(),
kFastAdvertisementLength);
// The data size field lives in index 1. Corrupt it.
memset(raw_ble_advertisement_bytes + 1, 0xFF, 1);
// Try to parse the Ble advertisement using our corrupted advertisement bytes.
ByteArray corrupted_ble_advertisement_bytes{raw_ble_advertisement_bytes,
kFastAdvertisementLength};
BleAdvertisement corrupted_ble_advertisement{
corrupted_ble_advertisement_bytes};
EXPECT_FALSE(corrupted_ble_advertisement.IsValid());
}
} // namespace
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/ble_packet.h"
#include "core_v2/internal/mediums/ble_v2/ble_packet.h"
#include "platform_v2/base/base_input_stream.h"
#include "platform_v2/public/logging.h"
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_PACKET_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_PACKET_H_
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_
#include <limits>
@@ -61,4 +61,4 @@ class BlePacket {
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_PACKET_H_
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PACKET_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/ble_packet.h"
#include "core_v2/internal/mediums/ble_v2/ble_packet.h"
#include "gtest/gtest.h"
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_
#include "platform_v2/base/byte_array.h"
@@ -46,4 +46,4 @@ class BlePeripheral {
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_PERIPHERAL_H_
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_BLE_PERIPHERAL_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core_v2/internal/mediums/ble_peripheral.h"
#include "core_v2/internal/mediums/ble_v2/ble_peripheral.h"
#include "gtest/gtest.h"
@@ -0,0 +1,45 @@
// Copyright 2020 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 CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_
#define CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_
#include "core_v2/internal/mediums/ble_v2/ble_peripheral.h"
#include "core_v2/listeners.h"
#include "platform_v2/base/byte_array.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
/** Callback that is invoked when a {@link BlePeripheral} is discovered. */
struct DiscoveredPeripheralCallback {
std::function<void(BlePeripheral& peripheral, const std::string& service_id,
const ByteArray& advertisement_byts,
bool fast_advertisement)>
peripheral_discovered_cb =
DefaultCallback<BlePeripheral&, const std::string&, const ByteArray&,
bool>();
std::function<void(BlePeripheral& peripheral, const std::string& service_id)>
peripheral_lost_cb =
DefaultCallback<BlePeripheral&, const std::string&>();
};
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_V2_DISCOVERED_PERIPHERAL_CALLBACK_H_
+5 -1
View File
@@ -45,8 +45,12 @@ ByteArray Utils::GenerateRandomBytes(size_t length) {
}
ByteArray Utils::Sha256Hash(const ByteArray& source, size_t length) {
return Utils::Sha256Hash(std::string(source), length);
}
ByteArray Utils::Sha256Hash(const std::string& source, size_t length) {
ByteArray full_hash(length);
full_hash.CopyAt(0, Crypto::Sha256(std::string(source)));
full_hash.CopyAt(0, Crypto::Sha256(source));
return full_hash;
}
+1
View File
@@ -27,6 +27,7 @@ class Utils {
public:
static ByteArray GenerateRandomBytes(size_t length);
static ByteArray Sha256Hash(const ByteArray& source, size_t length);
static ByteArray Sha256Hash(const std::string& source, size_t length);
};
} // namespace connections
+3
View File
@@ -262,6 +262,9 @@ bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id) {
connection_flow_ = ConnectionFlow::Create(GetLocalIceCandidateListener(),
GetDataChannelListener(), medium_);
if (!connection_flow_)
return false;
return true;
}
+2 -2
View File
@@ -24,14 +24,14 @@
#include "core_v2/internal/mediums/webrtc/peer_id.h"
#include "core_v2/internal/mediums/webrtc/webrtc_socket.h"
#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h"
#include "platform_v2/public/cancelable_alarm.h"
#include "platform_v2/public/scheduled_executor.h"
#include "platform_v2/base/byte_array.h"
#include "platform_v2/base/listeners.h"
#include "platform_v2/base/runnable.h"
#include "platform_v2/public/atomic_boolean.h"
#include "platform_v2/public/cancelable_alarm.h"
#include "platform_v2/public/future.h"
#include "platform_v2/public/mutex.h"
#include "platform_v2/public/scheduled_executor.h"
#include "platform_v2/public/single_thread_executor.h"
#include "platform_v2/public/webrtc.h"
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
@@ -249,6 +249,11 @@ bool ConnectionFlow::InitPeerConnection(WebRtcMedium& webrtc_medium) {
&peer_connection_observer_,
[this, &success_future](
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection) {
if (!peer_connection) {
success_future.Set(false);
return;
}
peer_connection_ = peer_connection;
success_future.Set(true);
});
@@ -338,7 +343,9 @@ bool ConnectionFlow::CloseLocked() {
state_ = State::kEnded;
data_channel_future_.SetException({Exception::kInterrupted});
peer_connection_->Close();
if (peer_connection_)
peer_connection_->Close();
data_channel_observer_.reset();
NEARBY_LOG(INFO, "Closed WebRTC connection.");
return true;
@@ -198,6 +198,16 @@ TEST_F(ConnectionFlowTest, CannotReceiveOfferAfterClose) {
EXPECT_FALSE(answerer->OnOfferReceived(offer));
}
TEST_F(ConnectionFlowTest, NullPeerConnection) {
MediumEnvironment::Instance().SetUseValidPeerConnection(
/*use_valid_peer_connection=*/false);
WebRtcMedium medium;
std::unique_ptr<ConnectionFlow> answerer = ConnectionFlow::Create(
LocalIceCandidateListener(), DataChannelListener(), medium);
EXPECT_EQ(answerer, nullptr);
}
} // namespace
} // namespace mediums
} // namespace connections
@@ -247,6 +247,38 @@ TEST_F(WebRtcTest, ConnectBothDevices_ShutdownSignaling_SendData) {
EXPECT_EQ(message, received_msg.result());
}
TEST_F(WebRtcTest, StartAcceptingConnections_NullPeerConnection) {
using MockAcceptedCallback =
testing::MockFunction<void(WebRtcSocketWrapper socket)>;
testing::StrictMock<MockAcceptedCallback> mock_accepted_callback_;
MediumEnvironment::Instance().SetUseValidPeerConnection(
/*use_valid_peer_connection=*/false);
WebRtc webrtc;
PeerId self_id("peer_id");
ASSERT_TRUE(webrtc.IsAvailable());
EXPECT_FALSE(webrtc.StartAcceptingConnections(
self_id, {mock_accepted_callback_.AsStdFunction()}));
}
TEST_F(WebRtcTest, Connect_NullPeerConnection) {
using MockAcceptedCallback =
testing::MockFunction<void(WebRtcSocketWrapper socket)>;
testing::StrictMock<MockAcceptedCallback> mock_accepted_callback_;
MediumEnvironment::Instance().SetUseValidPeerConnection(
/*use_valid_peer_connection=*/false);
WebRtc webrtc;
PeerId self_id("peer_id");
ASSERT_TRUE(webrtc.IsAvailable());
WebRtcSocketWrapper wrapper = webrtc.Connect(PeerId("random_peer_id"));
EXPECT_FALSE(wrapper.IsValid());
}
} // namespace
} // namespace mediums
+52 -36
View File
@@ -18,6 +18,7 @@
#include "core_v2/internal/ble_advertisement.h"
#include "core_v2/internal/ble_endpoint_channel.h"
#include "core_v2/internal/bluetooth_endpoint_channel.h"
#include "core_v2/internal/mediums/utils.h"
#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h"
#include "core_v2/internal/webrtc_endpoint_channel.h"
#include "core_v2/internal/wifi_lan_endpoint_channel.h"
@@ -33,10 +34,7 @@ namespace connections {
ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source,
size_t size) {
ByteArray full_hash = Crypto::Sha256(source);
ByteArray result(size);
result.CopyAt(0, full_hash);
return result;
return Utils::Sha256Hash(source, size);
}
P2pClusterPcpHandler::P2pClusterPcpHandler(
@@ -117,10 +115,8 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl(
}
if (options.allowed.ble) {
const ByteArray ble_hash =
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
proto::connections::Medium ble_medium = StartBleAdvertising(
client, service_id, ble_hash, local_endpoint_id, local_endpoint_info);
client, service_id, local_endpoint_id, local_endpoint_info, options);
if (ble_medium != proto::connections::UNKNOWN_MEDIUM) {
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added");
mediums_started_successfully.push_back(ble_medium);
@@ -278,12 +274,12 @@ bool P2pClusterPcpHandler::IsRecognizedBleEndpoint(
return false;
}
if (advertisement.GetVersion() != BleAdvertisement::Version::kV1) {
if (advertisement.GetVersion() != kBleAdvertisementVersion) {
NEARBY_LOG(
INFO,
"P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Version is "
"not matched; advertisement.Version=%d, Version=%d",
advertisement.GetVersion(), BleAdvertisement::Version::kV1);
advertisement.GetVersion(), kBleAdvertisementVersion);
return false;
}
@@ -295,17 +291,21 @@ bool P2pClusterPcpHandler::IsRecognizedBleEndpoint(
return false;
}
ByteArray expected_service_id_hash =
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
// Check ServiceId for normal advertisement.
// ServiceIdHash is empty for fast advertisement.
if (!advertisement.IsFastAdvertisement()) {
ByteArray expected_service_id_hash =
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
if (advertisement.GetServiceIdHash() != expected_service_id_hash) {
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::IsRecognizedBleEndpoint: service "
"id hash is "
"not matched; advertisement.service_id_hash=%s, expected=%s",
advertisement.GetServiceIdHash().data(),
expected_service_id_hash.data());
return false;
if (advertisement.GetServiceIdHash() != expected_service_id_hash) {
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::IsRecognizedBleEndpoint: service "
"id hash is "
"not matched; advertisement.service_id_hash=%s, expected=%s",
advertisement.GetServiceIdHash().data(),
expected_service_id_hash.data());
return false;
}
}
return true;
@@ -313,8 +313,9 @@ bool P2pClusterPcpHandler::IsRecognizedBleEndpoint(
void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
ClientProxy* client, BlePeripheral& peripheral,
const std::string& service_id) {
RunOnPcpHandlerThread([this, client, service_id, &peripheral]() {
const std::string& service_id, bool fast_advertisement) {
RunOnPcpHandlerThread([this, client, &peripheral, service_id,
fast_advertisement]() {
// Make sure we are still discovering before proceeding.
if (!client->IsDiscovering()) {
NEARBY_LOG(INFO,
@@ -326,7 +327,7 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
// Parse the Ble advertisement bytes.
BleAdvertisement advertisement(
/*fast_advertisement=*/false,
fast_advertisement,
peripheral.GetAdvertisementBytes(service_id));
// Make sure the Ble advertisement points to a valid
@@ -355,6 +356,8 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
},
peripheral,
}));
// TODO(b/156632928): Check for Bluetooth device with remote mac address.
});
}
@@ -685,8 +688,8 @@ proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising(
absl::BytesToHexString(local_endpoint_info.data()).c_str());
// Generate a BluetoothDeviceName with which to become Bluetooth discoverable.
std::string device_name(BluetoothDeviceName(
BluetoothDeviceName::Version::kV1, GetPcp(), local_endpoint_id,
service_id_hash, local_endpoint_info));
kBluetoothDeviceNameVersion, GetPcp(), local_endpoint_id, service_id_hash,
local_endpoint_info));
if (device_name.empty()) {
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::StartBluetoothAdvertising: generate "
@@ -761,8 +764,10 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl(
proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising(
ClientProxy* client, const std::string& service_id,
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
const ByteArray& local_endpoint_info) {
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
const ConnectionOptions& options) {
bool fast_advertisement = !options.fast_advertisement_service_uuid.empty();
// Start listening for connections before advertising in case a connection
// request comes in very quickly.
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
@@ -806,19 +811,30 @@ proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising(
<< service_id;
return proto::connections::UNKNOWN_MEDIUM;
}
// TODO(b/156632928): Should check for Bluetooth connection here
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::StartBleAdvertising: service=%s: "
"make advertisement; id=%s, hash=%s, name=%s",
"make advertisement; id=%s, name=%s",
service_id.c_str(), local_endpoint_id.c_str(),
std::string(service_id_hash).c_str(),
std::string(local_endpoint_info).c_str());
// Generate a BleAdvertisement with which to become Ble discoverable.
// TODO(edwinwu): Add a bluetooth_adapter method to get the mac address.
std::string bluetooth_mac_address;
ByteArray advertisement_bytes(BleAdvertisement(
BleAdvertisement::Version::kV1, GetPcp(), service_id_hash,
local_endpoint_id, local_endpoint_info, bluetooth_mac_address));
// Generate a BleAdvertisement. If a fast advertisement service UUID was
// provided, create a fast BleAdvertisement.
ByteArray advertisement_bytes;
if (fast_advertisement) {
advertisement_bytes =
ByteArray(BleAdvertisement(kBleAdvertisementVersion, GetPcp(),
local_endpoint_id, local_endpoint_info));
} else {
const ByteArray service_id_hash =
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
// TODO(b/156632928): Should advertise Bluetooth MacAddress Over Ble
std::string bluetooth_mac_address;
advertisement_bytes = ByteArray(BleAdvertisement(
kBleAdvertisementVersion, GetPcp(), service_id_hash, local_endpoint_id,
local_endpoint_info, bluetooth_mac_address));
}
if (advertisement_bytes.Empty()) {
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::StartBleAdvertising: generate "
@@ -936,8 +952,8 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising(
absl::BytesToHexString(local_endpoint_info.data()).c_str());
// Generate a WifiLanServiceInfo with which to become WifiLan discoverable.
std::string service_info_name(WifiLanServiceInfo(
WifiLanServiceInfo::Version::kV1, GetPcp(), local_endpoint_id,
service_id_hash, local_endpoint_info));
kWifiLanServiceInfoVersion, GetPcp(), local_endpoint_id, service_id_hash,
local_endpoint_info));
if (service_info_name.empty()) {
NEARBY_LOG(INFO,
"P2pClusterPcpHandler::StartWifiLanAdvertising: generate "
@@ -125,6 +125,8 @@ class P2pClusterPcpHandler : public BasePcpHandler {
static constexpr BluetoothDeviceName::Version kBluetoothDeviceNameVersion =
BluetoothDeviceName::Version::kV1;
static constexpr BleAdvertisement::Version kBleAdvertisementVersion =
BleAdvertisement::Version::kV1;
static constexpr WifiLanServiceInfo::Version kWifiLanServiceInfoVersion =
WifiLanServiceInfo::Version::kV1;
@@ -157,13 +159,14 @@ class P2pClusterPcpHandler : public BasePcpHandler {
const BleAdvertisement& advertisement) const;
void BlePeripheralDiscoveredHandler(ClientProxy* client,
BlePeripheral& peripheral,
const std::string& service_id);
const std::string& service_id,
bool fast_advertisement);
void BlePeripheralLostHandler(ClientProxy* client, BlePeripheral& peripheral,
const std::string& service_id);
proto::connections::Medium StartBleAdvertising(
ClientProxy* client, const std::string& service_id,
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
const ByteArray& local_endpoint_info);
const std::string& local_endpoint_id,
const ByteArray& local_endpoint_info, const ConnectionOptions& options);
proto::connections::Medium StartBleScanning(
BleDiscoveredPeripheralCallback callback, ClientProxy* client,
const std::string& service_id);
+2 -1
View File
@@ -70,8 +70,8 @@ struct MediumSelector {
// Mediums are sorted in order of decreasing preference.
if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN);
if (web_rtc == value) mediums.push_back(Medium::WEB_RTC);
if (ble == value) mediums.push_back(Medium::BLE);
if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH);
if (ble == value) mediums.push_back(Medium::BLE);
return mediums;
}
};
@@ -87,6 +87,7 @@ struct ConnectionOptions {
bool auto_upgrade_bandwidth;
bool enforce_topology_constraints;
ByteArray remote_bluetooth_mac_address;
std::string fast_advertisement_service_uuid;
// Verify if ConnectionOptions is in a not-initialized (Empty) state.
bool Empty() const { return strategy.IsNone(); }
// Bring ConnectionOptions to a not-initialized (Empty) state.
+77 -68
View File
@@ -174,7 +174,7 @@ api::BluetoothDevice* MediumEnvironment::FindBluetoothDevice(
const std::string& mac_address) {
api::BluetoothDevice* device = nullptr;
CountDownLatch latch(1);
RunOnMediumEnvironmentThread([this, &device, &latch, &mac_address](){
RunOnMediumEnvironmentThread([this, &device, &latch, &mac_address]() {
for (auto& item : bluetooth_mediums_) {
auto* adapter = item.second.adapter;
if (!adapter) continue;
@@ -320,85 +320,85 @@ void MediumEnvironment::UpdateBleMediumForAdvertising(
api::BleMedium& medium, api::BlePeripheral& peripheral,
const std::string& service_id, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, &peripheral, service_id,
enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumForAdvertising failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.ble_peripheral = &peripheral;
context.advertising = enabled;
NEARBY_LOG(INFO,
"Update Ble medium for advertising: this=%p; medium=%p; "
"service_id=%s; name=%s; enabled=%d; ",
this, &medium, service_id.c_str(), peripheral.GetName().c_str(),
enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
OnBlePeripheralStateChanged(info, peripheral, service_id, enabled);
}
});
RunOnMediumEnvironmentThread(
[this, &medium, &peripheral, service_id, enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumForAdvertising failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.ble_peripheral = &peripheral;
context.advertising = enabled;
NEARBY_LOG(INFO,
"Update Ble medium for advertising: this=%p; medium=%p; "
"service_id=%s; name=%s; enabled=%d; ",
this, &medium, service_id.c_str(),
peripheral.GetName().c_str(), enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
OnBlePeripheralStateChanged(info, peripheral, service_id, enabled);
}
});
}
void MediumEnvironment::UpdateBleMediumForScanning(
api::BleMedium& medium, const std::string& service_id,
BleDiscoveredPeripheralCallback callback, bool enabled) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, service_id,
callback = std::move(callback), enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumFoScanning failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.discovery_callback = std::move(callback);
NEARBY_LOG(INFO,
"Update Ble medium for scanning: this=%p; medium=%p; "
"service_id=%s; enabled=%d ;",
this, &medium, service_id.c_str(), enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
// Search advertising mediums and send notification.
if (info.advertising && enabled) {
OnBlePeripheralStateChanged(context, *(info.ble_peripheral), service_id,
enabled);
}
}
});
RunOnMediumEnvironmentThread(
[this, &medium, service_id, callback = std::move(callback), enabled]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(INFO,
"UpdateBleMediumFoScanning failed. There is no medium "
"registered.");
return;
}
auto& context = item->second;
context.discovery_callback = std::move(callback);
NEARBY_LOG(INFO,
"Update Ble medium for scanning: this=%p; medium=%p; "
"service_id=%s; enabled=%d ;",
this, &medium, service_id.c_str(), enabled);
for (auto& medium_info : ble_mediums_) {
auto& local_medium = medium_info.first;
auto& info = medium_info.second;
// Do not send notification to the same medium.
if (local_medium == &medium) continue;
// Search advertising mediums and send notification.
if (info.advertising && enabled) {
OnBlePeripheralStateChanged(context, *(info.ble_peripheral),
service_id, enabled);
}
}
});
}
void MediumEnvironment::UpdateBleMediumForAcceptedConnection(
api::BleMedium& medium, const std::string& service_id,
BleAcceptedConnectionCallback callback) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium, service_id,
callback = std::move(callback)]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(
INFO, "Update Ble medium failed. There is no medium registered.");
return;
}
auto& context = item->second;
context.accepted_connection_callback = std::move(callback);
NEARBY_LOG(INFO,
"Update Ble medium for accepted callback: this=%p; "
"medium=%p; service_id=%s; ",
this, &medium, service_id.c_str());
});
RunOnMediumEnvironmentThread(
[this, &medium, service_id, callback = std::move(callback)]() {
auto item = ble_mediums_.find(&medium);
if (item == ble_mediums_.end()) {
NEARBY_LOG(
INFO, "Update Ble medium failed. There is no medium registered.");
return;
}
auto& context = item->second;
context.accepted_connection_callback = std::move(callback);
NEARBY_LOG(INFO,
"Update Ble medium for accepted callback: this=%p; "
"medium=%p; service_id=%s; ",
this, &medium, service_id.c_str());
});
}
void MediumEnvironment::UnregisterBleMedium(api::BleMedium& medium) {
@@ -465,6 +465,15 @@ void MediumEnvironment::SendWebRtcSignalingMessage(absl::string_view peer_id,
});
}
void MediumEnvironment::SetUseValidPeerConnection(
bool use_valid_peer_connection) {
use_valid_peer_connection_ = use_valid_peer_connection;
}
bool MediumEnvironment::GetUseValidPeerConnection() {
return use_valid_peer_connection_;
}
void MediumEnvironment::RegisterWifiLanMedium(api::WifiLanMedium& medium) {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this, &medium]() {
+9 -1
View File
@@ -138,6 +138,12 @@ class MediumEnvironment {
void SendWebRtcSignalingMessage(absl::string_view peer_id,
const ByteArray& message);
// Used to set if WebRtcMedium should use a valid peer connection or nullptr
// in tests.
void SetUseValidPeerConnection(bool use_valid_peer_connection);
bool GetUseValidPeerConnection();
// Adds medium-related info to allow for scanning/advertising to work.
// This provides acccess to this medium from other mediums, when protocol
// expects they should communicate.
@@ -221,7 +227,7 @@ class MediumEnvironment {
// Returns WiFi LAN service matching IP address and port, or nullptr.
api::WifiLanService* FindWifiLanService(const std::string& ip_address,
int port);
int port);
private:
struct BluetoothMediumContext {
@@ -294,6 +300,8 @@ class MediumEnvironment {
absl::flat_hash_map<api::WifiLanMedium*, WifiLanMediumContext>
wifi_lan_mediums_;
bool use_valid_peer_connection_ = true;
};
} // namespace nearby
+6
View File
@@ -47,6 +47,12 @@ void WebRtcSignalingMessenger::StopReceivingMessages() {
void WebRtcMedium::CreatePeerConnection(
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
auto& env = MediumEnvironment::Instance();
if (!env.GetUseValidPeerConnection()) {
callback(nullptr);
return;
}
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
webrtc::PeerConnectionDependencies dependencies(observer);
+2 -1
View File
@@ -60,7 +60,8 @@ bool BleMedium::StartScanning(const std::string& service_id,
&context.peripheral, &peripheral,
peripheral.GetName().c_str());
discovered_peripheral_callback_.peripheral_discovered_cb(
context.peripheral, service_id);
context.peripheral, service_id,
/*fast_advertisement=*/false);
}
},
.peripheral_lost_cb =
+3 -2
View File
@@ -86,9 +86,10 @@ class BleMedium final {
using Platform = api::ImplementationPlatform;
struct DiscoveredPeripheralCallback {
std::function<void(BlePeripheral& peripheral,
const std::string& service_id)>
const std::string& service_id,
bool fast_advertisement)>
peripheral_discovered_cb =
DefaultCallback<BlePeripheral&, const std::string&>();
DefaultCallback<BlePeripheral&, const std::string&, bool>();
std::function<void(BlePeripheral& peripheral,
const std::string& service_id)>
peripheral_lost_cb =
+40 -36
View File
@@ -69,13 +69,13 @@ TEST_F(BleMediumTest, CanStartAdvertising) {
ble_a.StartAdvertising(service_id, advertisement_bytes);
EXPECT_TRUE(ble_b.StartScanning(
service_id, DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](BlePeripheral& peripheral,
const std::string& service_id) {
found_latch.CountDown();
},
}));
service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { found_latch.CountDown(); },
}));
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
EXPECT_TRUE(ble_a.StopAdvertising(service_id));
EXPECT_TRUE(ble_b.StopScanning(service_id));
@@ -93,19 +93,19 @@ TEST_F(BleMediumTest, CanStartScanning) {
CountDownLatch found_latch(1);
CountDownLatch lost_latch(1);
ble_a.StartScanning(service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](BlePeripheral& peripheral,
const std::string& service_id) {
found_latch.CountDown();
},
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
});
ble_a.StartScanning(
service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { found_latch.CountDown(); },
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
});
EXPECT_TRUE(ble_b.StartAdvertising(service_id, advertisement_bytes));
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
EXPECT_TRUE(ble_b.StopAdvertising(service_id));
@@ -125,19 +125,19 @@ TEST_F(BleMediumTest, CanStopDiscovery) {
CountDownLatch found_latch(1);
CountDownLatch lost_latch(1);
ble_a.StartScanning(service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](BlePeripheral& peripheral,
const std::string& service_id) {
found_latch.CountDown();
},
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
});
ble_a.StartScanning(
service_id,
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch](
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { found_latch.CountDown(); },
.peripheral_lost_cb =
[&lost_latch](BlePeripheral& peripheral,
const std::string& service_id) {
lost_latch.CountDown();
},
});
EXPECT_TRUE(ble_b.StartAdvertising(service_id, advertisement_bytes));
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
EXPECT_TRUE(ble_a.StopScanning(service_id));
@@ -163,9 +163,13 @@ TEST_F(BleMediumTest, CanStartAcceptingConnectionsAndConnect) {
DiscoveredPeripheralCallback{
.peripheral_discovered_cb =
[&found_latch, &discovered_peripheral](
BlePeripheral& peripheral, const std::string& service_id) {
NEARBY_LOG(INFO, "Peripheral discovered: %s, %p",
peripheral.GetName().c_str(), &peripheral);
BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) {
NEARBY_LOG(
INFO,
"Peripheral discovered: %s, %p, fast advertisement: %d",
peripheral.GetName().c_str(), &peripheral,
fast_advertisement);
discovered_peripheral = &peripheral;
found_latch.CountDown();
},