mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
[BLEREFACTOR]:Add CreateFromStream API to BleL2capPacket
PiperOrigin-RevId: 832082450
This commit is contained in:
committed by
Copybara-Service
parent
8375b82a86
commit
8d18c91e86
@@ -184,12 +184,12 @@ cc_test(
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation/g3", # buildcleaner: keep
|
||||
"//internal/test",
|
||||
"//proto/mediums:ble_frames_cc_proto",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/hash:hash_testing",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "connections/implementation/mediums/ble/ble_l2cap_packet.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -23,6 +24,8 @@
|
||||
#include "connections/implementation/mediums/ble/ble_advertisement.h"
|
||||
#include "connections/implementation/mediums/utils.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/platform/stream_reader.h"
|
||||
|
||||
@@ -42,6 +45,95 @@ BleL2capPacket::BleL2capPacket(Command command,
|
||||
}
|
||||
}
|
||||
|
||||
absl::StatusOr<BleL2capPacket> BleL2capPacket::CreateFromStream(
|
||||
InputStream& input_stream) {
|
||||
// The first 1 byte is the command.
|
||||
ExceptionOr<ByteArray> command_byte = input_stream.Read(kCommandLength);
|
||||
if (!command_byte.ok()) {
|
||||
LOG(WARNING) << "Cannot read BleL2capPacket: command byte not available.";
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: command byte not available.");
|
||||
}
|
||||
Command command_data =
|
||||
static_cast<Command>((int)command_byte.result().data()[0]);
|
||||
VLOG(1) << "command_data: " << static_cast<int>(command_data);
|
||||
|
||||
int data_length = 0;
|
||||
if (command_data == Command::kRequestAdvertisement ||
|
||||
command_data == Command::kResponseAdvertisement) {
|
||||
ExceptionOr<ByteArray> length_byte = input_stream.Read(2);
|
||||
if (!length_byte.ok()) {
|
||||
LOG(WARNING) << "Cannot read BleL2capPacket: length byte not available.";
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: length byte not available.");
|
||||
}
|
||||
data_length = (static_cast<uint8_t>(length_byte.result().data()[0]) << 8) |
|
||||
(static_cast<uint8_t>(length_byte.result().data()[1]));
|
||||
if (data_length == 0) {
|
||||
LOG(WARNING) << "Cannot read BleL2capPacket: data length incorrect.";
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: data length incorrect.");
|
||||
}
|
||||
}
|
||||
|
||||
switch (command_data) {
|
||||
case Command::kRequestAdvertisementFinish:
|
||||
case Command::kRequestDataConnection:
|
||||
case Command::kResponseServiceIdNotFound:
|
||||
case Command::kResponseDataConnectionReady:
|
||||
case Command::kResponseDataConnectionFailure:
|
||||
return BleL2capPacket(command_data, nullptr, nullptr);
|
||||
case Command::kRequestAdvertisement: {
|
||||
if (data_length < BleAdvertisement::kServiceIdHashLength) {
|
||||
LOG(WARNING)
|
||||
<< "Cannot read BleL2capPacket: service id hash length, got "
|
||||
<< data_length;
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: service id hash length "
|
||||
"incorrect.");
|
||||
}
|
||||
ExceptionOr<ByteArray> service_id_hash_byte =
|
||||
input_stream.Read(data_length);
|
||||
if (!service_id_hash_byte.ok() ||
|
||||
service_id_hash_byte.result().size() != data_length) {
|
||||
LOG(WARNING) << "Cannot read BleL2capPacket: service id hash byte "
|
||||
"not available.";
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: service id hash byte not "
|
||||
"available.");
|
||||
}
|
||||
return BleL2capPacket(command_data, &service_id_hash_byte.result(),
|
||||
nullptr);
|
||||
}
|
||||
case Command::kResponseAdvertisement: {
|
||||
if (data_length > BleAdvertisement::kMaxAdvertisementLength) {
|
||||
LOG(INFO) << "Cannot read BleL2capPacket: advertisement length, got "
|
||||
<< data_length;
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: advertisement length incorrect.");
|
||||
}
|
||||
ExceptionOr<ByteArray> advertisement_data =
|
||||
input_stream.Read(data_length);
|
||||
if (!advertisement_data.ok() ||
|
||||
advertisement_data.result().size() != data_length) {
|
||||
LOG(WARNING)
|
||||
<< "Cannot read BleL2capPacket: advertisement not available.";
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: advertisement not available.");
|
||||
}
|
||||
return BleL2capPacket(command_data, nullptr,
|
||||
&advertisement_data.result());
|
||||
}
|
||||
default:
|
||||
// fall through
|
||||
break;
|
||||
}
|
||||
LOG(WARNING) << "Cannot read BleL2capPacket: unsupported command "
|
||||
<< static_cast<int>(command_data);
|
||||
return absl::InvalidArgumentError(
|
||||
"Cannot read BleL2capPacket: unsupported command.");
|
||||
}
|
||||
|
||||
absl::StatusOr<BleL2capPacket> BleL2capPacket::CreateFromBytes(
|
||||
const ByteArray& bytes) {
|
||||
if (bytes.size() < kCommandLength) {
|
||||
@@ -182,7 +274,7 @@ ByteArray BleL2capPacket::ByteArrayForCommand(BleL2capPacket::Command command,
|
||||
out = absl::StrCat(std::string(1, static_cast<char>(command)),
|
||||
std::string(length_bytes), std::string(*data));
|
||||
} else {
|
||||
out = static_cast<char>(command);
|
||||
out = std::string(1, static_cast<char>(command));
|
||||
}
|
||||
return ByteArray{std::move(out)};
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "connections/implementation/mediums/ble/ble_advertisement.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
@@ -59,6 +60,9 @@ class BleL2capPacket {
|
||||
|
||||
// Creates a BleL2capPacket from the raw bytes.
|
||||
static absl::StatusOr<BleL2capPacket> CreateFromBytes(const ByteArray& bytes);
|
||||
// Creates a BleL2capPacket from the input stream.
|
||||
static absl::StatusOr<BleL2capPacket> CreateFromStream(
|
||||
InputStream& input_stream);
|
||||
// Creates a BleL2capPacket for requesting advertisement with service ID.
|
||||
static absl::StatusOr<ByteArray> ByteArrayForRequestAdvertisement(
|
||||
const std::string& service_id);
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
#include "connections/implementation/mediums/ble/ble_l2cap_packet.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/pipe.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
@@ -197,6 +200,209 @@ TEST(BleL2capPacketTest, CreateFromBytesWithInvalidLengthAdvertisement) {
|
||||
ASSERT_FALSE(result.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamFailsReadCommand) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
|
||||
output->Write(ByteArray{});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamRequestAdvertisement) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array =
|
||||
BleL2capPacket::ByteArrayForRequestAdvertisement(std::string(kServiceID));
|
||||
ASSERT_TRUE(byte_array.ok());
|
||||
|
||||
output->Write(*byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsFetchAdvertisementRequest());
|
||||
EXPECT_EQ(ble_l2cap_packet->GetServiceIdHash(),
|
||||
BleL2capPacket::GenerateServiceIdHash(std::string(kServiceID)));
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamZeroDataLength) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
std::string out = absl::StrCat(
|
||||
std::string(
|
||||
1, static_cast<char>(BleL2capPacket::Command::kRequestAdvertisement)),
|
||||
std::string("\x00\x00", 2));
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest,
|
||||
CreateFromStreamRequestAdvertisementBadServiceIdHashLength) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
std::string out = absl::StrCat(
|
||||
std::string(
|
||||
1, static_cast<char>(BleL2capPacket::Command::kRequestAdvertisement)),
|
||||
std::string("\x00\x01", 2));
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamFailsReadServiceIdHash) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
std::string out = absl::StrCat(
|
||||
std::string(
|
||||
1, static_cast<char>(BleL2capPacket::Command::kRequestAdvertisement)),
|
||||
std::string("\x00\x03", 2));
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamRequestAdvertisementFinish) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array = BleL2capPacket::ByteArrayForRequestAdvertisementFinish();
|
||||
|
||||
output->Write(byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsFetchAdvertisementFinished());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamResponseAdvertisement) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
ByteArray advertisement(kCorrectData.data(), kCorrectData.size());
|
||||
auto byte_array =
|
||||
BleL2capPacket::ByteArrayForResponseAdvertisement(advertisement);
|
||||
ASSERT_TRUE(byte_array.ok());
|
||||
|
||||
output->Write(*byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsAdvertisementResponse());
|
||||
EXPECT_EQ(ble_l2cap_packet->GetAdvertisement(), advertisement);
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest,
|
||||
CreateFromStreamResponseAdvertisementBadAdvertisementLength) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
// 0xFFFF is too large for advertisement length.
|
||||
std::string out = absl::StrCat(
|
||||
std::string(1, static_cast<char>(
|
||||
BleL2capPacket::Command::kResponseAdvertisement)),
|
||||
"\xFF\xFF");
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamFailsReadAdvertisement) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
std::string out = absl::StrCat(
|
||||
std::string(1, static_cast<char>(
|
||||
BleL2capPacket::Command::kResponseAdvertisement)),
|
||||
std::string("\x00\x0a", 2));
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamResponseLargeAdvertisement) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
ByteArray advertisement(300);
|
||||
auto byte_array =
|
||||
BleL2capPacket::ByteArrayForResponseAdvertisement(advertisement);
|
||||
ASSERT_TRUE(byte_array.ok());
|
||||
|
||||
output->Write(*byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsAdvertisementResponse());
|
||||
EXPECT_EQ(ble_l2cap_packet->GetAdvertisement(), advertisement);
|
||||
EXPECT_EQ(ble_l2cap_packet->GetAdvertisement().size(), 300);
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamServiceIdNotFound) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array = BleL2capPacket::ByteArrayForServiceIdNotFound();
|
||||
|
||||
output->Write(byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsErrorServiceIdNotFound());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamRequestDataConnection) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array = BleL2capPacket::ByteArrayForRequestDataConnection();
|
||||
|
||||
output->Write(byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsDataConnectionRequest());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamDataConnectionReady) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array = BleL2capPacket::ByteArrayForDataConnectionReady();
|
||||
|
||||
output->Write(byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsDataConnectionReadyResponse());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamDataConnectionFailure) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
auto byte_array = BleL2capPacket::ByteArrayForDataConnectionFailure();
|
||||
|
||||
output->Write(byte_array);
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_TRUE(ble_l2cap_packet.ok());
|
||||
EXPECT_TRUE(ble_l2cap_packet->IsDataConnectionFailureResponse());
|
||||
}
|
||||
|
||||
TEST(BleL2capPacketTest, CreateFromStreamUnsupportedCommand) {
|
||||
auto [input, output] = nearby::CreatePipe();
|
||||
std::string out = absl::StrCat(std::string(1, static_cast<char>(0XFF)));
|
||||
|
||||
output->Write(ByteArray{std::move(out)});
|
||||
output->Close();
|
||||
|
||||
auto ble_l2cap_packet = BleL2capPacket::CreateFromStream(*input);
|
||||
ASSERT_FALSE(ble_l2cap_packet.ok());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
|
||||
@@ -174,6 +174,37 @@ TEST(BlePacketTest, ConstructionFromSerializedShortLengthDataBytesFails) {
|
||||
EXPECT_FALSE(short_ble_packet.IsValid());
|
||||
}
|
||||
|
||||
TEST(BlePacketTest, ConstructionFromEmptyBytesIsInvalid) {
|
||||
BlePacket ble_packet((ByteArray()));
|
||||
EXPECT_FALSE(ble_packet.IsValid());
|
||||
}
|
||||
|
||||
TEST(BlePacketTest, ConstructionFromSerializedControlBytesWorks) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHash)};
|
||||
absl::StatusOr<BlePacket> org_ble_packet_status_or =
|
||||
BlePacket::CreateControlIntroductionPacket(service_id_hash);
|
||||
ASSERT_OK(org_ble_packet_status_or);
|
||||
|
||||
ByteArray ble_packet_bytes(org_ble_packet_status_or.value());
|
||||
BlePacket ble_packet(ble_packet_bytes);
|
||||
|
||||
EXPECT_TRUE(ble_packet.IsValid());
|
||||
EXPECT_TRUE(ble_packet.IsControlPacket());
|
||||
EXPECT_EQ(ble_packet.GetServiceIdHash(), service_id_hash);
|
||||
EXPECT_EQ(ble_packet.GetControlFrameType(),
|
||||
SocketControlFrame::INTRODUCTION);
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
SocketVersion version,
|
||||
ble_packet.GetIntroductonSocketVersion());
|
||||
EXPECT_EQ(version, SocketVersion::V2);
|
||||
}
|
||||
|
||||
TEST(BlePacketTest, ConstructionFromInvalidControlPacketIsInvalid) {
|
||||
ByteArray invalid_control_packet_bytes("\x00\x00\x00\x01\x02\x03", 6);
|
||||
BlePacket ble_packet(invalid_control_packet_bytes);
|
||||
EXPECT_FALSE(ble_packet.IsValid());
|
||||
}
|
||||
|
||||
TEST(BlePacketTest, IsControlPacketBytes) {
|
||||
EXPECT_TRUE(BlePacket::IsControlPacketBytes(ByteArray("\x00\x00\x00", 3)));
|
||||
EXPECT_FALSE(
|
||||
|
||||
Reference in New Issue
Block a user