mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Merge remote-tracking branch 'nearby/main'
# Conflicts: # connections/implementation/bwu_manager_test.cc # sharing/BUILD # sharing/certificates/fake_nearby_share_certificate_manager.cc # sharing/certificates/fake_nearby_share_certificate_manager.h # sharing/internal/base/utf_string_conversions.h
This commit is contained in:
@@ -535,6 +535,7 @@ let package = Package(
|
||||
.headerSearchPath("third_party/ukey2/ukey2/"),
|
||||
.headerSearchPath("third_party/ukey2/compiled_proto/src/main/proto"),
|
||||
.define("NO_WEBRTC"),
|
||||
.define("GITHUB_BUILD"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
@@ -553,6 +554,7 @@ let package = Package(
|
||||
.headerSearchPath("compiled_proto/"),
|
||||
.define("NO_WEBRTC"),
|
||||
.define("NC_OSS_BUILD"),
|
||||
.define("GITHUB_BUILD"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
@@ -566,6 +568,7 @@ let package = Package(
|
||||
.headerSearchPath("./"),
|
||||
.headerSearchPath("compiled_proto/"),
|
||||
.define("NO_WEBRTC"),
|
||||
.define("GITHUB_BUILD"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
|
||||
@@ -977,6 +977,9 @@ inline constexpr ConnectionResponseFrame::Impl_::Impl_(
|
||||
handshake_data_(
|
||||
&::google::protobuf::internal::fixed_address_empty_string,
|
||||
::_pbi::ConstantInitialized()),
|
||||
wifi_direct_device_name_(
|
||||
&::google::protobuf::internal::fixed_address_empty_string,
|
||||
::_pbi::ConstantInitialized()),
|
||||
os_info_{nullptr},
|
||||
location_hint_{nullptr},
|
||||
status_{0},
|
||||
@@ -4110,7 +4113,8 @@ PROTOBUF_NDEBUG_INLINE ConnectionResponseFrame::Impl_::Impl_(
|
||||
[[maybe_unused]] const ::location::nearby::connections::ConnectionResponseFrame& from_msg)
|
||||
: _has_bits_{from._has_bits_},
|
||||
_cached_size_{0},
|
||||
handshake_data_(arena, from.handshake_data_) {}
|
||||
handshake_data_(arena, from.handshake_data_),
|
||||
wifi_direct_device_name_(arena, from.wifi_direct_device_name_) {}
|
||||
|
||||
ConnectionResponseFrame::ConnectionResponseFrame(
|
||||
::google::protobuf::Arena* PROTOBUF_NULLABLE arena,
|
||||
@@ -4126,10 +4130,10 @@ ConnectionResponseFrame::ConnectionResponseFrame(
|
||||
from._internal_metadata_);
|
||||
new (&_impl_) Impl_(internal_visibility(), arena, from._impl_, from);
|
||||
::uint32_t cached_has_bits = _impl_._has_bits_[0];
|
||||
_impl_.os_info_ = (CheckHasBit(cached_has_bits, 0x00000002U))
|
||||
_impl_.os_info_ = (CheckHasBit(cached_has_bits, 0x00000004U))
|
||||
? ::google::protobuf::MessageLite::CopyConstruct(arena, *from._impl_.os_info_)
|
||||
: nullptr;
|
||||
_impl_.location_hint_ = (CheckHasBit(cached_has_bits, 0x00000004U))
|
||||
_impl_.location_hint_ = (CheckHasBit(cached_has_bits, 0x00000008U))
|
||||
? ::google::protobuf::MessageLite::CopyConstruct(arena, *from._impl_.location_hint_)
|
||||
: nullptr;
|
||||
::memcpy(reinterpret_cast<char*>(&_impl_) +
|
||||
@@ -4146,7 +4150,8 @@ PROTOBUF_NDEBUG_INLINE ConnectionResponseFrame::Impl_::Impl_(
|
||||
[[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility,
|
||||
[[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena)
|
||||
: _cached_size_{0},
|
||||
handshake_data_(arena) {}
|
||||
handshake_data_(arena),
|
||||
wifi_direct_device_name_(arena) {}
|
||||
|
||||
inline void ConnectionResponseFrame::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) {
|
||||
new (&_impl_) Impl_(internal_visibility(), arena);
|
||||
@@ -4169,6 +4174,7 @@ inline void ConnectionResponseFrame::SharedDtor(MessageLite& self) {
|
||||
this_._internal_metadata_.Delete<::std::string>();
|
||||
ABSL_DCHECK(this_.GetArena() == nullptr);
|
||||
this_._impl_.handshake_data_.Destroy();
|
||||
this_._impl_.wifi_direct_device_name_.Destroy();
|
||||
delete this_._impl_.os_info_;
|
||||
delete this_._impl_.location_hint_;
|
||||
this_._impl_.~Impl_();
|
||||
@@ -4214,16 +4220,16 @@ ConnectionResponseFrame::GetClassData() const {
|
||||
return ConnectionResponseFrame_class_data_.base();
|
||||
}
|
||||
PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
|
||||
const ::_pbi::TcParseTable<4, 9, 3, 0, 2>
|
||||
const ::_pbi::TcParseTable<4, 10, 3, 0, 2>
|
||||
ConnectionResponseFrame::_table_ = {
|
||||
{
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_._has_bits_),
|
||||
0, // no _extensions_
|
||||
9, 120, // max_field_number, fast_idx_mask
|
||||
10, 120, // max_field_number, fast_idx_mask
|
||||
offsetof(decltype(_table_), field_lookup_table),
|
||||
4294966784, // skipmap
|
||||
4294966272, // skipmap
|
||||
offsetof(decltype(_table_), field_entries),
|
||||
9, // num_field_entries
|
||||
10, // num_field_entries
|
||||
3, // num_aux_entries
|
||||
offsetof(decltype(_table_), aux_entries),
|
||||
ConnectionResponseFrame_class_data_.base(),
|
||||
@@ -4236,7 +4242,7 @@ ConnectionResponseFrame::_table_ = {
|
||||
{::_pbi::TcParser::MiniParse, {}},
|
||||
// optional int32 status = 1 [deprecated = true];
|
||||
{::_pbi::TcParser::FastV32S1,
|
||||
{8, 3, 0,
|
||||
{8, 4, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.status_)}},
|
||||
// optional bytes handshake_data = 2;
|
||||
{::_pbi::TcParser::FastBS1,
|
||||
@@ -4244,33 +4250,36 @@ ConnectionResponseFrame::_table_ = {
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.handshake_data_)}},
|
||||
// optional .location.nearby.connections.ConnectionResponseFrame.ResponseStatus response = 3;
|
||||
{::_pbi::TcParser::FastEr0S1,
|
||||
{24, 4, 2,
|
||||
{24, 5, 2,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.response_)}},
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
{::_pbi::TcParser::FastMtS1,
|
||||
{34, 1, 0,
|
||||
{34, 2, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.os_info_)}},
|
||||
// optional int32 multiplex_socket_bitmask = 5;
|
||||
{::_pbi::TcParser::FastV32S1,
|
||||
{40, 5, 0,
|
||||
{40, 6, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.multiplex_socket_bitmask_)}},
|
||||
// optional int32 nearby_connections_version = 6 [deprecated = true];
|
||||
{::_pbi::TcParser::FastV32S1,
|
||||
{48, 6, 0,
|
||||
{48, 7, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.nearby_connections_version_)}},
|
||||
// optional int32 safe_to_disconnect_version = 7;
|
||||
{::_pbi::TcParser::FastV32S1,
|
||||
{56, 7, 0,
|
||||
{56, 8, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.safe_to_disconnect_version_)}},
|
||||
// optional .location.nearby.connections.LocationHint location_hint = 8;
|
||||
{::_pbi::TcParser::FastMtS1,
|
||||
{66, 2, 1,
|
||||
{66, 3, 1,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.location_hint_)}},
|
||||
// optional int32 keep_alive_timeout_millis = 9;
|
||||
{::_pbi::TcParser::FastV32S1,
|
||||
{72, 8, 0,
|
||||
{72, 9, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.keep_alive_timeout_millis_)}},
|
||||
{::_pbi::TcParser::MiniParse, {}},
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
{::_pbi::TcParser::FastBS1,
|
||||
{82, 1, 0,
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.wifi_direct_device_name_)}},
|
||||
{::_pbi::TcParser::MiniParse, {}},
|
||||
{::_pbi::TcParser::MiniParse, {}},
|
||||
{::_pbi::TcParser::MiniParse, {}},
|
||||
@@ -4280,23 +4289,25 @@ ConnectionResponseFrame::_table_ = {
|
||||
65535, 65535
|
||||
}}, {{
|
||||
// optional int32 status = 1 [deprecated = true];
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.status_), _Internal::kHasBitsOffset + 3, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.status_), _Internal::kHasBitsOffset + 4, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
// optional bytes handshake_data = 2;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.handshake_data_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
|
||||
// optional .location.nearby.connections.ConnectionResponseFrame.ResponseStatus response = 3;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.response_), _Internal::kHasBitsOffset + 4, 2, (0 | ::_fl::kFcOptional | ::_fl::kEnumRange)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.response_), _Internal::kHasBitsOffset + 5, 2, (0 | ::_fl::kFcOptional | ::_fl::kEnumRange)},
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.os_info_), _Internal::kHasBitsOffset + 1, 0, (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.os_info_), _Internal::kHasBitsOffset + 2, 0, (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)},
|
||||
// optional int32 multiplex_socket_bitmask = 5;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.multiplex_socket_bitmask_), _Internal::kHasBitsOffset + 5, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.multiplex_socket_bitmask_), _Internal::kHasBitsOffset + 6, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
// optional int32 nearby_connections_version = 6 [deprecated = true];
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.nearby_connections_version_), _Internal::kHasBitsOffset + 6, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.nearby_connections_version_), _Internal::kHasBitsOffset + 7, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
// optional int32 safe_to_disconnect_version = 7;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.safe_to_disconnect_version_), _Internal::kHasBitsOffset + 7, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.safe_to_disconnect_version_), _Internal::kHasBitsOffset + 8, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
// optional .location.nearby.connections.LocationHint location_hint = 8;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.location_hint_), _Internal::kHasBitsOffset + 2, 1, (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.location_hint_), _Internal::kHasBitsOffset + 3, 1, (0 | ::_fl::kFcOptional | ::_fl::kMessage | ::_fl::kTvTable)},
|
||||
// optional int32 keep_alive_timeout_millis = 9;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.keep_alive_timeout_millis_), _Internal::kHasBitsOffset + 8, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.keep_alive_timeout_millis_), _Internal::kHasBitsOffset + 9, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
{PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.wifi_direct_device_name_), _Internal::kHasBitsOffset + 1, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
|
||||
}},
|
||||
{{
|
||||
{::_pbi::TcParser::GetTable<::location::nearby::connections::OsInfo>()},
|
||||
@@ -4314,25 +4325,32 @@ PROTOBUF_NOINLINE void ConnectionResponseFrame::Clear() {
|
||||
(void) cached_has_bits;
|
||||
|
||||
cached_has_bits = _impl_._has_bits_[0];
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x00000007U)) {
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x0000000fU)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000001U)) {
|
||||
_impl_.handshake_data_.ClearNonDefaultToEmpty();
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000002U)) {
|
||||
_impl_.wifi_direct_device_name_.ClearNonDefaultToEmpty();
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
ABSL_DCHECK(_impl_.os_info_ != nullptr);
|
||||
_impl_.os_info_->Clear();
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
ABSL_DCHECK(_impl_.location_hint_ != nullptr);
|
||||
_impl_.location_hint_->Clear();
|
||||
}
|
||||
}
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x000000f8U)) {
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x000000f0U)) {
|
||||
::memset(&_impl_.status_, 0, static_cast<::size_t>(
|
||||
reinterpret_cast<char*>(&_impl_.safe_to_disconnect_version_) -
|
||||
reinterpret_cast<char*>(&_impl_.status_)) + sizeof(_impl_.safe_to_disconnect_version_));
|
||||
reinterpret_cast<char*>(&_impl_.nearby_connections_version_) -
|
||||
reinterpret_cast<char*>(&_impl_.status_)) + sizeof(_impl_.nearby_connections_version_));
|
||||
}
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x00000300U)) {
|
||||
::memset(&_impl_.safe_to_disconnect_version_, 0, static_cast<::size_t>(
|
||||
reinterpret_cast<char*>(&_impl_.keep_alive_timeout_millis_) -
|
||||
reinterpret_cast<char*>(&_impl_.safe_to_disconnect_version_)) + sizeof(_impl_.keep_alive_timeout_millis_));
|
||||
}
|
||||
_impl_.keep_alive_timeout_millis_ = 0;
|
||||
_impl_._has_bits_.Clear();
|
||||
_internal_metadata_.Clear<::std::string>();
|
||||
}
|
||||
@@ -4357,7 +4375,7 @@ PROTOBUF_NOINLINE void ConnectionResponseFrame::Clear() {
|
||||
|
||||
cached_has_bits = this_._impl_._has_bits_[0];
|
||||
// optional int32 status = 1 [deprecated = true];
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<1>(
|
||||
stream, this_._internal_status(), target);
|
||||
@@ -4370,54 +4388,60 @@ PROTOBUF_NOINLINE void ConnectionResponseFrame::Clear() {
|
||||
}
|
||||
|
||||
// optional .location.nearby.connections.ConnectionResponseFrame.ResponseStatus response = 3;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
target = stream->EnsureSpace(target);
|
||||
target = ::_pbi::WireFormatLite::WriteEnumToArray(
|
||||
3, this_._internal_response(), target);
|
||||
}
|
||||
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000002U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage(
|
||||
4, *this_._impl_.os_info_, this_._impl_.os_info_->GetCachedSize(), target,
|
||||
stream);
|
||||
}
|
||||
|
||||
// optional int32 multiplex_socket_bitmask = 5;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<5>(
|
||||
stream, this_._internal_multiplex_socket_bitmask(), target);
|
||||
}
|
||||
|
||||
// optional int32 nearby_connections_version = 6 [deprecated = true];
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<6>(
|
||||
stream, this_._internal_nearby_connections_version(), target);
|
||||
}
|
||||
|
||||
// optional int32 safe_to_disconnect_version = 7;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<7>(
|
||||
stream, this_._internal_safe_to_disconnect_version(), target);
|
||||
}
|
||||
|
||||
// optional .location.nearby.connections.LocationHint location_hint = 8;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessage(
|
||||
8, *this_._impl_.location_hint_, this_._impl_.location_hint_->GetCachedSize(), target,
|
||||
stream);
|
||||
}
|
||||
|
||||
// optional int32 keep_alive_timeout_millis = 9;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000200U)) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<9>(
|
||||
stream, this_._internal_keep_alive_timeout_millis(), target);
|
||||
}
|
||||
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000002U)) {
|
||||
const ::std::string& _s = this_._internal_wifi_direct_device_name();
|
||||
target = stream->WriteStringMaybeAliased(10, _s, target);
|
||||
}
|
||||
|
||||
if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) {
|
||||
target = stream->WriteRaw(
|
||||
this_._internal_metadata_.unknown_fields<::std::string>(::google::protobuf::internal::GetEmptyString).data(),
|
||||
@@ -4449,45 +4473,50 @@ PROTOBUF_NOINLINE void ConnectionResponseFrame::Clear() {
|
||||
total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize(
|
||||
this_._internal_handshake_data());
|
||||
}
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000002U)) {
|
||||
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
|
||||
this_._internal_wifi_direct_device_name());
|
||||
}
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::MessageSize(*this_._impl_.os_info_);
|
||||
}
|
||||
// optional .location.nearby.connections.LocationHint location_hint = 8;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::MessageSize(*this_._impl_.location_hint_);
|
||||
}
|
||||
// optional int32 status = 1 [deprecated = true];
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
|
||||
this_._internal_status());
|
||||
}
|
||||
// optional .location.nearby.connections.ConnectionResponseFrame.ResponseStatus response = 3;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
total_size += 1 +
|
||||
::_pbi::WireFormatLite::EnumSize(this_._internal_response());
|
||||
}
|
||||
// optional int32 multiplex_socket_bitmask = 5;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
|
||||
this_._internal_multiplex_socket_bitmask());
|
||||
}
|
||||
// optional int32 nearby_connections_version = 6 [deprecated = true];
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
|
||||
this_._internal_nearby_connections_version());
|
||||
}
|
||||
}
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x00000300U)) {
|
||||
// optional int32 safe_to_disconnect_version = 7;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
|
||||
this_._internal_safe_to_disconnect_version());
|
||||
}
|
||||
}
|
||||
{
|
||||
// optional int32 keep_alive_timeout_millis = 9;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000200U)) {
|
||||
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
|
||||
this_._internal_keep_alive_timeout_millis());
|
||||
}
|
||||
@@ -4519,6 +4548,9 @@ void ConnectionResponseFrame::MergeImpl(::google::protobuf::MessageLite& to_msg,
|
||||
_this->_internal_set_handshake_data(from._internal_handshake_data());
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000002U)) {
|
||||
_this->_internal_set_wifi_direct_device_name(from._internal_wifi_direct_device_name());
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
ABSL_DCHECK(from._impl_.os_info_ != nullptr);
|
||||
if (_this->_impl_.os_info_ == nullptr) {
|
||||
_this->_impl_.os_info_ = ::google::protobuf::MessageLite::CopyConstruct(arena, *from._impl_.os_info_);
|
||||
@@ -4526,7 +4558,7 @@ void ConnectionResponseFrame::MergeImpl(::google::protobuf::MessageLite& to_msg,
|
||||
_this->_impl_.os_info_->MergeFrom(*from._impl_.os_info_);
|
||||
}
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000004U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
ABSL_DCHECK(from._impl_.location_hint_ != nullptr);
|
||||
if (_this->_impl_.location_hint_ == nullptr) {
|
||||
_this->_impl_.location_hint_ = ::google::protobuf::MessageLite::CopyConstruct(arena, *from._impl_.location_hint_);
|
||||
@@ -4534,24 +4566,26 @@ void ConnectionResponseFrame::MergeImpl(::google::protobuf::MessageLite& to_msg,
|
||||
_this->_impl_.location_hint_->MergeFrom(*from._impl_.location_hint_);
|
||||
}
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000008U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
_this->_impl_.status_ = from._impl_.status_;
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
_this->_impl_.response_ = from._impl_.response_;
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
_this->_impl_.multiplex_socket_bitmask_ = from._impl_.multiplex_socket_bitmask_;
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
_this->_impl_.nearby_connections_version_ = from._impl_.nearby_connections_version_;
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
|
||||
}
|
||||
if (BatchCheckHasBit(cached_has_bits, 0x00000300U)) {
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
_this->_impl_.safe_to_disconnect_version_ = from._impl_.safe_to_disconnect_version_;
|
||||
}
|
||||
}
|
||||
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
|
||||
_this->_impl_.keep_alive_timeout_millis_ = from._impl_.keep_alive_timeout_millis_;
|
||||
if (CheckHasBit(cached_has_bits, 0x00000200U)) {
|
||||
_this->_impl_.keep_alive_timeout_millis_ = from._impl_.keep_alive_timeout_millis_;
|
||||
}
|
||||
}
|
||||
_this->_impl_._has_bits_[0] |= cached_has_bits;
|
||||
_this->_internal_metadata_.MergeFrom<::std::string>(
|
||||
@@ -4573,6 +4607,7 @@ void ConnectionResponseFrame::InternalSwap(ConnectionResponseFrame* PROTOBUF_RES
|
||||
_internal_metadata_.InternalSwap(&other->_internal_metadata_);
|
||||
swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
|
||||
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.handshake_data_, &other->_impl_.handshake_data_, arena);
|
||||
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.wifi_direct_device_name_, &other->_impl_.wifi_direct_device_name_, arena);
|
||||
::google::protobuf::internal::memswap<
|
||||
PROTOBUF_FIELD_OFFSET(ConnectionResponseFrame, _impl_.keep_alive_timeout_millis_)
|
||||
+ sizeof(ConnectionResponseFrame::_impl_.keep_alive_timeout_millis_)
|
||||
|
||||
@@ -8114,6 +8114,7 @@ class ConnectionResponseFrame final : public ::google::protobuf::MessageLite
|
||||
// accessors -------------------------------------------------------
|
||||
enum : int {
|
||||
kHandshakeDataFieldNumber = 2,
|
||||
kWifiDirectDeviceNameFieldNumber = 10,
|
||||
kOsInfoFieldNumber = 4,
|
||||
kLocationHintFieldNumber = 8,
|
||||
kStatusFieldNumber = 1,
|
||||
@@ -8138,6 +8139,22 @@ class ConnectionResponseFrame final : public ::google::protobuf::MessageLite
|
||||
PROTOBUF_ALWAYS_INLINE void _internal_set_handshake_data(const ::std::string& value);
|
||||
::std::string* PROTOBUF_NONNULL _internal_mutable_handshake_data();
|
||||
|
||||
public:
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
bool has_wifi_direct_device_name() const;
|
||||
void clear_wifi_direct_device_name() ;
|
||||
const ::std::string& wifi_direct_device_name() const;
|
||||
template <typename Arg_ = const ::std::string&, typename... Args_>
|
||||
void set_wifi_direct_device_name(Arg_&& arg, Args_... args);
|
||||
::std::string* PROTOBUF_NONNULL mutable_wifi_direct_device_name();
|
||||
[[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_wifi_direct_device_name();
|
||||
void set_allocated_wifi_direct_device_name(::std::string* PROTOBUF_NULLABLE value);
|
||||
|
||||
private:
|
||||
const ::std::string& _internal_wifi_direct_device_name() const;
|
||||
PROTOBUF_ALWAYS_INLINE void _internal_set_wifi_direct_device_name(const ::std::string& value);
|
||||
::std::string* PROTOBUF_NONNULL _internal_mutable_wifi_direct_device_name();
|
||||
|
||||
public:
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
bool has_os_info() const;
|
||||
@@ -8239,7 +8256,7 @@ class ConnectionResponseFrame final : public ::google::protobuf::MessageLite
|
||||
private:
|
||||
class _Internal;
|
||||
friend class ::google::protobuf::internal::TcParser;
|
||||
static const ::google::protobuf::internal::TcParseTable<4, 9,
|
||||
static const ::google::protobuf::internal::TcParseTable<4, 10,
|
||||
3, 0,
|
||||
2>
|
||||
_table_;
|
||||
@@ -8262,6 +8279,7 @@ class ConnectionResponseFrame final : public ::google::protobuf::MessageLite
|
||||
::google::protobuf::internal::HasBits<1> _has_bits_;
|
||||
::google::protobuf::internal::CachedSize _cached_size_;
|
||||
::google::protobuf::internal::ArenaStringPtr handshake_data_;
|
||||
::google::protobuf::internal::ArenaStringPtr wifi_direct_device_name_;
|
||||
::location::nearby::connections::OsInfo* PROTOBUF_NULLABLE os_info_;
|
||||
::location::nearby::connections::LocationHint* PROTOBUF_NULLABLE location_hint_;
|
||||
::int32_t status_;
|
||||
@@ -13226,14 +13244,14 @@ inline ConnectionRequestFrame::DeviceCase ConnectionRequestFrame::Device_case()
|
||||
|
||||
// optional int32 status = 1 [deprecated = true];
|
||||
inline bool ConnectionResponseFrame::has_status() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000010U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_status() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.status_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000008U);
|
||||
0x00000010U);
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::status() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.status)
|
||||
@@ -13241,7 +13259,7 @@ inline ::int32_t ConnectionResponseFrame::status() const {
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_status(::int32_t value) {
|
||||
_internal_set_status(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000010U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.status)
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::_internal_status() const {
|
||||
@@ -13324,14 +13342,14 @@ inline void ConnectionResponseFrame::set_allocated_handshake_data(::std::string*
|
||||
|
||||
// optional .location.nearby.connections.ConnectionResponseFrame.ResponseStatus response = 3;
|
||||
inline bool ConnectionResponseFrame::has_response() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000010U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000020U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_response() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.response_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000010U);
|
||||
0x00000020U);
|
||||
}
|
||||
inline ::location::nearby::connections::ConnectionResponseFrame_ResponseStatus ConnectionResponseFrame::response() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.response)
|
||||
@@ -13339,7 +13357,7 @@ inline ::location::nearby::connections::ConnectionResponseFrame_ResponseStatus C
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_response(::location::nearby::connections::ConnectionResponseFrame_ResponseStatus value) {
|
||||
_internal_set_response(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000010U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000020U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.response)
|
||||
}
|
||||
inline ::location::nearby::connections::ConnectionResponseFrame_ResponseStatus ConnectionResponseFrame::_internal_response() const {
|
||||
@@ -13356,7 +13374,7 @@ inline void ConnectionResponseFrame::_internal_set_response(::location::nearby::
|
||||
|
||||
// optional .location.nearby.connections.OsInfo os_info = 4;
|
||||
inline bool ConnectionResponseFrame::has_os_info() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
PROTOBUF_ASSUME(!value || _impl_.os_info_ != nullptr);
|
||||
return value;
|
||||
}
|
||||
@@ -13364,7 +13382,7 @@ inline void ConnectionResponseFrame::clear_os_info() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
if (_impl_.os_info_ != nullptr) _impl_.os_info_->Clear();
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000002U);
|
||||
0x00000004U);
|
||||
}
|
||||
inline const ::location::nearby::connections::OsInfo& ConnectionResponseFrame::_internal_os_info() const {
|
||||
::google::protobuf::internal::TSanRead(&_impl_);
|
||||
@@ -13383,16 +13401,16 @@ inline void ConnectionResponseFrame::unsafe_arena_set_allocated_os_info(
|
||||
}
|
||||
_impl_.os_info_ = reinterpret_cast<::location::nearby::connections::OsInfo*>(value);
|
||||
if (value != nullptr) {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
} else {
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
}
|
||||
// @@protoc_insertion_point(field_unsafe_arena_set_allocated:location.nearby.connections.ConnectionResponseFrame.os_info)
|
||||
}
|
||||
inline ::location::nearby::connections::OsInfo* PROTOBUF_NULLABLE ConnectionResponseFrame::release_os_info() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
::location::nearby::connections::OsInfo* released = _impl_.os_info_;
|
||||
_impl_.os_info_ = nullptr;
|
||||
if (::google::protobuf::internal::DebugHardenForceCopyInRelease()) {
|
||||
@@ -13412,7 +13430,7 @@ inline ::location::nearby::connections::OsInfo* PROTOBUF_NULLABLE ConnectionResp
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
// @@protoc_insertion_point(field_release:location.nearby.connections.ConnectionResponseFrame.os_info)
|
||||
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
::location::nearby::connections::OsInfo* temp = _impl_.os_info_;
|
||||
_impl_.os_info_ = nullptr;
|
||||
return temp;
|
||||
@@ -13427,7 +13445,7 @@ inline ::location::nearby::connections::OsInfo* PROTOBUF_NONNULL ConnectionRespo
|
||||
}
|
||||
inline ::location::nearby::connections::OsInfo* PROTOBUF_NONNULL ConnectionResponseFrame::mutable_os_info()
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
::location::nearby::connections::OsInfo* _msg = _internal_mutable_os_info();
|
||||
// @@protoc_insertion_point(field_mutable:location.nearby.connections.ConnectionResponseFrame.os_info)
|
||||
return _msg;
|
||||
@@ -13444,9 +13462,9 @@ inline void ConnectionResponseFrame::set_allocated_os_info(::location::nearby::c
|
||||
if (message_arena != submessage_arena) {
|
||||
value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena);
|
||||
}
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
} else {
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
}
|
||||
|
||||
_impl_.os_info_ = reinterpret_cast<::location::nearby::connections::OsInfo*>(value);
|
||||
@@ -13455,14 +13473,14 @@ inline void ConnectionResponseFrame::set_allocated_os_info(::location::nearby::c
|
||||
|
||||
// optional int32 multiplex_socket_bitmask = 5;
|
||||
inline bool ConnectionResponseFrame::has_multiplex_socket_bitmask() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000020U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000040U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_multiplex_socket_bitmask() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.multiplex_socket_bitmask_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000020U);
|
||||
0x00000040U);
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::multiplex_socket_bitmask() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.multiplex_socket_bitmask)
|
||||
@@ -13470,7 +13488,7 @@ inline ::int32_t ConnectionResponseFrame::multiplex_socket_bitmask() const {
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_multiplex_socket_bitmask(::int32_t value) {
|
||||
_internal_set_multiplex_socket_bitmask(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000020U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.multiplex_socket_bitmask)
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::_internal_multiplex_socket_bitmask() const {
|
||||
@@ -13484,14 +13502,14 @@ inline void ConnectionResponseFrame::_internal_set_multiplex_socket_bitmask(::in
|
||||
|
||||
// optional int32 nearby_connections_version = 6 [deprecated = true];
|
||||
inline bool ConnectionResponseFrame::has_nearby_connections_version() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000040U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000080U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_nearby_connections_version() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.nearby_connections_version_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000040U);
|
||||
0x00000080U);
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::nearby_connections_version() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.nearby_connections_version)
|
||||
@@ -13499,7 +13517,7 @@ inline ::int32_t ConnectionResponseFrame::nearby_connections_version() const {
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_nearby_connections_version(::int32_t value) {
|
||||
_internal_set_nearby_connections_version(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000080U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.nearby_connections_version)
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::_internal_nearby_connections_version() const {
|
||||
@@ -13513,14 +13531,14 @@ inline void ConnectionResponseFrame::_internal_set_nearby_connections_version(::
|
||||
|
||||
// optional int32 safe_to_disconnect_version = 7;
|
||||
inline bool ConnectionResponseFrame::has_safe_to_disconnect_version() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000080U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000100U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_safe_to_disconnect_version() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.safe_to_disconnect_version_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000080U);
|
||||
0x00000100U);
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::safe_to_disconnect_version() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.safe_to_disconnect_version)
|
||||
@@ -13528,7 +13546,7 @@ inline ::int32_t ConnectionResponseFrame::safe_to_disconnect_version() const {
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_safe_to_disconnect_version(::int32_t value) {
|
||||
_internal_set_safe_to_disconnect_version(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000080U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000100U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.safe_to_disconnect_version)
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::_internal_safe_to_disconnect_version() const {
|
||||
@@ -13542,7 +13560,7 @@ inline void ConnectionResponseFrame::_internal_set_safe_to_disconnect_version(::
|
||||
|
||||
// optional .location.nearby.connections.LocationHint location_hint = 8;
|
||||
inline bool ConnectionResponseFrame::has_location_hint() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
PROTOBUF_ASSUME(!value || _impl_.location_hint_ != nullptr);
|
||||
return value;
|
||||
}
|
||||
@@ -13550,7 +13568,7 @@ inline void ConnectionResponseFrame::clear_location_hint() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
if (_impl_.location_hint_ != nullptr) _impl_.location_hint_->Clear();
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000004U);
|
||||
0x00000008U);
|
||||
}
|
||||
inline const ::location::nearby::connections::LocationHint& ConnectionResponseFrame::_internal_location_hint() const {
|
||||
::google::protobuf::internal::TSanRead(&_impl_);
|
||||
@@ -13569,16 +13587,16 @@ inline void ConnectionResponseFrame::unsafe_arena_set_allocated_location_hint(
|
||||
}
|
||||
_impl_.location_hint_ = reinterpret_cast<::location::nearby::connections::LocationHint*>(value);
|
||||
if (value != nullptr) {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
} else {
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
}
|
||||
// @@protoc_insertion_point(field_unsafe_arena_set_allocated:location.nearby.connections.ConnectionResponseFrame.location_hint)
|
||||
}
|
||||
inline ::location::nearby::connections::LocationHint* PROTOBUF_NULLABLE ConnectionResponseFrame::release_location_hint() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
::location::nearby::connections::LocationHint* released = _impl_.location_hint_;
|
||||
_impl_.location_hint_ = nullptr;
|
||||
if (::google::protobuf::internal::DebugHardenForceCopyInRelease()) {
|
||||
@@ -13598,7 +13616,7 @@ inline ::location::nearby::connections::LocationHint* PROTOBUF_NULLABLE Connecti
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
// @@protoc_insertion_point(field_release:location.nearby.connections.ConnectionResponseFrame.location_hint)
|
||||
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
::location::nearby::connections::LocationHint* temp = _impl_.location_hint_;
|
||||
_impl_.location_hint_ = nullptr;
|
||||
return temp;
|
||||
@@ -13613,7 +13631,7 @@ inline ::location::nearby::connections::LocationHint* PROTOBUF_NONNULL Connectio
|
||||
}
|
||||
inline ::location::nearby::connections::LocationHint* PROTOBUF_NONNULL ConnectionResponseFrame::mutable_location_hint()
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
::location::nearby::connections::LocationHint* _msg = _internal_mutable_location_hint();
|
||||
// @@protoc_insertion_point(field_mutable:location.nearby.connections.ConnectionResponseFrame.location_hint)
|
||||
return _msg;
|
||||
@@ -13630,9 +13648,9 @@ inline void ConnectionResponseFrame::set_allocated_location_hint(::location::nea
|
||||
if (message_arena != submessage_arena) {
|
||||
value = ::google::protobuf::internal::GetOwnedMessage(message_arena, value, submessage_arena);
|
||||
}
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
} else {
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000004U);
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000008U);
|
||||
}
|
||||
|
||||
_impl_.location_hint_ = reinterpret_cast<::location::nearby::connections::LocationHint*>(value);
|
||||
@@ -13641,14 +13659,14 @@ inline void ConnectionResponseFrame::set_allocated_location_hint(::location::nea
|
||||
|
||||
// optional int32 keep_alive_timeout_millis = 9;
|
||||
inline bool ConnectionResponseFrame::has_keep_alive_timeout_millis() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000100U);
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000200U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_keep_alive_timeout_millis() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.keep_alive_timeout_millis_ = 0;
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000100U);
|
||||
0x00000200U);
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::keep_alive_timeout_millis() const {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.keep_alive_timeout_millis)
|
||||
@@ -13656,7 +13674,7 @@ inline ::int32_t ConnectionResponseFrame::keep_alive_timeout_millis() const {
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_keep_alive_timeout_millis(::int32_t value) {
|
||||
_internal_set_keep_alive_timeout_millis(value);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000100U);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000200U);
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.keep_alive_timeout_millis)
|
||||
}
|
||||
inline ::int32_t ConnectionResponseFrame::_internal_keep_alive_timeout_millis() const {
|
||||
@@ -13668,6 +13686,75 @@ inline void ConnectionResponseFrame::_internal_set_keep_alive_timeout_millis(::i
|
||||
_impl_.keep_alive_timeout_millis_ = value;
|
||||
}
|
||||
|
||||
// optional string wifi_direct_device_name = 10;
|
||||
inline bool ConnectionResponseFrame::has_wifi_direct_device_name() const {
|
||||
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
return value;
|
||||
}
|
||||
inline void ConnectionResponseFrame::clear_wifi_direct_device_name() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.wifi_direct_device_name_.ClearToEmpty();
|
||||
ClearHasBit(_impl_._has_bits_[0],
|
||||
0x00000002U);
|
||||
}
|
||||
inline const ::std::string& ConnectionResponseFrame::wifi_direct_device_name() const
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
// @@protoc_insertion_point(field_get:location.nearby.connections.ConnectionResponseFrame.wifi_direct_device_name)
|
||||
return _internal_wifi_direct_device_name();
|
||||
}
|
||||
template <typename Arg_, typename... Args_>
|
||||
PROTOBUF_ALWAYS_INLINE void ConnectionResponseFrame::set_wifi_direct_device_name(Arg_&& arg, Args_... args) {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
_impl_.wifi_direct_device_name_.Set(static_cast<Arg_&&>(arg), args..., GetArena());
|
||||
// @@protoc_insertion_point(field_set:location.nearby.connections.ConnectionResponseFrame.wifi_direct_device_name)
|
||||
}
|
||||
inline ::std::string* PROTOBUF_NONNULL ConnectionResponseFrame::mutable_wifi_direct_device_name()
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
::std::string* _s = _internal_mutable_wifi_direct_device_name();
|
||||
// @@protoc_insertion_point(field_mutable:location.nearby.connections.ConnectionResponseFrame.wifi_direct_device_name)
|
||||
return _s;
|
||||
}
|
||||
inline const ::std::string& ConnectionResponseFrame::_internal_wifi_direct_device_name() const {
|
||||
::google::protobuf::internal::TSanRead(&_impl_);
|
||||
return _impl_.wifi_direct_device_name_.Get();
|
||||
}
|
||||
inline void ConnectionResponseFrame::_internal_set_wifi_direct_device_name(const ::std::string& value) {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
_impl_.wifi_direct_device_name_.Set(value, GetArena());
|
||||
}
|
||||
inline ::std::string* PROTOBUF_NONNULL ConnectionResponseFrame::_internal_mutable_wifi_direct_device_name() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
return _impl_.wifi_direct_device_name_.Mutable( GetArena());
|
||||
}
|
||||
inline ::std::string* PROTOBUF_NULLABLE ConnectionResponseFrame::release_wifi_direct_device_name() {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
// @@protoc_insertion_point(field_release:location.nearby.connections.ConnectionResponseFrame.wifi_direct_device_name)
|
||||
if (!CheckHasBit(_impl_._has_bits_[0], 0x00000002U)) {
|
||||
return nullptr;
|
||||
}
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
auto* released = _impl_.wifi_direct_device_name_.Release();
|
||||
if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) {
|
||||
_impl_.wifi_direct_device_name_.Set("", GetArena());
|
||||
}
|
||||
return released;
|
||||
}
|
||||
inline void ConnectionResponseFrame::set_allocated_wifi_direct_device_name(::std::string* PROTOBUF_NULLABLE value) {
|
||||
::google::protobuf::internal::TSanWrite(&_impl_);
|
||||
if (value != nullptr) {
|
||||
SetHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
} else {
|
||||
ClearHasBit(_impl_._has_bits_[0], 0x00000002U);
|
||||
}
|
||||
_impl_.wifi_direct_device_name_.SetAllocated(value, GetArena());
|
||||
if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.wifi_direct_device_name_.IsDefault()) {
|
||||
_impl_.wifi_direct_device_name_.Set("", GetArena());
|
||||
}
|
||||
// @@protoc_insertion_point(field_set_allocated:location.nearby.connections.ConnectionResponseFrame.wifi_direct_device_name)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// PayloadTransferFrame_PayloadHeader
|
||||
|
||||
@@ -99,6 +99,8 @@ cc_library(
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:mac_address",
|
||||
"//sharing/internal/base:utf_utils",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
@@ -262,6 +264,7 @@ cc_library(
|
||||
"//internal/platform/implementation:wifi_utils",
|
||||
"//proto:connections_enums_cc_proto",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/cleanup",
|
||||
"@com_google_absl//absl/container:btree",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
@@ -349,6 +352,7 @@ cc_test(
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -422,6 +422,15 @@ int BaseEndpointChannel::GetFrequency() const { return frequency_; }
|
||||
// Returns the try count of this EndpointChannel.
|
||||
int BaseEndpointChannel::GetTryCount() const { return try_count_; }
|
||||
|
||||
void BaseEndpointChannel::SetLocalEndpointId(
|
||||
const std::string& local_endpoint_id) {
|
||||
local_endpoint_id_ = local_endpoint_id;
|
||||
}
|
||||
|
||||
std::string BaseEndpointChannel::GetLocalEndpointId() const {
|
||||
return local_endpoint_id_;
|
||||
}
|
||||
|
||||
int BaseEndpointChannel::GetMaxAllowedReadBytes() const {
|
||||
int64_t max_allowed_read_bytes = NearbyFlags::GetInstance().GetInt64Flag(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
|
||||
@@ -81,6 +81,8 @@ class BaseEndpointChannel : public EndpointChannel {
|
||||
uint32_t GetNextKeepAliveSeqNo() const override;
|
||||
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
|
||||
const std::string& endpoint_id) override;
|
||||
void SetLocalEndpointId(const std::string& local_endpoint_id) override;
|
||||
std::string GetLocalEndpointId() const override;
|
||||
|
||||
// Reads a complete packet from the underlying medium.
|
||||
virtual ExceptionOr<ByteArray> DispatchPacket() {
|
||||
@@ -166,6 +168,7 @@ class BaseEndpointChannel : public EndpointChannel {
|
||||
|
||||
analytics::AnalyticsRecorder* analytics_recorder_ = nullptr;
|
||||
std::string endpoint_id_ = "";
|
||||
std::string local_endpoint_id_ = "";
|
||||
};
|
||||
|
||||
} // namespace nearby::connections
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "securegcm/ukey2_handshake.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/cleanup/cleanup.h"
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
@@ -94,7 +95,6 @@ using ::location::nearby::connections::ConnectionResponseFrame;
|
||||
using ::location::nearby::connections::ConnectionsDevice;
|
||||
using ::location::nearby::connections::MediumMetadata;
|
||||
using ::location::nearby::connections::OfflineFrame;
|
||||
using ::location::nearby::connections::OsInfo;
|
||||
using ::location::nearby::connections::PresenceDevice;
|
||||
using ::location::nearby::connections::V1Frame;
|
||||
using ::location::nearby::proto::connections::OperationResultCode;
|
||||
@@ -576,15 +576,16 @@ Status BasePcpHandler::WaitForResult(const std::string& method_name,
|
||||
return result.result();
|
||||
}
|
||||
|
||||
void BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
|
||||
bool BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
|
||||
Runnable runnable) {
|
||||
if (closed_.Get()) {
|
||||
LOG(WARNING) << "Skip to run PCP Handler task " << name
|
||||
<< " due to PCP Handler is closed";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
serial_executor_.Execute(name, std::move(runnable));
|
||||
return true;
|
||||
}
|
||||
|
||||
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener(
|
||||
@@ -894,13 +895,19 @@ ConnectionInfo BasePcpHandler::FillConnectionInfo(
|
||||
connection_info.ap_frequency = wifi_info.ap_frequency;
|
||||
if (NearbyFlags::GetInstance().GetBoolFlag(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch) &&
|
||||
client->GetLocalOsInfo().type() == OsInfo::APPLE) {
|
||||
::location::nearby::connections::MediumRole medium_role_info;
|
||||
medium_role_info.set_support_awdl_publisher(true);
|
||||
medium_role_info.set_support_awdl_subscriber(true);
|
||||
medium_role_info.set_support_wifi_hotspot_client(true);
|
||||
connection_info.medium_role.emplace(medium_role_info);
|
||||
kEnableDynamicRoleSwitch)) {
|
||||
LOG(INFO) << "kEnableDynamicRoleSwitch is enabled";
|
||||
ClientProxy::MediumsAvailability mediums_availability;
|
||||
mediums_availability.is_wifi_direct_go_available =
|
||||
mediums_->GetWifiDirect().IsGOAvailable();
|
||||
mediums_availability.is_wifi_direct_gc_available =
|
||||
mediums_->GetWifiDirect().IsGCAvailable();
|
||||
mediums_availability.is_wifi_hotspot_ap_available =
|
||||
mediums_->GetWifiHotspot().IsAPAvailable();
|
||||
mediums_availability.is_wifi_hotspot_client_available =
|
||||
mediums_->GetWifiHotspot().IsClientAvailable();
|
||||
connection_info.medium_role.emplace(
|
||||
client->GetLocalMediumRole(mediums_availability));
|
||||
}
|
||||
LOG(INFO) << "Query for WIFI information: is_supports_5_ghz="
|
||||
<< connection_info.supports_5_ghz
|
||||
@@ -1585,7 +1592,8 @@ Status BasePcpHandler::AcceptConnection(ClientProxy* client,
|
||||
|
||||
Exception write_exception =
|
||||
channel->Write(parser::ForConnectionResponse(
|
||||
Status::kSuccess, client->GetLocalOsInfo()));
|
||||
Status::kSuccess, client->GetLocalOsInfo(),
|
||||
client->GetLocalDeviceName()));
|
||||
if (!write_exception.Ok()) {
|
||||
LOG(INFO) << "AcceptConnection: failed to send response: endpoint_id="
|
||||
<< endpoint_id;
|
||||
@@ -1646,7 +1654,8 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client,
|
||||
|
||||
Exception write_exception =
|
||||
channel->Write(parser::ForConnectionResponse(
|
||||
Status::kConnectionRejected, client->GetLocalOsInfo()));
|
||||
Status::kConnectionRejected, client->GetLocalOsInfo(),
|
||||
client->GetLocalDeviceName()));
|
||||
if (!write_exception.Ok()) {
|
||||
LOG(INFO) << "RejectConnection: failed to send response: endpoint_id="
|
||||
<< endpoint_id;
|
||||
@@ -1673,9 +1682,10 @@ void BasePcpHandler::OnIncomingFrame(
|
||||
OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client,
|
||||
location::nearby::proto::connections::Medium medium) {
|
||||
CountDownLatch latch(1);
|
||||
RunOnPcpHandlerThread(
|
||||
bool scheduled = RunOnPcpHandlerThread(
|
||||
"incoming-frame",
|
||||
[this, client, endpoint_id, frame, &latch]() RUN_ON_PCP_HANDLER_THREAD() {
|
||||
absl::Cleanup release_caller = [&latch] { latch.CountDown(); };
|
||||
LOG(INFO) << "OnConnectionResponse: endpoint_id=" << endpoint_id;
|
||||
|
||||
if (client->HasRemoteEndpointResponded(endpoint_id)) {
|
||||
@@ -1729,9 +1739,14 @@ void BasePcpHandler::OnIncomingFrame(
|
||||
EvaluateConnectionResult(client, endpoint_id,
|
||||
/* can_close_immediately= */ true);
|
||||
|
||||
latch.CountDown();
|
||||
if (connection_response.has_wifi_direct_device_name()) {
|
||||
client->SetRemoteDeviceName(
|
||||
endpoint_id, connection_response.wifi_direct_device_name());
|
||||
}
|
||||
});
|
||||
WaitForLatch("OnIncomingFrame()", &latch);
|
||||
if (scheduled) {
|
||||
WaitForLatch("OnIncomingFrame()", &latch);
|
||||
}
|
||||
}
|
||||
|
||||
void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client,
|
||||
|
||||
@@ -278,7 +278,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
};
|
||||
|
||||
void Shutdown();
|
||||
void RunOnPcpHandlerThread(const std::string& name, Runnable runnable);
|
||||
bool RunOnPcpHandlerThread(const std::string& name, Runnable runnable);
|
||||
|
||||
BluetoothDevice GetRemoteBluetoothDevice(
|
||||
MacAddress remote_bluetooth_mac_address);
|
||||
|
||||
@@ -455,8 +455,7 @@ class BasePcpHandlerTest
|
||||
void TearDown() override { env_.Stop(); }
|
||||
|
||||
std::unique_ptr<analytics::AnalyticsRecorder> CreateAnalyticsRecorder() {
|
||||
auto recorder =
|
||||
std::make_unique<analytics::MockAnalyticsRecorder>();
|
||||
auto recorder = std::make_unique<analytics::MockAnalyticsRecorder>();
|
||||
mock_analytics_recorder_ptr_ = recorder.get();
|
||||
return recorder;
|
||||
}
|
||||
@@ -576,10 +575,9 @@ class BasePcpHandlerTest
|
||||
[channel = channel_a.get()]() { return channel->DoRead(); });
|
||||
EXPECT_CALL(*channel_a, Write(_))
|
||||
.WillOnce(Return(Exception{Exception::kSuccess}))
|
||||
.WillRepeatedly(
|
||||
[channel = channel_a.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
.WillRepeatedly([channel = channel_a.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium));
|
||||
EXPECT_CALL(*channel_a, GetLastReadTimestamp)
|
||||
.WillRepeatedly(Return(absl::Now()));
|
||||
@@ -588,10 +586,9 @@ class BasePcpHandlerTest
|
||||
.WillRepeatedly(
|
||||
[channel = channel_b.get()]() { return channel->DoRead(); });
|
||||
EXPECT_CALL(*channel_b, Write(_))
|
||||
.WillRepeatedly(
|
||||
[channel = channel_b.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
.WillRepeatedly([channel = channel_b.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
|
||||
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
|
||||
.WillRepeatedly(Return(absl::Now()));
|
||||
@@ -628,10 +625,9 @@ class BasePcpHandlerTest
|
||||
.WillRepeatedly(
|
||||
[channel = channel_b.get()]() { return channel->DoRead(); });
|
||||
EXPECT_CALL(*channel_b, Write(_))
|
||||
.WillRepeatedly(
|
||||
[channel = channel_b.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
.WillRepeatedly([channel = channel_b.get()](absl::string_view data) {
|
||||
return channel->DoWrite(data);
|
||||
});
|
||||
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
|
||||
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
|
||||
.WillRepeatedly(Return(absl::Now()));
|
||||
@@ -751,16 +747,15 @@ class BasePcpHandlerTest
|
||||
auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client);
|
||||
|
||||
EXPECT_CALL(*pcp_handler, ConnectImpl)
|
||||
.WillRepeatedly(
|
||||
[&channel_a, connect_medium](
|
||||
ClientProxy* client,
|
||||
MockPcpHandler::DiscoveredEndpoint* endpoint) {
|
||||
return MockPcpHandler::ConnectImplResult{
|
||||
.medium = connect_medium,
|
||||
.status = {Status::kSuccess},
|
||||
.endpoint_channel = std::move(channel_a),
|
||||
};
|
||||
});
|
||||
.WillRepeatedly([&channel_a, connect_medium](
|
||||
ClientProxy* client,
|
||||
MockPcpHandler::DiscoveredEndpoint* endpoint) {
|
||||
return MockPcpHandler::ConnectImplResult{
|
||||
.medium = connect_medium,
|
||||
.status = {Status::kSuccess},
|
||||
.endpoint_channel = std::move(channel_a),
|
||||
};
|
||||
});
|
||||
|
||||
for (const auto& discovered_medium : allowed_mediums) {
|
||||
pcp_handler->OnEndpointFound(
|
||||
@@ -1610,7 +1605,7 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
LOG(INFO) << "Simulating remote accept: id=" << endpoint_id;
|
||||
OsInfo os_info;
|
||||
auto frame = parser::FromBytes(
|
||||
parser::ForConnectionResponse(Status::kSuccess, os_info));
|
||||
parser::ForConnectionResponse(Status::kSuccess, os_info, "device_name"));
|
||||
EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1);
|
||||
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
|
||||
connect_medium);
|
||||
@@ -1621,6 +1616,48 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_P(BasePcpHandlerTest, OnIncomingFrameDuplicateFrameDoesNotDeadlock) {
|
||||
env_.Start();
|
||||
std::string endpoint_id{"1234"};
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
BwuManager bwu(m, em, ecm, {}, {});
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
|
||||
StartDiscovery(client_.get(), &pcp_handler);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id;
|
||||
EXPECT_CALL(mock_connection_listener_.accepted_cb, Call).Times(1);
|
||||
EXPECT_CALL(mock_connection_listener_.disconnected_cb, Call)
|
||||
.Times(AtLeast(0));
|
||||
EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}),
|
||||
Status{Status::kSuccess});
|
||||
LOG(INFO) << "Simulating remote accept: id=" << endpoint_id;
|
||||
OsInfo os_info;
|
||||
auto frame = parser::FromBytes(
|
||||
parser::ForConnectionResponse(Status::kSuccess, os_info, "device_name"));
|
||||
EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1);
|
||||
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
|
||||
connect_medium);
|
||||
LOG(INFO) << "Simulating duplicate remote accept: id=" << endpoint_id;
|
||||
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
|
||||
connect_medium);
|
||||
LOG(INFO) << "Closing connection: id=" << endpoint_id;
|
||||
channel_b->Close();
|
||||
bwu.Shutdown();
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
|
||||
env_.Start();
|
||||
std::atomic_int destroyed_flag = 0;
|
||||
@@ -1798,8 +1835,8 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) {
|
||||
|
||||
EXPECT_CALL(pcp_handler, InjectEndpointImpl(client_.get(), service_id, _))
|
||||
.WillOnce([&pcp_handler, &endpoint_id](
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
pcp_handler.OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
@@ -1862,8 +1899,8 @@ TEST_F(BasePcpHandlerTest,
|
||||
::testing::InSequence seq;
|
||||
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
|
||||
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
EXPECT_EQ(endpoint_id, id);
|
||||
EXPECT_EQ(endpoint_info, ByteArray{"ABCD"});
|
||||
});
|
||||
@@ -1875,8 +1912,8 @@ TEST_F(BasePcpHandlerTest,
|
||||
|
||||
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
|
||||
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
EXPECT_EQ(endpoint_id, id);
|
||||
EXPECT_EQ(endpoint_info, ByteArray{"ABCDEF"});
|
||||
});
|
||||
@@ -1975,8 +2012,8 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) {
|
||||
|
||||
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
|
||||
.WillOnce([&pcp_handler, &endpoint_id](
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
pcp_handler.OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
@@ -2038,8 +2075,8 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) {
|
||||
|
||||
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
|
||||
.WillOnce([&pcp_handler, &endpoint_id](
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
pcp_handler.OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
@@ -2103,31 +2140,30 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) {
|
||||
bool first_call = true;
|
||||
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
|
||||
.Times(2)
|
||||
.WillRepeatedly(
|
||||
[&pcp_handler, &endpoint_id, &first_call](
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
ByteArray endpoint_info;
|
||||
if (first_call) {
|
||||
endpoint_info = ByteArray("ABCD");
|
||||
} else {
|
||||
endpoint_info = ByteArray("ABCDE");
|
||||
}
|
||||
first_call = false;
|
||||
pcp_handler.OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
{
|
||||
endpoint_id,
|
||||
endpoint_info,
|
||||
service_id,
|
||||
Medium::BLUETOOTH,
|
||||
WebRtcState::kUndefined,
|
||||
},
|
||||
MockContext{nullptr},
|
||||
}));
|
||||
return Status{Status::kSuccess};
|
||||
});
|
||||
.WillRepeatedly([&pcp_handler, &endpoint_id, &first_call](
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const OutOfBandConnectionMetadata& metadata) {
|
||||
ByteArray endpoint_info;
|
||||
if (first_call) {
|
||||
endpoint_info = ByteArray("ABCD");
|
||||
} else {
|
||||
endpoint_info = ByteArray("ABCDE");
|
||||
}
|
||||
first_call = false;
|
||||
pcp_handler.OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
{
|
||||
endpoint_id,
|
||||
endpoint_info,
|
||||
service_id,
|
||||
Medium::BLUETOOTH,
|
||||
WebRtcState::kUndefined,
|
||||
},
|
||||
MockContext{nullptr},
|
||||
}));
|
||||
return Status{Status::kSuccess};
|
||||
});
|
||||
pcp_handler.InjectEndpoint(
|
||||
client_.get(), service_id,
|
||||
OutOfBandConnectionMetadata{
|
||||
@@ -2949,5 +2985,37 @@ TEST_F(BasePcpHandlerTest, TestForceUpdateEndpointIdAdvertisingOption) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_P(BasePcpHandlerTest,
|
||||
FillConnectionInfo_kEnableDynamicRoleSwitch_Enabled) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
BwuManager bwu(m, em, ecm, {}, {});
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
|
||||
|
||||
ConnectionRequestInfo request_info = {
|
||||
.endpoint_info = ByteArray("EndpointInfo"),
|
||||
};
|
||||
ConnectionOptions connection_options = {};
|
||||
|
||||
// Call FillConnectionInfo with dynamic role switch enabled
|
||||
ConnectionInfo connection_info = pcp_handler.FillConnectionInfo(
|
||||
client_.get(), request_info, connection_options);
|
||||
|
||||
// Verify that medium_role is set (populated) in connection_info!
|
||||
EXPECT_TRUE(connection_info.medium_role.has_value());
|
||||
|
||||
bwu.Shutdown();
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::connections
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "connections/implementation/mediums/mediums.h"
|
||||
#include "connections/implementation/offline_frames.h"
|
||||
#include "connections/implementation/service_id_constants.h"
|
||||
#include "connections/strategy.h"
|
||||
#include "internal/flags/nearby_flags.h"
|
||||
#include "connections/medium_selector.h"
|
||||
#include "internal/platform/cancelable_alarm.h"
|
||||
@@ -311,11 +312,16 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client,
|
||||
if (is_dynamic_role_switch_enabled_ &&
|
||||
client->GetMediumRole(endpoint_id).has_value()) {
|
||||
MediumRole medium_role = client->GetMediumRole(endpoint_id).value();
|
||||
if (NeedToSwitchRole(client, endpoint_id, proposed_medium, medium_role)) {
|
||||
auto remote_os_info = client->GetRemoteOsInfo(endpoint_id);
|
||||
|
||||
if (NeedToSwitchRole(client, endpoint_id, proposed_medium, medium_role,
|
||||
remote_os_info.value_or(OsInfo()))) {
|
||||
if (!channel
|
||||
->Write(parser::ForBwuPathRequest(
|
||||
proposed_medium,
|
||||
client->GetUpgradeMediums(endpoint_id).GetMediums(true),
|
||||
medium_role))
|
||||
medium_role,
|
||||
mediums_->GetWifi().GetCapability().supports_5_ghz))
|
||||
.Ok()) {
|
||||
LOG(ERROR) << "BwuManager couldn't complete the upgrade for endpoint "
|
||||
<< endpoint_id << " to medium "
|
||||
@@ -585,6 +591,12 @@ void BwuManager::OnBwuNegotiationFrame(
|
||||
/* record_analytic= */ true,
|
||||
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
|
||||
break;
|
||||
case BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_REQUEST:
|
||||
if (frame.upgrade_path_info().has_upgrade_path_request()) {
|
||||
ProcessUpgradePathRequest(client, endpoint_id,
|
||||
frame.upgrade_path_info());
|
||||
}
|
||||
break;
|
||||
case BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL:
|
||||
if (!in_progress_upgrades_.contains(endpoint_id)) {
|
||||
LOG(ERROR) << "Received LAST_WRITE_TO_PRIOR_CHANNEL for endpoint "
|
||||
@@ -670,7 +682,19 @@ void BwuManager::OnIncomingConnection(
|
||||
"OfflineFrame on EndpointChannel "
|
||||
<< channel->GetName();
|
||||
|
||||
const std::string& endpoint_id = introduction.endpoint_id();
|
||||
std::string endpoint_id = introduction.endpoint_id();
|
||||
if (is_dynamic_role_switch_enabled_ &&
|
||||
!in_progress_upgrades_.contains(endpoint_id) &&
|
||||
introduction.has_last_endpoint_id() &&
|
||||
!introduction.last_endpoint_id().empty()) {
|
||||
std::string last_endpoint_id = introduction.last_endpoint_id();
|
||||
if (in_progress_upgrades_.contains(last_endpoint_id)) {
|
||||
LOG(INFO) << "BwuManager: aliasing endpoint ID " << endpoint_id
|
||||
<< " to " << last_endpoint_id;
|
||||
endpoint_id = last_endpoint_id;
|
||||
}
|
||||
}
|
||||
|
||||
ClientProxy* mapped_client;
|
||||
const auto item = in_progress_upgrades_.find(endpoint_id);
|
||||
if (item == in_progress_upgrades_.end()) return;
|
||||
@@ -724,6 +748,7 @@ void BwuManager::RunOnBwuManagerThread(const std::string& name,
|
||||
void BwuManager::RunUpgradeProtocol(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> new_channel, bool enable_encryption) {
|
||||
new_channel->SetLocalEndpointId(client->GetLocalEndpointId());
|
||||
LOG(INFO) << "RunUpgradeProtocol new channel @" << new_channel.get()
|
||||
<< " name: " << new_channel->GetName() << ", medium: "
|
||||
<< location::nearby::proto::connections::Medium_Name(
|
||||
@@ -823,9 +848,11 @@ void BwuManager::ProcessBwuPathAvailableEvent(
|
||||
abort_bwu = true;
|
||||
} else {
|
||||
auto medium_role = client->GetMediumRole(endpoint_id);
|
||||
auto remote_os_info = client->GetRemoteOsInfo(endpoint_id);
|
||||
if (medium_role.has_value() &&
|
||||
!NeedToSwitchRole(client, endpoint_id, upgrade_medium,
|
||||
medium_role.value())) {
|
||||
medium_role.value(),
|
||||
remote_os_info.value_or(OsInfo()))) {
|
||||
abort_bwu = true;
|
||||
}
|
||||
}
|
||||
@@ -937,8 +964,13 @@ void BwuManager::ProcessBwuPathAvailableEvent(
|
||||
}
|
||||
|
||||
in_progress_upgrades_.emplace(endpoint_id, client);
|
||||
bool local_supports_disabling =
|
||||
(client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint ||
|
||||
client->GetDiscoveryOptions().strategy == Strategy::kP2pPointToPoint);
|
||||
bool enable_encryption = !upgrade_path_info.supports_disabling_encryption() ||
|
||||
!local_supports_disabling;
|
||||
RunUpgradeProtocol(client, endpoint_id, std::move(channel),
|
||||
!upgrade_path_info.supports_disabling_encryption());
|
||||
enable_encryption);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<EndpointChannel>>
|
||||
@@ -1032,10 +1064,25 @@ BwuManager::ProcessBwuPathAvailableEventInternal(
|
||||
|
||||
// Write the requisite BANDWIDTH_UPGRADE_NEGOTIATION.CLIENT_INTRODUCTION as
|
||||
// the first OfflineFrame on this new EndpointChannel.
|
||||
std::string last_local_endpoint_id = client->GetLastLocalEndpointId();
|
||||
std::shared_ptr<EndpointChannel> previous_channel =
|
||||
channel_manager_->GetChannelForEndpoint(endpoint_id);
|
||||
if (previous_channel != nullptr) {
|
||||
last_local_endpoint_id = previous_channel->GetLocalEndpointId();
|
||||
}
|
||||
LOG(INFO) << "BwuManager get last_local_endpoint_id "
|
||||
<< last_local_endpoint_id << " from "
|
||||
<< (previous_channel != nullptr ? "endpoint channel"
|
||||
: "client proxy");
|
||||
|
||||
bool local_supports_disabling =
|
||||
(client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint ||
|
||||
client->GetDiscoveryOptions().strategy == Strategy::kP2pPointToPoint);
|
||||
if (!new_channel
|
||||
->Write(parser::ForBwuIntroduction(
|
||||
client->GetLocalEndpointId(),
|
||||
upgrade_path_info.supports_disabling_encryption()))
|
||||
client->GetLocalEndpointId(), last_local_endpoint_id,
|
||||
local_supports_disabling &&
|
||||
upgrade_path_info.supports_disabling_encryption()))
|
||||
.Ok()) {
|
||||
// This was never a fully EstablishedConnection, no need to provide a
|
||||
// closure reason.
|
||||
@@ -1634,7 +1681,13 @@ void BwuManager::AttemptToRecordBandwidthUpgradeErrorForUnknownEndpoint(
|
||||
|
||||
bool BwuManager::NeedToSwitchRole(
|
||||
ClientProxy* client, const std::string& endpoint_id, Medium medium,
|
||||
const location::nearby::connections::MediumRole& medium_role) {
|
||||
const location::nearby::connections::MediumRole& medium_role,
|
||||
const location::nearby::connections::OsInfo& remote_os_info) {
|
||||
if (!is_dynamic_role_switch_enabled_) {
|
||||
return false;
|
||||
}
|
||||
// On called by receiver device, check if the sender device can host the
|
||||
// upgrade medium or not
|
||||
if (GetLocalOsInfo(client).type() == OsInfo::APPLE) {
|
||||
switch (medium) {
|
||||
case Medium::WIFI_HOTSPOT:
|
||||
@@ -1643,6 +1696,105 @@ bool BwuManager::NeedToSwitchRole(
|
||||
break;
|
||||
}
|
||||
}
|
||||
// For testing on Windows as a receiver device to request dynamic role switch.
|
||||
// No need for final check in.
|
||||
if (GetLocalOsInfo(client).type() == OsInfo::WINDOWS &&
|
||||
remote_os_info.type() == OsInfo::ANDROID) {
|
||||
LOG(INFO) << "Local: Windows OS, Remote: Android device detected. "
|
||||
"WifiDirect NeedToSwitchRole and let Android be GO. "
|
||||
"medium_role.support_wifi_direct_group_owner(): "
|
||||
<< medium_role.support_wifi_direct_group_owner();
|
||||
switch (medium) {
|
||||
case Medium::WIFI_DIRECT:
|
||||
return medium_role.support_wifi_direct_group_owner();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This feature currently is only used by Android as receiver device to request
|
||||
// a dynamic role switch to Windows as Wi-Fi Direct GO. So WIFI_DIRECT is the
|
||||
// preferred medium to upgrade to.
|
||||
void BwuManager::ProcessUpgradePathRequest(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
const location::nearby::connections::BandwidthUpgradeNegotiationFrame::
|
||||
UpgradePathInfo& upgrade_path_info) {
|
||||
if (!is_dynamic_role_switch_enabled_) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "BwuManager: processing incoming UPGRADE_PATH_REQUEST frame for "
|
||||
"endpoint "
|
||||
<< endpoint_id;
|
||||
|
||||
const auto& request = upgrade_path_info.upgrade_path_request();
|
||||
std::vector<Medium> upgrade_mediums;
|
||||
upgrade_mediums.reserve(request.mediums_size());
|
||||
bool has_wifi_direct = false;
|
||||
for (auto m : request.mediums()) {
|
||||
Medium medium = parser::UpgradePathInfoMediumToMedium(
|
||||
static_cast<BandwidthUpgradeNegotiationFrame::UpgradePathInfo::Medium>(
|
||||
m));
|
||||
LOG(INFO) << "BwuManager: UpgradePathRequest medium: "
|
||||
<< location::nearby::proto::connections::Medium_Name(medium);
|
||||
upgrade_mediums.push_back(medium);
|
||||
if (medium == Medium::WIFI_DIRECT) {
|
||||
has_wifi_direct = true;
|
||||
}
|
||||
}
|
||||
|
||||
const location::nearby::connections::MediumRole& medium_role =
|
||||
request.medium_meta_data().medium_role();
|
||||
LOG(INFO) << "BwuManager: medium_role: " << medium_role.DebugString();
|
||||
|
||||
if (CanHost(client, medium_role)) {
|
||||
Medium medium = ChooseBestUpgradeMedium(endpoint_id, upgrade_mediums);
|
||||
if (has_wifi_direct) {
|
||||
medium = Medium::WIFI_DIRECT;
|
||||
}
|
||||
LOG(INFO) << "BwuManager: Initiating BWU for endpoint " << endpoint_id
|
||||
<< " with medium "
|
||||
<< location::nearby::proto::connections::Medium_Name(medium);
|
||||
InitiateBwuForEndpoint(client, endpoint_id, medium);
|
||||
} else {
|
||||
ProcessUpgradeFailureEvent(
|
||||
client, endpoint_id, upgrade_path_info,
|
||||
BandwidthUpgradeResult::REMOTE_CONNECTION_ERROR,
|
||||
/* record_analytic= */ true,
|
||||
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
bool BwuManager::CanHost(
|
||||
ClientProxy* client,
|
||||
const location::nearby::connections::MediumRole& medium_role) {
|
||||
if (!is_dynamic_role_switch_enabled_) {
|
||||
return false;
|
||||
}
|
||||
ClientProxy::MediumsAvailability mediums_availability;
|
||||
mediums_availability.is_wifi_direct_go_available =
|
||||
mediums_->GetWifiDirect().IsGOAvailable();
|
||||
mediums_availability.is_wifi_direct_gc_available =
|
||||
mediums_->GetWifiDirect().IsGCAvailable();
|
||||
mediums_availability.is_wifi_hotspot_ap_available =
|
||||
mediums_->GetWifiHotspot().IsAPAvailable();
|
||||
mediums_availability.is_wifi_hotspot_client_available =
|
||||
mediums_->GetWifiHotspot().IsClientAvailable();
|
||||
const location::nearby::connections::MediumRole& local_medium_role =
|
||||
client->GetLocalMediumRole(mediums_availability);
|
||||
if ((local_medium_role.support_wifi_direct_group_owner() &&
|
||||
medium_role.support_wifi_direct_group_client() &&
|
||||
mediums_->GetWifiDirect().IsGOAvailable()) ||
|
||||
(local_medium_role.support_wifi_hotspot_host() &&
|
||||
medium_role.support_wifi_hotspot_client() &&
|
||||
mediums_->GetWifiHotspot().IsAPAvailable()) ||
|
||||
(local_medium_role.support_wifi_aware_publisher() &&
|
||||
medium_role.support_wifi_aware_subscriber())) {
|
||||
LOG(INFO) << "BwuManager: Can host the upgrade medium.";
|
||||
return true;
|
||||
}
|
||||
LOG(INFO) << "BwuManager: Can't host the upgrade medium.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,16 @@ class BwuManager : public EndpointManager::FrameProcessor {
|
||||
|
||||
bool NeedToSwitchRole(
|
||||
ClientProxy* client, const std::string& endpoint_id, Medium medium,
|
||||
const location::nearby::connections::MediumRole& medium_role);
|
||||
const location::nearby::connections::MediumRole& medium_role,
|
||||
const location::nearby::connections::OsInfo& remote_os_info);
|
||||
|
||||
void ProcessUpgradePathRequest(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
const location::nearby::connections::BandwidthUpgradeNegotiationFrame::
|
||||
UpgradePathInfo& upgrade_path_info);
|
||||
|
||||
bool CanHost(ClientProxy* client,
|
||||
const location::nearby::connections::MediumRole& medium_role);
|
||||
|
||||
virtual const location::nearby::connections::OsInfo& GetLocalOsInfo(
|
||||
ClientProxy* client) const;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/connection_options.h"
|
||||
#include "connections/implementation/analytics/analytics_recorder.h"
|
||||
#include "connections/implementation/bwu_handler.h"
|
||||
@@ -81,12 +82,193 @@ CreateWifiHotspotCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
class BwuManagerTest : public ::testing::Test {
|
||||
class BwuManagerBaseTest : public ::testing::Test {
|
||||
protected:
|
||||
BwuManagerTest() {
|
||||
void SetUp() override {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
|
||||
true);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
NearbyFlags::GetInstance().ResetOverridedValues();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) {
|
||||
ClientProxy client;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
Mediums mediums;
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to.SetAll(false);
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
|
||||
std::move(handlers), config);
|
||||
client.SetLocalOsType(OsInfo::APPLE);
|
||||
auto channel1 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
MediumRole medium_role;
|
||||
medium_role.set_support_wifi_hotspot_host(true);
|
||||
client.OnConnectionInitiated(
|
||||
std::string(kEndpointId1),
|
||||
{.remote_endpoint_info = ByteArray("remote endpoint")},
|
||||
{.auto_upgrade_bandwidth = false,
|
||||
.connection_info =
|
||||
{
|
||||
.medium_role = {medium_role},
|
||||
}},
|
||||
{}, "");
|
||||
client.OnConnectionAccepted(std::string(kEndpointId1));
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
|
||||
std::move(channel1));
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
bwu_manager->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerBaseTest,
|
||||
InitiateBwu_NeedToSwitchRole_WindowsAndroid_Success) {
|
||||
ClientProxy client;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
Mediums mediums;
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to.SetAll(false);
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
|
||||
std::move(handlers), config);
|
||||
|
||||
// Set up local as WINDOWS, remote as ANDROID
|
||||
client.SetLocalOsType(OsInfo::WINDOWS);
|
||||
OsInfo remote_os_info;
|
||||
remote_os_info.set_type(OsInfo::ANDROID);
|
||||
|
||||
auto channel1 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
auto* channel1_ptr = channel1.get();
|
||||
|
||||
MediumRole remote_medium_role;
|
||||
remote_medium_role.set_support_wifi_direct_group_owner(true);
|
||||
|
||||
client.OnConnectionInitiated(
|
||||
std::string(kEndpointId1),
|
||||
{.remote_endpoint_info = ByteArray("remote endpoint")},
|
||||
{.auto_upgrade_bandwidth = false,
|
||||
.connection_info =
|
||||
{
|
||||
.medium_role = {remote_medium_role},
|
||||
}},
|
||||
{}, "");
|
||||
client.OnConnectionAccepted(std::string(kEndpointId1));
|
||||
client.SetRemoteOsInfo(kEndpointId1, remote_os_info);
|
||||
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
|
||||
std::move(channel1));
|
||||
|
||||
// Verify that before upgrade, write_timestamp is infinite past
|
||||
EXPECT_EQ(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast());
|
||||
|
||||
// Initiate BWU for WiFi Direct on Windows, which forces
|
||||
// role switch to Android
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
|
||||
Medium::WIFI_DIRECT);
|
||||
|
||||
// Since role is switched, upgrade is NOT initiated locally, but delegated
|
||||
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
|
||||
// Verify that an UPGRADE_PATH_REQUEST frame was actually written to
|
||||
// the channel
|
||||
EXPECT_NE(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast());
|
||||
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
bwu_manager->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerBaseTest,
|
||||
InitiateBwu_NeedToSwitchRole_WindowsAndroid_NoSwitch_Success) {
|
||||
ClientProxy client;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
Mediums mediums;
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to.SetAll(false);
|
||||
config.allow_upgrade_to.wifi_direct = true;
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_wifi_direct = std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
|
||||
auto* fake_wifi_direct_ptr = fake_wifi_direct.get();
|
||||
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
|
||||
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
|
||||
std::move(handlers), config);
|
||||
|
||||
// Set up local as WINDOWS, remote as ANDROID
|
||||
client.SetLocalOsType(OsInfo::WINDOWS);
|
||||
OsInfo remote_os_info;
|
||||
remote_os_info.set_type(OsInfo::ANDROID);
|
||||
|
||||
auto channel1 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
|
||||
MediumRole remote_medium_role;
|
||||
remote_medium_role.set_support_wifi_direct_group_owner(false);
|
||||
|
||||
client.OnConnectionInitiated(
|
||||
std::string(kEndpointId1),
|
||||
{.remote_endpoint_info = ByteArray("remote endpoint")},
|
||||
{.auto_upgrade_bandwidth = false,
|
||||
.connection_info =
|
||||
{
|
||||
.medium_role = {remote_medium_role},
|
||||
}},
|
||||
{}, "");
|
||||
client.OnConnectionAccepted(std::string(kEndpointId1));
|
||||
client.SetRemoteOsInfo(kEndpointId1, remote_os_info);
|
||||
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
|
||||
std::move(channel1));
|
||||
|
||||
// Verify that before upgrade, upgrade is not ongoing
|
||||
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
|
||||
// Initiate BWU for WiFi Direct on Windows. Since remote doesn't support GO,
|
||||
// we do not switch roles, so we host/upgrade locally.
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
|
||||
Medium::WIFI_DIRECT);
|
||||
|
||||
// Upgrade is ongoing locally
|
||||
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
EXPECT_EQ(fake_wifi_direct_ptr->handle_initialize_calls().size(), 1u);
|
||||
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
bwu_manager->Shutdown();
|
||||
}
|
||||
|
||||
class BwuManagerTest : public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestSuite() {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
|
||||
true);
|
||||
}
|
||||
|
||||
static void TearDownTestSuite() {
|
||||
NearbyFlags::GetInstance().ResetOverridedValues();
|
||||
}
|
||||
|
||||
BwuManagerTest() {
|
||||
// Set up fake BWU handlers for WebRTC and WifiLAN.
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_web_rtc = std::make_unique<FakeBwuHandler>(Medium::WEB_RTC);
|
||||
@@ -210,65 +392,50 @@ class BwuManagerTest : public ::testing::Test {
|
||||
std::unique_ptr<BwuManager> bwu_manager_;
|
||||
};
|
||||
|
||||
TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
|
||||
true);
|
||||
ClientProxy client;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
Mediums mediums;
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to.SetAll(false);
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
|
||||
std::move(handlers), config);
|
||||
|
||||
TEST_F(BwuManagerTest, AllowToUpgradeMedium) {
|
||||
auto channel1 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
|
||||
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId1),
|
||||
std::move(channel1));
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_LAN);
|
||||
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
|
||||
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
|
||||
auto channel2 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId2),
|
||||
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId2),
|
||||
std::move(channel2));
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2),
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId2),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2)));
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId2),
|
||||
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)));
|
||||
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
|
||||
auto channel3 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::BLUETOOTH, std::string(kServiceIdA));
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId3),
|
||||
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId3),
|
||||
std::move(channel3));
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3),
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId3),
|
||||
Medium::WIFI_DIRECT);
|
||||
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3)));
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId3),
|
||||
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId3)));
|
||||
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId3),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
|
||||
auto channel4 = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::WEB_RTC, std::string(kServiceIdA));
|
||||
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId4),
|
||||
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId4),
|
||||
std::move(channel4));
|
||||
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4),
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId4),
|
||||
Medium::BLUETOOTH);
|
||||
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4)));
|
||||
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId4),
|
||||
EXPECT_FALSE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId4)));
|
||||
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId4),
|
||||
DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
|
||||
bwu_manager->Shutdown();
|
||||
}
|
||||
|
||||
TEST(BwuManagerBaseTest, GcOnlyDoesNotInitializeWifiDirectAsGO) {
|
||||
@@ -428,167 +595,6 @@ TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) {
|
||||
false);
|
||||
}
|
||||
|
||||
class BwuManagerTestParam : public BwuManagerTest,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
BwuManagerTestParam() {
|
||||
SetSupportMultipleBwuMediums(GetParam());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Success) {
|
||||
// Create the initial device-to-device Bluetooth connection.
|
||||
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
|
||||
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE
|
||||
// to the Responder over the initial Bluetooth channel.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
|
||||
// The appropriate upgrade medium handler is informed of the BWU initiation.
|
||||
ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA),
|
||||
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id);
|
||||
EXPECT_EQ(
|
||||
kEndpointId1,
|
||||
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id);
|
||||
|
||||
// Establish the incoming connection on the new medium. Verify that the
|
||||
// upgrade channel replaces the initial channel.
|
||||
std::shared_ptr<EndpointChannel> shared_initial_channel =
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
|
||||
EXPECT_EQ(initial_channel, shared_initial_channel.get());
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
EXPECT_EQ(upgraded_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
|
||||
// Confirm that upgrade channel is paused until initial channel is shut down.
|
||||
EXPECT_TRUE(upgraded_channel->IsPaused());
|
||||
EXPECT_FALSE(initial_channel->is_closed());
|
||||
|
||||
// Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then
|
||||
// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the
|
||||
// Responder device to trigger the shutdown of the initial Bluetooth channel.
|
||||
ExceptionOr<OfflineFrame> last_write_frame =
|
||||
parser::FromBytes(parser::ForBwuLastWrite());
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
ExceptionOr<OfflineFrame> safe_to_close_frame =
|
||||
parser::FromBytes(parser::ForBwuSafeToClose());
|
||||
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Confirm that upgrade channel is resumed after initial channel is shut down.
|
||||
// Note: If we didn't grab the shared initial channel pointer above, this
|
||||
// channel would have already been destroyed.
|
||||
auto old_channel =
|
||||
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
|
||||
EXPECT_FALSE(upgraded_channel->IsPaused());
|
||||
EXPECT_TRUE(old_channel->is_closed());
|
||||
EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED,
|
||||
old_channel->disconnection_reason());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH,
|
||||
/*upgrade_medium=*/Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// Ignore request to upgrade to WebRTC if we're already connected.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN);
|
||||
|
||||
// Ignore request to upgrade to WebRTC if we're already connected.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) {
|
||||
// Try to upgrade to a Medium without an initial Medium.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
|
||||
// Make sure none of the other medium handlers are called.
|
||||
EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// Try to upgrade an endpoint that already has an ungrade in progress. Should
|
||||
// just early return with no action.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_LAN);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) {
|
||||
// Create the initial device-to-device Bluetooth connection.
|
||||
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
|
||||
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Make the initial endpoint channel fail when writing the
|
||||
// UPGRADE_PATH_AVAILABLE frame.
|
||||
initial_channel->set_write_output(Exception{Exception::kIo});
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
|
||||
// After we notify the WebRTC handler, we try to write the
|
||||
// UPGRADE_PATH_AVAILABLE frame, but fail by just early returning.
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// However, we do not record an in-progress attempt. So, if we see an incoming
|
||||
// connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH
|
||||
// channel is still used.
|
||||
EXPECT_EQ(initial_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
EXPECT_NE(upgraded_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
EXPECT_EQ(initial_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest,
|
||||
InitiateBwu_Revert_OnDisconnect_MultipleEndpoints_FlagEnabled) {
|
||||
SetSupportMultipleBwuMediums(true);
|
||||
@@ -1286,6 +1292,374 @@ TEST_F(BwuManagerTest, ReceiveUnexpectedLastWriteBeforeUpgrade_NoWedge) {
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_CanHost_True) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
|
||||
// Shutdown original BwuManager to clean up registrations cleanly.
|
||||
bwu_manager_->Shutdown();
|
||||
|
||||
// Set up fake BWU handlers for WifiDirect.
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_wifi_direct =
|
||||
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
|
||||
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
|
||||
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
|
||||
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
|
||||
|
||||
bwu_manager_ = std::make_unique<BwuManager>(
|
||||
mediums_, em_, ecm_, std::move(handlers), config);
|
||||
bwu_manager_->MakeSingleThreadedForTesting();
|
||||
|
||||
// Create initial connection
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Build the UpgradePathRequest frame using the parser helper
|
||||
location::nearby::connections::MediumRole remote_medium_role;
|
||||
remote_medium_role.set_support_wifi_direct_group_client(true);
|
||||
std::string bytes = parser::ForBwuPathRequest(
|
||||
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
|
||||
/*supports_5_ghz=*/true);
|
||||
OfflineFrame frame;
|
||||
frame.ParseFromString(bytes);
|
||||
|
||||
// Process the request
|
||||
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Verify that WiFi Direct BWU was initiated
|
||||
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 1u);
|
||||
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_CanHost_False) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
|
||||
// Shutdown original BwuManager to clean up registrations cleanly.
|
||||
bwu_manager_->Shutdown();
|
||||
|
||||
// Set up fake BWU handlers for WifiDirect.
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_wifi_direct =
|
||||
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
|
||||
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
|
||||
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
|
||||
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
|
||||
|
||||
bwu_manager_ = std::make_unique<BwuManager>(
|
||||
mediums_, em_, ecm_, std::move(handlers), config);
|
||||
bwu_manager_->MakeSingleThreadedForTesting();
|
||||
|
||||
// Create initial connection
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Build the UpgradePathRequest frame where remote doesn't support GC
|
||||
location::nearby::connections::MediumRole remote_medium_role;
|
||||
std::string bytes = parser::ForBwuPathRequest(
|
||||
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
|
||||
/*supports_5_ghz=*/true);
|
||||
OfflineFrame frame;
|
||||
frame.ParseFromString(bytes);
|
||||
|
||||
// Process the request
|
||||
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Verify that WiFi Direct BWU was NOT initiated
|
||||
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 0u);
|
||||
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_DynamicRoleSwitchDisabled) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
|
||||
// Shutdown original BwuManager to clean up registrations cleanly.
|
||||
bwu_manager_->Shutdown();
|
||||
|
||||
// Set up fake BWU handlers for WifiDirect.
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_wifi_direct =
|
||||
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
|
||||
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
|
||||
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
|
||||
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
|
||||
|
||||
bwu_manager_ = std::make_unique<BwuManager>(
|
||||
mediums_, em_, ecm_, std::move(handlers), config);
|
||||
bwu_manager_->MakeSingleThreadedForTesting();
|
||||
|
||||
// Create initial connection
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Build the UpgradePathRequest frame where remote supports GC
|
||||
location::nearby::connections::MediumRole remote_medium_role;
|
||||
remote_medium_role.set_support_wifi_direct_group_client(true);
|
||||
std::string bytes = parser::ForBwuPathRequest(
|
||||
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
|
||||
/*supports_5_ghz=*/true);
|
||||
OfflineFrame frame;
|
||||
frame.ParseFromString(bytes);
|
||||
|
||||
// Process the request
|
||||
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Verify that WiFi Direct BWU was NOT initiated
|
||||
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 0u);
|
||||
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, OnIncomingConnection_EndpointAliasesToLastEndpointId) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
|
||||
// Shutdown original BwuManager to clean up registrations cleanly.
|
||||
bwu_manager_->Shutdown();
|
||||
|
||||
// Create a new BwuManager with the overridden flag. We use WEB_RTC since
|
||||
// it has a simple, standard BWU flow.
|
||||
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
|
||||
auto fake_web_rtc = std::make_unique<FakeBwuHandler>(Medium::WEB_RTC);
|
||||
handlers.emplace(Medium::WEB_RTC, std::move(fake_web_rtc));
|
||||
|
||||
BwuManager::Config config;
|
||||
config.allow_upgrade_to = BooleanMediumSelector{.web_rtc = true};
|
||||
|
||||
bwu_manager_ = std::make_unique<BwuManager>(
|
||||
mediums_, em_, ecm_, std::move(handlers), config);
|
||||
bwu_manager_->MakeSingleThreadedForTesting();
|
||||
|
||||
// Create initial connection with the old endpoint ID "OldEndpoint"
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, "OldEndpoint",
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Initiate upgrade for "OldEndpoint" (inserts into in_progress_upgrades_)
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, "OldEndpoint",
|
||||
Medium::WEB_RTC);
|
||||
|
||||
// Now simulate incoming upgraded connection. Set introduction read output:
|
||||
// - endpoint_id = "NewEndpoint"
|
||||
// - last_endpoint_id = "OldEndpoint"
|
||||
auto upgraded_channel = std::make_unique<FakeEndpointChannel>(
|
||||
Medium::WEB_RTC, std::string(kServiceIdA));
|
||||
FakeEndpointChannel* upgraded_channel_raw = upgraded_channel.get();
|
||||
|
||||
std::string intro_frame = parser::ForBwuIntroduction(
|
||||
"NewEndpoint", "OldEndpoint", /*supports_disabling_encryption=*/false);
|
||||
upgraded_channel->set_read_output(
|
||||
ExceptionOr<ByteArray>(ByteArray(intro_frame)));
|
||||
|
||||
auto connection = std::make_unique<BwuHandler::IncomingSocketConnection>();
|
||||
connection->channel = std::move(upgraded_channel);
|
||||
|
||||
// Invoke OnIncomingConnection
|
||||
bwu_manager_->InvokeOnIncomingConnectionForTesting(&client_,
|
||||
std::move(connection));
|
||||
|
||||
// Verify that an Ack frame was written to upgraded_channel_raw
|
||||
EXPECT_NE(upgraded_channel_raw->GetLastWriteTimestamp(),
|
||||
absl::InfinitePast());
|
||||
|
||||
// Clean up
|
||||
UnRegisterChannelForEndpoint("OldEndpoint");
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
}
|
||||
|
||||
class BwuManagerTestParam : public BwuManagerTest,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
BwuManagerTestParam() {
|
||||
SetSupportMultipleBwuMediums(GetParam());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Success) {
|
||||
// Create the initial device-to-device Bluetooth connection.
|
||||
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
|
||||
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE
|
||||
// to the Responder over the initial Bluetooth channel.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
|
||||
// The appropriate upgrade medium handler is informed of the BWU initiation.
|
||||
ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA),
|
||||
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id);
|
||||
EXPECT_EQ(
|
||||
kEndpointId1,
|
||||
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id);
|
||||
|
||||
// Establish the incoming connection on the new medium. Verify that the
|
||||
// upgrade channel replaces the initial channel.
|
||||
std::shared_ptr<EndpointChannel> shared_initial_channel =
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
|
||||
EXPECT_EQ(initial_channel, shared_initial_channel.get());
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
EXPECT_EQ(upgraded_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
|
||||
// Confirm that upgrade channel is paused until initial channel is shut down.
|
||||
EXPECT_TRUE(upgraded_channel->IsPaused());
|
||||
EXPECT_FALSE(initial_channel->is_closed());
|
||||
|
||||
// Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then
|
||||
// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the
|
||||
// Responder device to trigger the shutdown of the initial Bluetooth channel.
|
||||
ExceptionOr<OfflineFrame> last_write_frame =
|
||||
parser::FromBytes(parser::ForBwuLastWrite());
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
ExceptionOr<OfflineFrame> safe_to_close_frame =
|
||||
parser::FromBytes(parser::ForBwuSafeToClose());
|
||||
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
// Confirm that upgrade channel is resumed after initial channel is shut down.
|
||||
// Note: If we didn't grab the shared initial channel pointer above, this
|
||||
// channel would have already been destroyed.
|
||||
auto old_channel =
|
||||
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
|
||||
EXPECT_FALSE(upgraded_channel->IsPaused());
|
||||
EXPECT_TRUE(old_channel->is_closed());
|
||||
EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED,
|
||||
old_channel->disconnection_reason());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH,
|
||||
/*upgrade_medium=*/Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// Ignore request to upgrade to WebRTC if we're already connected.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN);
|
||||
|
||||
// Ignore request to upgrade to WebRTC if we're already connected.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) {
|
||||
// Try to upgrade to a Medium without an initial Medium.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_HOTSPOT);
|
||||
|
||||
// Make sure none of the other medium handlers are called.
|
||||
EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// Try to upgrade an endpoint that already has an ungrade in progress. Should
|
||||
// just early return with no action.
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WIFI_LAN);
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(
|
||||
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
|
||||
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_P(BwuManagerTestParam,
|
||||
InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) {
|
||||
// Create the initial device-to-device Bluetooth connection.
|
||||
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
|
||||
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
|
||||
// Make the initial endpoint channel fail when writing the
|
||||
// UPGRADE_PATH_AVAILABLE frame.
|
||||
initial_channel->set_write_output(Exception{Exception::kIo});
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
|
||||
// After we notify the WebRTC handler, we try to write the
|
||||
// UPGRADE_PATH_AVAILABLE frame, but fail by just early returning.
|
||||
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
|
||||
|
||||
// However, we do not record an in-progress attempt. So, if we see an incoming
|
||||
// connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH
|
||||
// channel is still used.
|
||||
EXPECT_EQ(initial_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
EXPECT_NE(upgraded_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
EXPECT_EQ(initial_channel,
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam,
|
||||
testing::Bool());
|
||||
|
||||
|
||||
@@ -276,6 +276,12 @@ ClientProxy::ClientProxy(std::unique_ptr<AnalyticsRecorder> analytics_recorder)
|
||||
// Load advertising info from preferences.
|
||||
LoadClientInfoFromPreferences();
|
||||
|
||||
#ifndef NEARBY_CHROMIUM
|
||||
local_device_name_ = api::ImplementationPlatform::CreateDeviceInfo()
|
||||
->GetOsDeviceName()
|
||||
.value_or("");
|
||||
#endif
|
||||
|
||||
if (preferences_manager_ != nullptr) {
|
||||
app_lifecycle_monitor_ =
|
||||
api::ImplementationPlatform::CreateAppLifecycleMonitor(
|
||||
@@ -376,9 +382,10 @@ void ClientProxy::SetBluetoothMacAddress(const std::string& endpoint_id,
|
||||
|
||||
std::string ClientProxy::GenerateLocalEndpointId() {
|
||||
if (!cached_endpoint_id_.empty()) {
|
||||
if (stable_endpoint_id_mode_) {
|
||||
if (stable_endpoint_id_mode_ || HasOngoingConnection()) {
|
||||
LOG(INFO) << "ClientProxy [Local Endpoint Re-using cached "
|
||||
"endpoint id due to in stable endpoint id mode]: "
|
||||
"endpoint id due to in stable endpoint id mode or having "
|
||||
"ongoing connection]: "
|
||||
"client="
|
||||
<< GetClientId()
|
||||
<< "; cached_endpoint_id_=" << cached_endpoint_id_;
|
||||
@@ -875,6 +882,48 @@ bool ClientProxy::HasOngoingConnection() const {
|
||||
!GetConnectedEndpoints().empty();
|
||||
}
|
||||
|
||||
bool ClientProxy::HasWifiDirectConnection() const {
|
||||
MutexLock lock(&mutex_);
|
||||
for (const auto& entry : connections_) {
|
||||
if (entry.second.first.connected_medium == Medium::WIFI_DIRECT) {
|
||||
LOG(INFO) << "ClientProxy [HasWifiDirectConnection]: true";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "ClientProxy [HasWifiDirectConnection]: false";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientProxy::HasWifiHotspotConnection() const {
|
||||
MutexLock lock(&mutex_);
|
||||
for (const auto& entry : connections_) {
|
||||
if (entry.second.first.connected_medium == Medium::WIFI_HOTSPOT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientProxy::HasWifiAwareConnection() const {
|
||||
MutexLock lock(&mutex_);
|
||||
for (const auto& entry : connections_) {
|
||||
if (entry.second.first.connected_medium == Medium::WIFI_AWARE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string ClientProxy::GetLastLocalEndpointId() const {
|
||||
MutexLock lock(&mutex_);
|
||||
return last_local_endpoint_id_;
|
||||
}
|
||||
|
||||
void ClientProxy::SetLastLocalEndpointId(absl::string_view endpoint_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
last_local_endpoint_id_ = std::string(endpoint_id);
|
||||
}
|
||||
|
||||
std::int32_t ClientProxy::GetNumOutgoingConnections() const {
|
||||
return GetMatchingEndpoints([](const Connection& connection) {
|
||||
return connection.status == Connection::kConnected &&
|
||||
@@ -1133,6 +1182,26 @@ void ClientProxy::SetRemoteOsInfo(absl::string_view endpoint_id,
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::SetRemoteDeviceName(absl::string_view endpoint_id,
|
||||
absl::string_view device_name) {
|
||||
MutexLock lock(&mutex_);
|
||||
ConnectionPair* item = LookupConnection(endpoint_id);
|
||||
if (item != nullptr) {
|
||||
item->first.device_name = std::string(device_name);
|
||||
LOG(INFO) << "ClientProxy [SetRemoteDeviceName]: " << device_name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ClientProxy::GetRemoteDeviceName(
|
||||
absl::string_view endpoint_id) const {
|
||||
MutexLock lock(&mutex_);
|
||||
const ConnectionPair* item = LookupConnection(endpoint_id);
|
||||
if (item != nullptr) {
|
||||
return item->first.device_name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::optional<std::int32_t> ClientProxy::GetRemoteSafeToDisconnectVersion(
|
||||
absl::string_view endpoint_id) const {
|
||||
MutexLock lock(&mutex_);
|
||||
@@ -1249,9 +1318,23 @@ void ClientProxy::RemoveAllEndpoints() {
|
||||
OnSessionComplete();
|
||||
}
|
||||
|
||||
void ClientProxy::ResetLocalEndpointId() {
|
||||
MutexLock lock(&mutex_);
|
||||
if (HasOngoingConnection()) {
|
||||
return;
|
||||
}
|
||||
if (!local_endpoint_id_.empty()) {
|
||||
last_local_endpoint_id_ = local_endpoint_id_;
|
||||
local_endpoint_id_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::OnSessionComplete() {
|
||||
MutexLock lock(&mutex_);
|
||||
if (connections_.empty() && !IsAdvertising()) {
|
||||
if (!local_endpoint_id_.empty()) {
|
||||
last_local_endpoint_id_ = local_endpoint_id_;
|
||||
}
|
||||
local_endpoint_id_.clear();
|
||||
|
||||
analytics_recorder_->LogSession();
|
||||
@@ -1298,6 +1381,9 @@ void ClientProxy::EnterStableEndpointIdMode() {
|
||||
<< GetClientId();
|
||||
|
||||
stable_endpoint_id_mode_ = true;
|
||||
if (!IsAdvertising() && !IsDiscovering() && !HasOngoingConnection()) {
|
||||
ResetLocalEndpointId();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::ExitStableEndpointIdMode() {
|
||||
@@ -1305,6 +1391,7 @@ void ClientProxy::ExitStableEndpointIdMode() {
|
||||
VLOG(1) << "ClientProxy [ExitStableEndpointIdMode]: client=" << GetClientId();
|
||||
|
||||
stable_endpoint_id_mode_ = false;
|
||||
ResetLocalEndpointId();
|
||||
ScheduleClearCachedEndpointIdAlarm();
|
||||
}
|
||||
|
||||
@@ -1318,7 +1405,7 @@ void ClientProxy::ScheduleClearCachedEndpointIdAlarm() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasOngoingConnection()) {
|
||||
if (IsAdvertising() || IsDiscovering() || HasOngoingConnection()) {
|
||||
VLOG(1) << "ClientProxy [Handle clearing cached endpoint ID "
|
||||
"during disconnection]: client="
|
||||
<< GetClientId();
|
||||
@@ -1431,6 +1518,41 @@ std::optional<MediumRole> ClientProxy::GetMediumRole(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
location::nearby::connections::MediumRole ClientProxy::GetLocalMediumRole(
|
||||
const ClientProxy::MediumsAvailability& mediums_availability) const {
|
||||
location::nearby::connections::MediumRole medium_role;
|
||||
if (!NearbyFlags::GetInstance().GetBoolFlag(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch)) {
|
||||
return medium_role;
|
||||
}
|
||||
|
||||
if (GetLocalOsInfo().type() == OsInfo::APPLE) {
|
||||
medium_role.set_support_awdl_publisher(true);
|
||||
medium_role.set_support_awdl_subscriber(true);
|
||||
// Apple always supports wifi hotspot client role since they can always
|
||||
// join a hotspot.
|
||||
medium_role.set_support_wifi_hotspot_client(true);
|
||||
return medium_role;
|
||||
}
|
||||
|
||||
medium_role.set_support_wifi_direct_group_owner(
|
||||
mediums_availability.is_wifi_direct_go_available && !IsUsingP2pMedium());
|
||||
medium_role.set_support_wifi_direct_group_client(
|
||||
mediums_availability.is_wifi_direct_gc_available);
|
||||
medium_role.set_support_wifi_hotspot_host(
|
||||
mediums_availability.is_wifi_hotspot_ap_available && !IsUsingP2pMedium());
|
||||
medium_role.set_support_wifi_hotspot_client(
|
||||
mediums_availability.is_wifi_hotspot_client_available);
|
||||
LOG(INFO) << "medium_role: " << medium_role.DebugString();
|
||||
return medium_role;
|
||||
}
|
||||
|
||||
bool ClientProxy::IsUsingP2pMedium() const {
|
||||
return HasWifiDirectConnection() || HasWifiHotspotConnection() ||
|
||||
HasWifiAwareConnection();
|
||||
}
|
||||
|
||||
std::optional<std::string> ClientProxy::GetEndpointIdForDct() const {
|
||||
MutexLock lock(&mutex_);
|
||||
if (dct_endpoint_id_.empty()) {
|
||||
@@ -1559,6 +1681,7 @@ std::string ClientProxy::Dump() {
|
||||
? location::nearby::connections::OsInfo::OsType_Name(
|
||||
it->second.first.os_info->type())
|
||||
: "unknown")
|
||||
<< ", (remote device name) " << it->second.first.device_name
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ class ClientProxy final {
|
||||
|
||||
std::string GetLocalEndpointId();
|
||||
std::string GetLocalEndpointInfo() { return local_endpoint_info_; }
|
||||
std::string GetLocalDeviceName() {
|
||||
return local_device_name_;
|
||||
}
|
||||
|
||||
// Override the base for received file attachments from a specific endpoint.
|
||||
// Returns true if the endpoint is found and the path is overridden.
|
||||
@@ -103,6 +106,9 @@ class ClientProxy final {
|
||||
// Clears all the runtime state of this client.
|
||||
void Reset();
|
||||
|
||||
// Resets the local endpoint ID and sets the last local endpoint ID.
|
||||
void ResetLocalEndpointId();
|
||||
|
||||
// Marks this client as advertising with the given callbacks.
|
||||
void StartedAdvertising(
|
||||
const std::string& service_id, Strategy strategy,
|
||||
@@ -145,7 +151,6 @@ class ClientProxy final {
|
||||
MutexLock lock(&mutex_);
|
||||
local_endpoint_info_ = std::string(endpoint_info);
|
||||
}
|
||||
|
||||
void UpdateAdvertisingOptions(const AdvertisingOptions& advertising_options) {
|
||||
MutexLock lock(&mutex_);
|
||||
advertising_options_ = advertising_options;
|
||||
@@ -210,6 +215,14 @@ class ClientProxy final {
|
||||
// Returns true if there is at least one connected connection or one pending
|
||||
// connection.
|
||||
bool HasOngoingConnection() const;
|
||||
// Returns true if there is at least one active WiFi Direct connection.
|
||||
bool HasWifiDirectConnection() const;
|
||||
// Returns true if there is at least one active WiFi Hotspot connection.
|
||||
bool HasWifiHotspotConnection() const;
|
||||
// Returns true if there is at least one active WiFi Aware connection.
|
||||
bool HasWifiAwareConnection() const;
|
||||
std::string GetLastLocalEndpointId() const;
|
||||
void SetLastLocalEndpointId(absl::string_view endpoint_id);
|
||||
// Returns the number of endpoints that are connected and outgoing.
|
||||
std::int32_t GetNumOutgoingConnections() const;
|
||||
// Returns the number of endpoints that are connected and incoming.
|
||||
@@ -287,6 +300,9 @@ class ClientProxy final {
|
||||
void SetRemoteOsInfo(
|
||||
absl::string_view endpoint_id,
|
||||
const location::nearby::connections::OsInfo& remote_os_info);
|
||||
void SetRemoteDeviceName(absl::string_view endpoint_id,
|
||||
absl::string_view device_name);
|
||||
std::string GetRemoteDeviceName(absl::string_view endpoint_id) const;
|
||||
|
||||
void RegisterDeviceProvider(NearbyDeviceProvider* provider) {
|
||||
external_device_provider_ = provider;
|
||||
@@ -333,6 +349,18 @@ class ClientProxy final {
|
||||
std::optional<location::nearby::connections::MediumRole> GetMediumRole(
|
||||
absl::string_view endpoint_id) const;
|
||||
|
||||
struct MediumsAvailability {
|
||||
bool is_wifi_direct_go_available = false;
|
||||
bool is_wifi_direct_gc_available = false;
|
||||
bool is_wifi_hotspot_ap_available = false;
|
||||
bool is_wifi_hotspot_client_available = false;
|
||||
};
|
||||
|
||||
location::nearby::connections::MediumRole GetLocalMediumRole(
|
||||
const MediumsAvailability& mediums_availability) const;
|
||||
|
||||
bool IsUsingP2pMedium() const;
|
||||
|
||||
// Forces client to regenerate a new local endpoint id.
|
||||
void ClearCachedLocalEndpointId();
|
||||
|
||||
@@ -372,6 +400,7 @@ class ClientProxy final {
|
||||
std::int32_t safe_to_disconnect_version;
|
||||
std::int32_t remote_multiplex_socket_bitmask;
|
||||
std::string save_path;
|
||||
std::string device_name;
|
||||
};
|
||||
using ConnectionPair = std::pair<Connection, PayloadListener>;
|
||||
|
||||
@@ -441,6 +470,8 @@ class ClientProxy final {
|
||||
std::int64_t client_id_;
|
||||
std::string local_endpoint_id_;
|
||||
std::string local_endpoint_info_;
|
||||
std::string last_local_endpoint_id_;
|
||||
std::string local_device_name_;
|
||||
|
||||
// If advertising is in stable endpoint ID mode, the endpoint ID is stable
|
||||
// for 30s after advertising or disconnection. When stable_endpoint_id_mode_
|
||||
|
||||
@@ -1345,6 +1345,7 @@ TEST_F(ClientProxyTest, GetRemoteInfoNullWithoutConnections) {
|
||||
EXPECT_FALSE(client1()
|
||||
->GetRemoteSafeToDisconnectVersion(advertising_endpoint.id)
|
||||
.has_value());
|
||||
EXPECT_EQ(client1()->GetRemoteDeviceName(advertising_endpoint.id), "");
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, SetRemoteInfoCorrect) {
|
||||
@@ -1365,6 +1366,10 @@ TEST_F(ClientProxyTest, SetRemoteInfoCorrect) {
|
||||
EXPECT_EQ(
|
||||
client1()->GetRemoteSafeToDisconnectVersion(advertising_endpoint.id),
|
||||
nearby_connections_version);
|
||||
std::string device_name = "device_name";
|
||||
client1()->SetRemoteDeviceName(advertising_endpoint.id, device_name);
|
||||
EXPECT_EQ(client1()->GetRemoteDeviceName(advertising_endpoint.id),
|
||||
device_name);
|
||||
}
|
||||
|
||||
// Test ClientProxy::AddCancellationFlag, where if a flag is already in the map,
|
||||
@@ -1563,6 +1568,257 @@ TEST_F(ClientProxyTest, GetSavePathDefaultsToEmpty) {
|
||||
EXPECT_THAT(client1()->GetSavePath(advertising_endpoint.id), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetLocalMediumRoleFlagDisabled) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
false);
|
||||
ClientProxy::MediumsAvailability availability;
|
||||
availability.is_wifi_direct_go_available = true;
|
||||
availability.is_wifi_direct_gc_available = true;
|
||||
availability.is_wifi_hotspot_ap_available = true;
|
||||
availability.is_wifi_hotspot_client_available = true;
|
||||
|
||||
location::nearby::connections::MediumRole role =
|
||||
client1()->GetLocalMediumRole(availability);
|
||||
EXPECT_FALSE(role.support_awdl_publisher());
|
||||
EXPECT_FALSE(role.support_awdl_subscriber());
|
||||
EXPECT_FALSE(role.support_wifi_direct_group_owner());
|
||||
EXPECT_FALSE(role.support_wifi_direct_group_client());
|
||||
EXPECT_FALSE(role.support_wifi_hotspot_host());
|
||||
EXPECT_FALSE(role.support_wifi_hotspot_client());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetLocalMediumRoleAppleOs) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
client1()->SetLocalOsType(location::nearby::connections::OsInfo::APPLE);
|
||||
ClientProxy::MediumsAvailability availability;
|
||||
|
||||
location::nearby::connections::MediumRole role =
|
||||
client1()->GetLocalMediumRole(availability);
|
||||
EXPECT_TRUE(role.support_awdl_publisher());
|
||||
EXPECT_TRUE(role.support_awdl_subscriber());
|
||||
EXPECT_TRUE(role.support_wifi_hotspot_client());
|
||||
EXPECT_FALSE(role.support_wifi_direct_group_owner());
|
||||
EXPECT_FALSE(role.support_wifi_direct_group_client());
|
||||
EXPECT_FALSE(role.support_wifi_hotspot_host());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetLocalMediumRoleNonAppleOsNoP2pConnection) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
client1()->SetLocalOsType(location::nearby::connections::OsInfo::ANDROID);
|
||||
ClientProxy::MediumsAvailability availability;
|
||||
availability.is_wifi_direct_go_available = true;
|
||||
availability.is_wifi_direct_gc_available = true;
|
||||
availability.is_wifi_hotspot_ap_available = true;
|
||||
availability.is_wifi_hotspot_client_available = true;
|
||||
|
||||
location::nearby::connections::MediumRole role =
|
||||
client1()->GetLocalMediumRole(availability);
|
||||
EXPECT_TRUE(role.support_wifi_direct_group_owner());
|
||||
EXPECT_TRUE(role.support_wifi_direct_group_client());
|
||||
EXPECT_TRUE(role.support_wifi_hotspot_host());
|
||||
EXPECT_TRUE(role.support_wifi_hotspot_client());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetLocalMediumRoleNonAppleOsWithP2pConnection) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kEnableDynamicRoleSwitch,
|
||||
true);
|
||||
client1()->SetLocalOsType(location::nearby::connections::OsInfo::ANDROID);
|
||||
|
||||
// Setup an active P2P connection to make IsUsingP2pMedium() true
|
||||
Endpoint advertising_endpoint =
|
||||
StartAdvertising(client1(), advertising_connection_listener_);
|
||||
OnAdvertisingConnectionInitiated(client1(), advertising_endpoint);
|
||||
client1()->OnBandwidthChanged(advertising_endpoint.id, Medium::WIFI_DIRECT);
|
||||
EXPECT_TRUE(client1()->IsUsingP2pMedium());
|
||||
|
||||
ClientProxy::MediumsAvailability availability;
|
||||
availability.is_wifi_direct_go_available = true;
|
||||
availability.is_wifi_direct_gc_available = true;
|
||||
availability.is_wifi_hotspot_ap_available = true;
|
||||
availability.is_wifi_hotspot_client_available = true;
|
||||
|
||||
location::nearby::connections::MediumRole role =
|
||||
client1()->GetLocalMediumRole(availability);
|
||||
EXPECT_FALSE(role.support_wifi_direct_group_owner());
|
||||
EXPECT_TRUE(role.support_wifi_direct_group_client());
|
||||
EXPECT_FALSE(role.support_wifi_hotspot_host());
|
||||
EXPECT_TRUE(role.support_wifi_hotspot_client());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetNumIncomingAndOutgoingConnections) {
|
||||
// Initially no connections
|
||||
EXPECT_EQ(client1()->GetNumIncomingConnections(), 0);
|
||||
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 0);
|
||||
|
||||
// Set expectation for acceptance callback on step 1
|
||||
// (which is outgoing based on discovery_connection_info_)
|
||||
EXPECT_CALL(mock_advertising_connection_.accepted_cb, Call).Times(1);
|
||||
|
||||
// Define a complete listener for advertising
|
||||
ConnectionListener advertising_listener = {
|
||||
.initiated_cb = mock_advertising_connection_.initiated_cb.AsStdFunction(),
|
||||
.accepted_cb = mock_advertising_connection_.accepted_cb.AsStdFunction(),
|
||||
};
|
||||
|
||||
// 1. Establish connection 1
|
||||
Endpoint advertising_endpoint =
|
||||
StartAdvertising(client1(), advertising_listener);
|
||||
EXPECT_CALL(mock_advertising_connection_.initiated_cb, Call).Times(1);
|
||||
client1()->OnConnectionInitiated(
|
||||
advertising_endpoint.id, discovery_connection_info_, connection_options_,
|
||||
advertising_listener, "connection_token1");
|
||||
|
||||
// Accept local, accept remote, and then OnConnectionAccepted
|
||||
client1()->LocalEndpointAcceptedConnection(
|
||||
advertising_endpoint.id,
|
||||
{
|
||||
.payload_cb = mock_discovery_payload_.payload_cb.AsStdFunction(),
|
||||
.payload_progress_cb =
|
||||
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
|
||||
});
|
||||
client1()->RemoteEndpointAcceptedConnection(advertising_endpoint.id);
|
||||
client1()->OnConnectionAccepted(advertising_endpoint.id);
|
||||
|
||||
// Verify client1 has 0 incoming connections and 1 outgoing connection
|
||||
EXPECT_EQ(client1()->GetNumIncomingConnections(), 0);
|
||||
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 1);
|
||||
|
||||
// Set expectation for acceptance callback on step 2
|
||||
// (which is incoming based on advertising_connection_info_)
|
||||
EXPECT_CALL(mock_discovery_connection_.accepted_cb, Call).Times(1);
|
||||
|
||||
// 2. Establish connection 2
|
||||
StartDiscovery(client1(), GetDiscoveryListener());
|
||||
Endpoint remote_endpoint = {
|
||||
.info = ByteArray{"remote endpoint name"},
|
||||
.id = "rem_ep_id",
|
||||
};
|
||||
OnDiscoveryEndpointFound(client1(), remote_endpoint);
|
||||
|
||||
EXPECT_CALL(mock_discovery_connection_.initiated_cb, Call).Times(1);
|
||||
client1()->OnConnectionInitiated(
|
||||
remote_endpoint.id, advertising_connection_info_, connection_options_,
|
||||
discovery_connection_listener_, "connection_token2");
|
||||
|
||||
// Accept local, accept remote, and then OnConnectionAccepted
|
||||
client1()->LocalEndpointAcceptedConnection(
|
||||
remote_endpoint.id,
|
||||
{
|
||||
.payload_cb = mock_discovery_payload_.payload_cb.AsStdFunction(),
|
||||
.payload_progress_cb =
|
||||
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
|
||||
});
|
||||
client1()->RemoteEndpointAcceptedConnection(remote_endpoint.id);
|
||||
client1()->OnConnectionAccepted(remote_endpoint.id);
|
||||
|
||||
// Verify client1 has 1 incoming connection and 1 outgoing connection
|
||||
EXPECT_EQ(client1()->GetNumIncomingConnections(), 1);
|
||||
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 1);
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, IsUsingP2pMediumTests) {
|
||||
// With no connections, IsUsingP2pMedium should be false
|
||||
EXPECT_FALSE(client1()->IsUsingP2pMedium());
|
||||
|
||||
// 1. Connection with Non-P2P medium (e.g. WIFI_LAN)
|
||||
Endpoint endpoint_lan =
|
||||
StartAdvertising(client1(), advertising_connection_listener_);
|
||||
OnAdvertisingConnectionInitiated(client1(), endpoint_lan);
|
||||
client1()->OnBandwidthChanged(endpoint_lan.id, Medium::WIFI_LAN);
|
||||
EXPECT_FALSE(client1()->IsUsingP2pMedium());
|
||||
|
||||
// Clean-up connection
|
||||
client1()->OnDisconnected(endpoint_lan.id, /*notify=*/false);
|
||||
EXPECT_FALSE(client1()->IsUsingP2pMedium());
|
||||
|
||||
// 2. Connection with WIFI_DIRECT
|
||||
Endpoint endpoint_direct =
|
||||
StartAdvertising(client1(), advertising_connection_listener_);
|
||||
OnAdvertisingConnectionInitiated(client1(), endpoint_direct);
|
||||
client1()->OnBandwidthChanged(endpoint_direct.id, Medium::WIFI_DIRECT);
|
||||
EXPECT_TRUE(client1()->IsUsingP2pMedium());
|
||||
client1()->OnDisconnected(endpoint_direct.id, /*notify=*/false);
|
||||
|
||||
// 3. Connection with WIFI_HOTSPOT
|
||||
Endpoint endpoint_hotspot =
|
||||
StartAdvertising(client1(), advertising_connection_listener_);
|
||||
OnAdvertisingConnectionInitiated(client1(), endpoint_hotspot);
|
||||
client1()->OnBandwidthChanged(endpoint_hotspot.id, Medium::WIFI_HOTSPOT);
|
||||
EXPECT_TRUE(client1()->IsUsingP2pMedium());
|
||||
client1()->OnDisconnected(endpoint_hotspot.id, /*notify=*/false);
|
||||
|
||||
// 4. Connection with WIFI_AWARE
|
||||
Endpoint endpoint_aware =
|
||||
StartAdvertising(client1(), advertising_connection_listener_);
|
||||
OnAdvertisingConnectionInitiated(client1(), endpoint_aware);
|
||||
client1()->OnBandwidthChanged(endpoint_aware.id, Medium::WIFI_AWARE);
|
||||
EXPECT_TRUE(client1()->IsUsingP2pMedium());
|
||||
client1()->OnDisconnected(endpoint_aware.id, /*notify=*/false);
|
||||
EXPECT_FALSE(client1()->IsUsingP2pMedium());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GetAndSetLastLocalEndpointId) {
|
||||
EXPECT_TRUE(client1()->GetLastLocalEndpointId().empty());
|
||||
client1()->SetLastLocalEndpointId("TestEndpointID");
|
||||
EXPECT_EQ(client1()->GetLastLocalEndpointId(), "TestEndpointID");
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, ResetLocalEndpointId_OngoingConnectionReturnsEarly) {
|
||||
std::string old_id = client1()->GetLocalEndpointId();
|
||||
ASSERT_FALSE(old_id.empty());
|
||||
|
||||
// Set up an ongoing connection
|
||||
OnAdvertisingConnectionInitiated(client1(),
|
||||
{ByteArray("EndpointInfo"), "EndA"});
|
||||
EXPECT_TRUE(client1()->HasOngoingConnection());
|
||||
|
||||
// ResetLocalEndpointId should NOT clear local_endpoint_id
|
||||
client1()->ResetLocalEndpointId();
|
||||
EXPECT_EQ(client1()->GetLocalEndpointId(), old_id);
|
||||
|
||||
// Terminate connection
|
||||
client1()->OnDisconnected("EndA", /*notify=*/false);
|
||||
EXPECT_FALSE(client1()->HasOngoingConnection());
|
||||
|
||||
// ResetLocalEndpointId should now successfully clear local_endpoint_id
|
||||
client1()->ResetLocalEndpointId();
|
||||
EXPECT_NE(client1()->GetLocalEndpointId(), old_id);
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, ResetLocalEndpointId_SavesToLastLocalEndpointId) {
|
||||
std::string old_id = client1()->GetLocalEndpointId();
|
||||
ASSERT_FALSE(old_id.empty());
|
||||
|
||||
client1()->ResetLocalEndpointId();
|
||||
EXPECT_EQ(client1()->GetLastLocalEndpointId(), old_id);
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, OnSessionComplete_SavesToLastLocalEndpointId) {
|
||||
std::string old_id = client1()->GetLocalEndpointId();
|
||||
ASSERT_FALSE(old_id.empty());
|
||||
|
||||
// Put client into advertising mode first
|
||||
client1()->StartedAdvertising(service_id_, strategy_, {}, {}, {});
|
||||
EXPECT_TRUE(client1()->IsAdvertising());
|
||||
|
||||
// Stopping advertising triggers OnSessionComplete.
|
||||
// Since connections_ is empty, it completes the session and should save last
|
||||
// endpoint ID.
|
||||
client1()->StoppedAdvertising();
|
||||
EXPECT_FALSE(client1()->IsAdvertising());
|
||||
EXPECT_EQ(client1()->GetLastLocalEndpointId(), old_id);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -103,6 +103,10 @@ class FakeEndpointChannel : public EndpointChannel {
|
||||
}
|
||||
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
|
||||
const std::string& endpoint_id) override {}
|
||||
void SetLocalEndpointId(const std::string& local_endpoint_id) override {
|
||||
local_endpoint_id_ = local_endpoint_id;
|
||||
}
|
||||
std::string GetLocalEndpointId() const override { return local_endpoint_id_; }
|
||||
|
||||
private:
|
||||
InputStream* in_ = nullptr;
|
||||
@@ -110,6 +114,7 @@ class FakeEndpointChannel : public EndpointChannel {
|
||||
absl::Time read_timestamp_ = absl::InfinitePast();
|
||||
absl::Time write_timestamp_ = absl::InfinitePast();
|
||||
mutable uint32_t next_keep_alive_seq_no_ = 0;
|
||||
std::string local_endpoint_id_;
|
||||
};
|
||||
|
||||
struct User {
|
||||
|
||||
@@ -128,6 +128,9 @@ class EndpointChannel {
|
||||
|
||||
// Enables the multiplex socket on the EndpointChannel.
|
||||
virtual bool EnableMultiplexSocket() { return false; }
|
||||
|
||||
virtual void SetLocalEndpointId(const std::string& local_endpoint_id) = 0;
|
||||
virtual std::string GetLocalEndpointId() const = 0;
|
||||
};
|
||||
|
||||
inline bool operator==(const EndpointChannel& lhs, const EndpointChannel& rhs) {
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/implementation/client_proxy.h"
|
||||
#include "connections/implementation/endpoint_channel.h"
|
||||
@@ -48,7 +50,9 @@ void EndpointChannelManager::RegisterChannelForEndpoint(
|
||||
|
||||
LOG(INFO) << "EndpointChannelManager registered channel of type "
|
||||
<< channel->GetType() << " to endpoint " << endpoint_id;
|
||||
SetActiveEndpointChannel(client, endpoint_id, std::move(channel),
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint =
|
||||
channel_state_.RegisterEndpoint(endpoint_id);
|
||||
SetActiveEndpointChannel(client, endpoint_id, endpoint, std::move(channel),
|
||||
true /* enable_encryption */);
|
||||
|
||||
LOG(INFO) << "Registered channel: id=" << endpoint_id;
|
||||
@@ -58,8 +62,17 @@ void EndpointChannelManager::ReplaceChannelForEndpoint(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint =
|
||||
channel_state_.GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) {
|
||||
LOG(WARNING) << "EndpointChannelManager failed to replace channel because "
|
||||
"endpoint "
|
||||
<< endpoint_id << " is not registered.";
|
||||
return;
|
||||
}
|
||||
if (client->IsSafeToDisconnectEnabled(endpoint_id) &&
|
||||
channel_state_.IsWaitingForSafeToDisconnectTimeout(endpoint_id)) {
|
||||
endpoint->IsWaitingForSafeToDisconnectTimeout()) {
|
||||
LOG(WARNING)
|
||||
<< "EndpointChannelManager failed to replace endpoint " << endpoint_id
|
||||
<< "'s channel with type " << channel->GetType()
|
||||
@@ -67,13 +80,7 @@ void EndpointChannelManager::ReplaceChannelForEndpoint(
|
||||
return;
|
||||
}
|
||||
|
||||
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
|
||||
if (endpoint != nullptr && endpoint->channel == nullptr) {
|
||||
LOG(INFO) << "EndpointChannelManager is missing channel while "
|
||||
"trying to update: endpoint "
|
||||
<< endpoint_id;
|
||||
}
|
||||
SetActiveEndpointChannel(client, endpoint_id, std::move(channel),
|
||||
SetActiveEndpointChannel(client, endpoint_id, endpoint, std::move(channel),
|
||||
enable_encryption);
|
||||
}
|
||||
|
||||
@@ -82,37 +89,47 @@ bool EndpointChannelManager::EncryptChannelForEndpoint(
|
||||
std::unique_ptr<EncryptionContext> context) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
channel_state_.UpdateEncryptionContextForEndpoint(endpoint_id,
|
||||
std::move(context));
|
||||
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
|
||||
return channel_state_.EncryptChannel(endpoint);
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint =
|
||||
channel_state_.GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) {
|
||||
LOG(WARNING) << "EncryptChannelForEndpoint failed "
|
||||
<< "because endpoint is not registered: " << endpoint_id;
|
||||
return false;
|
||||
}
|
||||
endpoint->set_context(std::move(context));
|
||||
return endpoint->EncryptChannel();
|
||||
}
|
||||
|
||||
std::shared_ptr<EndpointChannel> EndpointChannelManager::GetChannelForEndpoint(
|
||||
const std::string& endpoint_id) {
|
||||
absl::string_view endpoint_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint =
|
||||
channel_state_.GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) {
|
||||
LOG(INFO) << "No channel info for endpoint " << endpoint_id;
|
||||
return {};
|
||||
}
|
||||
|
||||
return endpoint->channel;
|
||||
return endpoint->channel();
|
||||
}
|
||||
|
||||
void EndpointChannelManager::SetActiveEndpointChannel(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint,
|
||||
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
// Update the channel first, then encrypt this new channel, if
|
||||
// crypto context is present.
|
||||
channel->SetAnalyticsRecorder(&client->GetAnalyticsRecorder(), endpoint_id);
|
||||
channel_state_.UpdateChannelForEndpoint(endpoint_id, std::move(channel));
|
||||
channel_state_.UpdateSafeToDisconnectForEndpoint(
|
||||
endpoint_id, client->IsSafeToDisconnectEnabled(endpoint_id));
|
||||
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
|
||||
if (endpoint->IsEncrypted() && enable_encryption)
|
||||
channel_state_.EncryptChannel(endpoint);
|
||||
channel->SetLocalEndpointId(client->GetLocalEndpointId());
|
||||
|
||||
endpoint->set_channel(std::move(channel));
|
||||
endpoint->set_safe_to_disconnect_enabled(
|
||||
client->IsSafeToDisconnectEnabled(endpoint_id));
|
||||
|
||||
if (endpoint->IsEncrypted() && enable_encryption) {
|
||||
endpoint->EncryptChannel();
|
||||
}
|
||||
}
|
||||
|
||||
int EndpointChannelManager::GetConnectedEndpointsCount() const {
|
||||
@@ -133,7 +150,7 @@ void EndpointChannelManager::UpdateSafeToDisconnectForEndpoint(
|
||||
}
|
||||
|
||||
void EndpointChannelManager::MarkEndpointStopWaitToDisconnect(
|
||||
const std::string& endpoint_id, bool is_safe_to_disconnect,
|
||||
absl::string_view endpoint_id, bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting) {
|
||||
MutexLock lock(&mutex_);
|
||||
channel_state_.MarkEndpointStopWaitToDisconnect(
|
||||
@@ -141,61 +158,128 @@ void EndpointChannelManager::MarkEndpointStopWaitToDisconnect(
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::CreateNewTimeoutDisconnectedState(
|
||||
const std::string& endpoint_id, absl::Duration timeout_millis) {
|
||||
return channel_state_.CreateNewTimeoutDisconnectedState(endpoint_id,
|
||||
timeout_millis);
|
||||
absl::string_view endpoint_id, absl::Duration timeout_millis) {
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint_data;
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
endpoint_data = channel_state_.GetEndpointData(endpoint_id);
|
||||
}
|
||||
if (!endpoint_data) return false;
|
||||
|
||||
LOG(INFO) << "[safe-to-disconnect] "
|
||||
"Create TimeoutDisconnectedState for endpoint: "
|
||||
<< endpoint_id;
|
||||
endpoint_data->CreateNewTimeoutDisconnectedState(timeout_millis);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::IsSafeToDisconnect(
|
||||
const std::string& endpoint_id) {
|
||||
bool EndpointChannelManager::IsSafeToDisconnect(absl::string_view endpoint_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
return channel_state_.IsSafeToDisconnect(endpoint_id);
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::IsWaitingForSafeToDisconnectTimeoutForTesting(
|
||||
absl::string_view endpoint_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
return channel_state_.IsWaitingForSafeToDisconnectTimeoutForTesting(
|
||||
endpoint_id);
|
||||
}
|
||||
|
||||
void EndpointChannelManager::RemoveTimeoutDisconnectedState(
|
||||
const std::string& endpoint_id) {
|
||||
absl::string_view endpoint_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
channel_state_.RemoveTimeoutDisconnectedState(endpoint_id);
|
||||
}
|
||||
|
||||
///////////////////////////////// ChannelState /////////////////////////////////
|
||||
|
||||
// endpoint - channel endpoint to encrypt
|
||||
bool EndpointChannelManager::ChannelState::EncryptChannel(
|
||||
EndpointChannelManager::ChannelState::EndpointData* endpoint) {
|
||||
if (endpoint != nullptr && endpoint->channel != nullptr &&
|
||||
endpoint->context != nullptr) {
|
||||
endpoint->channel->EnableEncryption(endpoint->context);
|
||||
void EndpointChannelManager::ChannelState::EndpointData::
|
||||
CreateNewTimeoutDisconnectedState(absl::Duration timeout_millis) {
|
||||
MutexLock lock(&timeout_to_disconnected_mutex_);
|
||||
timeout_to_disconnected_enabled_ = true;
|
||||
timeout_to_disconnected_notified_ = false;
|
||||
timeout_to_disconnected_.Wait(timeout_millis);
|
||||
LOG(INFO) << "[safe-to-disconnect] Wait is done with "
|
||||
<< (timeout_to_disconnected_notified_ ? "notification" : "timeout");
|
||||
if (!timeout_to_disconnected_notified_) {
|
||||
is_safe_to_disconnect_ = true;
|
||||
}
|
||||
timeout_to_disconnected_notified_ = false;
|
||||
timeout_to_disconnected_enabled_ = false;
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::EndpointData::
|
||||
MarkEndpointStopWaitToDisconnect(bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting) {
|
||||
MutexLock lock(&timeout_to_disconnected_mutex_);
|
||||
this->is_safe_to_disconnect_ = is_safe_to_disconnect;
|
||||
if (!timeout_to_disconnected_enabled_) return;
|
||||
if (notify_stop_waiting) {
|
||||
LOG(INFO) << "[safe-to-disconnect] Notify stop waiting before timeout.";
|
||||
timeout_to_disconnected_.Notify();
|
||||
timeout_to_disconnected_notified_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::EndpointData::
|
||||
IsWaitingForSafeToDisconnectTimeout() const {
|
||||
MutexLock lock(&timeout_to_disconnected_mutex_);
|
||||
return timeout_to_disconnected_enabled_;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::EndpointData::IsSafeToDisconnect()
|
||||
const {
|
||||
MutexLock lock(&timeout_to_disconnected_mutex_);
|
||||
return is_safe_to_disconnect_;
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::EndpointData::
|
||||
RemoveTimeoutDisconnectedState() {
|
||||
MutexLock lock(&timeout_to_disconnected_mutex_);
|
||||
timeout_to_disconnected_notified_ = false;
|
||||
timeout_to_disconnected_enabled_ = false;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::EndpointData::EncryptChannel() {
|
||||
if (context_ != nullptr) {
|
||||
channel_->EnableEncryption(context_);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EndpointChannelManager::ChannelState::EndpointData*
|
||||
EndpointChannelManager::ChannelState::LookupEndpointData(
|
||||
const std::string& endpoint_id) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
return item != endpoints_.end() ? &item->second : nullptr;
|
||||
std::shared_ptr<EndpointChannelManager::ChannelState::EndpointData>
|
||||
EndpointChannelManager::ChannelState::GetEndpointData(
|
||||
absl::string_view endpoint_id) {
|
||||
auto it = endpoints_.find(endpoint_id);
|
||||
return it != endpoints_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<EndpointChannelManager::ChannelState::EndpointData>
|
||||
EndpointChannelManager::ChannelState::RegisterEndpoint(
|
||||
absl::string_view endpoint_id) {
|
||||
std::shared_ptr<EndpointData>& endpoint = endpoints_[endpoint_id];
|
||||
if (endpoint == nullptr) {
|
||||
endpoint = std::make_shared<EndpointData>();
|
||||
} else {
|
||||
LOG(DFATAL) << "Endpoint " << endpoint_id
|
||||
<< " is already registered. It might not have been cleaned up "
|
||||
"properly.";
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::DestroyAll() {
|
||||
for (auto& item : endpoints_) {
|
||||
RemoveEndpoint(item.first, DisconnectionReason::SHUTDOWN,
|
||||
/* safe_to_disconnect_enabled */ false,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
// Collect all endpoint IDs to avoid iterator invalidation.
|
||||
std::vector<std::string> endpoint_ids;
|
||||
endpoint_ids.reserve(endpoints_.size());
|
||||
for (const auto& [endpoint_id, endpoint_data] : endpoints_) {
|
||||
endpoint_ids.push_back(endpoint_id);
|
||||
}
|
||||
endpoints_.clear();
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint(
|
||||
const std::string& endpoint_id, std::shared_ptr<EndpointChannel> channel) {
|
||||
// Create EndpointData instance, if necessary, and populate channel.
|
||||
endpoints_[endpoint_id].channel = std::move(channel);
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::UpdateEncryptionContextForEndpoint(
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<EncryptionContext> context) {
|
||||
// Create EndpointData instance, if necessary, and populate crypto context.
|
||||
endpoints_[endpoint_id].context = std::move(context);
|
||||
for (const auto& endpoint_id : endpoint_ids) {
|
||||
RemoveEndpoint(endpoint_id, DisconnectionReason::SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::UpdateSafeToDisconnectForEndpoint(
|
||||
@@ -204,32 +288,28 @@ void EndpointChannelManager::ChannelState::UpdateSafeToDisconnectForEndpoint(
|
||||
"UpdateSafeToDisconnectForEndpoint for: "
|
||||
<< endpoint_id << " " << safe_to_disconnect_enabled;
|
||||
|
||||
endpoints_[endpoint_id].safe_to_disconnect_enabled =
|
||||
safe_to_disconnect_enabled;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::GetSafeToDisconnectForEndpoint(
|
||||
const std::string& endpoint_id) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return false;
|
||||
LOG(INFO) << "[safe-to-disconnect] GetSafeToDisconnectForEndpoint: "
|
||||
<< item->second.safe_to_disconnect_enabled;
|
||||
return item->second.safe_to_disconnect_enabled;
|
||||
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) {
|
||||
LOG(WARNING) << "UpdateSafeToDisconnectForEndpoint failed because endpoint "
|
||||
<< endpoint_id << " is not registered.";
|
||||
return;
|
||||
}
|
||||
endpoint->set_safe_to_disconnect_enabled(safe_to_disconnect_enabled);
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::RemoveEndpoint(
|
||||
const std::string& endpoint_id, DisconnectionReason reason,
|
||||
bool safe_to_disconnect_enabled, SafeDisconnectionResult result) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return false;
|
||||
absl::string_view endpoint_id, DisconnectionReason reason) {
|
||||
auto it = endpoints_.find(endpoint_id);
|
||||
if (it == endpoints_.end()) return false;
|
||||
|
||||
MarkEndpointStopWaitToDisconnect(endpoint_id,
|
||||
/* is_safe_to_disconnect */ true,
|
||||
/* notify_stop_waiting */ true);
|
||||
item->second.disconnect_reason = reason;
|
||||
auto channel = item->second.channel;
|
||||
it->second->set_disconnect_reason(reason);
|
||||
std::shared_ptr<EndpointChannel> channel = it->second->channel();
|
||||
bool safe_to_disconnect_enabled = it->second->safe_to_disconnect_enabled();
|
||||
|
||||
if (channel && !channel->IsClosed() && !safe_to_disconnect_enabled) {
|
||||
if (!channel->IsClosed() && !safe_to_disconnect_enabled) {
|
||||
// If the channel was paused (i.e. during a bandwidth upgrade negotiation)
|
||||
// we resume to ensure the thread won't hang when trying to write to it.
|
||||
channel->Resume();
|
||||
@@ -246,18 +326,16 @@ bool EndpointChannelManager::ChannelState::RemoveEndpoint(
|
||||
}
|
||||
|
||||
LOG(INFO) << "Remove Endpoint: " << endpoint_id;
|
||||
endpoints_.erase(item);
|
||||
endpoints_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::isWifiLanConnected() const {
|
||||
for (auto& endpoint : endpoints_) {
|
||||
auto channel = endpoint.second.channel;
|
||||
if (channel) {
|
||||
if (channel->GetMedium() == Medium::WIFI_LAN) {
|
||||
LOG(INFO) << "Found WIFI_LAN Medium for endpoint:" << endpoint.first;
|
||||
return true;
|
||||
}
|
||||
for (const auto& [endpoint_id, endpoint_data] : endpoints_) {
|
||||
std::shared_ptr<EndpointChannel> channel = endpoint_data->channel();
|
||||
if (channel->GetMedium() == Medium::WIFI_LAN) {
|
||||
LOG(INFO) << "Found WIFI_LAN Medium for endpoint:" << endpoint_id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,96 +343,53 @@ bool EndpointChannelManager::ChannelState::isWifiLanConnected() const {
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::MarkEndpointStopWaitToDisconnect(
|
||||
const std::string& endpoint_id, bool is_safe_to_disconnect,
|
||||
absl::string_view endpoint_id, bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return;
|
||||
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) return;
|
||||
LOG(INFO) << "[safe-to-disconnect] is_safe_to_disconnect= "
|
||||
<< is_safe_to_disconnect
|
||||
<< ", notify_stop_waiting= " << notify_stop_waiting
|
||||
<< " for endpoint: " << endpoint_id;
|
||||
{
|
||||
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
|
||||
item->second.is_safe_to_disconnect = is_safe_to_disconnect;
|
||||
if (!item->second.timeout_to_disconnected_enabled) return;
|
||||
if (notify_stop_waiting) {
|
||||
LOG(INFO) << "[safe-to-disconnect] Notify stop "
|
||||
"waiting before timeout.";
|
||||
item->second.timeout_to_disconnected.Notify();
|
||||
item->second.timeout_to_disconnected_notified = true;
|
||||
}
|
||||
}
|
||||
endpoint->MarkEndpointStopWaitToDisconnect(is_safe_to_disconnect,
|
||||
notify_stop_waiting);
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::CreateNewTimeoutDisconnectedState(
|
||||
const std::string& endpoint_id, absl::Duration timeout_millis) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return false;
|
||||
bool EndpointChannelManager::ChannelState::
|
||||
IsWaitingForSafeToDisconnectTimeoutForTesting(
|
||||
absl::string_view endpoint_id) {
|
||||
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) return false;
|
||||
bool enabled = endpoint->IsWaitingForSafeToDisconnectTimeout();
|
||||
LOG(INFO) << "[safe-to-disconnect] "
|
||||
"Create TimeoutDisconnectedState for endpoint: "
|
||||
<< endpoint_id;
|
||||
{
|
||||
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
|
||||
item->second.timeout_to_disconnected_enabled = true;
|
||||
item->second.timeout_to_disconnected_notified = false;
|
||||
item->second.timeout_to_disconnected.Wait(timeout_millis);
|
||||
LOG(INFO) << "[safe-to-disconnect] Wait is done with "
|
||||
<< (item->second.timeout_to_disconnected_notified ? "notification"
|
||||
: "timeout");
|
||||
if (!item->second.timeout_to_disconnected_notified)
|
||||
item->second.is_safe_to_disconnect = true;
|
||||
item->second.timeout_to_disconnected_notified = false;
|
||||
item->second.timeout_to_disconnected_enabled = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool EndpointChannelManager::ChannelState::IsWaitingForSafeToDisconnectTimeout(
|
||||
const std::string& endpoint_id) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return false;
|
||||
{
|
||||
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
|
||||
LOG(INFO) << "[safe-to-disconnect] "
|
||||
"IsWaitingForSafeToDisconnectTimeout for endpoint: "
|
||||
<< endpoint_id << ": "
|
||||
<< item->second.timeout_to_disconnected_enabled;
|
||||
return (item->second.timeout_to_disconnected_enabled);
|
||||
}
|
||||
"IsWaitingForSafeToDisconnectTimeout for endpoint: "
|
||||
<< endpoint_id << ": " << enabled;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::ChannelState::IsSafeToDisconnect(
|
||||
const std::string& endpoint_id) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return true;
|
||||
{
|
||||
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
|
||||
LOG(INFO)
|
||||
<< "[safe-to-disconnect] Get SafeToDisconnect status for endpoint: "
|
||||
<< endpoint_id << ": " << item->second.is_safe_to_disconnect;
|
||||
return (item->second.is_safe_to_disconnect);
|
||||
}
|
||||
absl::string_view endpoint_id) {
|
||||
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) return true;
|
||||
bool is_safe = endpoint->IsSafeToDisconnect();
|
||||
LOG(INFO) << "[safe-to-disconnect] Get SafeToDisconnect status for endpoint: "
|
||||
<< endpoint_id << ": " << is_safe;
|
||||
return is_safe;
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::RemoveTimeoutDisconnectedState(
|
||||
const std::string& endpoint_id) {
|
||||
auto item = endpoints_.find(endpoint_id);
|
||||
if (item == endpoints_.end()) return;
|
||||
{
|
||||
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
|
||||
item->second.timeout_to_disconnected_notified = false;
|
||||
item->second.timeout_to_disconnected_enabled = false;
|
||||
}
|
||||
absl::string_view endpoint_id) {
|
||||
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
|
||||
if (endpoint == nullptr) return;
|
||||
endpoint->RemoveTimeoutDisconnectedState();
|
||||
}
|
||||
|
||||
bool EndpointChannelManager::UnregisterChannelForEndpoint(
|
||||
const std::string& endpoint_id, DisconnectionReason reason,
|
||||
absl::string_view endpoint_id, DisconnectionReason reason,
|
||||
SafeDisconnectionResult result) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
auto safe_to_disconnect_enabled =
|
||||
channel_state_.GetSafeToDisconnectForEndpoint(endpoint_id);
|
||||
if (!channel_state_.RemoveEndpoint(endpoint_id, reason,
|
||||
safe_to_disconnect_enabled, result)) {
|
||||
if (!channel_state_.RemoveEndpoint(endpoint_id, reason)) {
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "EndpointChannelManager unregistered channel for endpoint "
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/implementation/analytics/analytics_recorder.h"
|
||||
#include "connections/implementation/client_proxy.h"
|
||||
@@ -91,11 +93,11 @@ class EndpointChannelManager final {
|
||||
// EndpointManager methods that use a channel are running, it is better to
|
||||
// have a shared ownership.
|
||||
std::shared_ptr<EndpointChannel> GetChannelForEndpoint(
|
||||
const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
absl::string_view endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true if 'endpoint_id' actually had a registered EndpointChannel.
|
||||
// IOW, a return of false signifies a no-op.
|
||||
bool UnregisterChannelForEndpoint(const std::string& endpoint_id,
|
||||
bool UnregisterChannelForEndpoint(absl::string_view endpoint_id,
|
||||
DisconnectionReason reason,
|
||||
SafeDisconnectionResult result)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
@@ -107,16 +109,19 @@ class EndpointChannelManager final {
|
||||
void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id,
|
||||
bool safe_to_disconnect_enabled)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id,
|
||||
bool CreateNewTimeoutDisconnectedState(absl::string_view endpoint_id,
|
||||
absl::Duration timeout_millis)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void MarkEndpointStopWaitToDisconnect(absl::string_view endpoint_id,
|
||||
bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id,
|
||||
absl::Duration timeout_millis)
|
||||
|
||||
bool IsSafeToDisconnect(absl::string_view endpoint_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool IsSafeToDisconnect(const std::string& endpoint_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void RemoveTimeoutDisconnectedState(const std::string& endpoint_id)
|
||||
bool IsWaitingForSafeToDisconnectTimeoutForTesting(
|
||||
absl::string_view endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void RemoveTimeoutDisconnectedState(absl::string_view endpoint_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
@@ -125,32 +130,69 @@ class EndpointChannelManager final {
|
||||
// been encrypted yet.
|
||||
class ChannelState {
|
||||
public:
|
||||
struct EndpointData {
|
||||
class EndpointData {
|
||||
public:
|
||||
EndpointData() = default;
|
||||
EndpointData(EndpointData&&) = default;
|
||||
EndpointData& operator=(EndpointData&&) = default;
|
||||
~EndpointData() {
|
||||
if (channel != nullptr) {
|
||||
channel->Close(disconnect_reason);
|
||||
if (channel_ != nullptr) {
|
||||
channel_->Close(disconnect_reason_);
|
||||
}
|
||||
}
|
||||
|
||||
// True if we have a 'context' for the endpoint.
|
||||
bool IsEncrypted() const { return context != nullptr; }
|
||||
bool IsEncrypted() const { return context_ != nullptr; }
|
||||
|
||||
std::shared_ptr<EndpointChannel> channel;
|
||||
std::shared_ptr<EncryptionContext> context;
|
||||
DisconnectionReason disconnect_reason =
|
||||
void CreateNewTimeoutDisconnectedState(absl::Duration timeout_millis)
|
||||
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
|
||||
void MarkEndpointStopWaitToDisconnect(bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting)
|
||||
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
|
||||
bool IsWaitingForSafeToDisconnectTimeout() const
|
||||
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
|
||||
bool IsSafeToDisconnect() const
|
||||
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
|
||||
void RemoveTimeoutDisconnectedState()
|
||||
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
|
||||
bool EncryptChannel();
|
||||
|
||||
std::shared_ptr<EndpointChannel> channel() const { return channel_; }
|
||||
void set_channel(std::shared_ptr<EndpointChannel> channel) {
|
||||
channel_ = std::move(channel);
|
||||
}
|
||||
|
||||
std::shared_ptr<EncryptionContext> context() const { return context_; }
|
||||
void set_context(std::shared_ptr<EncryptionContext> context) {
|
||||
context_ = std::move(context);
|
||||
}
|
||||
|
||||
void set_disconnect_reason(DisconnectionReason disconnect_reason) {
|
||||
disconnect_reason_ = disconnect_reason;
|
||||
}
|
||||
|
||||
bool safe_to_disconnect_enabled() const {
|
||||
return safe_to_disconnect_enabled_;
|
||||
}
|
||||
void set_safe_to_disconnect_enabled(bool safe_to_disconnect_enabled) {
|
||||
safe_to_disconnect_enabled_ = safe_to_disconnect_enabled;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<EndpointChannel> channel_;
|
||||
std::shared_ptr<EncryptionContext> context_;
|
||||
DisconnectionReason disconnect_reason_ =
|
||||
DisconnectionReason::UNKNOWN_DISCONNECTION_REASON;
|
||||
bool safe_to_disconnect_enabled = false;
|
||||
mutable Mutex timeout_to_disconnected_mutex;
|
||||
ConditionVariable timeout_to_disconnected{&timeout_to_disconnected_mutex};
|
||||
bool timeout_to_disconnected_enabled
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
|
||||
bool timeout_to_disconnected_notified
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
|
||||
bool is_safe_to_disconnect
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
|
||||
bool safe_to_disconnect_enabled_ = false;
|
||||
mutable Mutex timeout_to_disconnected_mutex_;
|
||||
ConditionVariable timeout_to_disconnected_{
|
||||
&timeout_to_disconnected_mutex_};
|
||||
bool timeout_to_disconnected_enabled_
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
|
||||
bool timeout_to_disconnected_notified_
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
|
||||
bool is_safe_to_disconnect_
|
||||
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
|
||||
};
|
||||
|
||||
ChannelState() = default;
|
||||
@@ -160,57 +202,48 @@ class EndpointChannelManager final {
|
||||
|
||||
// Provides a way to destroy contents of a container, while holding a lock.
|
||||
void DestroyAll();
|
||||
|
||||
// Return pointer to endpoint data, or nullptr, it not found.
|
||||
EndpointData* LookupEndpointData(const std::string& endpoint_id);
|
||||
std::shared_ptr<EndpointData> GetEndpointData(
|
||||
absl::string_view endpoint_id);
|
||||
|
||||
// Stores a new EndpointChannel for the endpoint.
|
||||
// Prevoius one is destroyed, if it existed.
|
||||
void UpdateChannelForEndpoint(const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> channel);
|
||||
|
||||
// Stores a new EncryptionContext for the endpoint.
|
||||
// Prevoius one is destroyed, if it existed.
|
||||
void UpdateEncryptionContextForEndpoint(
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<EncryptionContext> context);
|
||||
// Registers a new endpoint id. This is the only spot EndpointData is
|
||||
// created.
|
||||
std::shared_ptr<EndpointData> RegisterEndpoint(
|
||||
absl::string_view endpoint_id);
|
||||
|
||||
void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id,
|
||||
bool safe_to_disconnect_enabled);
|
||||
bool GetSafeToDisconnectForEndpoint(const std::string& endpoint_id);
|
||||
|
||||
// Removes all knowledge of this endpoint, cleaning up as necessary.
|
||||
// Returns false if the endpoint was not found.
|
||||
bool RemoveEndpoint(const std::string& endpoint_id,
|
||||
DisconnectionReason reason,
|
||||
bool safe_to_disconnect_enabled,
|
||||
SafeDisconnectionResult result);
|
||||
bool RemoveEndpoint(absl::string_view endpoint_id,
|
||||
DisconnectionReason reason);
|
||||
|
||||
bool EncryptChannel(EndpointData* endpoint);
|
||||
int GetConnectedEndpointsCount() const { return endpoints_.size(); }
|
||||
bool isWifiLanConnected() const;
|
||||
void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id,
|
||||
void MarkEndpointStopWaitToDisconnect(absl::string_view endpoint_id,
|
||||
bool is_safe_to_disconnect,
|
||||
bool notify_stop_waiting);
|
||||
bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id,
|
||||
absl::Duration timeout_millis);
|
||||
bool IsWaitingForSafeToDisconnectTimeout(const std::string& endpoint_id);
|
||||
bool IsSafeToDisconnect(const std::string& endpoint_id);
|
||||
void RemoveTimeoutDisconnectedState(const std::string& endpoint_id);
|
||||
bool IsWaitingForSafeToDisconnectTimeoutForTesting(
|
||||
absl::string_view endpoint_id);
|
||||
bool IsSafeToDisconnect(absl::string_view endpoint_id);
|
||||
void RemoveTimeoutDisconnectedState(absl::string_view endpoint_id);
|
||||
|
||||
private:
|
||||
// Endpoint ID -> EndpointData. Contains everything we know about the
|
||||
// endpoint.
|
||||
absl::flat_hash_map<std::string, EndpointData> endpoints_;
|
||||
absl::flat_hash_map<std::string, std::shared_ptr<EndpointData>> endpoints_;
|
||||
};
|
||||
|
||||
void SetActiveEndpointChannel(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
bool enable_encryption)
|
||||
void SetActiveEndpointChannel(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<ChannelState::EndpointData> endpoint,
|
||||
std::shared_ptr<EndpointChannel> channel, bool enable_encryption)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
mutable Mutex mutex_;
|
||||
ChannelState channel_state_;
|
||||
ChannelState channel_state_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace nearby::connections
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/implementation/analytics/analytics_recorder.h"
|
||||
#include "connections/implementation/base_endpoint_channel.h"
|
||||
@@ -210,16 +211,16 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
|
||||
ASSERT_NE(context.second, nullptr);
|
||||
|
||||
EndpointChannelManager ecm_a;
|
||||
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.first));
|
||||
ecm_a.RegisterChannelForEndpoint(&proxy_a, std::string(kEndpointId),
|
||||
std::move(channel_a));
|
||||
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.first));
|
||||
|
||||
EndpointChannelManager ecm_b;
|
||||
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.second));
|
||||
ecm_b.RegisterChannelForEndpoint(&proxy_b, std::string(kEndpointId),
|
||||
std::move(channel_b));
|
||||
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.second));
|
||||
|
||||
EXPECT_EQ(channel_a_raw->GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_EQ(channel_b_raw->GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
@@ -241,10 +242,10 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
|
||||
channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
ecm_a.UnregisterChannelForEndpoint(
|
||||
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
ecm_b.UnregisterChannelForEndpoint(
|
||||
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
|
||||
kEndpointId, DisconnectionReason::REMOTE_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
}
|
||||
|
||||
@@ -290,13 +291,26 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
|
||||
ASSERT_NE(context.first, nullptr);
|
||||
ASSERT_NE(context.second, nullptr);
|
||||
|
||||
auto client_a_dummy = CreatePipe();
|
||||
auto server_a_dummy = CreatePipe();
|
||||
auto channel_a_init = std::make_shared<MockEndpointChannel>(
|
||||
server_a_dummy.first.get(), client_a_dummy.second.get());
|
||||
auto client_b_dummy = CreatePipe();
|
||||
auto server_b_dummy = CreatePipe();
|
||||
auto channel_b_init = std::make_shared<MockEndpointChannel>(
|
||||
server_b_dummy.first.get(), client_b_dummy.second.get());
|
||||
|
||||
EndpointChannelManager ecm_a;
|
||||
ecm_a.RegisterChannelForEndpoint(&proxy_a, std::string(kEndpointId),
|
||||
std::move(channel_a_init));
|
||||
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.first));
|
||||
ecm_a.ReplaceChannelForEndpoint(&proxy_a, std::string(kEndpointId),
|
||||
std::move(channel_a), false);
|
||||
|
||||
EndpointChannelManager ecm_b;
|
||||
ecm_b.RegisterChannelForEndpoint(&proxy_b, std::string(kEndpointId),
|
||||
std::move(channel_b_init));
|
||||
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
|
||||
std::move(context.second));
|
||||
ecm_b.ReplaceChannelForEndpoint(&proxy_b, std::string(kEndpointId),
|
||||
@@ -309,12 +323,75 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
|
||||
channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
ecm_a.UnregisterChannelForEndpoint(
|
||||
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
ecm_b.UnregisterChannelForEndpoint(
|
||||
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
|
||||
kEndpointId, DisconnectionReason::REMOTE_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
}
|
||||
|
||||
TEST(BaseEndpointChannelManagerTest,
|
||||
CreateNewTimeoutDisconnectedStateUnregisterDuringWait) {
|
||||
ClientProxy proxy;
|
||||
EndpointChannelManager ecm;
|
||||
auto client = CreatePipe();
|
||||
auto server = CreatePipe();
|
||||
auto channel = std::make_shared<MockEndpointChannel>(server.first.get(),
|
||||
client.second.get());
|
||||
auto channel_raw = channel.get();
|
||||
|
||||
ON_CALL(*channel_raw, GetMedium).WillByDefault([]() {
|
||||
return Medium::BLUETOOTH;
|
||||
});
|
||||
|
||||
ecm.RegisterChannelForEndpoint(&proxy, std::string(kEndpointId),
|
||||
std::move(channel));
|
||||
|
||||
EXPECT_EQ(ecm.GetConnectedEndpointsCount(), 1);
|
||||
|
||||
MultiThreadExecutor executor(1);
|
||||
CountDownLatch start_latch(1);
|
||||
CountDownLatch finish_latch(1);
|
||||
bool wait_result = false;
|
||||
|
||||
executor.Execute([&]() {
|
||||
start_latch.CountDown();
|
||||
wait_result =
|
||||
ecm.CreateNewTimeoutDisconnectedState(kEndpointId, absl::Seconds(5));
|
||||
finish_latch.CountDown();
|
||||
});
|
||||
|
||||
ASSERT_TRUE(start_latch.Await(absl::Seconds(1)).result());
|
||||
|
||||
// Wait for the endpoint to enter the waiting state.
|
||||
absl::Time deadline = absl::Now() + absl::Seconds(1);
|
||||
while (!ecm.IsWaitingForSafeToDisconnectTimeoutForTesting(kEndpointId)) {
|
||||
ASSERT_TRUE(absl::Now() < deadline)
|
||||
<< "Timed out waiting for endpoint to enter wait state.";
|
||||
absl::SleepFor(absl::Milliseconds(10));
|
||||
}
|
||||
|
||||
// Close the channel first to prevent UnregisterChannelForEndpoint from
|
||||
// attempting to write disconnection frames to it, bypassing the 500ms data
|
||||
// transfer delay and potential segfaults.
|
||||
channel_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
|
||||
bool unregister_result = ecm.UnregisterChannelForEndpoint(
|
||||
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
|
||||
SafeDisconnectionResult::kSafeDisconnection);
|
||||
EXPECT_TRUE(unregister_result);
|
||||
|
||||
EXPECT_TRUE(finish_latch.Await(absl::Seconds(2)).result());
|
||||
EXPECT_TRUE(wait_result);
|
||||
EXPECT_EQ(ecm.GetConnectedEndpointsCount(), 0);
|
||||
}
|
||||
|
||||
TEST(BaseEndpointChannelManagerTest,
|
||||
CreateNewTimeoutDisconnectedStateReturnsFalseForNonexistentEndpoint) {
|
||||
EndpointChannelManager ecm;
|
||||
EXPECT_FALSE(ecm.CreateNewTimeoutDisconnectedState("NonexistentEndpoint",
|
||||
absl::Seconds(1)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::connections
|
||||
|
||||
@@ -28,11 +28,13 @@
|
||||
#include "connections/implementation/client_proxy.h"
|
||||
#include "connections/implementation/endpoint_channel.h"
|
||||
#include "connections/implementation/endpoint_channel_manager.h"
|
||||
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
|
||||
#include "connections/implementation/offline_frames.h"
|
||||
#include "connections/implementation/proto/offline_wire_formats.pb.h"
|
||||
#include "connections/implementation/service_id_constants.h"
|
||||
#include "connections/listeners.h"
|
||||
#include "connections/medium_selector.h"
|
||||
#include "internal/flags/nearby_flags.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/exception.h"
|
||||
@@ -64,6 +66,15 @@ constexpr absl::Time kInvalidTimestamp = absl::InfinitePast();
|
||||
// The maximum time we will wait for the encryption setup during negotiating a
|
||||
// connection.
|
||||
constexpr absl::Duration kDecryptRetryTimeout = absl::Seconds(3);
|
||||
|
||||
// Returns true if the given `frame_type` is allowed before the connection to
|
||||
// the endpoint is confirmed (i.e., KEEP_ALIVE, CONNECTION_RESPONSE, and
|
||||
// DISCONNECTION frames).
|
||||
bool IsAllowedPreConfirmationFrameType(V1Frame::FrameType frame_type) {
|
||||
return frame_type == V1Frame::KEEP_ALIVE ||
|
||||
frame_type == V1Frame::CONNECTION_RESPONSE ||
|
||||
frame_type == V1Frame::DISCONNECTION;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class EndpointManager::LockedFrameProcessor {
|
||||
@@ -112,7 +123,8 @@ class EndpointManager::LockedFrameProcessor {
|
||||
void EndpointManager::EndpointChannelLoopRunnable(
|
||||
const std::string& runnable_name, ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
absl::AnyInvocable<ExceptionOr<bool>(EndpointChannel*)> handler) {
|
||||
absl::AnyInvocable<ExceptionOr<bool>(std::shared_ptr<EndpointChannel>)>
|
||||
handler) {
|
||||
// EndpointChannelManager will not let multiple channels exist simultaneously
|
||||
// for the same endpoint_id; it will be closing "old" channels as new ones
|
||||
// come.
|
||||
@@ -143,7 +155,7 @@ void EndpointManager::EndpointChannelLoopRunnable(
|
||||
break;
|
||||
}
|
||||
|
||||
ExceptionOr<bool> keep_using_channel = handler(channel.get());
|
||||
ExceptionOr<bool> keep_using_channel = handler(channel);
|
||||
|
||||
if (!keep_using_channel.ok()) {
|
||||
Exception exception = keep_using_channel.GetException();
|
||||
@@ -195,7 +207,7 @@ void EndpointManager::EndpointChannelLoopRunnable(
|
||||
}
|
||||
|
||||
ExceptionOr<OfflineFrame> EndpointManager::TryDecryptFrame(
|
||||
const ByteArray& data, EndpointChannel* endpoint_channel) {
|
||||
const ByteArray& data, std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
auto start_time = SystemClock::ElapsedRealtime();
|
||||
while (true) {
|
||||
ExceptionOr<ByteArray> decrypted = endpoint_channel->TryDecrypt(data);
|
||||
@@ -222,7 +234,7 @@ ExceptionOr<OfflineFrame> EndpointManager::TryDecryptFrame(
|
||||
|
||||
ExceptionOr<bool> EndpointManager::HandleData(
|
||||
const std::string& endpoint_id, ClientProxy* client,
|
||||
EndpointChannel* endpoint_channel) {
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
bool try_decrypting = !endpoint_channel->IsEncrypted();
|
||||
// Read as much as we can from the healthy EndpointChannel - when it is no
|
||||
// longer in good shape (i.e. our read from it throws an Exception), our
|
||||
@@ -274,8 +286,23 @@ ExceptionOr<bool> EndpointManager::HandleData(
|
||||
|
||||
// Route the incoming offlineFrame to its registered processor.
|
||||
V1Frame::FrameType frame_type = parser::GetFrameType(frame);
|
||||
LockedFrameProcessor frame_processor = GetFrameProcessor(frame_type);
|
||||
if (!frame_processor) {
|
||||
if (NearbyFlags::GetInstance().GetBoolFlag(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kFilterUnconfirmedEndpointFrames) &&
|
||||
client->HasPendingConnectionToEndpoint(endpoint_id) &&
|
||||
!IsAllowedPreConfirmationFrameType(frame_type)) {
|
||||
LOG(WARNING) << "EndpointManager discarded unauthorized frame ("
|
||||
<< V1Frame::FrameType_Name(frame_type)
|
||||
<< ") from unconfirmed endpoint " << endpoint_id << ".";
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameProcessor* processor = nullptr;
|
||||
{
|
||||
LockedFrameProcessor frame_processor = GetFrameProcessor(frame_type);
|
||||
processor = frame_processor.get();
|
||||
}
|
||||
if (!processor) {
|
||||
// report messages without handlers, except KEEP_ALIVE, which has
|
||||
// no explicit handler.
|
||||
if (frame_type == V1Frame::KEEP_ALIVE) {
|
||||
@@ -310,14 +337,14 @@ ExceptionOr<bool> EndpointManager::HandleData(
|
||||
continue;
|
||||
}
|
||||
|
||||
frame_processor->OnIncomingFrame(frame, endpoint_id, client,
|
||||
endpoint_channel->GetMedium());
|
||||
processor->OnIncomingFrame(frame, endpoint_id, client,
|
||||
endpoint_channel->GetMedium());
|
||||
}
|
||||
}
|
||||
|
||||
void EndpointManager::ProcessDisconnectionFrame(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel, OfflineFrame& frame) {
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel, OfflineFrame& frame) {
|
||||
if (!client->IsSafeToDisconnectEnabled(endpoint_id)) {
|
||||
LOG(INFO) << "EndpointManager received a DISCONNECTION frame from endpoint "
|
||||
<< endpoint_id << " on channel " << endpoint_channel->GetType()
|
||||
@@ -371,9 +398,9 @@ void EndpointManager::ProcessDisconnectionFrame(
|
||||
}
|
||||
|
||||
ExceptionOr<bool> EndpointManager::HandleKeepAlive(
|
||||
EndpointChannel* endpoint_channel, absl::Duration keep_alive_interval,
|
||||
absl::Duration keep_alive_timeout, Mutex* keep_alive_waiter_mutex,
|
||||
ConditionVariable* keep_alive_waiter) {
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
absl::Duration keep_alive_interval, absl::Duration keep_alive_timeout,
|
||||
Mutex* keep_alive_waiter_mutex, ConditionVariable* keep_alive_waiter) {
|
||||
// Check if it has been too long since we received a frame from our endpoint.
|
||||
absl::Time last_read_time = endpoint_channel->GetLastReadTimestamp();
|
||||
absl::Duration duration_until_timeout =
|
||||
@@ -578,7 +605,8 @@ void EndpointManager::RegisterEndpoint(
|
||||
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
|
||||
EndpointChannelLoopRunnable(
|
||||
"Read", client, endpoint_id,
|
||||
[this, client, endpoint_id](EndpointChannel* channel) {
|
||||
[this, client,
|
||||
endpoint_id](std::shared_ptr<EndpointChannel> channel) {
|
||||
return HandleData(endpoint_id, client, channel);
|
||||
});
|
||||
});
|
||||
@@ -605,7 +633,7 @@ void EndpointManager::RegisterEndpoint(
|
||||
"KeepAliveManager", client, endpoint_id,
|
||||
[this, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex,
|
||||
keep_alive_waiter](EndpointChannel* channel) {
|
||||
keep_alive_waiter](std::shared_ptr<EndpointChannel> channel) {
|
||||
return HandleKeepAlive(
|
||||
channel, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex, keep_alive_waiter);
|
||||
@@ -745,8 +773,8 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
|
||||
SafeDisconnectionResult::kSafeDisconnection;
|
||||
|
||||
// Grab the service ID before we destroy the channel.
|
||||
EndpointChannel* channel =
|
||||
channel_manager_->GetChannelForEndpoint(endpoint_id).get();
|
||||
std::shared_ptr<EndpointChannel> channel =
|
||||
channel_manager_->GetChannelForEndpoint(endpoint_id);
|
||||
std::string service_id =
|
||||
channel ? channel->GetServiceId() : std::string(kUnknownServiceId);
|
||||
|
||||
@@ -784,9 +812,10 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
|
||||
RemoveEndpointState(endpoint_id);
|
||||
}
|
||||
|
||||
bool EndpointManager::ApplySafeToDisconnect(const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
DisconnectionReason reason) {
|
||||
bool EndpointManager::ApplySafeToDisconnect(
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
DisconnectionReason reason) {
|
||||
LOG(INFO) << "[safe-to-disconnect] ApplySafeToDisconnect reason: " << reason;
|
||||
// TODO(b/303544913): clean up the safe-to-disconnect logic
|
||||
bool is_safe_disconnection = false;
|
||||
|
||||
@@ -229,15 +229,14 @@ class EndpointManager {
|
||||
LockedFrameProcessor GetFrameProcessor(
|
||||
location::nearby::connections::V1Frame::FrameType frame_type);
|
||||
|
||||
ExceptionOr<bool> HandleData(const std::string& endpoint_id,
|
||||
ClientProxy* client_proxy,
|
||||
EndpointChannel* endpoint_channel);
|
||||
ExceptionOr<bool> HandleData(
|
||||
const std::string& endpoint_id, ClientProxy* client_proxy,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
|
||||
ExceptionOr<bool> HandleKeepAlive(EndpointChannel* endpoint_channel,
|
||||
absl::Duration keep_alive_interval,
|
||||
absl::Duration keep_alive_timeout,
|
||||
Mutex* keep_alive_waiter_mutex,
|
||||
ConditionVariable* keep_alive_waiter);
|
||||
ExceptionOr<bool> HandleKeepAlive(
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
absl::Duration keep_alive_interval, absl::Duration keep_alive_timeout,
|
||||
Mutex* keep_alive_waiter_mutex, ConditionVariable* keep_alive_waiter);
|
||||
|
||||
// Waits for a given endpoint EndpointChannelLoopRunnable() workers to
|
||||
// terminate.
|
||||
@@ -249,7 +248,8 @@ class EndpointManager {
|
||||
void EndpointChannelLoopRunnable(
|
||||
const std::string& runnable_name, ClientProxy* client_proxy,
|
||||
const std::string& endpoint_id,
|
||||
absl::AnyInvocable<ExceptionOr<bool>(EndpointChannel*)> handler);
|
||||
absl::AnyInvocable<ExceptionOr<bool>(std::shared_ptr<EndpointChannel>)>
|
||||
handler);
|
||||
|
||||
static void WaitForLatch(const std::string& method_name,
|
||||
CountDownLatch* latch);
|
||||
@@ -265,7 +265,7 @@ class EndpointManager {
|
||||
void RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id,
|
||||
bool notify, DisconnectionReason reason);
|
||||
bool ApplySafeToDisconnect(const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
DisconnectionReason reason);
|
||||
void WaitForEndpointDisconnectionProcessing(ClientProxy* client,
|
||||
const std::string& service_id,
|
||||
@@ -273,7 +273,7 @@ class EndpointManager {
|
||||
DisconnectionReason reason);
|
||||
void ProcessDisconnectionFrame(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
location::nearby::connections::OfflineFrame& frame);
|
||||
CountDownLatch NotifyFrameProcessorsOnEndpointDisconnect(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
@@ -287,8 +287,8 @@ class EndpointManager {
|
||||
// Executes all jobs sequentially, on a serial_executor_.
|
||||
void RunOnEndpointManagerThread(const std::string& name, Runnable runnable);
|
||||
|
||||
ExceptionOr<OfflineFrame> TryDecryptFrame(const ByteArray& data,
|
||||
EndpointChannel* endpoint_channel);
|
||||
ExceptionOr<OfflineFrame> TryDecryptFrame(
|
||||
const ByteArray& data, std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
EndpointChannelManager* channel_manager_;
|
||||
|
||||
RecursiveMutex frame_processors_lock_;
|
||||
|
||||
@@ -94,6 +94,10 @@ class SetSafeToDisconnect {
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kSafeToDisconnectVersion,
|
||||
safe_to_disconnect_version);
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kFilterUnconfirmedEndpointFrames,
|
||||
false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,11 +112,11 @@ class EndpointManagerTest : public ::testing::Test {
|
||||
protected:
|
||||
void RegisterEndpoint(std::unique_ptr<MockEndpointChannel> channel,
|
||||
bool should_close = true) {
|
||||
CountDownLatch done(1);
|
||||
auto done = std::make_shared<CountDownLatch>(1);
|
||||
if (should_close) {
|
||||
ON_CALL(*channel, Close(_))
|
||||
.WillByDefault(
|
||||
[&done](DisconnectionReason reason) { done.CountDown(); });
|
||||
[done](DisconnectionReason reason) { done->CountDown(); });
|
||||
}
|
||||
EXPECT_CALL(*channel, GetMedium()).WillRepeatedly(Return(Medium::BLE));
|
||||
EXPECT_CALL(*channel, GetLastReadTimestamp())
|
||||
@@ -124,7 +128,7 @@ class EndpointManagerTest : public ::testing::Test {
|
||||
connection_options_, std::move(channel), listener_,
|
||||
connection_token_);
|
||||
if (should_close) {
|
||||
EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_TRUE(done->Await(absl::Milliseconds(1000)).result());
|
||||
}
|
||||
}
|
||||
SetSafeToDisconnect set_safe_to_disconnect_{true, true, 5};
|
||||
@@ -429,6 +433,70 @@ TEST_F(EndpointManagerTest, TryDecrypt) {
|
||||
RegisterEndpoint(std::move(endpoint_channel));
|
||||
}
|
||||
|
||||
TEST_F(EndpointManagerTest,
|
||||
FilterUnconfirmedFrames_DiscardsPayloadBeforeConfirmation) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kFilterUnconfirmedEndpointFrames,
|
||||
true);
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
|
||||
header.set_total_size(1024);
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(150);
|
||||
chunk.set_flags(1);
|
||||
std::string payload_bytes = parser::ForDataPayloadTransfer(header, chunk);
|
||||
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
|
||||
auto payload_processor = std::make_unique<MockFrameProcessor>();
|
||||
EXPECT_CALL(*payload_processor, OnIncomingFrame).Times(0);
|
||||
EXPECT_CALL(*payload_processor, OnEndpointDisconnect);
|
||||
EXPECT_CALL(*endpoint_channel, Read())
|
||||
.WillOnce(Return(ExceptionOr<ByteArray>(ByteArray(payload_bytes))))
|
||||
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
|
||||
EXPECT_CALL(*endpoint_channel, Write(_))
|
||||
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
|
||||
em_.RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER,
|
||||
payload_processor.get());
|
||||
processors_.emplace_back(std::move(payload_processor));
|
||||
RegisterEndpoint(std::move(endpoint_channel));
|
||||
}
|
||||
|
||||
TEST_F(EndpointManagerTest,
|
||||
FilterUnconfirmedFrames_AllowsPayloadAfterConfirmation) {
|
||||
NearbyFlags::GetInstance().OverrideBoolFlagValue(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kFilterUnconfirmedEndpointFrames,
|
||||
true);
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
|
||||
header.set_total_size(1024);
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(150);
|
||||
chunk.set_flags(1);
|
||||
std::string payload_bytes = parser::ForDataPayloadTransfer(header, chunk);
|
||||
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
|
||||
auto payload_processor = std::make_unique<MockFrameProcessor>();
|
||||
EXPECT_CALL(mock_listener_.accepted_cb, Call).Times(1);
|
||||
EXPECT_CALL(*payload_processor, OnIncomingFrame).Times(1);
|
||||
EXPECT_CALL(*payload_processor, OnEndpointDisconnect);
|
||||
EXPECT_CALL(*endpoint_channel, Read())
|
||||
.WillOnce([this, payload_bytes]() {
|
||||
client_->OnConnectionAccepted(endpoint_id_);
|
||||
return ExceptionOr<ByteArray>(ByteArray(payload_bytes));
|
||||
})
|
||||
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
|
||||
EXPECT_CALL(*endpoint_channel, Write(_))
|
||||
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
|
||||
em_.RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER,
|
||||
payload_processor.get());
|
||||
processors_.emplace_back(std::move(payload_processor));
|
||||
RegisterEndpoint(std::move(endpoint_channel));
|
||||
}
|
||||
|
||||
// Regression test for b/278729669.
|
||||
//
|
||||
// During the destruction of NearbyConnections, Core (which owns ClientProxy)
|
||||
|
||||
@@ -89,6 +89,7 @@ class FakeBwuHandler : public BaseBwuHandler {
|
||||
upgraded_channel->set_read_output(
|
||||
ExceptionOr<ByteArray>(ByteArray(parser::ForBwuIntroduction(
|
||||
*handle_initialize_calls_[initialize_call_index].endpoint_id,
|
||||
/*last_endpoint_id=*/"",
|
||||
false /* supports_disabling_encryption */))));
|
||||
auto connection = std::make_unique<IncomingSocketConnection>();
|
||||
connection->channel = std::move(upgraded_channel);
|
||||
|
||||
@@ -93,6 +93,10 @@ class FakeEndpointChannel : public EndpointChannel {
|
||||
}
|
||||
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
|
||||
const std::string& endpoint_id) override {}
|
||||
void SetLocalEndpointId(const std::string& local_endpoint_id) override {
|
||||
local_endpoint_id_ = local_endpoint_id;
|
||||
}
|
||||
std::string GetLocalEndpointId() const override { return local_endpoint_id_; }
|
||||
|
||||
void set_read_output(ExceptionOr<ByteArray> output) { read_output_ = output; }
|
||||
void set_write_output(Exception output) { write_output_ = output; }
|
||||
@@ -113,6 +117,7 @@ class FakeEndpointChannel : public EndpointChannel {
|
||||
bool is_paused_ = false;
|
||||
location::nearby::proto::connections::DisconnectionReason
|
||||
disconnection_reason_;
|
||||
std::string local_endpoint_id_;
|
||||
mutable uint32_t next_keep_alive_seq_no_ = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -83,6 +83,11 @@ constexpr auto kEnableWifiDirectGcOnly =
|
||||
// by default, enable Wi-Fi Hotspot client.
|
||||
constexpr auto kEnableWifiHotspotClient =
|
||||
flags::Flag<bool>(kConfigPackage, "45648734", true);
|
||||
// Enforces frame filtering on unconfirmed endpoints in EndpointManager and
|
||||
// BaseEndpointChannel so application payloads and upgrade requests are blocked
|
||||
// before connection acceptance.
|
||||
constexpr auto kFilterUnconfirmedEndpointFrames =
|
||||
flags::Flag<bool>(kConfigPackage, "45813128", true);
|
||||
// When true, fix the BleServerSocket deadlock/use-after-free (b/494335036).
|
||||
constexpr auto kFixBleServerSocketDeadlock =
|
||||
flags::Flag<bool>(kConfigPackage, "45782647", true);
|
||||
|
||||
@@ -248,6 +248,7 @@ cc_test(
|
||||
"//connections/implementation:client_proxy",
|
||||
"//connections/implementation:endpoint_channel",
|
||||
"//connections/implementation:offline_frames",
|
||||
"//connections/implementation:service_id_constants",
|
||||
"//connections/implementation/flags:connections_flags",
|
||||
"//internal/flags:nearby_flags",
|
||||
"//internal/platform:base",
|
||||
|
||||
@@ -29,7 +29,6 @@ cc_library(
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:util",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -45,7 +44,6 @@ cc_library(
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:types",
|
||||
"//internal/platform:util",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -54,9 +52,7 @@ cc_library(
|
||||
srcs = ["advertisement_util.cc"],
|
||||
hdrs = ["advertisement_util.h"],
|
||||
deps = [
|
||||
":dct_advertisement",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:util",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
],
|
||||
@@ -79,8 +75,6 @@ cc_test(
|
||||
srcs = ["dct_advertisement_test.cc"],
|
||||
deps = [
|
||||
":dct_advertisement",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:util",
|
||||
"//internal/platform/implementation/g3",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
@@ -93,7 +87,6 @@ cc_test(
|
||||
deps = [
|
||||
":util",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:util",
|
||||
"//internal/platform/implementation/g3",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
|
||||
@@ -129,7 +129,8 @@ std::optional<DctAdvertisement> DctAdvertisement::Parse(
|
||||
LOG(WARNING) << "Failed to read device information.";
|
||||
return std::nullopt;
|
||||
}
|
||||
if (device_information->type() != kDataTypeDeviceInformation) {
|
||||
if (device_information->type() != kDataTypeDeviceInformation ||
|
||||
device_information->value().empty()) {
|
||||
LOG(WARNING) << "Invalid device information.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -113,5 +113,10 @@ TEST(DctAdvertisementTest, ParseData) {
|
||||
EXPECT_EQ(dct_advertisement->GetPsm(), 192);
|
||||
}
|
||||
|
||||
TEST(DctAdvertisementTest, ParseWithEmptyDeviceInformationDataElement) {
|
||||
std::string data = std::string("\x20\x25\0\0\x24\0\0\x07", 8);
|
||||
EXPECT_FALSE(DctAdvertisement::Parse(data).has_value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::connections::advertisements::ble
|
||||
|
||||
@@ -182,6 +182,7 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
|
||||
OperationResultCode::NEARBY_AWDL_ENDPOINT_CHANNEL_CREATION_FAILURE)};
|
||||
}
|
||||
|
||||
awdl_medium_.StopDiscovery(upgrade_service_id);
|
||||
return {std::move(channel)};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
#include "internal/platform/mock_input_stream.h"
|
||||
#include "internal/platform/mock_output_stream.h"
|
||||
#include "internal/platform/nsd_service_info.h"
|
||||
#include "internal/platform/output_stream.h"
|
||||
#include "connections/implementation/service_id_constants.h"
|
||||
|
||||
|
||||
namespace nearby {
|
||||
|
||||
@@ -175,7 +176,9 @@ TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*awdl_medium_mock, ConnectToService(_, _, _))
|
||||
.WillOnce(Return(ByMove(std::move(awdl_socket))));
|
||||
|
||||
@@ -191,6 +194,8 @@ TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) {
|
||||
path_info);
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_FALSE(mediums_.GetAwdl().IsDiscovering(
|
||||
WrapInitiatorUpgradeServiceId(kServiceId)));
|
||||
}
|
||||
|
||||
TEST_F(AwdlBwuHandlerTest,
|
||||
|
||||
@@ -66,8 +66,7 @@ constexpr absl::Duration kAdvertisementHeaderExpiry = absl::Seconds(15);
|
||||
// Private c'tor for testing.
|
||||
DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
|
||||
bool is_extended_advertisement_available, bool start_fetch_executor)
|
||||
: is_extended_advertisement_available_(
|
||||
is_extended_advertisement_available),
|
||||
: is_extended_advertisement_available_(is_extended_advertisement_available),
|
||||
start_fetch_executor_(start_fetch_executor) {}
|
||||
|
||||
DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
|
||||
@@ -75,9 +74,7 @@ DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
|
||||
: DiscoveredPeripheralTracker(is_extended_advertisement_available,
|
||||
/*start_fetch_executor=*/true) {}
|
||||
|
||||
DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() {
|
||||
Shutdown();
|
||||
}
|
||||
DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() { Shutdown(); }
|
||||
|
||||
void DiscoveredPeripheralTracker::StartFetchExecutorIfNeeded() {
|
||||
if (executor_ != nullptr) {
|
||||
@@ -199,7 +196,8 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement(
|
||||
return;
|
||||
}
|
||||
|
||||
if (advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) {
|
||||
if (!dct_service_id_hash_to_service_id_map_.empty() &&
|
||||
advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) {
|
||||
std::optional<BleAdvertisementData> dct_advertisement_data =
|
||||
HandleDctAdvertisement(advertisement_data);
|
||||
|
||||
@@ -749,15 +747,14 @@ void DiscoveredPeripheralTracker::HandleAdvertisementHeader(
|
||||
// support extended advertisement.
|
||||
if (!advertisement_header.IsSupportExtendedAdvertisement()) {
|
||||
for (auto& item : service_id_infos_) {
|
||||
item.second.discovered_peripheral_callback
|
||||
.legacy_device_discovered_cb();
|
||||
item.second.discovered_peripheral_callback.legacy_device_discovered_cb();
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether or not we need to read a fresh GATT advertisement.
|
||||
VLOG(1) << "Handle GATT advertisement header with hash "
|
||||
<< absl::BytesToHexString(
|
||||
advertisement_header.GetAdvertisementHash().AsStringView())
|
||||
advertisement_header.GetAdvertisementHash().AsStringView())
|
||||
<< " in thread";
|
||||
|
||||
if (!ShouldReadRawAdvertisementFromServer(advertisement_header)) {
|
||||
@@ -1015,7 +1012,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() {
|
||||
}
|
||||
if (!found_task) {
|
||||
LOG(WARNING) << "No task found, skip to fetch raw advertisement.";
|
||||
continue;;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the task is expired.
|
||||
@@ -1027,8 +1024,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() {
|
||||
.AsStringView())
|
||||
<< " is expired, skip to fetch raw advertisement.";
|
||||
} else {
|
||||
FetchRawAdvertisementsInThread(task.peripheral,
|
||||
task.advertisement_header,
|
||||
FetchRawAdvertisementsInThread(task.peripheral, task.advertisement_header,
|
||||
std::move(task.advertisement_fetcher));
|
||||
}
|
||||
// Clear in progress header after the task is done.
|
||||
|
||||
@@ -60,7 +60,8 @@ class WifiDirect {
|
||||
bool IsGOStarted() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
// Start WifiDirect Group Owner. Returns true if WifiDirect GO is successfully
|
||||
// started.
|
||||
bool StartWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool StartWifiDirect()
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
// Stop WifiDirect Group Owner
|
||||
bool StopWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@ WifiDirectBwuHandler::WifiDirectBwuHandler(
|
||||
std::string WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
|
||||
ClientProxy* client, const std::string& upgrade_service_id,
|
||||
const std::string& endpoint_id) {
|
||||
auto remote_device_name = client->GetRemoteDeviceName(endpoint_id);
|
||||
WifiDirectCredentials* wifi_direct_crendential =
|
||||
wifi_direct_medium_.GetCredentials(upgrade_service_id);
|
||||
wifi_direct_crendential->SetRemoteDeviceName(remote_device_name);
|
||||
|
||||
// Create WifiDirect GO
|
||||
if (!wifi_direct_medium_.StartWifiDirect()) {
|
||||
LOG(INFO) << "Failed to start Wifi Direct!";
|
||||
@@ -82,7 +87,7 @@ std::string WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
|
||||
// Note: Credentials are not generated until Medium StartWifiDirect() is
|
||||
// called and the server socket is created. Be careful moving this codeblock
|
||||
// around.
|
||||
WifiDirectCredentials* wifi_direct_crendential =
|
||||
wifi_direct_crendential =
|
||||
wifi_direct_medium_.GetCredentials(upgrade_service_id);
|
||||
std::string ssid = wifi_direct_crendential->GetSSID();
|
||||
std::string password = wifi_direct_crendential->GetPassword();
|
||||
|
||||
@@ -194,7 +194,9 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel(
|
||||
}
|
||||
// Add gateway and port to address candidates if address candidates is empty.
|
||||
if (service_addresses.empty() &&
|
||||
upgrade_path_info_credentials.has_gateway()) {
|
||||
upgrade_path_info_credentials.has_gateway() &&
|
||||
upgrade_path_info_credentials.port() > 0 &&
|
||||
upgrade_path_info_credentials.port() <= 65535) {
|
||||
std::vector<char> address_bytes =
|
||||
GatewayToAddressBytes(upgrade_path_info_credentials.gateway());
|
||||
if (!address_bytes.empty()) {
|
||||
@@ -230,7 +232,8 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel(
|
||||
LOG(ERROR) << "WifiHotspotBwuHandler failed to connect to the WifiHotspot "
|
||||
"service for endpoint "
|
||||
<< endpoint_id;
|
||||
return {Error(socket_result.error().operation_result_code().value())};
|
||||
return {Error(socket_result.error().operation_result_code().value_or(
|
||||
OperationResultCode::DETAIL_UNKNOWN))};
|
||||
}
|
||||
VLOG(1)
|
||||
<< "WifiHotspotBwuHandler successfully connected to WifiHotspot service "
|
||||
|
||||
@@ -55,8 +55,9 @@ class WifiHotspotTest : public testing::Test {
|
||||
~WifiHotspotTest() override { env_.Stop(); }
|
||||
void SetUp() override {
|
||||
nearby::NearbyFlags::GetInstance().OverrideInt64FlagValue(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionIntervalMillis, 1);
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionIntervalMillis,
|
||||
1);
|
||||
}
|
||||
void TearDown() override {
|
||||
nearby::NearbyFlags::GetInstance().ResetOverridedValues();
|
||||
@@ -89,9 +90,10 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) {
|
||||
ExceptionOr<OfflineFrame> upgrade_frame;
|
||||
|
||||
auto handler_1 = std::make_unique<WifiHotspotBwuHandler>(
|
||||
&mediums_HS_ap.GetWifiHotspot(), [&](ClientProxy* client,
|
||||
std::unique_ptr<BwuHandler::IncomingSocketConnection>
|
||||
mutable_connection) {
|
||||
&mediums_HS_ap.GetWifiHotspot(),
|
||||
[&](ClientProxy* client,
|
||||
std::unique_ptr<BwuHandler::IncomingSocketConnection>
|
||||
mutable_connection) {
|
||||
LOG(INFO) << "Server socket connection accept call back, Socket name: "
|
||||
<< mutable_connection->socket->ToString();
|
||||
accept_latch.CountDown();
|
||||
@@ -169,5 +171,42 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) {
|
||||
EXPECT_FALSE(mediums_HS_sta.GetWifiHotspot().IsConnectedToHotspot());
|
||||
}
|
||||
|
||||
TEST_F(WifiHotspotTest, CreateUpgradedEndpointChannel_RejectGatewayPort0) {
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointID));
|
||||
Mediums mediums;
|
||||
WifiHotspotBwuHandler handler(&mediums.GetWifiHotspot(), nullptr);
|
||||
|
||||
UpgradePathInfo path_info;
|
||||
auto* credentials = path_info.mutable_wifi_hotspot_credentials();
|
||||
credentials->set_ssid("SSID");
|
||||
credentials->set_password("password");
|
||||
credentials->set_gateway("192.168.43.1");
|
||||
|
||||
// Port 0
|
||||
credentials->set_port(0);
|
||||
auto result = handler.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
|
||||
EXPECT_TRUE(result.has_error());
|
||||
EXPECT_EQ(result.error().operation_result_code().value(),
|
||||
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
|
||||
|
||||
// Port > 65535
|
||||
credentials->set_port(65536);
|
||||
result = handler.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
|
||||
EXPECT_TRUE(result.has_error());
|
||||
EXPECT_EQ(result.error().operation_result_code().value(),
|
||||
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
|
||||
|
||||
// Port < 0
|
||||
credentials->set_port(-1);
|
||||
result = handler.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
|
||||
EXPECT_TRUE(result.has_error());
|
||||
EXPECT_EQ(result.error().operation_result_code().value(),
|
||||
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -79,21 +79,42 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel(
|
||||
<< address_candidate.ip_address().size();
|
||||
continue;
|
||||
}
|
||||
if (service_address.IsLoopbackAddress() ||
|
||||
service_address.IsLinkLocalAddress()) {
|
||||
LOG(WARNING) << "Loopback/link-local address candidate is rejected.";
|
||||
return {
|
||||
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
|
||||
}
|
||||
address_candidates.push_back(std::move(service_address));
|
||||
}
|
||||
// Only use ip_address and wifi_port if address_candidates is empty.
|
||||
if (address_candidates.empty()) {
|
||||
address_candidates.push_back(ServiceAddress{
|
||||
.address =
|
||||
std::vector<char>(upgrade_path_info_socket.ip_address().begin(),
|
||||
upgrade_path_info_socket.ip_address().end()),
|
||||
.port = static_cast<uint16_t>(upgrade_path_info_socket.wifi_port())});
|
||||
if (upgrade_path_info_socket.ip_address().size() != 4 ||
|
||||
upgrade_path_info_socket.wifi_port() <= 0 ||
|
||||
upgrade_path_info_socket.wifi_port() > 65535) {
|
||||
LOG(ERROR) << "WifiLanBwuHandler: fallback ip_address size is not 4 "
|
||||
<< "or port is invalid (IPv4 only).";
|
||||
return {
|
||||
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_IP_ADDRESS_ERROR)};
|
||||
}
|
||||
ServiceAddress service_address;
|
||||
service_address.address = {upgrade_path_info_socket.ip_address().begin(),
|
||||
upgrade_path_info_socket.ip_address().end()};
|
||||
service_address.port =
|
||||
static_cast<uint16_t>(upgrade_path_info_socket.wifi_port());
|
||||
if (service_address.IsLoopbackAddress() ||
|
||||
service_address.IsLinkLocalAddress()) {
|
||||
LOG(WARNING) << "Loopback/link-local fallback address is rejected.";
|
||||
return {
|
||||
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
|
||||
}
|
||||
address_candidates.push_back(std::move(service_address));
|
||||
}
|
||||
Error error;
|
||||
for (const auto& address_candidate : address_candidates) {
|
||||
VLOG(1) << "WifiLanBwuHandler is attempting to connect to available "
|
||||
"WifiLan service (" << address_candidate << ") for endpoint "
|
||||
<< endpoint_id;
|
||||
"WifiLan service ("
|
||||
<< address_candidate << ") for endpoint " << endpoint_id;
|
||||
std::shared_ptr<CancellationFlag> cancellation_flag =
|
||||
client->GetCancellationFlag(endpoint_id);
|
||||
ErrorOr<WifiLanSocket> socket_result = wifi_lan_medium_.Connect(
|
||||
@@ -102,7 +123,8 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel(
|
||||
LOG(ERROR)
|
||||
<< "WifiLanBwuHandler failed to connect to the WifiLan service ("
|
||||
<< address_candidate << ") for endpoint " << endpoint_id;
|
||||
error = Error(socket_result.error().operation_result_code().value());
|
||||
error = Error(socket_result.error().operation_result_code().value_or(
|
||||
OperationResultCode::DETAIL_UNKNOWN));
|
||||
continue;
|
||||
}
|
||||
VLOG(1) << "WifiLanBwuHandler successfully connected to WifiLan service ("
|
||||
|
||||
@@ -209,6 +209,98 @@ TEST_F(WifiLanBwuHandlerTest,
|
||||
EXPECT_TRUE(result.has_value());
|
||||
};
|
||||
|
||||
TEST_F(WifiLanBwuHandlerTest,
|
||||
CreateUpgradedEndpointChannel_RejectLoopbackAndLinkLocalCandidates) {
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointId));
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
|
||||
|
||||
// 1st candidate: Loopback
|
||||
auto* address_candidate =
|
||||
path_info.mutable_wifi_lan_socket()->add_address_candidates();
|
||||
address_candidate->set_ip_address(std::string("\x7f\x00\x00\x01", 4));
|
||||
address_candidate->set_port(8080);
|
||||
|
||||
// 2nd candidate: Link-Local (169.254.1.1)
|
||||
address_candidate =
|
||||
path_info.mutable_wifi_lan_socket()->add_address_candidates();
|
||||
address_candidate->set_ip_address("\xa9\xfe\x01\x01");
|
||||
address_candidate->set_port(8080);
|
||||
|
||||
// 3rd candidate: Valid IP
|
||||
address_candidate =
|
||||
path_info.mutable_wifi_lan_socket()->add_address_candidates();
|
||||
address_candidate->set_ip_address(kIpv4Address);
|
||||
address_candidate->set_port(8080);
|
||||
|
||||
auto result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId),
|
||||
std::move(path_info));
|
||||
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(WifiLanBwuHandlerTest,
|
||||
CreateUpgradedEndpointChannel_RejectLoopbackFallbackIp) {
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointId));
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
|
||||
path_info.mutable_wifi_lan_socket()->set_ip_address(
|
||||
std::string("\x7f\x00\x00\x01", 4));
|
||||
path_info.mutable_wifi_lan_socket()->set_wifi_port(8080);
|
||||
|
||||
auto result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId),
|
||||
std::move(path_info));
|
||||
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(WifiLanBwuHandlerTest,
|
||||
CreateUpgradedEndpointChannel_RejectInvalidFallbackIpLength) {
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointId));
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
|
||||
path_info.mutable_wifi_lan_socket()->set_ip_address("123");
|
||||
path_info.mutable_wifi_lan_socket()->set_wifi_port(8080);
|
||||
|
||||
auto result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId),
|
||||
std::move(path_info));
|
||||
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(WifiLanBwuHandlerTest,
|
||||
CreateUpgradedEndpointChannel_RejectFallbackPort0) {
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointId));
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
|
||||
path_info.mutable_wifi_lan_socket()->set_ip_address(kIpv4Address);
|
||||
|
||||
// Port 0
|
||||
path_info.mutable_wifi_lan_socket()->set_wifi_port(0);
|
||||
auto result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
|
||||
EXPECT_FALSE(result.has_value());
|
||||
|
||||
// Port > 65535
|
||||
path_info.mutable_wifi_lan_socket()->set_wifi_port(65536);
|
||||
result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
|
||||
EXPECT_FALSE(result.has_value());
|
||||
|
||||
// Port < 0
|
||||
path_info.mutable_wifi_lan_socket()->set_wifi_port(-1);
|
||||
result = handler_.CreateUpgradedEndpointChannel(
|
||||
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(WifiLanBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) {
|
||||
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
|
||||
ClientProxy client;
|
||||
@@ -289,9 +381,8 @@ TEST_F(WifiLanBwuHandlerTest,
|
||||
mediums_.GetWifiLan().IsAcceptingConnections("service_id_UPGRADE"));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
WifiLanBwuHandlerTest,
|
||||
InitializeUpgradedMediumForEndpoint_AlreadyAccepting_KeepAccepting) {
|
||||
TEST_F(WifiLanBwuHandlerTest,
|
||||
InitializeUpgradedMediumForEndpoint_AlreadyAccepting_KeepAccepting) {
|
||||
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
|
||||
ClientProxy client;
|
||||
client.AddCancellationFlag(std::string(kEndpointId));
|
||||
|
||||
@@ -69,6 +69,9 @@ class MockEndpointChannel : public EndpointChannel {
|
||||
MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override));
|
||||
MOCK_METHOD(void, SetAnalyticsRecorder,
|
||||
(analytics::AnalyticsRecorder*, const std::string&), (override));
|
||||
MOCK_METHOD(void, SetLocalEndpointId, (const std::string& local_endpoint_id),
|
||||
(override));
|
||||
MOCK_METHOD(std::string, GetLocalEndpointId, (), (const, override));
|
||||
};
|
||||
|
||||
} // namespace nearby::connections
|
||||
|
||||
@@ -180,7 +180,8 @@ std::string ForConnectionRequestPresence(
|
||||
return frame.SerializeAsString();
|
||||
}
|
||||
|
||||
std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info) {
|
||||
std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info,
|
||||
const std::string& device_name) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
@@ -201,6 +202,7 @@ std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info) {
|
||||
NearbyFlags::GetInstance().GetInt64Flag(
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kSafeToDisconnectVersion));
|
||||
sub_frame->set_wifi_direct_device_name(device_name);
|
||||
|
||||
return frame.SerializeAsString();
|
||||
}
|
||||
@@ -460,6 +462,7 @@ std::string ForBwuSafeToClose() {
|
||||
}
|
||||
|
||||
std::string ForBwuIntroduction(const std::string& endpoint_id,
|
||||
const std::string& last_endpoint_id,
|
||||
bool supports_disabling_encryption) {
|
||||
OfflineFrame frame;
|
||||
|
||||
@@ -473,6 +476,9 @@ std::string ForBwuIntroduction(const std::string& endpoint_id,
|
||||
client_introduction->set_endpoint_id(endpoint_id);
|
||||
client_introduction->set_supports_disabling_encryption(
|
||||
supports_disabling_encryption);
|
||||
if (!last_endpoint_id.empty()) {
|
||||
client_introduction->set_last_endpoint_id(last_endpoint_id);
|
||||
}
|
||||
|
||||
return frame.SerializeAsString();
|
||||
}
|
||||
@@ -498,16 +504,14 @@ std::string ForBwuFailure(const UpgradePathInfo& info) {
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
sub_frame->set_event_type(BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
*upgrade_path_info = info;
|
||||
|
||||
*sub_frame->mutable_upgrade_path_info() = info;
|
||||
|
||||
return frame.SerializeAsString();
|
||||
}
|
||||
|
||||
std::string ForBwuPathRequest(const std::vector<Medium>& mediums,
|
||||
const MediumRole& medium_role) {
|
||||
std::string ForBwuPathRequest(Medium medium, const std::vector<Medium>& mediums,
|
||||
const MediumRole& medium_role,
|
||||
bool supports_5_ghz) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
@@ -516,11 +520,16 @@ std::string ForBwuPathRequest(const std::vector<Medium>& mediums,
|
||||
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
sub_frame->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_REQUEST);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(MediumToUpgradePathInfoMedium(medium));
|
||||
auto* upgrade_path_request =
|
||||
sub_frame->mutable_upgrade_path_info()->mutable_upgrade_path_request();
|
||||
upgrade_path_info->mutable_upgrade_path_request();
|
||||
for (const auto& medium : mediums) {
|
||||
upgrade_path_request->add_mediums(MediumToUpgradePathInfoMedium(medium));
|
||||
}
|
||||
LOG(INFO) << "ForBwuPathRequest: supports_5_ghz: " << supports_5_ghz;
|
||||
upgrade_path_request->mutable_medium_meta_data()->set_supports_5_ghz(
|
||||
supports_5_ghz);
|
||||
auto* role =
|
||||
upgrade_path_request->mutable_medium_meta_data()->mutable_medium_role();
|
||||
role->MergeFrom(medium_role);
|
||||
|
||||
@@ -59,7 +59,8 @@ std::string ForConnectionRequestPresence(
|
||||
const location::nearby::connections::PresenceDevice& proto_presence_device,
|
||||
const ConnectionInfo& connection_info);
|
||||
std::string ForConnectionResponse(
|
||||
std::int32_t status, const location::nearby::connections::OsInfo& os_info);
|
||||
std::int32_t status, const location::nearby::connections::OsInfo& os_info,
|
||||
const std::string& device_name);
|
||||
|
||||
// Builds Payload transfer messages.
|
||||
std::string ForDataPayloadTransfer(
|
||||
@@ -76,6 +77,7 @@ std::string ForPayloadAckPayloadTransfer(std::int64_t payload_id);
|
||||
|
||||
// Builds Bandwidth Upgrade [BWU] messages.
|
||||
std::string ForBwuIntroduction(const std::string& endpoint_id,
|
||||
const std::string& last_endpoint_id,
|
||||
bool supports_disabling_encryption);
|
||||
std::string ForBwuIntroductionAck();
|
||||
std::string ForBwuWifiHotspotPathAvailable(
|
||||
@@ -107,8 +109,9 @@ std::string ForBwuWebrtcPathAvailable(
|
||||
const location::nearby::connections::LocationHint& location_hint_a);
|
||||
std::string ForBwuFailure(const UpgradePathInfo& info);
|
||||
std::string ForBwuPathRequest(
|
||||
const std::vector<Medium>& mediums,
|
||||
const location::nearby::connections::MediumRole& medium_role);
|
||||
Medium medium, const std::vector<Medium>& mediums,
|
||||
const location::nearby::connections::MediumRole& medium_role,
|
||||
bool supports_5_ghz);
|
||||
std::string ForBwuLastWrite();
|
||||
std::string ForBwuSafeToClose();
|
||||
|
||||
|
||||
@@ -352,6 +352,7 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) {
|
||||
os_info { type: LINUX }
|
||||
multiplex_socket_bitmask: 0
|
||||
safe_to_disconnect_version: 5
|
||||
wifi_direct_device_name: "device_name"
|
||||
>
|
||||
>)pb";
|
||||
|
||||
@@ -361,7 +362,8 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) {
|
||||
config_package_nearby::nearby_connections_feature::
|
||||
kSafeToDisconnectVersion,
|
||||
5);
|
||||
auto response = FromBytes(ForConnectionResponse(1, os_info));
|
||||
auto response = FromBytes(
|
||||
ForConnectionResponse(1, os_info, "device_name"));
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = response.result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
@@ -502,10 +504,7 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) {
|
||||
ip_address: "\x2a\x00\x79\xe0\x2e\x87\x00\x06\xb7\x28\x67\x45\x7a\xdd\x01\x53"
|
||||
port: 1234
|
||||
>
|
||||
address_candidates: <
|
||||
ip_address: "\001\002\003\004"
|
||||
port: 1234
|
||||
>
|
||||
address_candidates: < ip_address: "\001\002\003\004" port: 1234 >
|
||||
>
|
||||
supports_client_introduction_ack: true
|
||||
>
|
||||
@@ -679,11 +678,13 @@ TEST(OfflineFramesTest, CanGenerateBwuIntroduction) {
|
||||
client_introduction: <
|
||||
endpoint_id: "ABC"
|
||||
supports_disabling_encryption: false
|
||||
last_endpoint_id: "DEF"
|
||||
>
|
||||
>
|
||||
>)pb";
|
||||
auto response = FromBytes(ForBwuIntroduction(
|
||||
std::string(kEndpointId), false /* supports_disabling_encryption */));
|
||||
auto response =
|
||||
FromBytes(ForBwuIntroduction(std::string(kEndpointId), "DEF",
|
||||
false /* supports_disabling_encryption */));
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = response.result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
@@ -722,7 +723,6 @@ TEST(OfflineFramesTest, CanGenerateDisconnection) {
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
|
||||
constexpr absl::string_view kExpected =
|
||||
R"pb(
|
||||
@@ -732,9 +732,11 @@ TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
|
||||
bandwidth_upgrade_negotiation: <
|
||||
event_type: UPGRADE_PATH_REQUEST
|
||||
upgrade_path_info: <
|
||||
medium: WIFI_HOTSPOT
|
||||
upgrade_path_request: <
|
||||
mediums: WIFI_HOTSPOT
|
||||
medium_meta_data: <
|
||||
supports_5_ghz: true
|
||||
medium_role: < support_wifi_hotspot_client: true >
|
||||
>
|
||||
>
|
||||
@@ -745,7 +747,9 @@ TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
|
||||
mediums.push_back(Medium::WIFI_HOTSPOT);
|
||||
MediumRole medium_role;
|
||||
medium_role.set_support_wifi_hotspot_client(true);
|
||||
auto response = FromBytes(ForBwuPathRequest(mediums, medium_role));
|
||||
auto response =
|
||||
FromBytes(ForBwuPathRequest(Medium::WIFI_HOTSPOT, mediums, medium_role,
|
||||
/*supports_5_ghz=*/true));
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = response.result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <regex> //NOLINT
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "connections/implementation/internal_payload.h"
|
||||
#include "connections/implementation/offline_frames.h"
|
||||
@@ -26,9 +28,12 @@
|
||||
#include "connections/medium_selector.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/platform/service_address.h"
|
||||
#include "sharing/internal/base/utf_string_conversions.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
namespace parser {
|
||||
namespace {
|
||||
|
||||
@@ -72,7 +77,12 @@ constexpr int kWifiDirectPinMinLength = 0;
|
||||
constexpr int kWifiDirectPinMaxLength = 16;
|
||||
|
||||
inline bool WithinRange(int value, int min, int max) {
|
||||
return value >= min && value < max;
|
||||
return value >= min && value <= max;
|
||||
}
|
||||
|
||||
bool IsValidWifiLanServiceAddress(const ServiceAddress& service_address) {
|
||||
return !service_address.IsLoopbackAddress() &&
|
||||
!service_address.IsLinkLocalAddress();
|
||||
}
|
||||
|
||||
Exception EnsureValidConnectionRequestFrame(
|
||||
@@ -140,16 +150,25 @@ Exception EnsureValidPayloadTransferControlFrame(
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
bool CheckForIllegalCharacters(std::string toBeValidated,
|
||||
bool CheckForIllegalCharacters(absl::string_view toBeValidated,
|
||||
const absl::string_view illegalPatterns[],
|
||||
size_t illegalPatternsSize) {
|
||||
if (toBeValidated.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Null bytes are rejected to prevent null-byte injection attacks. C-style
|
||||
// APIs (like system file operations) treat '\0' as a string terminator,
|
||||
// whereas C++ strings can contain them. This discrepancy can lead to
|
||||
// validation bypasses (e.g., validating "file.sh\0.png" as a PNG but
|
||||
// creating "file.sh" on disk).
|
||||
if (absl::StrContains(toBeValidated, '\0') ||
|
||||
!nearby::utils::IsStringUtf8(toBeValidated)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int index = 0; index < illegalPatternsSize; index++) {
|
||||
if (toBeValidated.find(std::string(illegalPatterns[index])) !=
|
||||
std::string::npos) {
|
||||
if (absl::StrContains(toBeValidated, illegalPatterns[index])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -178,20 +197,21 @@ Exception EnsureValidPayloadTransferFrame(const PayloadTransferFrame& frame) {
|
||||
location::nearby::connections::PayloadTransferFrame::PayloadHeader::
|
||||
FILE) {
|
||||
if (frame.payload_header().has_file_name()) {
|
||||
if (CheckForIllegalCharacters(frame.payload_header().file_name(),
|
||||
kIllegalFileNamePatterns,
|
||||
const std::string& file_name = frame.payload_header().file_name();
|
||||
if (CheckForIllegalCharacters(file_name, kIllegalFileNamePatterns,
|
||||
kIllegalFileNamePatternsSize)) {
|
||||
LOG(ERROR) << "File name " << frame.payload_header().file_name()
|
||||
<< " has illegal characters";
|
||||
LOG(ERROR) << "File name (hex) " << absl::BytesToHexString(file_name)
|
||||
<< " has illegal characters or invalid UTF-8";
|
||||
return {Exception::kIllegalCharacters};
|
||||
}
|
||||
}
|
||||
if (frame.payload_header().has_parent_folder()) {
|
||||
if (CheckForIllegalCharacters(frame.payload_header().parent_folder(),
|
||||
kIllegalParentFolderPatterns,
|
||||
const std::string& parent_folder = frame.payload_header().parent_folder();
|
||||
if (CheckForIllegalCharacters(parent_folder, kIllegalParentFolderPatterns,
|
||||
kIllegalParentFolderPatternsSize)) {
|
||||
LOG(ERROR) << "Parent folder " << frame.payload_header().parent_folder()
|
||||
<< " has illegal characters";
|
||||
LOG(ERROR) << "Parent folder (hex) "
|
||||
<< absl::BytesToHexString(parent_folder)
|
||||
<< " has illegal characters or invalid UTF-8";
|
||||
return {Exception::kIllegalCharacters};
|
||||
}
|
||||
}
|
||||
@@ -234,21 +254,29 @@ Exception EnsureValidBandwidthUpgradeWifiHotspotPathAvailableFrame(
|
||||
!WithinRange(wifi_hotspot_credentials.password().length(),
|
||||
kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength))
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
if (!wifi_hotspot_credentials.has_gateway() &&
|
||||
wifi_hotspot_credentials.address_candidates_size() == 0)
|
||||
|
||||
if ((!wifi_hotspot_credentials.has_gateway() ||
|
||||
wifi_hotspot_credentials.gateway().empty()) &&
|
||||
wifi_hotspot_credentials.address_candidates_size() == 0) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
const std::regex ip4_pattern(std::string(kIpv4PatternString).c_str());
|
||||
if (!wifi_hotspot_credentials.gateway().empty() &&
|
||||
!(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern))) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
for (const auto& address_candidate :
|
||||
wifi_hotspot_credentials.address_candidates()) {
|
||||
if (!address_candidate.has_ip_address() || !address_candidate.has_port()) {
|
||||
|
||||
const std::regex ip4_pattern(std::string(kIpv4PatternString).c_str());
|
||||
if (wifi_hotspot_credentials.has_gateway() &&
|
||||
!wifi_hotspot_credentials.gateway().empty()) {
|
||||
if (!(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern))) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
if (address_candidate.ip_address().size() != 4 &&
|
||||
address_candidate.ip_address().size() != 16) {
|
||||
if (!wifi_hotspot_credentials.has_port() ||
|
||||
!WithinRange(wifi_hotspot_credentials.port(), 1, 65535)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& address_candidate :
|
||||
wifi_hotspot_credentials.address_candidates()) {
|
||||
ServiceAddress service_address;
|
||||
if (!ServiceAddressFromProto(address_candidate, service_address)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
}
|
||||
@@ -265,6 +293,29 @@ Exception EnsureValidBandwidthUpgradeWifiLanPathAvailableFrame(
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
|
||||
if (wifi_lan_socket.has_ip_address()) {
|
||||
location::nearby::connections::ServiceAddress proto;
|
||||
proto.set_ip_address(wifi_lan_socket.ip_address());
|
||||
proto.set_port(wifi_lan_socket.wifi_port());
|
||||
ServiceAddress service_address;
|
||||
if (!ServiceAddressFromProto(proto, service_address)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
if (!IsValidWifiLanServiceAddress(service_address)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& address_candidate : wifi_lan_socket.address_candidates()) {
|
||||
ServiceAddress service_address;
|
||||
if (!ServiceAddressFromProto(address_candidate, service_address)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
if (!IsValidWifiLanServiceAddress(service_address)) {
|
||||
return {Exception::kInvalidProtocolBuffer};
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility reasons, no other fields should be null-checked
|
||||
// for this frame. Parameter checking (eg. must be within this range) is fine.
|
||||
return {Exception::kSuccess};
|
||||
@@ -292,7 +343,7 @@ Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame(
|
||||
std::string(kWifiDirectSsidPatternString).c_str());
|
||||
bool ssid_valid =
|
||||
wifi_direct_credentials.has_ssid() &&
|
||||
wifi_direct_credentials.ssid().length() < kWifiDirectSsidMaxLength &&
|
||||
wifi_direct_credentials.ssid().length() <= kWifiDirectSsidMaxLength &&
|
||||
std::regex_match(wifi_direct_credentials.ssid(), ssid_pattern);
|
||||
bool password_valid =
|
||||
wifi_direct_credentials.has_password() &&
|
||||
@@ -300,8 +351,7 @@ Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame(
|
||||
kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength);
|
||||
bool device_name_valid =
|
||||
wifi_direct_credentials.has_device_name() &&
|
||||
wifi_direct_credentials.device_name().length() <
|
||||
kWifiDirectSsidMaxLength;
|
||||
wifi_direct_credentials.device_name().length() < kWifiDirectSsidMaxLength;
|
||||
bool pin_valid =
|
||||
wifi_direct_credentials.has_pin() &&
|
||||
WithinRange(wifi_direct_credentials.pin().length(),
|
||||
|
||||
@@ -36,6 +36,7 @@ using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame;
|
||||
using ::location::nearby::connections::OfflineFrame;
|
||||
using ::location::nearby::connections::OsInfo;
|
||||
using ::location::nearby::connections::PayloadTransferFrame;
|
||||
using ::location::nearby::connections::V1Frame;
|
||||
|
||||
constexpr absl::string_view kEndpointId{"ABC"};
|
||||
constexpr absl::string_view kEndpointName{"XYZ"};
|
||||
@@ -122,7 +123,7 @@ TEST_F(OfflineFramesConnectionRequestTest,
|
||||
ValidatesAsFailWithEmptyEndpointIdInConnectionRequestFrame) {
|
||||
connection_info_.local_endpoint_id = "";
|
||||
std::string bytes = ForConnectionRequestConnections({}, connection_info_);
|
||||
location::nearby::connections::OfflineFrame frame;
|
||||
OfflineFrame frame;
|
||||
frame.ParseFromString(bytes);
|
||||
frame.mutable_v1()->mutable_connection_request()->set_endpoint_id("");
|
||||
ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id());
|
||||
@@ -179,7 +180,8 @@ TEST(OfflineFramesValidatorTest,
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
OsInfo os_info;
|
||||
std::string bytes = ForConnectionResponse(kStatusAccepted, os_info);
|
||||
std::string bytes =
|
||||
ForConnectionResponse(kStatusAccepted, os_info, "device_name");
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
@@ -192,7 +194,8 @@ TEST(OfflineFramesValidatorTest,
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
OsInfo os_info;
|
||||
std::string bytes = ForConnectionResponse(kStatusAccepted, os_info);
|
||||
std::string bytes =
|
||||
ForConnectionResponse(kStatusAccepted, os_info, "device_name");
|
||||
offline_frame.ParseFromString(bytes);
|
||||
auto* v1_frame = offline_frame.mutable_v1();
|
||||
|
||||
@@ -208,7 +211,7 @@ TEST(OfflineFramesValidatorTest,
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
OsInfo os_info;
|
||||
std::string bytes = ForConnectionResponse(-1, os_info);
|
||||
std::string bytes = ForConnectionResponse(-1, os_info, "device_name");
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
@@ -365,6 +368,92 @@ TEST(OfflineFramesValidatorTest,
|
||||
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithNonUtf8FilePath) {
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
|
||||
header.set_total_size(100);
|
||||
header.set_file_name(std::string("hello\xffworld"));
|
||||
header.set_parent_folder(std::string());
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(0);
|
||||
chunk.set_flags(1);
|
||||
|
||||
OfflineFrame offline_frame;
|
||||
std::string bytes = ForDataPayloadTransfer(header, chunk);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidatesAsFailedTypeFileWithNonUtf8ParentFolder) {
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
|
||||
header.set_total_size(100);
|
||||
header.set_file_name(std::string("valid.txt"));
|
||||
header.set_parent_folder(std::string("folder\xff"));
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(0);
|
||||
chunk.set_flags(1);
|
||||
|
||||
OfflineFrame offline_frame;
|
||||
std::string bytes = ForDataPayloadTransfer(header, chunk);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithNullInFilePath) {
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
|
||||
header.set_total_size(100);
|
||||
header.set_file_name(std::string("hello\0world", 11));
|
||||
header.set_parent_folder(std::string());
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(0);
|
||||
chunk.set_flags(1);
|
||||
|
||||
OfflineFrame offline_frame;
|
||||
std::string bytes = ForDataPayloadTransfer(header, chunk);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidatesAsFailedTypeFileWithNullInParentFolder) {
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
header.set_id(12345);
|
||||
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
|
||||
header.set_total_size(100);
|
||||
header.set_file_name(std::string("valid.txt"));
|
||||
header.set_parent_folder(std::string("folder\0name", 11));
|
||||
chunk.set_body("payload data");
|
||||
chunk.set_offset(0);
|
||||
chunk.set_flags(1);
|
||||
|
||||
OfflineFrame offline_frame;
|
||||
std::string bytes = ForDataPayloadTransfer(header, chunk);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest, ValidatesAsFailWithNullPayloadTransferFrame) {
|
||||
PayloadTransferFrame::PayloadHeader header;
|
||||
PayloadTransferFrame::PayloadChunk chunk;
|
||||
@@ -677,6 +766,86 @@ TEST(OfflineFramesValidatorTest,
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateHotspotUpgradeFrameWithLargePortCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
|
||||
credentials;
|
||||
credentials.set_ssid(kSsid);
|
||||
credentials.set_password(kPassword);
|
||||
credentials.set_frequency(kHotspotFrequency);
|
||||
auto* candidate = credentials.mutable_address_candidates()->Add();
|
||||
candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4));
|
||||
candidate->set_port(70000);
|
||||
std::string bytes = ForBwuWifiHotspotPathAvailable(
|
||||
std::move(credentials), kSupportsDisablingEncryption);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateHotspotUpgradeFrameWithFallbackInvalidPortFails) {
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
|
||||
credentials;
|
||||
credentials.set_ssid(kSsid);
|
||||
credentials.set_password(kPassword);
|
||||
credentials.set_frequency(kHotspotFrequency);
|
||||
credentials.set_gateway(std::string(kWifiHotspotGateway));
|
||||
credentials.set_port(70000);
|
||||
std::string bytes = ForBwuWifiHotspotPathAvailable(
|
||||
std::move(credentials), kSupportsDisablingEncryption);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateHotspotUpgradeFrameWithEmptyGatewayAndNoCandidatesFails) {
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
|
||||
credentials;
|
||||
credentials.set_ssid(kSsid);
|
||||
credentials.set_password(kPassword);
|
||||
credentials.set_frequency(kHotspotFrequency);
|
||||
credentials.set_gateway("");
|
||||
std::string bytes = ForBwuWifiHotspotPathAvailable(
|
||||
std::move(credentials), kSupportsDisablingEncryption);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateHotspotUpgradeFrameWithNoGatewayAndNoCandidatesFails) {
|
||||
OfflineFrame offline_frame;
|
||||
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
|
||||
credentials;
|
||||
credentials.set_ssid(kSsid);
|
||||
credentials.set_password(kPassword);
|
||||
credentials.set_frequency(kHotspotFrequency);
|
||||
// Do not set gateway
|
||||
// Do not set address candidates
|
||||
std::string bytes = ForBwuWifiHotspotPathAvailable(
|
||||
std::move(credentials), kSupportsDisablingEncryption);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithAddressCandidatesSucceeds) {
|
||||
OfflineFrame offline_frame;
|
||||
@@ -694,6 +863,144 @@ TEST(OfflineFramesValidatorTest,
|
||||
EXPECT_TRUE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithLoopbackAddressCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
std::vector<ServiceAddress> address_candidates = {
|
||||
{{127, 0, 0, 1}, kPort},
|
||||
};
|
||||
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithLinkLocalAddressCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
std::vector<ServiceAddress> address_candidates = {
|
||||
{{169, 254, 1, 1}, kPort},
|
||||
};
|
||||
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithInvalidIpAddressSizeCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
std::vector<ServiceAddress> address_candidates = {
|
||||
{{1, 2, 3}, kPort},
|
||||
};
|
||||
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithZeroPortCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
std::vector<ServiceAddress> address_candidates = {
|
||||
{{192, 168, 1, 1}, 0},
|
||||
};
|
||||
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithLargePortCandidateFails) {
|
||||
OfflineFrame offline_frame;
|
||||
std::vector<ServiceAddress> address_candidates = {
|
||||
{{192, 168, 1, 1}, kPort},
|
||||
};
|
||||
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
|
||||
offline_frame.ParseFromString(bytes);
|
||||
|
||||
auto* negotiation =
|
||||
offline_frame.mutable_v1()->mutable_bandwidth_upgrade_negotiation();
|
||||
auto* wifi_lan_socket =
|
||||
negotiation->mutable_upgrade_path_info()->mutable_wifi_lan_socket();
|
||||
if (wifi_lan_socket->address_candidates_size() > 0) {
|
||||
wifi_lan_socket->mutable_address_candidates(0)->set_port(70000);
|
||||
}
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithFallbackLoopbackAddressFails) {
|
||||
OfflineFrame offline_frame;
|
||||
offline_frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = offline_frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
negotiation->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
|
||||
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
|
||||
wifi_lan_socket->set_ip_address(std::string({127, 0, 0, 1}));
|
||||
wifi_lan_socket->set_wifi_port(kPort);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithFallbackLinkLocalAddressFails) {
|
||||
OfflineFrame offline_frame;
|
||||
offline_frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = offline_frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
negotiation->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
|
||||
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
|
||||
wifi_lan_socket->set_ip_address(std::string({169, 254, 1, 1}));
|
||||
wifi_lan_socket->set_wifi_port(kPort);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidateWifiLanUpgradeFrameWithFallbackInvalidPortFails) {
|
||||
OfflineFrame offline_frame;
|
||||
offline_frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = offline_frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
negotiation->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
|
||||
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
|
||||
wifi_lan_socket->set_ip_address(std::string({192, 168, 1, 1}));
|
||||
wifi_lan_socket->set_wifi_port(70000);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
}
|
||||
|
||||
TEST(OfflineFramesValidatorTest,
|
||||
ValidatesAsFailWithNullBandwidthUpgradeNegotiationFrame) {
|
||||
OfflineFrame offline_frame;
|
||||
@@ -765,18 +1072,35 @@ TEST(OfflineFramesValidatorTest,
|
||||
OfflineFrame offline_frame_2;
|
||||
|
||||
std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"};
|
||||
std::string wifi_direct_pin_wrong_length = "abcefghijklmnopqrstuvwxyz";
|
||||
std::string wifi_direct_pin_wrong_length = "01234567890123456";
|
||||
std::string bytes = ForBwuWifiDirectPathAvailable(
|
||||
wifi_direct_ssid, std::string(kWifiDirectPassword), kPort,
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption,
|
||||
std::string(kGateway), std::string(kWifiDirectDeviceName),
|
||||
wifi_direct_pin_wrong_length);
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
|
||||
std::string(kWifiDirectDeviceName), wifi_direct_pin_wrong_length);
|
||||
offline_frame_1.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame_1);
|
||||
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
|
||||
std::string wifi_direct_ssid_64_length = "DIRECT-A0-" + std::string(54, 'A');
|
||||
bytes = ForBwuWifiDirectPathAvailable(
|
||||
wifi_direct_ssid_64_length, std::string(kWifiDirectPassword), kPort,
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
|
||||
std::string(kWifiDirectDeviceName), /*pin=*/"01234567890123456");
|
||||
offline_frame_2.ParseFromString(bytes);
|
||||
ret_value = EnsureValidOfflineFrame(offline_frame_2);
|
||||
EXPECT_FALSE(ret_value.Ok());
|
||||
|
||||
std::string wifi_direct_pin_16_length = "0123456789012345";
|
||||
bytes = ForBwuWifiDirectPathAvailable(
|
||||
std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort,
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
|
||||
std::string(kWifiDirectDeviceName), wifi_direct_pin_16_length);
|
||||
offline_frame_2.ParseFromString(bytes);
|
||||
ret_value = EnsureValidOfflineFrame(offline_frame_2);
|
||||
EXPECT_TRUE(ret_value.Ok());
|
||||
|
||||
std::string wifi_direct_ssid_wrong_length =
|
||||
std::string{kWifiDirectSsid} + "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
|
||||
std::string wifi_direct_device_name_wrong_length =
|
||||
@@ -784,9 +1108,8 @@ TEST(OfflineFramesValidatorTest,
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
|
||||
bytes = ForBwuWifiDirectPathAvailable(
|
||||
wifi_direct_ssid_wrong_length, std::string(kWifiDirectPassword), kPort,
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption,
|
||||
std::string(kGateway), wifi_direct_device_name_wrong_length,
|
||||
std::string(kWifiDirectPin));
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
|
||||
wifi_direct_device_name_wrong_length, std::string(kWifiDirectPin));
|
||||
offline_frame_2.ParseFromString(bytes);
|
||||
|
||||
ret_value = EnsureValidOfflineFrame(offline_frame_2);
|
||||
@@ -807,9 +1130,8 @@ TEST(OfflineFramesValidatorTest,
|
||||
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
|
||||
std::string bytes = ForBwuWifiDirectPathAvailable(
|
||||
std::string(kWifiDirectSsid), long_wifi_direct_password, kPort,
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption,
|
||||
std::string(kGateway), std::string(kWifiDirectDeviceName),
|
||||
long_wifi_direct_pin);
|
||||
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
|
||||
std::string(kWifiDirectDeviceName), long_wifi_direct_pin);
|
||||
offline_frame_2.ParseFromString(bytes);
|
||||
|
||||
auto ret_value = EnsureValidOfflineFrame(offline_frame_2);
|
||||
|
||||
@@ -307,6 +307,9 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
|
||||
<< bluetooth_classic_advertiser_client_id_;
|
||||
}
|
||||
|
||||
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
||||
|
||||
bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
||||
ble_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
||||
@@ -316,9 +319,6 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
|
||||
client->GetAdvertisingServiceId());
|
||||
}
|
||||
|
||||
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
||||
|
||||
if (NearbyFlags::GetInstance().GetBoolFlag(
|
||||
config_package_nearby::nearby_connections_feature::kEnableAwdl)) {
|
||||
awdl_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
@@ -1238,8 +1238,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
|
||||
client_proxy, local_endpoint_id,
|
||||
options.listening_endpoint_type));
|
||||
client_proxy, options.listening_endpoint_type));
|
||||
if (bluetooth_result.has_error()) {
|
||||
LOG(WARNING)
|
||||
<< "Failed to start listening for incoming connections on Bluetooth";
|
||||
@@ -1266,8 +1265,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
|
||||
client_proxy, local_endpoint_id,
|
||||
options.listening_endpoint_type))) {
|
||||
client_proxy, options.listening_endpoint_type))) {
|
||||
LOG(WARNING) << "Failed to start listening for incoming L2CAP "
|
||||
"connections on ble";
|
||||
} else {
|
||||
@@ -1278,8 +1276,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler,
|
||||
this, client_proxy, local_endpoint_id,
|
||||
options.listening_endpoint_type))) {
|
||||
this, client_proxy, options.listening_endpoint_type))) {
|
||||
LOG(WARNING) << "Failed to start listening for incoming L2CAP "
|
||||
"connections on ble";
|
||||
} else {
|
||||
@@ -1295,8 +1292,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
|
||||
client_proxy, local_endpoint_id,
|
||||
options.listening_endpoint_type))) {
|
||||
client_proxy, options.listening_endpoint_type))) {
|
||||
LOG(WARNING)
|
||||
<< "Failed to start listening for incoming connections on ble_v2";
|
||||
} else {
|
||||
@@ -1307,8 +1303,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleConnectionAcceptedHandler, this,
|
||||
client_proxy, local_endpoint_id,
|
||||
options.listening_endpoint_type))) {
|
||||
client_proxy, options.listening_endpoint_type))) {
|
||||
LOG(WARNING)
|
||||
<< "Failed to start listening for incoming connections on ble";
|
||||
} else {
|
||||
@@ -1327,7 +1322,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
|
||||
std::string(service_id),
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this,
|
||||
client_proxy, local_endpoint_id, "",
|
||||
client_proxy, std::string(local_endpoint_id),
|
||||
options.listening_endpoint_type));
|
||||
if (wifi_lan_result.has_error()) {
|
||||
LOG(WARNING)
|
||||
@@ -1680,8 +1675,7 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl(
|
||||
restarted_mediums.push_back(AWDL);
|
||||
operation_result_with_mediums.push_back(
|
||||
GetOperationResultWithMediumByResultCode(
|
||||
client, AWDL, update_index,
|
||||
OperationResultCode::DETAIL_SUCCESS));
|
||||
client, AWDL, update_index, OperationResultCode::DETAIL_SUCCESS));
|
||||
} else {
|
||||
ErrorOr<Medium> awdl_result =
|
||||
StartAwdlDiscovery(client, std::string(service_id));
|
||||
@@ -1739,15 +1733,8 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler(
|
||||
ClientProxy* client, absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type, const std::string& service_id,
|
||||
BluetoothSocket socket) {
|
||||
if (!socket.IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
ClientProxy* client, NearbyDevice::Type device_type,
|
||||
const std::string& service_id, BluetoothSocket socket) {
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-bt-on-incoming-connection",
|
||||
[this, client, service_id, socket = std::move(socket), device_type]()
|
||||
@@ -1782,8 +1769,7 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBluetoothAdvertising(
|
||||
service_id,
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
|
||||
client, local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
client, NearbyDevice::Type::kConnectionsDevice));
|
||||
if (accept_result.has_error()) {
|
||||
error = {Error(accept_result.error().operation_result_code().value())};
|
||||
}
|
||||
@@ -1987,15 +1973,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BleConnectionAcceptedHandler(
|
||||
ClientProxy* client, absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type, BleSocket socket,
|
||||
ClientProxy* client, NearbyDevice::Type device_type, BleSocket socket,
|
||||
const std::string& service_id) {
|
||||
if (!socket.IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-ble-on-incoming-connection",
|
||||
[this, client, service_id, device_type,
|
||||
@@ -2010,15 +1989,8 @@ void P2pClusterPcpHandler::BleConnectionAcceptedHandler(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler(
|
||||
ClientProxy* client, absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type, BleL2capSocket socket,
|
||||
ClientProxy* client, NearbyDevice::Type device_type, BleL2capSocket socket,
|
||||
const std::string& service_id) {
|
||||
if (!socket.IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept L2CAP callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-ble-l2cap-on-incoming-connection",
|
||||
[this, client, service_id, device_type,
|
||||
@@ -2033,15 +2005,8 @@ void P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BleConnectionAcceptedHandler2(
|
||||
ClientProxy* client, absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type, std::unique_ptr<mediums::BleSocket> socket,
|
||||
const std::string& service_id) {
|
||||
if (socket == nullptr || !socket->IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
ClientProxy* client, NearbyDevice::Type device_type,
|
||||
std::unique_ptr<mediums::BleSocket> socket, const std::string& service_id) {
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-ble-on-incoming-connection",
|
||||
[this, client, service_id, device_type, socket = std::move(socket)]()
|
||||
@@ -2101,15 +2066,13 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
|
||||
service_id,
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
|
||||
client, local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
client, NearbyDevice::Type::kConnectionsDevice));
|
||||
} else {
|
||||
ble_l2cap_result = ble_medium_.StartAcceptingL2capConnections(
|
||||
service_id,
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler, this,
|
||||
client, local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
client, NearbyDevice::Type::kConnectionsDevice));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2118,13 +2081,13 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
|
||||
ble_result = ble_medium_.StartAcceptingConnections(
|
||||
service_id,
|
||||
absl::bind_front(&P2pClusterPcpHandler::BleConnectionAcceptedHandler2,
|
||||
this, client, local_endpoint_info.AsStringView(),
|
||||
this, client,
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
} else {
|
||||
ble_result = ble_medium_.StartAcceptingConnections(
|
||||
service_id,
|
||||
absl::bind_front(&P2pClusterPcpHandler::BleConnectionAcceptedHandler,
|
||||
this, client, local_endpoint_info.AsStringView(),
|
||||
this, client,
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
}
|
||||
if (ble_result.has_error() && ble_l2cap_result.has_error()) {
|
||||
@@ -2169,8 +2132,7 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
|
||||
service_id,
|
||||
absl::bind_front(
|
||||
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
|
||||
client, local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
client, NearbyDevice::Type::kConnectionsDevice));
|
||||
if (accept_result.has_error()) {
|
||||
LOG(WARNING)
|
||||
<< "In BT StartBleAdvertising("
|
||||
@@ -2430,23 +2392,16 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::AwdlConnectionAcceptedHandler(
|
||||
ClientProxy* client, absl::string_view local_endpoint_id,
|
||||
absl::string_view local_endpoint_info, NearbyDevice::Type device_type,
|
||||
const std::string& service_id, AwdlSocket socket) {
|
||||
if (!socket.IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
ClientProxy* client, const std::string& local_endpoint_id,
|
||||
NearbyDevice::Type device_type, const std::string& service_id,
|
||||
AwdlSocket socket) {
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-awdl-on-incoming-connection",
|
||||
[this, client, local_endpoint_id, service_id, device_type,
|
||||
socket = std::move(socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
std::string remote_service_name = std::string(local_endpoint_id);
|
||||
auto channel = std::make_unique<AwdlEndpointChannel>(
|
||||
service_id, /*channel_name=*/remote_service_name, socket);
|
||||
ByteArray remote_service_name_byte{remote_service_name};
|
||||
service_id, /*channel_name=*/local_endpoint_id, socket);
|
||||
ByteArray remote_service_name_byte{local_endpoint_id};
|
||||
|
||||
OnIncomingConnection(client, remote_service_name_byte,
|
||||
std::move(channel), AWDL, device_type);
|
||||
@@ -2454,23 +2409,16 @@ void P2pClusterPcpHandler::AwdlConnectionAcceptedHandler(
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler(
|
||||
ClientProxy* client, absl::string_view local_endpoint_id,
|
||||
absl::string_view local_endpoint_info, NearbyDevice::Type device_type,
|
||||
const std::string& service_id, WifiLanSocket socket) {
|
||||
if (!socket.IsValid()) {
|
||||
LOG(WARNING) << "Invalid socket in accept callback("
|
||||
<< absl::BytesToHexString(local_endpoint_info)
|
||||
<< "), client=" << client->GetClientId();
|
||||
return;
|
||||
}
|
||||
ClientProxy* client, const std::string& local_endpoint_id,
|
||||
NearbyDevice::Type device_type, const std::string& service_id,
|
||||
WifiLanSocket socket) {
|
||||
RunOnPcpHandlerThread(
|
||||
"p2p-wifi-on-incoming-connection",
|
||||
[this, client, local_endpoint_id, service_id, device_type,
|
||||
socket = std::move(socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
std::string remote_service_name = std::string(local_endpoint_id);
|
||||
auto channel = std::make_unique<WifiLanEndpointChannel>(
|
||||
service_id, /*channel_name=*/remote_service_name, socket);
|
||||
ByteArray remote_service_name_byte{remote_service_name};
|
||||
service_id, /*channel_name=*/local_endpoint_id, socket);
|
||||
ByteArray remote_service_name_byte{local_endpoint_id};
|
||||
|
||||
OnIncomingConnection(client, remote_service_name_byte,
|
||||
std::move(channel), WIFI_LAN, device_type);
|
||||
@@ -2490,7 +2438,6 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartAwdlAdvertising(
|
||||
service_id,
|
||||
absl::bind_front(&P2pClusterPcpHandler::AwdlConnectionAcceptedHandler,
|
||||
this, client, local_endpoint_id,
|
||||
local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
if (awdl_result.has_error()) {
|
||||
LOG(WARNING)
|
||||
@@ -2608,7 +2555,6 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartWifiLanAdvertising(
|
||||
service_id, nsd_service_info,
|
||||
absl::bind_front(&P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler,
|
||||
this, client, local_endpoint_id,
|
||||
local_endpoint_info.AsStringView(),
|
||||
NearbyDevice::Type::kConnectionsDevice));
|
||||
if (wifi_lan_result.has_error()) {
|
||||
LOG(WARNING) << "In StartWifiLanAdvertising("
|
||||
|
||||
@@ -40,10 +40,13 @@
|
||||
#include "connections/implementation/mediums/bluetooth_classic.h"
|
||||
#include "connections/implementation/mediums/bluetooth_radio.h"
|
||||
#include "connections/implementation/mediums/mediums.h"
|
||||
#include "connections/implementation/mediums/webrtc.h"
|
||||
#include "connections/implementation/mediums/wifi_direct.h"
|
||||
#include "connections/implementation/mediums/wifi_hotspot.h"
|
||||
#include "connections/implementation/mediums/wifi_lan.h"
|
||||
#include "connections/implementation/pcp.h"
|
||||
#include "connections/implementation/webrtc_state.h"
|
||||
#include "connections/implementation/wifi_lan_service_info.h"
|
||||
#include "connections/medium_selector.h"
|
||||
#include "connections/out_of_band_connection_metadata.h"
|
||||
#include "connections/power_level.h"
|
||||
@@ -54,13 +57,10 @@
|
||||
#include "internal/platform/ble.h"
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
#include "internal/platform/bluetooth_classic.h"
|
||||
#include "internal/platform/nsd_service_info.h"
|
||||
#include "internal/platform/wifi_lan.h"
|
||||
#include "connections/implementation/mediums/webrtc.h"
|
||||
#include "connections/implementation/pcp.h"
|
||||
#include "connections/implementation/wifi_lan_service_info.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/expected.h"
|
||||
#include "internal/platform/nsd_service_info.h"
|
||||
#include "internal/platform/wifi_lan.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
@@ -192,7 +192,6 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
const std::string& service_id,
|
||||
BluetoothDevice& device);
|
||||
void BluetoothConnectionAcceptedHandler(ClientProxy* client,
|
||||
absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type,
|
||||
const std::string& service_id,
|
||||
BluetoothSocket socket);
|
||||
@@ -232,19 +231,16 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
bool fast_advertisement);
|
||||
void BleLegacyDeviceDiscoveredHandler();
|
||||
void BleConnectionAcceptedHandler(ClientProxy* client,
|
||||
absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type,
|
||||
BleSocket socket,
|
||||
const std::string& service_id);
|
||||
void BleL2capConnectionAcceptedHandler(ClientProxy* client,
|
||||
absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type,
|
||||
BleL2capSocket socket,
|
||||
const std::string& service_id);
|
||||
// The refactor version of BleConnectionAcceptedHandler() and
|
||||
// BleL2capConnectionAcceptedHandler above.
|
||||
void BleConnectionAcceptedHandler2(ClientProxy* client,
|
||||
absl::string_view local_endpoint_info,
|
||||
NearbyDevice::Type device_type,
|
||||
std::unique_ptr<mediums::BleSocket> socket,
|
||||
const std::string& service_id);
|
||||
@@ -265,8 +261,7 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
void AwdlServiceLostHandler(ClientProxy* client, NsdServiceInfo service_info,
|
||||
const std::string& service_id);
|
||||
void AwdlConnectionAcceptedHandler(ClientProxy* client,
|
||||
absl::string_view local_endpoint_id,
|
||||
absl::string_view local_endpoint_info,
|
||||
const std::string& local_endpoint_id,
|
||||
NearbyDevice::Type device_type,
|
||||
const std::string& service_id,
|
||||
AwdlSocket socket);
|
||||
@@ -290,8 +285,7 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
NsdServiceInfo service_info,
|
||||
const std::string& service_id);
|
||||
void WifiLanConnectionAcceptedHandler(ClientProxy* client,
|
||||
absl::string_view local_endpoint_id,
|
||||
absl::string_view local_endpoint_info,
|
||||
const std::string& local_endpoint_id,
|
||||
NearbyDevice::Type device_type,
|
||||
const std::string& service_id,
|
||||
WifiLanSocket socket);
|
||||
|
||||
@@ -157,6 +157,7 @@ message ConnectionResponseFrame {
|
||||
optional int32 safe_to_disconnect_version = 7;
|
||||
optional LocationHint location_hint = 8;
|
||||
optional int32 keep_alive_timeout_millis = 9;
|
||||
optional string wifi_direct_device_name = 10;
|
||||
}
|
||||
|
||||
message PayloadTransferFrame {
|
||||
|
||||
@@ -25,7 +25,6 @@ cc_library(
|
||||
visibility = [
|
||||
"//internal/account:__subpackages__",
|
||||
"//internal/platform:__subpackages__",
|
||||
"//internal/test:__pkg__",
|
||||
"//location/nearby/sharing/lib:__subpackages__",
|
||||
"//sharing:__subpackages__",
|
||||
],
|
||||
|
||||
@@ -142,4 +142,8 @@ std::optional<size_t> Files::GetAvailableDiskSpaceInBytes(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool Files::IsAbsolutePath(const FilePath& path) {
|
||||
return path.path_.is_absolute();
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -75,6 +75,11 @@ class Files {
|
||||
// determined.
|
||||
static std::optional<size_t> GetAvailableDiskSpaceInBytes(
|
||||
const FilePath& path);
|
||||
|
||||
// Returns true if the path is an absolute path.
|
||||
// On Posix systems, this is a path that starts with a `/`.
|
||||
// On Windows, this is a path that starts with a drive letter or a UNC path.
|
||||
static bool IsAbsolutePath(const FilePath& path);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -46,5 +46,21 @@ TEST(FilesTest, CreateHardLinkSuccess) {
|
||||
Files::RemoveFile(target);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
TEST(FilesTest, IsAbsolutePathWindows) {
|
||||
EXPECT_TRUE(Files::IsAbsolutePath(FilePath("C:\\Users\\test\\file.txt")));
|
||||
EXPECT_TRUE(Files::IsAbsolutePath(FilePath("\\\\server\\share\\file.txt")));
|
||||
EXPECT_FALSE(Files::IsAbsolutePath(FilePath("file.txt")));
|
||||
EXPECT_FALSE(Files::IsAbsolutePath(FilePath("C:Users\\test\\file.txt")));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
TEST(FilesTest, IsAbsolutePathPosix) {
|
||||
EXPECT_TRUE(Files::IsAbsolutePath(FilePath("/Users/test/file.txt")));
|
||||
EXPECT_FALSE(Files::IsAbsolutePath(FilePath("file.txt")));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
|
||||
@@ -114,7 +114,7 @@ std::optional<std::vector<uint8_t>> Aead::Open(
|
||||
size_t output_length;
|
||||
if (!Open(ciphertext, nonce, additional_data, ret.data(), &output_length,
|
||||
max_output_length)) {
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ret.resize(output_length);
|
||||
|
||||
@@ -176,7 +176,7 @@ std::optional<size_t> Encryptor::Crypt(bool do_encrypt,
|
||||
if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
iv_.data(), do_encrypt)) {
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Encrypting needs a block size of space to allow for any padding.
|
||||
@@ -184,13 +184,13 @@ std::optional<size_t> Encryptor::Crypt(bool do_encrypt,
|
||||
int out_len;
|
||||
if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
|
||||
input.size()))
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
|
||||
// Write out the final block plus padding (if any) to the end of the data
|
||||
// just written.
|
||||
int tail_len;
|
||||
if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
|
||||
out_len += tail_len;
|
||||
DCHECK_LE(out_len, static_cast<int>(output.size()));
|
||||
@@ -202,13 +202,13 @@ std::optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
|
||||
absl::Span<uint8_t> output) {
|
||||
if (iv_.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Counter value not set in CTR mode.";
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
|
||||
key_->key().size() * 8, &aes_key) != 0) {
|
||||
return absl::nullopt;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint8_t ecount_buf[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
@@ -89,28 +89,27 @@ TEST(NearbyFlags, SetFlagReader) {
|
||||
auto flag_reader = std::make_unique<::testing::NiceMock<MockFlagReader>>();
|
||||
NearbyFlags::GetInstance().SetFlagReader(*flag_reader.get());
|
||||
EXPECT_CALL(*flag_reader, GetBoolFlag(::testing::_))
|
||||
.WillOnce(::testing::Invoke([=](const flags::Flag<bool>& flag) {
|
||||
.WillOnce([=](const flags::Flag<bool>& flag) {
|
||||
return kTestBoolFlagTestValue;
|
||||
}));
|
||||
});
|
||||
EXPECT_EQ(NearbyFlags::GetInstance().GetBoolFlag(kTestBoolFlag),
|
||||
kTestBoolFlagTestValue);
|
||||
EXPECT_CALL(*flag_reader, GetInt64Flag(::testing::_))
|
||||
.WillOnce(::testing::Invoke([=](const flags::Flag<int64_t>& flag) {
|
||||
.WillOnce([=](const flags::Flag<int64_t>& flag) {
|
||||
return kTestInt64FlagTestValue;
|
||||
}));
|
||||
});
|
||||
EXPECT_EQ(NearbyFlags::GetInstance().GetInt64Flag(kTestInt64Flag),
|
||||
kTestInt64FlagTestValue);
|
||||
EXPECT_CALL(*flag_reader, GetDoubleFlag(::testing::_))
|
||||
.WillOnce(::testing::Invoke([=](const flags::Flag<double>& flag) {
|
||||
.WillOnce([=](const flags::Flag<double>& flag) {
|
||||
return kTestDoubleFlagTestValue;
|
||||
}));
|
||||
});
|
||||
EXPECT_EQ(NearbyFlags::GetInstance().GetDoubleFlag(kTestDoubleFlag),
|
||||
kTestDoubleFlagTestValue);
|
||||
EXPECT_CALL(*flag_reader, GetStringFlag(::testing::_))
|
||||
.WillOnce(
|
||||
::testing::Invoke([=](const flags::Flag<absl::string_view>& flag) {
|
||||
return std::string(kTestStringFlagTestValue);
|
||||
}));
|
||||
.WillOnce([=](const flags::Flag<absl::string_view>& flag) {
|
||||
return std::string(kTestStringFlagTestValue);
|
||||
});
|
||||
EXPECT_EQ(NearbyFlags::GetInstance().GetStringFlag(kTestStringFlag),
|
||||
kTestStringFlagTestValue);
|
||||
}
|
||||
|
||||
@@ -80,8 +80,6 @@ cc_library(
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/meta:type_traits",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
@@ -323,7 +321,6 @@ cc_library(
|
||||
":types",
|
||||
":uuid",
|
||||
"//connections/implementation/flags:connections_flags",
|
||||
"//internal/base",
|
||||
"//internal/flags:nearby_flags",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation:platform",
|
||||
@@ -374,7 +371,6 @@ cc_library(
|
||||
":mac_address",
|
||||
":types",
|
||||
":uuid",
|
||||
"//internal/base",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation:webrtc_platform",
|
||||
"//internal/platform/implementation:wifi_utils",
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
#include "internal/platform/implementation/bluetooth_classic.h"
|
||||
@@ -57,11 +56,6 @@ MediumSocket* BluetoothSocket::CreateVirtualSocket(
|
||||
}
|
||||
|
||||
BluetoothClassicMedium::~BluetoothClassicMedium() {
|
||||
LOG(INFO) << "~BluetoothClassicMedium: observer_list_ size: "
|
||||
<< observer_list_.size();
|
||||
if (!observer_list_.empty()) {
|
||||
impl_->RemoveObserver(this);
|
||||
}
|
||||
StopDiscovery();
|
||||
LOG(INFO) << "eof ~BluetoothClassicMedium";
|
||||
}
|
||||
@@ -160,71 +154,4 @@ bool BluetoothClassicMedium::StopDiscovery() {
|
||||
return impl_->StopDiscovery();
|
||||
}
|
||||
|
||||
void BluetoothClassicMedium::AddObserver(Observer* observer) {
|
||||
LOG(INFO) << "BT AddObserver; impl=" << &GetImpl();
|
||||
MutexLock lock(&mutex_);
|
||||
if (observer_list_.empty()) {
|
||||
impl_->AddObserver(this);
|
||||
}
|
||||
observer_list_.AddObserver(observer);
|
||||
LOG(INFO) << "BT AddObserver done";
|
||||
}
|
||||
void BluetoothClassicMedium::RemoveObserver(Observer* observer) {
|
||||
LOG(INFO) << "BT RemoveObserver; impl=" << &GetImpl();
|
||||
MutexLock lock(&mutex_);
|
||||
observer_list_.RemoveObserver(observer);
|
||||
if (observer_list_.empty()) {
|
||||
impl_->RemoveObserver(this);
|
||||
}
|
||||
LOG(INFO) << "BT RemoveObserver done";
|
||||
}
|
||||
|
||||
// api::BluetoothClassicMedium::Observer methods
|
||||
void BluetoothClassicMedium::DeviceAdded(api::BluetoothDevice& device) {
|
||||
VLOG(1) << "BT DeviceAdded; name=" << device.GetName()
|
||||
<< ", address=" << device.GetMacAddress().ToString();
|
||||
BluetoothDevice bt_device(&device);
|
||||
for (auto* observer : observer_list_.GetObservers()) {
|
||||
observer->DeviceAdded(bt_device);
|
||||
}
|
||||
}
|
||||
void BluetoothClassicMedium::DeviceRemoved(api::BluetoothDevice& device) {
|
||||
VLOG(1) << "BT DeviceRemoved; name=" << device.GetName()
|
||||
<< ", address=" << device.GetMacAddress().ToString();
|
||||
BluetoothDevice bt_device(&device);
|
||||
for (auto* observer : observer_list_.GetObservers()) {
|
||||
observer->DeviceRemoved(bt_device);
|
||||
}
|
||||
}
|
||||
void BluetoothClassicMedium::DeviceAddressChanged(
|
||||
api::BluetoothDevice& device, absl::string_view old_address) {
|
||||
VLOG(1) << "BT DeviceAddressChanged; name=" << device.GetName()
|
||||
<< ", address=" << device.GetMacAddress().ToString()
|
||||
<< ", old_address=" << old_address;
|
||||
BluetoothDevice bt_device(&device);
|
||||
for (auto* observer : observer_list_.GetObservers()) {
|
||||
observer->DeviceAddressChanged(bt_device, old_address);
|
||||
}
|
||||
}
|
||||
void BluetoothClassicMedium::DevicePairedChanged(api::BluetoothDevice& device,
|
||||
bool new_paired_status) {
|
||||
VLOG(1) << "BT DevicePairedChanged; name=" << device.GetName()
|
||||
<< ", address=" << device.GetMacAddress().ToString()
|
||||
<< ", status=" << new_paired_status;
|
||||
BluetoothDevice bt_device(&device);
|
||||
for (auto* observer : observer_list_.GetObservers()) {
|
||||
observer->DevicePairedChanged(bt_device, new_paired_status);
|
||||
}
|
||||
}
|
||||
void BluetoothClassicMedium::DeviceConnectedStateChanged(
|
||||
api::BluetoothDevice& device, bool connected) {
|
||||
VLOG(1) << "BT DeviceConnectedStateChanged: name=" << device.GetName()
|
||||
<< ", address=" << device.GetMacAddress().ToString()
|
||||
<< ", connected=" << connected;
|
||||
BluetoothDevice bt_device(&device);
|
||||
for (auto* observer : observer_list_.GetObservers()) {
|
||||
observer->DeviceConnectedStateChanged(bt_device, connected);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/base/observer_list.h"
|
||||
#include "internal/platform/blocking_queue_stream.h"
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
@@ -157,7 +156,7 @@ class BluetoothServerSocket final {
|
||||
BluetoothServerSocket& operator=(const BluetoothServerSocket&) = default;
|
||||
~BluetoothServerSocket() = default;
|
||||
explicit BluetoothServerSocket(
|
||||
std::unique_ptr<api::BluetoothServerSocket> socket)
|
||||
std::shared_ptr<api::BluetoothServerSocket> socket)
|
||||
: impl_(std::move(socket)) {}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
|
||||
@@ -223,7 +222,7 @@ class BluetoothPairing final {
|
||||
|
||||
// Container of operations that can be performed over the Bluetooth Classic
|
||||
// medium.
|
||||
class BluetoothClassicMedium : public api::BluetoothClassicMedium::Observer {
|
||||
class BluetoothClassicMedium {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
struct DiscoveryCallback {
|
||||
@@ -246,39 +245,11 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium::Observer {
|
||||
BluetoothDevice device;
|
||||
};
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() = default;
|
||||
|
||||
// Called when a new `device` is added. The `device` parameter becomes
|
||||
// invalid after the call.
|
||||
virtual void DeviceAdded(BluetoothDevice& device) {}
|
||||
|
||||
// Called when `device` is removed. The `device` parameter becomes invalid
|
||||
// after the call.
|
||||
virtual void DeviceRemoved(BluetoothDevice& device) {}
|
||||
|
||||
// Called when the address of `device` changed due to pairing. The
|
||||
// `device` parameter becomes invalid after the call.
|
||||
virtual void DeviceAddressChanged(BluetoothDevice& device,
|
||||
absl::string_view old_address) {}
|
||||
|
||||
// Called when the paired property of `device` changed. The `device`
|
||||
// parameter becomes invalid after the call.
|
||||
virtual void DevicePairedChanged(BluetoothDevice& device,
|
||||
bool new_paired_status) {}
|
||||
|
||||
// Called when `device` has connected or disconnected. The `device`
|
||||
// parameter becomes invalid after the call.
|
||||
virtual void DeviceConnectedStateChanged(BluetoothDevice& device,
|
||||
bool connected) {}
|
||||
};
|
||||
|
||||
explicit BluetoothClassicMedium(BluetoothAdapter& adapter)
|
||||
: impl_(Platform::CreateBluetoothClassicMedium(adapter.GetImpl())),
|
||||
adapter_(adapter) {}
|
||||
|
||||
~BluetoothClassicMedium() override;
|
||||
virtual ~BluetoothClassicMedium();
|
||||
|
||||
// NOTE(DiscoveryCallback):
|
||||
// BluetoothDevice is a proxy object created as a result of BT discovery.
|
||||
@@ -353,23 +324,6 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium::Observer {
|
||||
return BluetoothDevice(impl_->GetRemoteDevice(mac_address));
|
||||
}
|
||||
|
||||
// Adds an observer. `observer` must be valid until RemoveObserver is called,
|
||||
// or BluetoothClassicMedium is destroyed.
|
||||
void AddObserver(Observer* observer);
|
||||
|
||||
// Removes an observer. It's OK to remove an unregistered observer.
|
||||
void RemoveObserver(Observer* observer);
|
||||
|
||||
// api::BluetoothClassicMedium::Observer methods
|
||||
void DeviceAdded(api::BluetoothDevice& device) override;
|
||||
void DeviceRemoved(api::BluetoothDevice& device) override;
|
||||
void DeviceAddressChanged(api::BluetoothDevice& device,
|
||||
absl::string_view old_address) override;
|
||||
void DevicePairedChanged(api::BluetoothDevice& device,
|
||||
bool new_paired_status) override;
|
||||
void DeviceConnectedStateChanged(api::BluetoothDevice& device,
|
||||
bool connected) override;
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
std::unique_ptr<api::BluetoothClassicMedium> impl_;
|
||||
@@ -379,7 +333,6 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium::Observer {
|
||||
devices_ ABSL_GUARDED_BY(mutex_);
|
||||
DiscoveryCallback discovery_callback_ ABSL_GUARDED_BY(mutex_);
|
||||
bool discovery_enabled_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
ObserverList<Observer> observer_list_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -49,39 +49,6 @@ constexpr FeatureFlags kTestCases[] = {
|
||||
},
|
||||
};
|
||||
|
||||
class BluetoothClassicMediumObserver
|
||||
: public BluetoothClassicMedium ::Observer {
|
||||
public:
|
||||
explicit BluetoothClassicMediumObserver(
|
||||
CountDownLatch* device_added_latch, CountDownLatch* device_removed_latch,
|
||||
CountDownLatch* device_paired_changed_latch)
|
||||
: device_added_latch_(device_added_latch),
|
||||
device_removed_latch_(device_removed_latch),
|
||||
device_paired_changed_latch_(device_paired_changed_latch) {}
|
||||
|
||||
void DeviceAdded(BluetoothDevice& device) override {
|
||||
if (!device_added_latch_) return;
|
||||
device_added_latch_->CountDown();
|
||||
}
|
||||
|
||||
void DeviceRemoved(BluetoothDevice& device) override {
|
||||
if (!device_removed_latch_) return;
|
||||
device_removed_latch_->CountDown();
|
||||
}
|
||||
|
||||
void DevicePairedChanged(BluetoothDevice& device,
|
||||
bool new_paired_status) override {
|
||||
if (!device_paired_changed_latch_) return;
|
||||
paired_status_ = new_paired_status;
|
||||
device_paired_changed_latch_->CountDown();
|
||||
}
|
||||
|
||||
CountDownLatch* device_added_latch_;
|
||||
CountDownLatch* device_removed_latch_;
|
||||
CountDownLatch* device_paired_changed_latch_;
|
||||
bool paired_status_ = false;
|
||||
};
|
||||
|
||||
class BluetoothClassicMediumTest
|
||||
: public ::testing::TestWithParam<FeatureFlags> {
|
||||
protected:
|
||||
@@ -341,11 +308,6 @@ TEST_F(BluetoothClassicMediumTest, CanStartDiscovery) {
|
||||
adapter_a_->SetScanMode(BluetoothAdapter::ScanMode::kConnectable);
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
CountDownLatch device_added_latch(1);
|
||||
CountDownLatch device_removed_latch(1);
|
||||
BluetoothClassicMediumObserver observer(&device_added_latch,
|
||||
&device_removed_latch, nullptr);
|
||||
bt_a_->AddObserver(&observer);
|
||||
|
||||
bt_a_->StartDiscovery(DiscoveryCallback{
|
||||
.device_discovered_cb =
|
||||
@@ -365,21 +327,15 @@ TEST_F(BluetoothClassicMediumTest, CanStartDiscovery) {
|
||||
EXPECT_EQ(adapter_b_->GetScanMode(),
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
|
||||
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_TRUE(device_added_latch.Await(absl::Milliseconds(1000)).result());
|
||||
adapter_b_->SetStatus(BluetoothAdapter::Status::kDisabled);
|
||||
EXPECT_FALSE(adapter_b_->IsEnabled());
|
||||
EXPECT_TRUE(lost_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_TRUE(device_removed_latch.Await(absl::Milliseconds(1000)).result());
|
||||
}
|
||||
|
||||
TEST_F(BluetoothClassicMediumTest, DiscoveryCallbackAfterStopDiscovery) {
|
||||
SingleThreadExecutor executor;
|
||||
adapter_a_->SetScanMode(BluetoothAdapter::ScanMode::kConnectable);
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch device_added_latch(1);
|
||||
BluetoothClassicMediumObserver observer(&device_added_latch, nullptr,
|
||||
nullptr);
|
||||
bt_a_->AddObserver(&observer);
|
||||
|
||||
bt_a_->StartDiscovery(DiscoveryCallback{
|
||||
.device_discovered_cb =
|
||||
@@ -397,7 +353,6 @@ TEST_F(BluetoothClassicMediumTest, DiscoveryCallbackAfterStopDiscovery) {
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
|
||||
bt_a_->StopDiscovery();
|
||||
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_TRUE(device_added_latch.Await(absl::Milliseconds(1000)).result());
|
||||
executor.Shutdown();
|
||||
}
|
||||
|
||||
@@ -491,10 +446,6 @@ TEST_F(BluetoothClassicMediumTest, BluetoothPairingSuccess) {
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch initiated_latch(1);
|
||||
CountDownLatch error_latch(1);
|
||||
CountDownLatch device_paired_latch(1);
|
||||
BluetoothClassicMediumObserver observer(nullptr, nullptr,
|
||||
&device_paired_latch);
|
||||
bt_a_->AddObserver(&observer);
|
||||
EXPECT_TRUE(bluetooth_pairing->InitiatePairing({
|
||||
.on_paired_cb = [&]() { paired_latch.CountDown(); },
|
||||
.on_pairing_error_cb =
|
||||
@@ -520,8 +471,6 @@ TEST_F(BluetoothClassicMediumTest, BluetoothPairingSuccess) {
|
||||
// Finishes pairing with remote device.
|
||||
EXPECT_TRUE(bluetooth_pairing->FinishPairing(received_passkey));
|
||||
paired_latch.Await();
|
||||
device_paired_latch.Await();
|
||||
EXPECT_TRUE(observer.paired_status_);
|
||||
EXPECT_TRUE(bluetooth_pairing->IsPaired());
|
||||
|
||||
// Unpairs with remote device.
|
||||
|
||||
@@ -190,6 +190,9 @@ cc_library(
|
||||
],
|
||||
deps = [
|
||||
] + select({
|
||||
"@platforms//os:platform_macos": [
|
||||
"//internal/platform/implementation/apple",
|
||||
],
|
||||
"@platforms//os:windows": [
|
||||
"//internal/platform/implementation/windows",
|
||||
],
|
||||
|
||||
@@ -221,6 +221,7 @@ objc_library(
|
||||
"//internal/platform/implementation/apple/Mediums/BLE/Sockets:Peripheral",
|
||||
"//third_party/apple_frameworks:CoreBluetooth",
|
||||
"//third_party/apple_frameworks:Foundation",
|
||||
"@com_google_absl//absl/algorithm:container",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/strings",
|
||||
|
||||
@@ -386,6 +386,10 @@ static const int kMaxAdvertisementLengthOnIOS = 23;
|
||||
[_peripheralManager respondToRequest:request withResult:CBATTErrorAttributeNotFound];
|
||||
return;
|
||||
}
|
||||
if (request.offset > value.length) {
|
||||
[_peripheralManager respondToRequest:request withResult:CBATTErrorInvalidOffset];
|
||||
return;
|
||||
}
|
||||
request.value =
|
||||
[value subdataWithRange:NSMakeRange(request.offset, value.length - request.offset)];
|
||||
[_peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCMConnection.h"
|
||||
|
||||
enum { kL2CAPPacketLength = 4 };
|
||||
static const NSUInteger kGNCBLEL2CAPMaxFrameLength = 5 * 1024 * 1024; // 5 MB
|
||||
static const CGFloat kRequestDataConnectionDelayInSeconds = 0.0;
|
||||
static const UInt8 kRequestDataConnectionTimeoutInSeconds = 5;
|
||||
|
||||
@@ -266,6 +267,20 @@ static NSData *PrefixLengthData(NSData *data) {
|
||||
}
|
||||
_expectedDataLength = CFSwapInt32BigToHost(
|
||||
*(int *)([[data subdataWithRange:NSMakeRange(0, kL2CAPPacketLength)] bytes]));
|
||||
if (_expectedDataLength == 0 || _expectedDataLength > kGNCBLEL2CAPMaxFrameLength) {
|
||||
GNCLoggerError(@"[NEARBY] Rejecting L2CAP frame: declared length %lu out of range "
|
||||
@"(max %lu); closing.",
|
||||
(unsigned long)_expectedDataLength,
|
||||
(unsigned long)kGNCBLEL2CAPMaxFrameLength);
|
||||
_expectedDataLength = 0;
|
||||
[_stream close];
|
||||
if (_connectionHandlers.disconnectedHandler) {
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
_connectionHandlers.disconnectedHandler();
|
||||
});
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
NSUInteger realDataLength = data.length - kL2CAPPacketLength;
|
||||
if (realDataLength < _expectedDataLength) {
|
||||
|
||||
@@ -74,6 +74,9 @@ enum { READ_BUFFER_SIZE = 409600 };
|
||||
|
||||
/// Whether the stream is closed.
|
||||
BOOL _closed;
|
||||
|
||||
/// Buffer for reading data from the input stream.
|
||||
uint8_t _readBuffer[READ_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
#pragma mark Public
|
||||
@@ -319,12 +322,11 @@ enum { READ_BUFFER_SIZE = 409600 };
|
||||
/// Receives data from device and invokes |_receivedDataBlock|.
|
||||
- (void)receiveStreamData {
|
||||
dispatch_assert_queue_debug(_streamQueue);
|
||||
uint8_t readBuffer[READ_BUFFER_SIZE];
|
||||
NSInteger bytesRead = [self.inputStream read:readBuffer maxLength:READ_BUFFER_SIZE];
|
||||
NSInteger bytesRead = [self.inputStream read:_readBuffer maxLength:READ_BUFFER_SIZE];
|
||||
|
||||
if (bytesRead > 0) {
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
[data appendBytes:readBuffer length:(NSUInteger)bytesRead];
|
||||
[data appendBytes:_readBuffer length:(NSUInteger)bytesRead];
|
||||
|
||||
if (_verboseLoggingEnabled) {
|
||||
GNCLoggerDebug(@"[NEARBY] Stream data from device of length %@", @(data.length));
|
||||
|
||||
@@ -140,7 +140,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return;
|
||||
}
|
||||
|
||||
if (![[data subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) {
|
||||
// IntroductionFrame.service_id_hash. We MUST bounds-check before
|
||||
// -subdataWithRange:, otherwise a short follow-up packet throws
|
||||
// NSRangeException on CoreBluetooth's dispatch queue -> objc_terminate.
|
||||
if (data.length < prefixLength ||
|
||||
![[data subdataWithRange:NSMakeRange(0, prefixLength)] isEqual:_serviceIDHash]) {
|
||||
GNCLoggerInfo(@"[NEARBY] Input stream: Received wrong data packet and discarded");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,11 @@ NSData *_Nullable GNCMParseBLEFramesIntroductionPacket(NSData *_Nullable data) {
|
||||
::location::nearby::mediums::SocketVersion::V2 &&
|
||||
socket_control_frame.introduction().has_service_id_hash()) {
|
||||
std::string service_id_hash = socket_control_frame.introduction().service_id_hash();
|
||||
// service_id_hash is attacker-supplied; clamp to the protocol-defined
|
||||
// 3-byte length so it cannot be used to inflate prefixLength downstream.
|
||||
if (service_id_hash.size() != GNCMBleAdvertisementLengthServiceIDHash) {
|
||||
return nil;
|
||||
}
|
||||
return [NSData dataWithBytes:service_id_hash.data() length:service_id_hash.length()];
|
||||
}
|
||||
}
|
||||
|
||||
+28
-20
@@ -111,15 +111,17 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f;
|
||||
|
||||
- (void)addPeripheralServiceManager:(GNSPeripheralServiceManager *)peripheralServiceManager
|
||||
bleServiceAddedCompletion:(GNSErrorHandler)completion {
|
||||
[_peripheralServiceManagers setObject:peripheralServiceManager
|
||||
forKey:peripheralServiceManager.serviceUUID];
|
||||
[peripheralServiceManager addedToPeripheralManager:self bleServiceAddedCompletion:completion];
|
||||
if (_started) {
|
||||
[self addBleServiceForServiceManager:peripheralServiceManager];
|
||||
}
|
||||
// Update all advertised services to make sure that the right services are advertised in case
|
||||
// all BLE services were already added.
|
||||
[self updateAdvertisedServices];
|
||||
dispatch_async(_queue, ^{
|
||||
[self->_peripheralServiceManagers setObject:peripheralServiceManager
|
||||
forKey:peripheralServiceManager.serviceUUID];
|
||||
[peripheralServiceManager addedToPeripheralManager:self bleServiceAddedCompletion:completion];
|
||||
if (self->_started) {
|
||||
[self addBleServiceForServiceManager:peripheralServiceManager];
|
||||
}
|
||||
// Update all advertised services to make sure that the right services are advertised in case
|
||||
// all BLE services were already added.
|
||||
[self updateAdvertisedServices];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
@@ -211,18 +213,24 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f;
|
||||
|
||||
- (void)removePeripheralServiceManagerForServiceUUID:(CBUUID *)serviceUUID
|
||||
bleServiceRemovedCompletion:(GNSErrorHandler)completion {
|
||||
GNSPeripheralServiceManager *peripheralServiceManager =
|
||||
[_peripheralServiceManagers objectForKey:serviceUUID];
|
||||
if (peripheralServiceManager == nil) {
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
[_cbPeripheralManager removeService:peripheralServiceManager.cbService];
|
||||
[_peripheralServiceManagers removeObjectForKey:serviceUUID];
|
||||
[peripheralServiceManager didRemoveCBService];
|
||||
dispatch_async(_queue, ^{
|
||||
GNSPeripheralServiceManager *peripheralServiceManager =
|
||||
[self->_peripheralServiceManagers objectForKey:serviceUUID];
|
||||
if (peripheralServiceManager == nil) {
|
||||
if (completion) {
|
||||
completion(nil);
|
||||
}
|
||||
return;
|
||||
}
|
||||
[self->_cbPeripheralManager removeService:peripheralServiceManager.cbService];
|
||||
[self->_peripheralServiceManagers removeObjectForKey:serviceUUID];
|
||||
[peripheralServiceManager didRemoveCBService];
|
||||
|
||||
[self updateAdvertisedServices];
|
||||
completion(nil);
|
||||
[self updateAdvertisedServices];
|
||||
if (completion) {
|
||||
completion(nil);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)removeAllBleServices {
|
||||
|
||||
+474
-372
File diff suppressed because it is too large
Load Diff
@@ -140,6 +140,32 @@ static const NSTimeInterval kTestTimeout = 1.0;
|
||||
XCTAssertNil(realData);
|
||||
}
|
||||
|
||||
- (void)testExtractRealDataFromData_oversizedData {
|
||||
_connection = [self createConnectionWithIncoming:YES];
|
||||
|
||||
XCTestExpectation *disconnectionExpectation =
|
||||
[self expectationWithDescription:@"disconnection handler"];
|
||||
_connection.connectionHandlers = [GNCMConnectionHandlers
|
||||
payloadHandler:^(NSData *data) {
|
||||
XCTFail(@"Unexpected payload");
|
||||
}
|
||||
disconnectedHandler:^{
|
||||
[disconnectionExpectation fulfill];
|
||||
}];
|
||||
|
||||
// 6 MB frame length
|
||||
uint32_t oversizedLength = 6 * 1024 * 1024;
|
||||
uint32_t lengthBigEndian = CFSwapInt32HostToBig(oversizedLength);
|
||||
NSMutableData *prefixData = [NSMutableData dataWithCapacity:sizeof(uint32_t)];
|
||||
[prefixData appendBytes:&lengthBigEndian length:sizeof(uint32_t)];
|
||||
|
||||
NSData *realData = [_connection extractRealDataFromData:prefixData];
|
||||
XCTAssertNil(realData);
|
||||
XCTAssertEqual(_connection.expectedDataLength, 0);
|
||||
|
||||
[self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testExtractRealDataFromData_moreThanExpectedData {
|
||||
_connection = [self createConnectionWithIncoming:YES];
|
||||
NSData *testData = [self createDataWithLength:10];
|
||||
|
||||
@@ -47,6 +47,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/** Expectation fulfilled when peripheral responds to a request with an error. */
|
||||
@property(nonatomic, readonly) XCTestExpectation *respondToRequestErrorExpectation;
|
||||
|
||||
/** The last response result. */
|
||||
@property(nonatomic, assign) CBATTError lastResponseResult;
|
||||
|
||||
/** Expectation fulfilled when peripheral unpublishes an L2CAP channel. */
|
||||
@property(nonatomic, readonly) XCTestExpectation *unpublishExpectation;
|
||||
|
||||
@@ -117,6 +120,20 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)simulatePeripheralManagerDidReceiveReadRequestForService:(CBUUID *)service
|
||||
characteristic:(CBUUID *)characteristic;
|
||||
|
||||
/**
|
||||
* Simulates a read request event with an offset.
|
||||
*
|
||||
* Creates a fake read request with the given offset for the given service and characteristic UUIDs
|
||||
* and calls the @c gnc_peripheralManager:didReceiveReadRequest: delegate method.
|
||||
*
|
||||
* @param service The service UUID of the characteristic to read from.
|
||||
* @param characteristic The characteristic UUID to read from.
|
||||
* @param offset The offset to read from.
|
||||
*/
|
||||
- (void)simulatePeripheralManagerDidReceiveReadRequestForService:(CBUUID *)service
|
||||
characteristic:(CBUUID *)characteristic
|
||||
offset:(NSUInteger)offset;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
// Keep a strong reference to the service.
|
||||
@property(readwrite, nonatomic) CBService *service;
|
||||
|
||||
// Change property to readwrite for tests.
|
||||
@property(readwrite, nonatomic) NSUInteger offset;
|
||||
|
||||
- (instancetype)initWithService:(CBUUID *)service characteristic:(CBUUID *)characteristic;
|
||||
|
||||
@end
|
||||
@@ -115,6 +118,7 @@ static const uint16_t kPSM = 192;
|
||||
}
|
||||
|
||||
- (void)respondToRequest:(CBATTRequest *)request withResult:(CBATTError)result {
|
||||
self.lastResponseResult = result;
|
||||
if (result == CBATTErrorSuccess) {
|
||||
[_respondToRequestSuccessExpectation fulfill];
|
||||
return;
|
||||
@@ -176,6 +180,15 @@ static const uint16_t kPSM = 192;
|
||||
[_peripheralDelegate gnc_peripheralManager:self didReceiveReadRequest:request];
|
||||
}
|
||||
|
||||
- (void)simulatePeripheralManagerDidReceiveReadRequestForService:(CBUUID *)service
|
||||
characteristic:(CBUUID *)characteristic
|
||||
offset:(NSUInteger)offset {
|
||||
CBATTRequest *request = [[CBATTRequest alloc] initWithService:service
|
||||
characteristic:characteristic];
|
||||
request.offset = offset;
|
||||
[_peripheralDelegate gnc_peripheralManager:self didReceiveReadRequest:request];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<CBPeripheralManagerDelegate>)delegate {
|
||||
self.peripheralDelegate = (id<GNCPeripheralManagerDelegate>)delegate;
|
||||
}
|
||||
|
||||
@@ -241,4 +241,33 @@ static const NSTimeInterval kTimeout = 1.0;
|
||||
[self waitForExpectationsWithTimeout:kTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testReceiveShortDataPacketAfterIntro {
|
||||
_connection = [GNCMBleConnection connectionWithSocket:(GNSSocket *)_fakeSocket
|
||||
serviceID:nil
|
||||
expectedIntroPacket:YES
|
||||
callbackQueue:_callbackQueue];
|
||||
|
||||
NSData *introPacket = GNCMGenerateBLEFramesIntroductionPacket(GNCMServiceIDHash(kServiceID));
|
||||
|
||||
// Receive the intro packet first to set `_serviceIDHash`.
|
||||
[_fakeSocket simulateSocketDidReceiveData:introPacket];
|
||||
|
||||
// Receive a data packet that is shorter than the service ID hash length.
|
||||
// This should not crash; it should just be discarded.
|
||||
NSData *shortPacket = [@"ab" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Payload handler not called"];
|
||||
expectation.inverted = YES;
|
||||
|
||||
GNCMConnectionHandlers *handlers = [[GNCMConnectionHandlers alloc] init];
|
||||
handlers.payloadHandler = ^(NSData *data) {
|
||||
[expectation fulfill];
|
||||
};
|
||||
_connection.connectionHandlers = handlers;
|
||||
|
||||
[_fakeSocket simulateSocketDidReceiveData:shortPacket];
|
||||
|
||||
[self waitForExpectationsWithTimeout:kTimeout handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -45,6 +45,18 @@ static const NSTimeInterval kWaitForConnectionTimeout = 6.0; // Allow for the 5
|
||||
XCTAssertEqualObjects(parsedHash, serviceIDHash);
|
||||
}
|
||||
|
||||
- (void)testParseBLEFramesIntroductionPacketFailure_InvalidHashLength {
|
||||
// Too long hash (4 bytes, protocol expects 3 bytes)
|
||||
NSData *longHash = [@"1234" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *longPacket = GNCMGenerateBLEFramesIntroductionPacket(longHash);
|
||||
XCTAssertNil(GNCMParseBLEFramesIntroductionPacket(longPacket));
|
||||
|
||||
// Too short hash (2 bytes, protocol expects 3 bytes)
|
||||
NSData *shortHash = [@"12" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *shortPacket = GNCMGenerateBLEFramesIntroductionPacket(shortHash);
|
||||
XCTAssertNil(GNCMParseBLEFramesIntroductionPacket(shortPacket));
|
||||
}
|
||||
|
||||
- (void)testParseBLEFramesIntroductionPacketFailure_NilData {
|
||||
NSData *parsedHash = GNCMParseBLEFramesIntroductionPacket(nil);
|
||||
XCTAssertNil(parsedHash);
|
||||
|
||||
@@ -57,7 +57,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (nullable NSString *)getBonjourServiceNameFromEndpoint:(nw_endpoint_t)endpoint {
|
||||
const char *name = nw_endpoint_get_bonjour_service_name(endpoint);
|
||||
return name ? @(name) : nil;
|
||||
if (name == NULL) return nil;
|
||||
// @() returns nil on non-UTF-8 input; the wire format does not guarantee UTF-8.
|
||||
// Round-trip through Latin-1 so callers always get a non-nil NSString.
|
||||
return @(name) ?: [NSString stringWithCString:name encoding:NSISOLatin1StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -63,11 +63,14 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
block:^bool(const char *key, const nw_txt_record_find_key_t found,
|
||||
const uint8_t *value, const size_t value_len) {
|
||||
if (found == nw_txt_record_find_key_non_empty_value) {
|
||||
NSString *keyString = @(key);
|
||||
NSString *valueString =
|
||||
[[NSString alloc] initWithBytes:value
|
||||
length:value_len
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[txtRecords setValue:valueString forKey:@(key)];
|
||||
if (keyString != nil && valueString != nil) {
|
||||
[txtRecords setObject:valueString forKey:keyString];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
@@ -231,6 +234,11 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
[browseResultWrapper copyEndpointFromResult:new_result];
|
||||
NSString *name = [browseResultWrapper
|
||||
getBonjourServiceNameFromEndpoint:endpoint];
|
||||
if (name == nil) {
|
||||
GNCLoggerInfo(
|
||||
@"Dropping mDNS result with unrepresentable name.");
|
||||
break;
|
||||
}
|
||||
NSDictionary<NSString *, NSString *> *txtRecords =
|
||||
GNCTXTRecordForBrowseResult(new_result);
|
||||
serviceFoundHandler(name, txtRecords);
|
||||
@@ -250,6 +258,11 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
[browseResultWrapper copyEndpointFromResult:old_result];
|
||||
NSString *oldName = [browseResultWrapper
|
||||
getBonjourServiceNameFromEndpoint:old_endpoint];
|
||||
if (oldName == nil) {
|
||||
GNCLoggerInfo(
|
||||
@"Dropping mDNS result with unrepresentable old name.");
|
||||
break;
|
||||
}
|
||||
NSDictionary<NSString *, NSString *> *oldTXTRecords =
|
||||
GNCTXTRecordForBrowseResult(old_result);
|
||||
serviceLostHandler(oldName, oldTXTRecords);
|
||||
@@ -258,6 +271,11 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
[browseResultWrapper copyEndpointFromResult:new_result];
|
||||
NSString *newName = [browseResultWrapper
|
||||
getBonjourServiceNameFromEndpoint:new_endpoint];
|
||||
if (newName == nil) {
|
||||
GNCLoggerInfo(
|
||||
@"Dropping mDNS result with unrepresentable new name.");
|
||||
break;
|
||||
}
|
||||
NSDictionary<NSString *, NSString *> *newTXTRecords =
|
||||
GNCTXTRecordForBrowseResult(new_result);
|
||||
serviceFoundHandler(newName, newTXTRecords);
|
||||
@@ -276,6 +294,11 @@ NSDictionary<NSString *, NSString *> *GNCTXTRecordForBrowseResult(nw_browse_resu
|
||||
[browseResultWrapper copyEndpointFromResult:old_result];
|
||||
NSString *name = [browseResultWrapper
|
||||
getBonjourServiceNameFromEndpoint:endpoint];
|
||||
if (name == nil) {
|
||||
GNCLoggerInfo(
|
||||
@"Dropping mDNS result with unrepresentable name.");
|
||||
break;
|
||||
}
|
||||
NSDictionary<NSString *, NSString *> *txtRecords =
|
||||
GNCTXTRecordForBrowseResult(old_result);
|
||||
serviceLostHandler(name, txtRecords);
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property(nonatomic) nw_browse_result_change_t getChangesFromResult;
|
||||
@property(nonatomic, nullable) nw_endpoint_t endpointFromResultResult;
|
||||
@property(nonatomic, nullable) NSString *getBonjourServiceNameFromEndpointResult;
|
||||
@property(nonatomic) BOOL returnNilServiceName;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+3
@@ -67,6 +67,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (nullable NSString *)getBonjourServiceNameFromEndpoint:(nw_endpoint_t)endpoint {
|
||||
if (self.returnNilServiceName) {
|
||||
return nil;
|
||||
}
|
||||
return self.getBonjourServiceNameFromEndpointResult ?: @"FakeService";
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -53,16 +53,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* @param serviceName The name of the service found.
|
||||
* @param txtRecords The TXT records of the service found.
|
||||
*/
|
||||
- (void)triggerServiceFound:(NSString*)serviceName
|
||||
txtRecords:(NSDictionary<NSString*, NSString*>*)txtRecords;
|
||||
- (void)triggerServiceFound:(nullable NSString*)serviceName
|
||||
txtRecords:(nullable NSDictionary<NSString*, NSString*>*)txtRecords;
|
||||
/**
|
||||
* Triggers the service lost handler with the given service info.
|
||||
*
|
||||
* @param serviceName The name of the service lost.
|
||||
* @param txtRecords The TXT records of the service lost.
|
||||
*/
|
||||
- (void)triggerServiceLost:(NSString*)serviceName
|
||||
txtRecords:(NSDictionary<NSString*, NSString*>*)txtRecords;
|
||||
- (void)triggerServiceLost:(nullable NSString*)serviceName
|
||||
txtRecords:(nullable NSDictionary<NSString*, NSString*>*)txtRecords;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+4
-4
@@ -122,15 +122,15 @@
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
- (void)triggerServiceFound:(NSString *)serviceName
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
- (void)triggerServiceFound:(nullable NSString *)serviceName
|
||||
txtRecords:(nullable NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
if (self.serviceFoundHandler) {
|
||||
self.serviceFoundHandler(serviceName, txtRecords);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)triggerServiceLost:(NSString *)serviceName
|
||||
txtRecords:(NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
- (void)triggerServiceLost:(nullable NSString *)serviceName
|
||||
txtRecords:(nullable NSDictionary<NSString *, NSString *> *)txtRecords {
|
||||
if (self.serviceLostHandler) {
|
||||
self.serviceLostHandler(serviceName, txtRecords);
|
||||
}
|
||||
|
||||
+13
@@ -67,4 +67,17 @@
|
||||
XCTAssertEqualObjects(results[@"key2"], @"value2");
|
||||
}
|
||||
|
||||
- (void)testGetBonjourServiceName_InvalidUTF8 {
|
||||
GNCNWBrowseResultImpl *browseResult = [[GNCNWBrowseResultImpl alloc] init];
|
||||
const char *raw_invalid = "\xc3\x28"
|
||||
"abc";
|
||||
nw_endpoint_t endpoint =
|
||||
nw_endpoint_create_bonjour_service(raw_invalid, "_servicetype._tcp", "local.");
|
||||
XCTAssertNotNil(endpoint);
|
||||
|
||||
NSString *serviceName = [browseResult getBonjourServiceNameFromEndpoint:endpoint];
|
||||
XCTAssertNotNil(serviceName);
|
||||
XCTAssertEqualObjects(serviceName, @"�(abc");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+55
-25
@@ -61,7 +61,6 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
_mockConnectionImpl = OCMClassMock([GNCNWConnectionImpl class]);
|
||||
}
|
||||
|
||||
|
||||
- (void)testGNCNWFrameworkCanBeInstantiated {
|
||||
GNCNWFramework *framework = [[GNCNWFramework alloc] init];
|
||||
XCTAssertNotNil(framework);
|
||||
@@ -272,6 +271,49 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
XCTAssertEqualObjects(foundTXTRecords, @{@"key" : @"value"});
|
||||
}
|
||||
|
||||
- (void)testStartDiscoveryForServiceTypeNilName API_AVAILABLE(ios(13.0)) {
|
||||
GNCNWFramework *framework = [[GNCNWFramework alloc] init];
|
||||
GNCFakeNWBrowser *fakeBrowser = [[GNCFakeNWBrowser alloc] init];
|
||||
fakeBrowser.createWithDescriptorResult = (nw_browser_t)fakeBrowser;
|
||||
OCMStub([_mockBrowserImpl alloc]).andReturn(fakeBrowser);
|
||||
|
||||
XCTestExpectation *serviceFoundExpectation = [self expectationWithDescription:@"Service found"];
|
||||
serviceFoundExpectation.inverted = YES;
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL result = [framework startDiscoveryForServiceType:kServiceType
|
||||
serviceFoundHandler:^(NSString *serviceName,
|
||||
NSDictionary<NSString *, NSString *> *txtRecords) {
|
||||
[serviceFoundExpectation fulfill];
|
||||
}
|
||||
serviceLostHandler:^(NSString *serviceName,
|
||||
NSDictionary<NSString *, NSString *> *txtRecords) {
|
||||
}
|
||||
includePeerToPeer:NO
|
||||
error:&error];
|
||||
|
||||
XCTAssertTrue(result);
|
||||
XCTAssertNil(error);
|
||||
|
||||
// Simulate a service being found with nil name.
|
||||
GNCFakeNWBrowseResult *fakeBrowseResult = [[GNCFakeNWBrowseResult alloc] init];
|
||||
fakeBrowseResult.txtRecord = @{@"key" : @"value"};
|
||||
fakeBrowseResult.getChangesFromResult = nw_browse_result_change_result_added;
|
||||
nw_endpoint_t fakeEndpoint =
|
||||
nw_endpoint_create_host("localhost", [[NSString stringWithFormat:@"%ld", kPort] UTF8String]);
|
||||
fakeBrowseResult.endpointFromResultResult = fakeEndpoint;
|
||||
fakeBrowseResult.returnNilServiceName = YES;
|
||||
OCMStub([_mockBrowseResultImpl sharedInstance]).andReturn(fakeBrowseResult);
|
||||
|
||||
if (fakeBrowser.browseResultsChangedHandler) {
|
||||
GNCFakeNWBrowseResult *oldFakeBrowseResult = [[GNCFakeNWBrowseResult alloc] init];
|
||||
fakeBrowser.browseResultsChangedHandler((nw_browse_result_t)oldFakeBrowseResult,
|
||||
(nw_browse_result_t)fakeBrowseResult, true);
|
||||
}
|
||||
|
||||
[self waitForExpectations:@[ serviceFoundExpectation ] timeout:0.1];
|
||||
}
|
||||
|
||||
- (void)testStartDiscoveryForServiceTypeDuplicate API_AVAILABLE(ios(13.0)) {
|
||||
GNCNWFramework *framework = [[GNCNWFramework alloc] init];
|
||||
GNCFakeNWBrowser *fakeBrowser = [[GNCFakeNWBrowser alloc] init];
|
||||
@@ -449,12 +491,13 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
// TODO: b/377543997 - Migrate to dependency injection and remove mocks.
|
||||
OCMStub([_mockBrowserImpl alloc]).andReturn(fakeBrowser);
|
||||
|
||||
__block BOOL serviceFound = NO;
|
||||
XCTestExpectation *serviceFoundExpectation = [self expectationWithDescription:@"Service found"];
|
||||
serviceFoundExpectation.inverted = YES;
|
||||
NSError *error = nil;
|
||||
[framework startDiscoveryForServiceType:kServiceType
|
||||
serviceFoundHandler:^(NSString *serviceName,
|
||||
NSDictionary<NSString *, NSString *> *txtRecords) {
|
||||
serviceFound = YES;
|
||||
[serviceFoundExpectation fulfill];
|
||||
}
|
||||
serviceLostHandler:^(NSString *serviceName,
|
||||
NSDictionary<NSString *, NSString *> *txtRecords) {
|
||||
@@ -478,14 +521,7 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
(nw_browse_result_t)fakeBrowseResult, true);
|
||||
}
|
||||
|
||||
// Allow async blocks to run.
|
||||
XCTestExpectation *delay = [[XCTestExpectation alloc] initWithDescription:@"delay"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
[delay fulfill];
|
||||
});
|
||||
[self waitForExpectations:@[ delay ] timeout:0.5];
|
||||
|
||||
XCTAssertFalse(serviceFound);
|
||||
[self waitForExpectations:@[ serviceFoundExpectation ] timeout:0.1];
|
||||
}
|
||||
|
||||
- (void)testStartDiscoveryIgnoresLoopbackRemove API_AVAILABLE(ios(13.0)) {
|
||||
@@ -495,7 +531,8 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
// TODO: b/377543997 - Migrate to dependency injection and remove mocks.
|
||||
OCMStub([_mockBrowserImpl alloc]).andReturn(fakeBrowser);
|
||||
|
||||
__block BOOL serviceLost = NO;
|
||||
XCTestExpectation *serviceLostExpectation = [self expectationWithDescription:@"Service lost"];
|
||||
serviceLostExpectation.inverted = YES;
|
||||
NSError *error = nil;
|
||||
[framework startDiscoveryForServiceType:kServiceType
|
||||
serviceFoundHandler:^(NSString *serviceName,
|
||||
@@ -503,7 +540,7 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
}
|
||||
serviceLostHandler:^(NSString *serviceName,
|
||||
NSDictionary<NSString *, NSString *> *txtRecords) {
|
||||
serviceLost = YES;
|
||||
[serviceLostExpectation fulfill];
|
||||
}
|
||||
includePeerToPeer:NO
|
||||
error:&error];
|
||||
@@ -524,14 +561,7 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
(nw_browse_result_t)newFakeBrowseResult, true);
|
||||
}
|
||||
|
||||
// Allow async blocks to run.
|
||||
XCTestExpectation *delay = [[XCTestExpectation alloc] initWithDescription:@"delay"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
[delay fulfill];
|
||||
});
|
||||
[self waitForExpectations:@[ delay ] timeout:0.5];
|
||||
|
||||
XCTAssertFalse(serviceLost);
|
||||
[self waitForExpectations:@[ serviceLostExpectation ] timeout:0.1];
|
||||
}
|
||||
|
||||
- (void)testStopDiscoveryForServiceType API_AVAILABLE(ios(13.0)) {
|
||||
@@ -722,8 +752,8 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
GNCNWFrameworkSocket *socket = [framework connectToHost:address
|
||||
port:kPort
|
||||
includePeerToPeer:NO
|
||||
cancelSource:nil
|
||||
queue:nil
|
||||
cancelSource:nil
|
||||
queue:nil
|
||||
error:&error];
|
||||
|
||||
XCTAssertNotNil(socket);
|
||||
@@ -742,8 +772,8 @@ static NSString *const kHostAddress = @"127.0.0.1";
|
||||
GNCNWFrameworkSocket *socket = [framework connectToHost:address
|
||||
port:kPort
|
||||
includePeerToPeer:NO
|
||||
cancelSource:nil
|
||||
queue:nil
|
||||
cancelSource:nil
|
||||
queue:nil
|
||||
error:&error];
|
||||
|
||||
XCTAssertNil(socket);
|
||||
|
||||
@@ -208,7 +208,7 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
}
|
||||
|
||||
- (void)testStartMultipleServicesScanning_Success {
|
||||
std::vector<nearby::Uuid> service_uuids = {nearby::Uuid(0, 0)};
|
||||
std::vector<nearby::Uuid> service_uuids = {nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB)};
|
||||
nearby::api::ble::TxPowerLevel tx_power_level = nearby::api::ble::TxPowerLevel::kUltraLow;
|
||||
|
||||
bool result = _medium->StartMultipleServicesScanning(service_uuids, tx_power_level, {});
|
||||
@@ -217,7 +217,7 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
}
|
||||
|
||||
- (void)testStartMultipleServicesScanning_Failure {
|
||||
std::vector<nearby::Uuid> service_uuids = {nearby::Uuid(0, 0)};
|
||||
std::vector<nearby::Uuid> service_uuids = {nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB)};
|
||||
nearby::api::ble::TxPowerLevel tx_power_level = nearby::api::ble::TxPowerLevel::kUltraLow;
|
||||
_fakeGNCBLEMedium.startScanningError = [NSError errorWithDomain:@"test" code:0 userInfo:nil];
|
||||
|
||||
@@ -300,8 +300,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -326,8 +326,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -385,8 +385,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -413,8 +413,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -450,8 +450,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -483,8 +483,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -650,6 +650,239 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
XCTAssertEqual(server_socket.get(), nullptr);
|
||||
}
|
||||
|
||||
- (void)testOpenServerSocket_Cleanup_InitialState {
|
||||
id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]);
|
||||
OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES);
|
||||
|
||||
id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]);
|
||||
|
||||
__block BOOL added = NO;
|
||||
OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any]
|
||||
bleServiceAddedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager,
|
||||
void (^completion)(NSError *error)) {
|
||||
added = YES;
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
__block BOOL removed = NO;
|
||||
OCMStub([mockPeripheralManager removePeripheralServiceManagerForServiceUUID:[OCMArg any]
|
||||
bleServiceRemovedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, CBUUID *serviceUUID,
|
||||
void (^completion)(NSError *error)) {
|
||||
removed = YES;
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() {
|
||||
return mockPeripheralManager;
|
||||
});
|
||||
|
||||
// Open the server socket.
|
||||
auto server_socket = _medium->OpenServerSocket(kTestServiceID);
|
||||
XCTAssertNotEqual(server_socket.get(), nullptr);
|
||||
XCTAssertTrue(added);
|
||||
XCTAssertFalse(removed);
|
||||
|
||||
server_socket->Close();
|
||||
}
|
||||
|
||||
- (void)testOpenServerSocket_Cleanup_AcceptConnection {
|
||||
id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]);
|
||||
OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES);
|
||||
|
||||
id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]);
|
||||
|
||||
OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any]
|
||||
bleServiceAddedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager,
|
||||
void (^completion)(NSError *error)) {
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
__block BOOL removed = NO;
|
||||
OCMStub([mockPeripheralManager removePeripheralServiceManagerForServiceUUID:[OCMArg any]
|
||||
bleServiceRemovedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, CBUUID *serviceUUID,
|
||||
void (^completion)(NSError *error)) {
|
||||
removed = YES;
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() {
|
||||
return mockPeripheralManager;
|
||||
});
|
||||
|
||||
__block BOOL (^capturedHandler)(GNSSocket *) = nil;
|
||||
id mockServiceManagerClass = OCMClassMock([GNSPeripheralServiceManager class]);
|
||||
OCMStub([mockServiceManagerClass alloc]).andReturn(mockServiceManagerClass);
|
||||
OCMStub([mockServiceManagerClass initWithBleServiceUUID:[OCMArg any]
|
||||
addPairingCharacteristic:NO
|
||||
shouldAcceptSocketHandler:[OCMArg any]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
BOOL (^handler)(GNSSocket *);
|
||||
[invocation getArgument:&handler atIndex:4];
|
||||
capturedHandler = handler;
|
||||
})
|
||||
.andReturn(mockServiceManagerClass);
|
||||
|
||||
auto server_socket = _medium->OpenServerSocket(kTestServiceID);
|
||||
XCTAssertNotEqual(server_socket.get(), nullptr);
|
||||
XCTAssertNotNil(capturedHandler);
|
||||
|
||||
// Simulate connection accepted -> client socket is created.
|
||||
GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init];
|
||||
BOOL result = capturedHandler((GNSSocket *)fakeSocket);
|
||||
XCTAssertTrue(result);
|
||||
|
||||
XCTAssertFalse(removed); // Accepting socket shouldn't remove service manager.
|
||||
|
||||
server_socket->Close();
|
||||
}
|
||||
|
||||
- (void)testOpenServerSocket_Cleanup_CloseClientSocket {
|
||||
id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]);
|
||||
OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES);
|
||||
|
||||
id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]);
|
||||
|
||||
OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any]
|
||||
bleServiceAddedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager,
|
||||
void (^completion)(NSError *error)) {
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
__block BOOL removed = NO;
|
||||
OCMStub([mockPeripheralManager removePeripheralServiceManagerForServiceUUID:[OCMArg any]
|
||||
bleServiceRemovedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, CBUUID *serviceUUID,
|
||||
void (^completion)(NSError *error)) {
|
||||
removed = YES;
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() {
|
||||
return mockPeripheralManager;
|
||||
});
|
||||
|
||||
__block BOOL (^capturedHandler)(GNSSocket *) = nil;
|
||||
id mockServiceManagerClass = OCMClassMock([GNSPeripheralServiceManager class]);
|
||||
OCMStub([mockServiceManagerClass alloc]).andReturn(mockServiceManagerClass);
|
||||
OCMStub([mockServiceManagerClass initWithBleServiceUUID:[OCMArg any]
|
||||
addPairingCharacteristic:NO
|
||||
shouldAcceptSocketHandler:[OCMArg any]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
BOOL (^handler)(GNSSocket *);
|
||||
[invocation getArgument:&handler atIndex:4];
|
||||
capturedHandler = handler;
|
||||
})
|
||||
.andReturn(mockServiceManagerClass);
|
||||
|
||||
auto server_socket = _medium->OpenServerSocket(kTestServiceID);
|
||||
XCTAssertNotEqual(server_socket.get(), nullptr);
|
||||
|
||||
GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init];
|
||||
capturedHandler((GNSSocket *)fakeSocket);
|
||||
[fakeSocket simulateSocketDidConnect];
|
||||
|
||||
__block std::unique_ptr<nearby::api::ble::BleSocket> client_socket = nullptr;
|
||||
XCTestExpectation *acceptExpectation = [self expectationWithDescription:@"Accept connection"];
|
||||
nearby::api::ble::BleServerSocket *raw_server_socket = server_socket.get();
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
client_socket = raw_server_socket->Accept();
|
||||
[acceptExpectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectations:@[ acceptExpectation ] timeout:1.0];
|
||||
XCTAssertTrue(client_socket != nullptr);
|
||||
|
||||
// Close the client socket.
|
||||
client_socket->Close();
|
||||
|
||||
// Wait a bit for any async callbacks
|
||||
XCTestExpectation *expectation2 = [self expectationWithDescription:@"Wait after client close"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(), ^{
|
||||
[expectation2 fulfill];
|
||||
});
|
||||
[self waitForExpectations:@[ expectation2 ] timeout:1.0];
|
||||
|
||||
XCTAssertFalse(removed); // Closing client socket shouldn't remove service manager!
|
||||
|
||||
server_socket->Close();
|
||||
}
|
||||
|
||||
- (void)testOpenServerSocket_Cleanup_CloseServerSocket {
|
||||
id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]);
|
||||
OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES);
|
||||
|
||||
id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]);
|
||||
|
||||
OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any]
|
||||
bleServiceAddedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager,
|
||||
void (^completion)(NSError *error)) {
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
__block BOOL removed = NO;
|
||||
OCMStub([mockPeripheralManager removePeripheralServiceManagerForServiceUUID:[OCMArg any]
|
||||
bleServiceRemovedCompletion:[OCMArg any]])
|
||||
.andDo(^(GNSPeripheralManager *localSelf, CBUUID *serviceUUID,
|
||||
void (^completion)(NSError *error)) {
|
||||
removed = YES;
|
||||
completion(nil);
|
||||
});
|
||||
|
||||
nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() {
|
||||
return mockPeripheralManager;
|
||||
});
|
||||
|
||||
__block BOOL (^capturedHandler)(GNSSocket *) = nil;
|
||||
id mockServiceManagerClass = OCMClassMock([GNSPeripheralServiceManager class]);
|
||||
OCMStub([mockServiceManagerClass alloc]).andReturn(mockServiceManagerClass);
|
||||
OCMStub([mockServiceManagerClass initWithBleServiceUUID:[OCMArg any]
|
||||
addPairingCharacteristic:NO
|
||||
shouldAcceptSocketHandler:[OCMArg any]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
BOOL (^handler)(GNSSocket *);
|
||||
[invocation getArgument:&handler atIndex:4];
|
||||
capturedHandler = handler;
|
||||
})
|
||||
.andReturn(mockServiceManagerClass);
|
||||
|
||||
auto server_socket = _medium->OpenServerSocket(kTestServiceID);
|
||||
XCTAssertNotEqual(server_socket.get(), nullptr);
|
||||
|
||||
GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init];
|
||||
capturedHandler((GNSSocket *)fakeSocket);
|
||||
[fakeSocket simulateSocketDidConnect];
|
||||
|
||||
__block std::unique_ptr<nearby::api::ble::BleSocket> client_socket = nullptr;
|
||||
XCTestExpectation *acceptExpectation = [self expectationWithDescription:@"Accept connection"];
|
||||
nearby::api::ble::BleServerSocket *raw_server_socket = server_socket.get();
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
client_socket = raw_server_socket->Accept();
|
||||
[acceptExpectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectations:@[ acceptExpectation ] timeout:1.0];
|
||||
|
||||
// Close the server socket.
|
||||
server_socket->Close();
|
||||
|
||||
// Wait a bit for any async callbacks
|
||||
XCTestExpectation *expectation3 = [self expectationWithDescription:@"Wait after server close"];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(), ^{
|
||||
[expectation3 fulfill];
|
||||
});
|
||||
[self waitForExpectations:@[ expectation3 ] timeout:1.0];
|
||||
|
||||
XCTAssertTrue(removed); // Closing server socket MUST remove service manager!
|
||||
}
|
||||
|
||||
#pragma mark - Other Tests
|
||||
|
||||
- (void)testIsExtendedAdvertisementsAvailable {
|
||||
@@ -669,8 +902,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -717,8 +950,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
[expectation fulfill];
|
||||
})};
|
||||
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
@@ -742,8 +975,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation1 fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback1));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback1));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData1);
|
||||
}
|
||||
@@ -766,8 +999,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
serviceData2[[CBUUID UUIDWithString:kTestServiceUUIDString]]);
|
||||
[expectation2 fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback2));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback2));
|
||||
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData2);
|
||||
@@ -799,8 +1032,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
[expectation2 fulfill];
|
||||
}
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -826,8 +1059,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation1 fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback1));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback1));
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
}
|
||||
@@ -843,8 +1076,8 @@ static const char *const kTestServiceID = "TestServiceID";
|
||||
const nearby::api::ble::BleAdvertisementData &advertisement) {
|
||||
[expectation2 fulfill];
|
||||
})};
|
||||
_medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow,
|
||||
std::move(callback2));
|
||||
_medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB),
|
||||
nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback2));
|
||||
|
||||
if (_fakeGNCBLEMedium.advertisementFoundHandler) {
|
||||
_fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData);
|
||||
|
||||
@@ -157,4 +157,30 @@ static NSString *const kServiceType = @"_test._tcp";
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testStartDiscoveryCallbacksWithNilName {
|
||||
XCTestExpectation *foundExpectation = [self expectationWithDescription:@"Service found callback"];
|
||||
XCTestExpectation *lostExpectation = [self expectationWithDescription:@"Service lost callback"];
|
||||
|
||||
nearby::apple::network_utils::NetworkDiscoveredServiceCallback callback;
|
||||
callback.network_service_discovered_cb = [&](const nearby::NsdServiceInfo &service_info) {
|
||||
XCTAssertEqual(service_info.GetServiceName(), std::string(""));
|
||||
XCTAssertEqual(service_info.GetServiceType(), kServiceType.UTF8String);
|
||||
[foundExpectation fulfill];
|
||||
};
|
||||
callback.network_service_lost_cb = [&](const nearby::NsdServiceInfo &service_info) {
|
||||
XCTAssertEqual(service_info.GetServiceName(), std::string(""));
|
||||
XCTAssertEqual(service_info.GetServiceType(), kServiceType.UTF8String);
|
||||
[lostExpectation fulfill];
|
||||
};
|
||||
|
||||
BOOL result = nearby::apple::network_utils::StartDiscovery(
|
||||
_fakeNWFramework, kServiceType.UTF8String, std::move(callback), YES);
|
||||
XCTAssertTrue(result);
|
||||
|
||||
[_fakeNWFramework triggerServiceFound:nil txtRecords:@{}];
|
||||
[_fakeNWFramework triggerServiceLost:nil txtRecords:@{}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -247,6 +247,7 @@ class BleMedium : public api::ble::BleMedium {
|
||||
GNSPeripheralManager *socketPeripheralManager_;
|
||||
|
||||
absl::Mutex scanning_mutex_;
|
||||
std::vector<Uuid> scanning_service_uuids_ ABSL_GUARDED_BY(scanning_mutex_);
|
||||
GNSCentralManager *socketCentralManager_ ABSL_GUARDED_BY(scanning_mutex_);
|
||||
|
||||
// Used for the blocking version of StartAdvertising and only has an advertisement found callback.
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#import "internal/platform/implementation/apple/ble_medium.h"
|
||||
|
||||
#import <CoreBluetooth/CoreBluetooth.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -157,8 +159,17 @@ void BleMedium::HandleAdvertisementFound(id<GNCPeripheral> peripheral,
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Uuid> scanning_uuids;
|
||||
{
|
||||
absl::MutexLock lock(&scanning_mutex_);
|
||||
scanning_uuids = scanning_service_uuids_;
|
||||
}
|
||||
for (CBUUID *key in serviceData.allKeys) {
|
||||
data.service_data[CPPUUIDFromObjC(key)] = ByteArrayFromNSData(serviceData[key]);
|
||||
Uuid cpp_uuid = CPPUUIDFromObjC(key);
|
||||
if (absl::c_find(scanning_uuids, cpp_uuid) == scanning_uuids.end()) {
|
||||
continue;
|
||||
}
|
||||
data.service_data[cpp_uuid] = ByteArrayFromNSData(serviceData[key]);
|
||||
}
|
||||
|
||||
// Add the peripheral to the map if we haven't discovered it yet.
|
||||
@@ -197,6 +208,7 @@ std::unique_ptr<api::ble::BleMedium::ScanningSession> BleMedium::StartScanning(
|
||||
{
|
||||
absl::MutexLock lock(&scanning_mutex_);
|
||||
scanning_cb_ = std::make_shared<api::ble::BleMedium::ScanningCallback>(std::move(callback));
|
||||
scanning_service_uuids_ = {service_uuid};
|
||||
|
||||
if (central_manager_factory_) {
|
||||
socketCentralManager_ = central_manager_factory_(serviceUUID);
|
||||
@@ -273,6 +285,7 @@ bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble::TxPowerLevel t
|
||||
{
|
||||
absl::MutexLock lock(&scanning_mutex_);
|
||||
scan_cb_ = std::make_shared<api::ble::BleMedium::ScanCallback>(std::move(callback));
|
||||
scanning_service_uuids_ = {service_uuid};
|
||||
|
||||
if (central_manager_factory_) {
|
||||
socketCentralManager_ = central_manager_factory_(serviceUUID);
|
||||
@@ -331,6 +344,7 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector<Uuid> &service_u
|
||||
{
|
||||
absl::MutexLock lock(&scanning_mutex_);
|
||||
scan_cb_ = std::make_shared<api::ble::BleMedium::ScanCallback>(std::move(callback));
|
||||
scanning_service_uuids_ = service_uuids;
|
||||
|
||||
if (central_manager_factory_) {
|
||||
socketCentralManager_ = central_manager_factory_(serviceUUIDs[0]);
|
||||
@@ -379,6 +393,7 @@ bool BleMedium::StopScanning() {
|
||||
[socketCentralManager_ stopNoScanMode];
|
||||
scan_cb_ = nullptr;
|
||||
scanning_cb_ = nullptr;
|
||||
scanning_service_uuids_.clear();
|
||||
}
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
@@ -534,6 +549,13 @@ std::unique_ptr<api::ble::BleServerSocket> BleMedium::OpenServerSocketWithDeadlo
|
||||
server_socket->SetCloseNotifier([this]() {
|
||||
absl::MutexLock lock(server_socket_mutex_);
|
||||
server_socket_ptr_ = nullptr;
|
||||
if (socketPeripheralManager_ != nil && socketPeripheralServiceManager_ != nil) {
|
||||
[socketPeripheralManager_
|
||||
removePeripheralServiceManagerForServiceUUID:socketPeripheralServiceManager_.serviceUUID
|
||||
bleServiceRemovedCompletion:^(NSError *_Nullable error) {
|
||||
GNCLoggerInfo(@"Weave service removed from peripheral manager.");
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc]
|
||||
@@ -549,15 +571,6 @@ std::unique_ptr<api::ble::BleServerSocket> BleMedium::OpenServerSocketWithDeadlo
|
||||
callbackQueue:connection_callback_queue_];
|
||||
|
||||
auto socket_wrapper = std::make_unique<BleSocket>(connection);
|
||||
socket_wrapper->SetCloseNotifier(
|
||||
[socketPeripheralManager = socketPeripheralManager_,
|
||||
serviceUUID = socketPeripheralServiceManager_.serviceUUID]() {
|
||||
[socketPeripheralManager
|
||||
removePeripheralServiceManagerForServiceUUID:serviceUUID
|
||||
bleServiceRemovedCompletion:^(NSError *_Nullable error) {
|
||||
GNCLoggerInfo(@"BleSocket is removed peripheral manager.");
|
||||
}];
|
||||
});
|
||||
|
||||
connection.connectionHandlers = socket_wrapper->GetInputStream().GetConnectionHandlers();
|
||||
|
||||
@@ -612,6 +625,16 @@ std::unique_ptr<api::ble::BleServerSocket> BleMedium::OpenServerSocketLegacy(
|
||||
// Raw pointer for closure capture in the legacy path (risks use-after-free).
|
||||
BleServerSocket *server_socket_ptr = server_socket.get();
|
||||
|
||||
server_socket->SetCloseNotifier([this]() {
|
||||
if (socketPeripheralManager_ != nil && socketPeripheralServiceManager_ != nil) {
|
||||
[socketPeripheralManager_
|
||||
removePeripheralServiceManagerForServiceUUID:socketPeripheralServiceManager_.serviceUUID
|
||||
bleServiceRemovedCompletion:^(NSError *_Nullable error) {
|
||||
GNCLoggerInfo(@"Weave service removed from peripheral manager.");
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc]
|
||||
initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID]
|
||||
addPairingCharacteristic:NO
|
||||
@@ -627,14 +650,6 @@ std::unique_ptr<api::ble::BleServerSocket> BleMedium::OpenServerSocketLegacy(
|
||||
callbackQueue:connection_callback_queue_];
|
||||
|
||||
auto socket = std::make_unique<BleSocket>(connection);
|
||||
socket->SetCloseNotifier([socketPeripheralManager = socketPeripheralManager_,
|
||||
serviceUUID = socketPeripheralServiceManager_.serviceUUID]() {
|
||||
[socketPeripheralManager
|
||||
removePeripheralServiceManagerForServiceUUID:serviceUUID
|
||||
bleServiceRemovedCompletion:^(NSError *_Nullable error) {
|
||||
GNCLoggerInfo(@"BleSocket is removed peripheral manager.");
|
||||
}];
|
||||
});
|
||||
|
||||
connection.connectionHandlers = socket->GetInputStream().GetConnectionHandlers();
|
||||
if (server_socket_ptr) {
|
||||
|
||||
@@ -63,7 +63,7 @@ bool StartDiscovery(GNCNWFramework* medium, const std::string& service_type,
|
||||
serviceFoundHandler:^(NSString* name, NSDictionary<NSString*, NSString*>* txtRecords) {
|
||||
NsdServiceInfo nsd_service_info;
|
||||
nsd_service_info.SetServiceType([serviceType UTF8String]);
|
||||
nsd_service_info.SetServiceName([name UTF8String]);
|
||||
nsd_service_info.SetServiceName(name ? [name UTF8String] : "");
|
||||
[txtRecords
|
||||
enumerateKeysAndObjectsUsingBlock:[nsd_service_info = &nsd_service_info](
|
||||
NSString* key, NSString* val, BOOL* stop) {
|
||||
@@ -74,7 +74,7 @@ bool StartDiscovery(GNCNWFramework* medium, const std::string& service_type,
|
||||
serviceLostHandler:^(NSString* name, NSDictionary<NSString*, NSString*>* txtRecords) {
|
||||
NsdServiceInfo nsd_service_info;
|
||||
nsd_service_info.SetServiceType([serviceType UTF8String]);
|
||||
nsd_service_info.SetServiceName([name UTF8String]);
|
||||
nsd_service_info.SetServiceName(name ? [name UTF8String] : "");
|
||||
[txtRecords
|
||||
enumerateKeysAndObjectsUsingBlock:[nsd_service_info = &nsd_service_info](
|
||||
NSString* key, NSString* val, BOOL* stop) {
|
||||
|
||||
@@ -51,8 +51,12 @@ namespace api {
|
||||
std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder,
|
||||
const std::string& file_name) {
|
||||
// Collapse any path escaping characters.
|
||||
NSString* parentFolder = [@(parent_folder.c_str()) stringByReplacingOccurrencesOfString:@"../"
|
||||
withString:@""];
|
||||
NSString* parentFolderRaw = @(parent_folder.c_str());
|
||||
if (parentFolderRaw == nil) {
|
||||
return std::string();
|
||||
}
|
||||
NSString* parentFolder = [parentFolderRaw stringByReplacingOccurrencesOfString:@"../"
|
||||
withString:@""];
|
||||
NSURL* parentFolderURL = [NSURL fileURLWithPath:parentFolder];
|
||||
|
||||
// The only reserved character in a file name on macOS is the forward-slash. It's unclear if iOS
|
||||
@@ -66,8 +70,12 @@ std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_
|
||||
// """
|
||||
//
|
||||
// See: https://en.wikipedia.org/wiki/Filename
|
||||
NSString* fileName = [@(file_name.c_str()) stringByReplacingOccurrencesOfString:@"/"
|
||||
withString:@":"];
|
||||
NSString* fileNameRaw = @(file_name.c_str());
|
||||
if (fileNameRaw == nil) {
|
||||
return std::string();
|
||||
}
|
||||
NSString* fileName = [fileNameRaw stringByReplacingOccurrencesOfString:@"/"
|
||||
withString:@":"];
|
||||
NSString* baseName = [fileName stringByDeletingPathExtension];
|
||||
NSString* extension = [fileName pathExtension];
|
||||
|
||||
@@ -86,8 +94,12 @@ std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_
|
||||
|
||||
std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder,
|
||||
const std::string& file_name) {
|
||||
NSString* parentFolderRaw = @(parent_folder.c_str());
|
||||
if (parentFolderRaw == nil) {
|
||||
return std::string();
|
||||
}
|
||||
NSString* customSavePath =
|
||||
[NSTemporaryDirectory() stringByAppendingPathComponent:@(parent_folder.c_str())];
|
||||
[NSTemporaryDirectory() stringByAppendingPathComponent:parentFolderRaw];
|
||||
return GetCustomSavePath(customSavePath.UTF8String, file_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "absl/time/time.h"
|
||||
#import "internal/platform/implementation/apple/Log/GNCLogger.h"
|
||||
#include "internal/platform/runnable.h"
|
||||
|
||||
// Defines the state of a scheduled task. This enum is at global scope
|
||||
@@ -93,7 +94,23 @@ class ExecutorCancelable : public nearby::api::Cancelable {
|
||||
|
||||
namespace nearby {
|
||||
namespace apple {
|
||||
namespace {
|
||||
|
||||
void ExecuteRunnable(Runnable &runnable) {
|
||||
@try {
|
||||
try {
|
||||
runnable();
|
||||
} catch (const std::exception &e) {
|
||||
GNCLoggerError(@"Runnable threw C++ exception: %s", e.what());
|
||||
} catch (...) {
|
||||
GNCLoggerError(@"Runnable threw unknown C++ exception");
|
||||
}
|
||||
} @catch (NSException *e) {
|
||||
GNCLoggerError(@"Runnable threw ObjC exception: %@: %@", e.name, e.reason);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScheduledExecutor::ScheduledExecutor() { impl_ = [GNCOperationQueueImpl implWithMaxConcurrency:1]; }
|
||||
|
||||
@@ -106,7 +123,6 @@ ScheduledExecutor::~ScheduledExecutor() {
|
||||
impl_ = nil;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(Runnable &&runnable,
|
||||
absl::Duration duration) {
|
||||
if (impl_.shuttingDown) return std::shared_ptr<api::Cancelable>(nullptr);
|
||||
@@ -133,7 +149,7 @@ std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(Runnable &&runnable
|
||||
}
|
||||
GNCScheduledTaskState expected = GNCScheduledTaskState::kScheduled;
|
||||
if (task->_state.compare_exchange_strong(expected, GNCScheduledTaskState::kRunning)) {
|
||||
task->_runnable();
|
||||
ExecuteRunnable(task->_runnable);
|
||||
task->_state.store(GNCScheduledTaskState::kDone);
|
||||
}
|
||||
}];
|
||||
@@ -152,7 +168,7 @@ bool ScheduledExecutor::DoSubmit(Runnable &&runnable) {
|
||||
// Submit the runnable to the queue.
|
||||
__block Runnable local_runnable = std::move(runnable);
|
||||
[impl_.queue addOperationWithBlock:^{
|
||||
local_runnable();
|
||||
ExecuteRunnable(local_runnable);
|
||||
}];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
@@ -29,8 +28,7 @@
|
||||
#include "internal/platform/mac_address.h"
|
||||
#include "internal/platform/output_stream.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
namespace nearby::api {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
|
||||
class BluetoothDevice {
|
||||
@@ -213,29 +211,6 @@ class BluetoothClassicMedium {
|
||||
DefaultCallback<BluetoothDevice&>();
|
||||
};
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() = default;
|
||||
|
||||
// Called when a new `device` is added to the adapter.
|
||||
virtual void DeviceAdded(BluetoothDevice& device) {}
|
||||
|
||||
// Called when `device` is removed from the adapter.
|
||||
virtual void DeviceRemoved(BluetoothDevice& device) {}
|
||||
|
||||
// Called when the address of `device` changed due to pairing.
|
||||
virtual void DeviceAddressChanged(BluetoothDevice& device,
|
||||
absl::string_view old_address) {}
|
||||
|
||||
// Called when the paired property of `device` changed.
|
||||
virtual void DevicePairedChanged(BluetoothDevice& device,
|
||||
bool new_paired_status) {}
|
||||
|
||||
// Called when `device` has connected or disconnected.
|
||||
virtual void DeviceConnectedStateChanged(BluetoothDevice& device,
|
||||
bool connected) {}
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
|
||||
//
|
||||
// Returns true once the process of discovery has been initiated.
|
||||
@@ -273,7 +248,7 @@ class BluetoothClassicMedium {
|
||||
// UUID.
|
||||
//
|
||||
// Returns nullptr error.
|
||||
virtual std::unique_ptr<BluetoothServerSocket> ListenForService(
|
||||
virtual std::shared_ptr<BluetoothServerSocket> ListenForService(
|
||||
const std::string& service_name, const std::string& service_uuid) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()
|
||||
@@ -285,12 +260,8 @@ class BluetoothClassicMedium {
|
||||
BluetoothDevice& remote_device) = 0;
|
||||
|
||||
virtual BluetoothDevice* GetRemoteDevice(MacAddress mac_address) = 0;
|
||||
|
||||
virtual void AddObserver(Observer* observer) = 0;
|
||||
virtual void RemoveObserver(Observer* observer) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace nearby::api
|
||||
|
||||
#endif // PLATFORM_API_BLUETOOTH_CLASSIC_H_
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define PLATFORM_API_DEVICE_INFO_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -39,6 +40,7 @@ class DeviceInfo {
|
||||
kWindows,
|
||||
kMacOS
|
||||
};
|
||||
enum class SuspendResumeEvent { kSuspend, kResume };
|
||||
|
||||
virtual ~DeviceInfo() = default;
|
||||
|
||||
@@ -69,6 +71,14 @@ class DeviceInfo {
|
||||
// Control device sleep
|
||||
virtual bool PreventSleep() = 0;
|
||||
virtual bool AllowSleep() = 0;
|
||||
|
||||
// Monitor suspend/resume events.
|
||||
// Returns a listener id that can be used to unregister the listener.
|
||||
virtual int64_t RegisterSuspendResumeListener(
|
||||
std::function<void(SuspendResumeEvent)> callback) {
|
||||
return 0;
|
||||
}
|
||||
virtual void UnregisterSuspendResumeListener(int64_t listener_id) {}
|
||||
};
|
||||
|
||||
template <typename Sink>
|
||||
|
||||
@@ -59,10 +59,11 @@ cc_library(
|
||||
"//internal/platform/implementation:types",
|
||||
"//internal/platform/implementation/shared:count_down_latch",
|
||||
"//internal/platform/implementation/shared:posix_mutex",
|
||||
"//internal/test",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/base:nullability",
|
||||
"@com_google_absl//absl/container:btree",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
@@ -151,13 +152,13 @@ cc_test(
|
||||
"//internal/platform:test_util",
|
||||
"//internal/platform:uuid",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//third_party/gloop/thread/fiber",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
"@com_google_nisaba//nisaba/port:thread_pool/fiber",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -187,13 +188,11 @@ cc_library(
|
||||
visibility = [
|
||||
"//connections:__subpackages__",
|
||||
"//connections:partners",
|
||||
"//internal/account:__subpackages__",
|
||||
"//internal/auth:__subpackages__",
|
||||
"//internal/crypto:__subpackages__",
|
||||
"//internal/data:__subpackages__",
|
||||
"//internal/network:__subpackages__",
|
||||
"//internal/platform:__subpackages__",
|
||||
"//internal/preferences:__subpackages__",
|
||||
"//internal/proto/analytics:__subpackages__",
|
||||
"//internal/weave:__subpackages__",
|
||||
"//location/nearby/sharing/sdk:__subpackages__",
|
||||
@@ -217,6 +216,7 @@ cc_library(
|
||||
"//internal/platform/implementation/shared:file",
|
||||
"//third_party/gloop/thread",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/base:no_destructor",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
@@ -237,3 +237,18 @@ cc_library(
|
||||
"@nlohmann_json//:json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "scheduled_executor_test",
|
||||
srcs = ["scheduled_executor_test.cc"],
|
||||
deps = [
|
||||
":g3",
|
||||
":types",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:test_util",
|
||||
"//internal/platform:types",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/synchronization/notification.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "third_party/gloop/thread/fiber/fiber.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
#include "internal/platform/implementation/awdl.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
#include "internal/platform/nsd_service_info.h"
|
||||
#include "thread/fiber/fiber.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
@@ -240,10 +240,10 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
return socket;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::BluetoothServerSocket>
|
||||
std::shared_ptr<api::BluetoothServerSocket>
|
||||
BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
const std::string& service_uuid) {
|
||||
auto socket = std::make_unique<BluetoothServerSocket>(GetAdapter());
|
||||
auto socket = std::make_shared<BluetoothServerSocket>(GetAdapter());
|
||||
socket->SetCloseNotifier([this, uuid = service_uuid]() {
|
||||
absl::MutexLock lock(mutex_);
|
||||
sockets_.erase(uuid);
|
||||
@@ -264,15 +264,5 @@ api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
|
||||
return MediumEnvironment::Instance().FindBluetoothDevice(mac_address);
|
||||
}
|
||||
|
||||
void BluetoothClassicMedium::AddObserver(
|
||||
api::BluetoothClassicMedium::Observer* observer) {
|
||||
MediumEnvironment::Instance().AddObserver(observer);
|
||||
}
|
||||
|
||||
void BluetoothClassicMedium::RemoveObserver(
|
||||
api::BluetoothClassicMedium::Observer* observer) {
|
||||
MediumEnvironment::Instance().RemoveObserver(observer);
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
|
||||
@@ -195,7 +195,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
// UUID.
|
||||
//
|
||||
// Returns nullptr on error.
|
||||
std::unique_ptr<api::BluetoothServerSocket> ListenForService(
|
||||
std::shared_ptr<api::BluetoothServerSocket> ListenForService(
|
||||
const std::string& service_name, const std::string& service_uuid) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
@@ -206,9 +206,6 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
|
||||
api::BluetoothDevice* GetRemoteDevice(MacAddress mac_address) override;
|
||||
|
||||
void AddObserver(Observer* observer) override;
|
||||
void RemoveObserver(Observer* observer) override;
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
BluetoothAdapter* adapter_; // Our device adapter; read-only.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/no_destructor.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
@@ -239,7 +240,8 @@ ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Timer> ImplementationPlatform::CreateTimer() {
|
||||
return std::make_unique<g3::Timer>();
|
||||
static absl::NoDestructor<g3::ScheduledExecutor> timer_executor;
|
||||
return std::make_unique<g3::Timer>(timer_executor.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<nearby::api::DeviceInfo>
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
// 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 "internal/platform/scheduled_executor.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/cancelable.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
|
||||
namespace nearby {
|
||||
|
||||
// kShortDelay must be significant enough to guarantee that OS under heavy load
|
||||
// should be able to execute the non-blocking test paths within this time.
|
||||
absl::Duration kShortDelay = absl::Milliseconds(200);
|
||||
|
||||
// kLongDelay must be long enough to make sure that under OS under heavy load
|
||||
// will let kShortDelay fire and jobs scheduled before the kLongDelay fires.
|
||||
absl::Duration kLongDelay = 10 * kShortDelay;
|
||||
|
||||
TEST(ScheduledExecutorTest, SimulatedClockCanSchedule) {
|
||||
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
|
||||
ScheduledExecutor executor;
|
||||
std::atomic_int value = 0;
|
||||
CountDownLatch first_task_latch(1);
|
||||
CountDownLatch second_task_latch(1);
|
||||
// schedule job due in kLongDelay.
|
||||
executor.Schedule(
|
||||
[&]() {
|
||||
EXPECT_EQ(value, 1);
|
||||
value = 5;
|
||||
first_task_latch.CountDown();
|
||||
},
|
||||
kLongDelay);
|
||||
// schedule job due in kShortDelay; must fire before the first one.
|
||||
executor.Schedule(
|
||||
[&]() {
|
||||
EXPECT_EQ(value, 0);
|
||||
value = 1;
|
||||
second_task_latch.CountDown();
|
||||
},
|
||||
kShortDelay);
|
||||
EXPECT_EQ(value, 0);
|
||||
MediumEnvironment::Instance().FastForward(kShortDelay -
|
||||
absl::Milliseconds(1));
|
||||
EXPECT_EQ(value, 0);
|
||||
MediumEnvironment::Instance().FastForward(absl::Milliseconds(1));
|
||||
second_task_latch.Await();
|
||||
EXPECT_EQ(value, 1);
|
||||
MediumEnvironment::Instance().FastForward(kLongDelay - kShortDelay);
|
||||
first_task_latch.Await();
|
||||
EXPECT_EQ(value, 5);
|
||||
// Very long sleep to make sure that the sleep is truly simulated.
|
||||
MediumEnvironment::Instance().FastForward(absl::Minutes(30));
|
||||
MediumEnvironment::Instance().Stop();
|
||||
}
|
||||
|
||||
TEST(ScheduledExecutorTest,
|
||||
DestroyExecutorWithSimulatedClockIgnoresPendingTasks) {
|
||||
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
|
||||
{
|
||||
ScheduledExecutor executor;
|
||||
executor.Schedule(
|
||||
[&]() {
|
||||
// This task should never be executed.
|
||||
EXPECT_TRUE(false);
|
||||
},
|
||||
kShortDelay);
|
||||
}
|
||||
MediumEnvironment::Instance().FastForward(absl::Minutes(30));
|
||||
MediumEnvironment::Instance().Stop();
|
||||
}
|
||||
|
||||
TEST(ScheduledExecutorTest, SimulatedClockCanScheduleRepeatedly) {
|
||||
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
|
||||
ScheduledExecutor executor;
|
||||
std::atomic_int value = 0;
|
||||
std::atomic_int i = 0;
|
||||
CountDownLatch latch[] = {CountDownLatch(1), CountDownLatch(1)};
|
||||
|
||||
Cancelable cancelable = executor.ScheduleRepeatedly(
|
||||
[&]() {
|
||||
value++;
|
||||
latch[i.fetch_add(1)].CountDown();
|
||||
},
|
||||
kShortDelay);
|
||||
|
||||
EXPECT_EQ(value, 0);
|
||||
// Advance to just before the first execution.
|
||||
MediumEnvironment::Instance().FastForward(kShortDelay -
|
||||
absl::Milliseconds(1));
|
||||
EXPECT_EQ(value, 0);
|
||||
|
||||
// Advance past the first execution.
|
||||
MediumEnvironment::Instance().FastForward(absl::Milliseconds(1));
|
||||
latch[0].Await(absl::Seconds(1));
|
||||
EXPECT_EQ(value, 1);
|
||||
|
||||
// Advance to just before the second execution.
|
||||
MediumEnvironment::Instance().FastForward(kShortDelay -
|
||||
absl::Milliseconds(1));
|
||||
EXPECT_EQ(value, 1);
|
||||
|
||||
// Advance past the second execution.
|
||||
MediumEnvironment::Instance().FastForward(absl::Milliseconds(1));
|
||||
latch[1].Await(absl::Seconds(1));
|
||||
EXPECT_EQ(value, 2);
|
||||
|
||||
// Cancel the task.
|
||||
cancelable.Cancel();
|
||||
|
||||
// Advance a long time and make sure it doesn't run again.
|
||||
MediumEnvironment::Instance().FastForward(kLongDelay * 5);
|
||||
EXPECT_EQ(value, 2);
|
||||
|
||||
MediumEnvironment::Instance().Stop();
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
@@ -19,10 +19,13 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/implementation/g3/scheduled_executor.h"
|
||||
#include "internal/platform/implementation/cancelable.h"
|
||||
#include "internal/platform/implementation/scheduled_executor.h"
|
||||
#include "internal/platform/implementation/timer.h"
|
||||
|
||||
namespace nearby {
|
||||
@@ -30,8 +33,11 @@ namespace g3 {
|
||||
|
||||
class Timer : public api::Timer {
|
||||
public:
|
||||
Timer() = default;
|
||||
~Timer() override = default;
|
||||
explicit Timer(api::ScheduledExecutor* absl_nonnull executor)
|
||||
: executor_(executor) {};
|
||||
~Timer() override {
|
||||
Stop();
|
||||
};
|
||||
|
||||
bool Create(int delay, int interval,
|
||||
absl::AnyInvocable<void()> callback) override {
|
||||
@@ -52,13 +58,16 @@ class Timer : public api::Timer {
|
||||
task_.reset();
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool Schedule(absl::Duration delay) {
|
||||
absl::MutexLock lock(mutex_);
|
||||
task_ = executor_.Schedule([this]() { TriggerCallback(); }, delay);
|
||||
if (is_stopped_) {
|
||||
return false;
|
||||
}
|
||||
task_ = executor_->Schedule([this]() { TriggerCallback(); }, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,7 +86,7 @@ class Timer : public api::Timer {
|
||||
std::atomic_bool is_stopped_;
|
||||
absl::Duration interval_;
|
||||
std::shared_ptr<api::Cancelable> task_ ABSL_GUARDED_BY(mutex_);
|
||||
ScheduledExecutor executor_;
|
||||
api::ScheduledExecutor* absl_nonnull const executor_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#ifndef PLATFORM_API_SCHEDULED_EXECUTOR_H_
|
||||
#define PLATFORM_API_SCHEDULED_EXECUTOR_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/time/time.h"
|
||||
|
||||
@@ -72,7 +72,13 @@ cc_library(
|
||||
"timer.h",
|
||||
"utils.h",
|
||||
],
|
||||
defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"],
|
||||
defines = [
|
||||
"_SILENCE_CLANG_COROUTINE_MESSAGE",
|
||||
"_WIN32_WINNT=_WIN32_WINNT_WIN10",
|
||||
],
|
||||
linkopts = [
|
||||
"powrprof.lib",
|
||||
],
|
||||
tags = ["windows"],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "internal/platform/implementation/bluetooth_classic.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_server_socket.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_pairing.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
|
||||
@@ -43,8 +44,7 @@
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/platform/mac_address.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace nearby::windows {
|
||||
namespace {
|
||||
using ::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService;
|
||||
using ::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId;
|
||||
@@ -124,7 +124,13 @@ BluetoothClassicMedium::BluetoothClassicMedium(
|
||||
&BluetoothClassicMedium::OnScanModeChanged, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
BluetoothClassicMedium::~BluetoothClassicMedium() {}
|
||||
BluetoothClassicMedium::~BluetoothClassicMedium() {
|
||||
// Clear the close notifier to prevent UAF if the server_socket_ outlives
|
||||
// the BluetoothClassicMedium.
|
||||
if (raw_server_socket_ != nullptr) {
|
||||
raw_server_socket_->SetCloseNotifier(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StartDiscovery(
|
||||
BluetoothClassicMedium::DiscoveryCallback discovery_callback) {
|
||||
@@ -259,7 +265,7 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
// UUID.
|
||||
//
|
||||
// Returns nullptr error.
|
||||
std::unique_ptr<api::BluetoothServerSocket>
|
||||
std::shared_ptr<api::BluetoothServerSocket>
|
||||
BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
const std::string& service_uuid) {
|
||||
VLOG(1) << "ListenForService is called with service name: " << service_name
|
||||
@@ -283,14 +289,24 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
bool radio_discoverable =
|
||||
scan_mode_ == BluetoothAdapter::ScanMode::kConnectableDiscoverable;
|
||||
|
||||
bool result = StartAdvertising(radio_discoverable);
|
||||
if (rfcomm_provider_ != nullptr &&
|
||||
is_radio_discoverable_ == radio_discoverable) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Ignore StartAdvertising due to no change to "
|
||||
"current advertising.";
|
||||
return server_socket_;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
auto server_socket = StartAdvertising(radio_discoverable);
|
||||
|
||||
if (!server_socket) {
|
||||
LOG(ERROR) << __func__ << ": Failed to start listening.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(server_socket_);
|
||||
raw_server_socket_ = server_socket.get();
|
||||
server_socket_ = std::move(server_socket);
|
||||
return server_socket_;
|
||||
}
|
||||
|
||||
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
|
||||
@@ -685,9 +701,6 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
|
||||
if (discovery_callback_.device_discovered_cb != nullptr) {
|
||||
discovery_callback_.device_discovered_cb(*device);
|
||||
}
|
||||
for (auto& observer : observers_.GetObservers()) {
|
||||
observer->DeviceAdded(*device);
|
||||
}
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
@@ -753,9 +766,6 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
|
||||
LOG(INFO) << __func__
|
||||
<< ": Notifying device paired changed: " << std::boolalpha
|
||||
<< new_paired_status;
|
||||
for (auto& observer : observers_.GetObservers()) {
|
||||
observer->DevicePairedChanged(*device, new_paired_status);
|
||||
}
|
||||
}
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
@@ -803,10 +813,6 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Removed(
|
||||
discovery_callback_.device_lost_cb(*device);
|
||||
}
|
||||
|
||||
for (auto& observer : observers_.GetObservers()) {
|
||||
observer->DeviceRemoved(*device);
|
||||
}
|
||||
|
||||
RemoveRemoteDevice(mac_address);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
@@ -833,25 +839,19 @@ bool BluetoothClassicMedium::IsWatcherRunning() {
|
||||
(status == DeviceWatcherStatus::Stopping);
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
|
||||
std::shared_ptr<BluetoothServerSocket>
|
||||
BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
|
||||
LOG(INFO) << __func__
|
||||
<< ": StartAdvertising is called with radio_discoverable: "
|
||||
<< radio_discoverable << ".";
|
||||
|
||||
std::shared_ptr<BluetoothServerSocket> server_socket;
|
||||
try {
|
||||
if (rfcomm_provider_ != nullptr &&
|
||||
is_radio_discoverable_ == radio_discoverable) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Ignore StartAdvertising due to no change to "
|
||||
"current advertising.";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr && !StopAdvertising()) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Failed to StartAdvertising due to cannot stop "
|
||||
"running advertising.";
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rfcomm_provider_ =
|
||||
@@ -859,79 +859,57 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
|
||||
RfcommServiceId::FromUuid(winrt::guid(service_uuid_)))
|
||||
.get();
|
||||
|
||||
server_socket_ = std::make_unique<BluetoothServerSocket>(
|
||||
server_socket = BluetoothServerSocket::Create(
|
||||
winrt::to_string(rfcomm_provider_.ServiceId().AsString()));
|
||||
|
||||
raw_server_socket_ = server_socket_.get();
|
||||
|
||||
if (!server_socket_->listen()) {
|
||||
if (!server_socket->listen()) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Failed to StartAdvertising due to cannot start socket.";
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
rfcomm_provider_ = nullptr;
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
server_socket_->SetCloseNotifier([&]() { StopAdvertising(); });
|
||||
server_socket->SetCloseNotifier([&]() { StopAdvertising(); });
|
||||
|
||||
// Set the SDP attributes and start Bluetooth advertising
|
||||
InitializeServiceSdpAttributes(rfcomm_provider_, service_name_);
|
||||
|
||||
// Start to advertising.
|
||||
rfcomm_provider_.StartAdvertising(server_socket_->stream_socket_listener(),
|
||||
rfcomm_provider_.StartAdvertising(server_socket->stream_socket_listener(),
|
||||
radio_discoverable);
|
||||
is_radio_discoverable_ = radio_discoverable;
|
||||
|
||||
LOG(INFO) << ": StartListening completed successfully.";
|
||||
return true;
|
||||
return server_socket;
|
||||
} catch (std::exception exception) {
|
||||
// We will log and eat the exception since the caller
|
||||
// expects nullptr if it fails
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Exception setting up for listen: " << exception.what();
|
||||
|
||||
if (server_socket_ != nullptr) {
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr) {
|
||||
rfcomm_provider_ = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
LOG(ERROR) << __func__ << ": Exception setting up for listen: " << ex.code()
|
||||
<< ": " << winrt::to_string(ex.message());
|
||||
if (server_socket_ != nullptr) {
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr) {
|
||||
rfcomm_provider_ = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exception.";
|
||||
if (server_socket_ != nullptr) {
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr) {
|
||||
rfcomm_provider_ = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StopAdvertising() {
|
||||
VLOG(1) << __func__ << ": StopAdvertising is called";
|
||||
|
||||
bool result = false;
|
||||
try {
|
||||
if (rfcomm_provider_ == nullptr) {
|
||||
LOG(ERROR) << __func__
|
||||
@@ -940,12 +918,9 @@ bool BluetoothClassicMedium::StopAdvertising() {
|
||||
}
|
||||
|
||||
rfcomm_provider_.StopAdvertising();
|
||||
rfcomm_provider_ = nullptr;
|
||||
raw_server_socket_ = nullptr;
|
||||
server_socket_ = nullptr;
|
||||
|
||||
LOG(INFO) << ": StopAdvertising completed successfully.";
|
||||
return true;
|
||||
result = true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": StopAdvertising exception: " << exception.what();
|
||||
@@ -957,9 +932,9 @@ bool BluetoothClassicMedium::StopAdvertising() {
|
||||
}
|
||||
|
||||
rfcomm_provider_ = nullptr;
|
||||
raw_server_socket_ = nullptr;
|
||||
server_socket_ = nullptr;
|
||||
return false;
|
||||
raw_server_socket_ = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::InitializeServiceSdpAttributes(
|
||||
@@ -988,5 +963,4 @@ bool BluetoothClassicMedium::InitializeServiceSdpAttributes(
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace nearby::windows
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user