Merge branch 'sync-upstream'

bringing main up to speed with upstream
This commit is contained in:
Lasan Mahaliyana
2026-06-13 22:05:46 +05:30
699 changed files with 62077 additions and 42733 deletions
+6
View File
@@ -1,4 +1,10 @@
build --action_env=BAZEL_CXXOPTS=-"std=c++20" --repo_env=BAZEL_CONLYOPTS="-std=gnu17"
build --action_env=CC=/usr/bin/clang
build --action_env=CXX=/usr/bin/clang++
build --check_visibility=false --spawn_strategy=standalone --verbose_failures
build --cxxopt=-std=c++20
build --cxxopt='-fvisibility-inlines-hidden'
build --host_cxxopt=-std=c++20
# Definition of --config=memcheck
build:memcheck --strip=never --test_timeout=3600
common --enable_bzlmod
+10 -17
View File
@@ -1,4 +1,4 @@
# Copyright 2022 Google LLC
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,25 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
licenses(["notice"])
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
package(default_visibility = ["//visibility:public"])
proto_library(
name = "sharing_log_proto",
srcs = [
"nearby_sharing_log.proto",
],
deps = [
"//proto:sharing_enums_proto",
"@com_google_protobuf//:duration_proto",
],
licenses(["notice"])
bool_flag(
name = "enable_webrtc",
build_setting_default = False,
)
cc_proto_library(
name = "sharing_log_cc_proto",
deps = [":sharing_log_proto"],
config_setting(
name = "webrtc_enabled",
flag_values = {":enable_webrtc": "True"},
)
+2 -1
View File
@@ -190,10 +190,11 @@ cmake(
"CMAKE_C_STANDARD": "17",
"CMAKE_C_STANDARD_REQUIRED": "ON",
"CMAKE_C_EXTENSIONS": "ON",
"CMAKE_INSTALL_LIBDIR": "lib",
},
env = {
# CMake still needs pkg-config to pass its internal configuration checks for systemd
"PKG_CONFIG_PATH": "/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig",
"PKG_CONFIG_PATH": "/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib64/pkgconfig:/usr/share/pkgconfig",
},
# Link the systemd dependency you defined in your WORKSPACE
deps = ["@libsystemd//:libsystemd"],
+20 -32
View File
@@ -92,7 +92,7 @@ let package = Package(
.target(
name: "protobuf-utf8",
dependencies: [
.product(name: "abseil", package: "abseil-cpp-SwiftPM"),
.product(name: "abseil", package: "abseil-cpp-SwiftPM")
],
path: "third_party/protobuf/third_party/utf8_range",
sources: [
@@ -102,13 +102,13 @@ let package = Package(
],
publicHeadersPath: ".",
cSettings: [
.headerSearchPath("./"),
.headerSearchPath("./")
],
),
.target(
name: "protobuf",
dependencies: [
"protobuf-utf8",
"protobuf-utf8"
],
path: "third_party/protobuf/src",
exclude: [
@@ -282,11 +282,11 @@ let package = Package(
"google/protobuf/io/zero_copy_sink_test.cc",
],
sources: [
"google/protobuf",
"google/protobuf"
],
publicHeadersPath: ".",
cSettings: [
.headerSearchPath("./"),
.headerSearchPath("./")
]
),
.target(
@@ -321,7 +321,6 @@ let package = Package(
"connections/implementation/flags/BUILD",
"connections/implementation/mediums/advertisements/BUILD",
"connections/implementation/mediums/ble/BUILD",
"connections/implementation/mediums/multiplex/BUILD",
"connections/implementation/mediums/BUILD",
"connections/implementation/BUILD",
"connections/implementation/fuzzers",
@@ -346,7 +345,6 @@ let package = Package(
"internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD",
"internal/platform/implementation/BUILD",
"internal/platform/BUILD",
"internal/analytics/BUILD",
"internal/flags/BUILD",
"internal/network/BUILD",
"internal/rpc/BUILD",
@@ -369,17 +367,12 @@ let package = Package(
"connections/implementation/payload_manager_test.cc",
"connections/implementation/offline_frames_validator_test.cc",
"connections/implementation/service_controller_router_test.cc",
"connections/implementation/awdl_bwu_handler_test.cc",
"connections/implementation/bluetooth_bwu_test.cc",
"connections/implementation/wifi_direct_bwu_test.cc",
"connections/implementation/wifi_hotspot_bwu_test.cc",
"connections/implementation/wifi_lan_bwu_handler_test.cc",
"connections/implementation/analytics/analytics_recorder_test.cc",
"connections/implementation/analytics/throughput_recorder_test.cc",
"connections/implementation/analytics/analytics_recorder_impl_test.cc",
"connections/implementation/mediums/advertisements/data_element_test.cc",
"connections/implementation/mediums/advertisements/dct_advertisement_test.cc",
"connections/implementation/mediums/advertisements/advertisement_util_test.cc",
"connections/implementation/mediums/awdl_test.cc",
"connections/implementation/mediums/awdl_bwu_handler_test.cc",
"connections/implementation/mediums/ble_test.cc",
"connections/implementation/mediums/ble/bloom_filter_test.cc",
"connections/implementation/mediums/ble/ble_l2cap_packet_test.cc",
@@ -392,18 +385,19 @@ let package = Package(
"connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc",
"connections/implementation/mediums/ble/instant_on_lost_advertisement_test.cc",
"connections/implementation/mediums/ble/instant_on_lost_manager_test.cc",
"connections/implementation/mediums/multiplex/multiplex_frames_test.cc",
"connections/implementation/mediums/multiplex/multiplex_socket_test.cc",
"connections/implementation/mediums/multiplex/multiplex_output_stream_test.cc",
"connections/implementation/mediums/webrtc_peer_id_test.cc",
"connections/implementation/mediums/wifi_lan_test.cc",
"connections/implementation/mediums/bluetooth_classic_test.cc",
"connections/implementation/mediums/ble_test.cc",
"connections/implementation/mediums/webrtc_test.cc",
"connections/implementation/mediums/lost_entity_tracker_test.cc",
"connections/implementation/mediums/bluetooth_bwu_handler_test.cc",
"connections/implementation/mediums/bluetooth_classic_test.cc",
"connections/implementation/mediums/bluetooth_radio_test.cc",
"connections/implementation/mediums/lost_entity_tracker_test.cc",
"connections/implementation/mediums/webrtc_peer_id_test.cc",
"connections/implementation/mediums/webrtc_test.cc",
"connections/implementation/mediums/wifi_direct_bwu_handler_test.cc",
"connections/implementation/mediums/wifi_direct_test.cc",
"connections/implementation/mediums/wifi_hotspot_bwu_handler_test.cc",
"connections/implementation/mediums/wifi_hotspot_test.cc",
"connections/implementation/mediums/wifi_lan_bwu_handler_test.cc",
"connections/implementation/mediums/wifi_lan_test.cc",
"connections/implementation/mediums/wifi_test.cc",
"connections/implementation/endpoint_channel_manager_test.cc",
"connections/implementation/bwu_manager_test.cc",
@@ -438,13 +432,13 @@ let package = Package(
"internal/encoding/base85_test.cc",
"internal/data/leveldb_data_set_test.cc",
"internal/flags/nearby_flags_test.cc",
"internal/proto/analytics/connections_log_test.cc",
"internal/platform/feature_flags_test.cc",
"internal/platform/file_test.cc",
"internal/platform/cancelable_alarm_test.cc",
"internal/platform/crypto_test.cc",
"internal/platform/byte_array_test.cc",
"internal/platform/credential_storage_impl_test.cc",
"internal/platform/implementation/device_info_test.cc",
"internal/platform/implementation/g3/awdl_test.cc",
"internal/platform/implementation/g3/ble_test.cc",
"internal/platform/input_stream_test.cc",
@@ -479,6 +473,7 @@ let package = Package(
"internal/platform/implementation/apple/mutex_test.cc",
"internal/platform/implementation/apple/atomic_boolean_test.cc",
"internal/platform/implementation/apple/atomic_uint32_test.cc",
"internal/platform/implementation/apple/webrtc_platform.mm",
"internal/platform/implementation/shared/file_test.cc",
"internal/platform/implementation/wifi_utils_test.cc",
"internal/platform/atomic_boolean_test.cc",
@@ -501,7 +496,6 @@ let package = Package(
"internal/network/http_client_impl_test.cc",
"internal/network/http_status_code_test.cc",
"internal/test/fake_clock_test.cc",
"internal/test/fake_webrtc.cc",
"internal/test/fake_timer_test.cc",
"internal/test/fake_device_info_test.cc",
"internal/test/fake_task_runner_test.cc",
@@ -523,16 +517,9 @@ let package = Package(
"proto",
"internal/data/leveldb_data_set_test.proto",
// webrtc
"connections/implementation/webrtc_bwu_handler.cc",
"connections/implementation/webrtc_endpoint_channel.cc",
"connections/implementation/mediums/webrtc.cc",
"connections/implementation/mediums/webrtc_peer_id.cc",
"connections/implementation/mediums/webrtc",
"internal/platform/tachyon_express_signaling_messenger.cc",
"internal/platform/tachyon_express_signaling_messenger.h",
"internal/platform/implementation/apple/webrtc.h",
"internal/platform/implementation/apple/webrtc.mm",
// This breaks the build, but seems to work fine without it?
// Only used in tests
"internal/platform/medium_environment.cc",
],
sources: [
@@ -565,6 +552,7 @@ let package = Package(
.headerSearchPath("./"),
.headerSearchPath("compiled_proto/"),
.define("NO_WEBRTC"),
.define("NC_OSS_BUILD"),
]
),
.target(
@@ -562,6 +562,9 @@ inline constexpr BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCred
pin_(
&::google::protobuf::internal::fixed_address_empty_string,
::_pbi::ConstantInitialized()),
device_name_(
&::google::protobuf::internal::fixed_address_empty_string,
::_pbi::ConstantInitialized()),
port_{0},
frequency_{0} {}
@@ -2056,44 +2059,47 @@ bool AutoReconnectFrame_EventType_Parse(::absl::string_view name, AutoReconnectF
return success;
}
PROTOBUF_CONSTINIT const uint32_t MediumMetadata_WifiDirectAuthType_internal_data_[] = {
196608u, 0u, };
262144u, 0u, };
static ::google::protobuf::internal::ExplicitlyConstructed<::std::string>
MediumMetadata_WifiDirectAuthType_strings[3] = {};
MediumMetadata_WifiDirectAuthType_strings[4] = {};
static const char MediumMetadata_WifiDirectAuthType_names[] = {
"WIFI_DIRECT_TYPE_UNKNOWN"
"WIFI_DIRECT_WITH_DEVICE_NAME"
"WIFI_DIRECT_WITH_PASSWORD"
"WIFI_DIRECT_WITH_PIN"
};
static const ::google::protobuf::internal::EnumEntry MediumMetadata_WifiDirectAuthType_entries[] = {
{{&MediumMetadata_WifiDirectAuthType_names[0], 24}, 0},
{{&MediumMetadata_WifiDirectAuthType_names[24], 25}, 1},
{{&MediumMetadata_WifiDirectAuthType_names[49], 20}, 2},
{{&MediumMetadata_WifiDirectAuthType_names[24], 28}, 3},
{{&MediumMetadata_WifiDirectAuthType_names[52], 25}, 1},
{{&MediumMetadata_WifiDirectAuthType_names[77], 20}, 2},
};
static const int MediumMetadata_WifiDirectAuthType_entries_by_number[] = {
0, // 0 -> WIFI_DIRECT_TYPE_UNKNOWN
1, // 1 -> WIFI_DIRECT_WITH_PASSWORD
2, // 2 -> WIFI_DIRECT_WITH_PIN
2, // 1 -> WIFI_DIRECT_WITH_PASSWORD
3, // 2 -> WIFI_DIRECT_WITH_PIN
1, // 3 -> WIFI_DIRECT_WITH_DEVICE_NAME
};
const ::std::string& MediumMetadata_WifiDirectAuthType_Name(MediumMetadata_WifiDirectAuthType value) {
static const bool kDummy = ::google::protobuf::internal::InitializeEnumStrings(
MediumMetadata_WifiDirectAuthType_entries, MediumMetadata_WifiDirectAuthType_entries_by_number, 3,
MediumMetadata_WifiDirectAuthType_entries, MediumMetadata_WifiDirectAuthType_entries_by_number, 4,
MediumMetadata_WifiDirectAuthType_strings);
(void)kDummy;
int idx = ::google::protobuf::internal::LookUpEnumName(MediumMetadata_WifiDirectAuthType_entries,
MediumMetadata_WifiDirectAuthType_entries_by_number,
3, value);
4, value);
return idx == -1 ? ::google::protobuf::internal::GetEmptyString() : MediumMetadata_WifiDirectAuthType_strings[idx].get();
}
bool MediumMetadata_WifiDirectAuthType_Parse(::absl::string_view name, MediumMetadata_WifiDirectAuthType* PROTOBUF_NONNULL value) {
int int_value;
bool success = ::google::protobuf::internal::LookUpEnumValue(
MediumMetadata_WifiDirectAuthType_entries, 3, name, &int_value);
MediumMetadata_WifiDirectAuthType_entries, 4, name, &int_value);
if (success) {
*value = static_cast<MediumMetadata_WifiDirectAuthType>(int_value);
}
@@ -7696,7 +7702,8 @@ PROTOBUF_NDEBUG_INLINE BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
gateway_(arena, from.gateway_, _i_give_permission_to_break_this_code_default_gateway_),
ip_v6_address_(arena, from.ip_v6_address_),
service_name_(arena, from.service_name_),
pin_(arena, from.pin_) {}
pin_(arena, from.pin_),
device_name_(arena, from.device_name_) {}
BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials(
::google::protobuf::Arena* PROTOBUF_NULLABLE arena,
@@ -7730,7 +7737,8 @@ PROTOBUF_NDEBUG_INLINE BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
gateway_(arena, Impl_::_i_give_permission_to_break_this_code_default_gateway_),
ip_v6_address_(arena),
service_name_(arena),
pin_(arena) {}
pin_(arena),
device_name_(arena) {}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) {
new (&_impl_) Impl_(internal_visibility(), arena);
@@ -7758,6 +7766,7 @@ inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentia
this_._impl_.ip_v6_address_.Destroy();
this_._impl_.service_name_.Destroy();
this_._impl_.pin_.Destroy();
this_._impl_.device_name_.Destroy();
this_._impl_.~Impl_();
}
@@ -7801,16 +7810,16 @@ BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::GetClass
return BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials_class_data_.base();
}
PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
const ::_pbi::TcParseTable<3, 8, 0, 0, 2>
const ::_pbi::TcParseTable<4, 9, 0, 0, 2>
BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_table_ = {
{
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_._has_bits_),
0, // no _extensions_
8, 56, // max_field_number, fast_idx_mask
9, 120, // max_field_number, fast_idx_mask
offsetof(decltype(_table_), field_lookup_table),
4294967040, // skipmap
4294966784, // skipmap
offsetof(decltype(_table_), field_entries),
8, // num_field_entries
9, // num_field_entries
0, // num_aux_entries
offsetof(decltype(_table_), field_names), // no aux_entries
BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials_class_data_.base(),
@@ -7820,10 +7829,7 @@ BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_table_
::_pbi::TcParser::GetTable<::location::nearby::connections::BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials>(), // to_prefetch
#endif // PROTOBUF_PREFETCH_PARSE_TABLE
}, {{
// optional string pin = 8;
{::_pbi::TcParser::FastBS1,
{66, 5, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.pin_)}},
{::_pbi::TcParser::MiniParse, {}},
// optional string ssid = 1;
{::_pbi::TcParser::FastBS1,
{10, 0, 0,
@@ -7834,11 +7840,11 @@ BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_table_
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.password_)}},
// optional int32 port = 3;
{::_pbi::TcParser::FastV32S1,
{24, 6, 0,
{24, 7, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.port_)}},
// optional int32 frequency = 4;
{::_pbi::TcParser::FastV32S1,
{32, 7, 0,
{32, 8, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.frequency_)}},
// optional string gateway = 5 [default = "0.0.0.0"];
{::_pbi::TcParser::FastBS1,
@@ -7848,10 +7854,24 @@ BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_table_
{::_pbi::TcParser::FastBS1,
{50, 3, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.ip_v6_address_)}},
// optional string service_name = 7;
// optional string service_name = 7 [deprecated = true];
{::_pbi::TcParser::FastBS1,
{58, 4, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.service_name_)}},
// optional string pin = 8;
{::_pbi::TcParser::FastBS1,
{66, 5, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.pin_)}},
// optional string device_name = 9;
{::_pbi::TcParser::FastBS1,
{74, 6, 0,
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.device_name_)}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
}}, {{
65535, 65535
}}, {{
@@ -7860,17 +7880,19 @@ BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_table_
// optional string password = 2;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.password_), _Internal::kHasBitsOffset + 1, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
// optional int32 port = 3;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.port_), _Internal::kHasBitsOffset + 6, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.port_), _Internal::kHasBitsOffset + 7, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
// optional int32 frequency = 4;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.frequency_), _Internal::kHasBitsOffset + 7, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.frequency_), _Internal::kHasBitsOffset + 8, 0, (0 | ::_fl::kFcOptional | ::_fl::kInt32)},
// optional string gateway = 5 [default = "0.0.0.0"];
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.gateway_), _Internal::kHasBitsOffset + 2, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
// optional bytes ip_v6_address = 6;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.ip_v6_address_), _Internal::kHasBitsOffset + 3, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
// optional string service_name = 7;
// optional string service_name = 7 [deprecated = true];
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.service_name_), _Internal::kHasBitsOffset + 4, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
// optional string pin = 8;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.pin_), _Internal::kHasBitsOffset + 5, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
// optional string device_name = 9;
{PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.device_name_), _Internal::kHasBitsOffset + 6, 0, (0 | ::_fl::kFcOptional | ::_fl::kBytes | ::_fl::kRepAString)},
}},
// no aux_entries
{{
@@ -7884,7 +7906,7 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
(void) cached_has_bits;
cached_has_bits = _impl_._has_bits_[0];
if (BatchCheckHasBit(cached_has_bits, 0x0000003fU)) {
if (BatchCheckHasBit(cached_has_bits, 0x0000007fU)) {
if (CheckHasBit(cached_has_bits, 0x00000001U)) {
_impl_.ssid_.ClearNonDefaultToEmpty();
}
@@ -7903,12 +7925,12 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
if (CheckHasBit(cached_has_bits, 0x00000020U)) {
_impl_.pin_.ClearNonDefaultToEmpty();
}
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
_impl_.device_name_.ClearNonDefaultToEmpty();
}
}
if (BatchCheckHasBit(cached_has_bits, 0x000000c0U)) {
::memset(&_impl_.port_, 0, static_cast<::size_t>(
reinterpret_cast<char*>(&_impl_.frequency_) -
reinterpret_cast<char*>(&_impl_.port_)) + sizeof(_impl_.frequency_));
}
_impl_.port_ = 0;
_impl_.frequency_ = 0;
_impl_._has_bits_.Clear();
_internal_metadata_.Clear<::std::string>();
}
@@ -7945,14 +7967,14 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
}
// optional int32 port = 3;
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
target =
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<3>(
stream, this_._internal_port(), target);
}
// optional int32 frequency = 4;
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
target =
::google::protobuf::internal::WireFormatLite::WriteInt32ToArrayWithField<4>(
stream, this_._internal_frequency(), target);
@@ -7970,7 +7992,7 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
target = stream->WriteBytesMaybeAliased(6, _s, target);
}
// optional string service_name = 7;
// optional string service_name = 7 [deprecated = true];
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
const ::std::string& _s = this_._internal_service_name();
target = stream->WriteStringMaybeAliased(7, _s, target);
@@ -7982,6 +8004,12 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
target = stream->WriteStringMaybeAliased(8, _s, target);
}
// optional string device_name = 9;
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
const ::std::string& _s = this_._internal_device_name();
target = stream->WriteStringMaybeAliased(9, _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(),
@@ -8028,7 +8056,7 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize(
this_._internal_ip_v6_address());
}
// optional string service_name = 7;
// optional string service_name = 7 [deprecated = true];
if (CheckHasBit(cached_has_bits, 0x00000010U)) {
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this_._internal_service_name());
@@ -8038,13 +8066,20 @@ PROTOBUF_NOINLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDire
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this_._internal_pin());
}
// optional int32 port = 3;
// optional string device_name = 9;
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this_._internal_device_name());
}
// optional int32 port = 3;
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
this_._internal_port());
}
}
{
// optional int32 frequency = 4;
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(
this_._internal_frequency());
}
@@ -8090,12 +8125,15 @@ void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::Mer
_this->_internal_set_pin(from._internal_pin());
}
if (CheckHasBit(cached_has_bits, 0x00000040U)) {
_this->_impl_.port_ = from._impl_.port_;
_this->_internal_set_device_name(from._internal_device_name());
}
if (CheckHasBit(cached_has_bits, 0x00000080U)) {
_this->_impl_.frequency_ = from._impl_.frequency_;
_this->_impl_.port_ = from._impl_.port_;
}
}
if (CheckHasBit(cached_has_bits, 0x00000100U)) {
_this->_impl_.frequency_ = from._impl_.frequency_;
}
_this->_impl_._has_bits_[0] |= cached_has_bits;
_this->_internal_metadata_.MergeFrom<::std::string>(
from._internal_metadata_);
@@ -8121,6 +8159,7 @@ void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::Int
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.ip_v6_address_, &other->_impl_.ip_v6_address_, arena);
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.service_name_, &other->_impl_.service_name_, arena);
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.pin_, &other->_impl_.pin_, arena);
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.device_name_, &other->_impl_.device_name_, arena);
::google::protobuf::internal::memswap<
PROTOBUF_FIELD_OFFSET(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials, _impl_.frequency_)
+ sizeof(BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_impl_.frequency_)
@@ -13302,7 +13341,7 @@ MediumMetadata::_table_ = {
PROTOBUF_FIELD_OFFSET(MediumMetadata, _impl_.medium_role_)}},
// repeated .location.nearby.connections.MediumMetadata.WifiDirectAuthType supported_wifi_direct_auth_types = 13 [packed = true];
{::_pbi::TcParser::FastEr0P1,
{106, 0, 2,
{106, 0, 3,
PROTOBUF_FIELD_OFFSET(MediumMetadata, _impl_.supported_wifi_direct_auth_types_)}},
{::_pbi::TcParser::MiniParse, {}},
{::_pbi::TcParser::MiniParse, {}},
@@ -13343,7 +13382,7 @@ MediumMetadata::_table_ = {
{::_pbi::TcParser::GetTable<::location::nearby::connections::WifiAwareUsableChannels>()},
{::_pbi::TcParser::GetTable<::location::nearby::connections::WifiHotspotStaUsableChannels>()},
{::_pbi::TcParser::GetTable<::location::nearby::connections::MediumRole>()},
{0, 2},
{0, 3},
}},
{{
}},
@@ -722,18 +722,19 @@ bool AutoReconnectFrame_EventType_Parse(
enum MediumMetadata_WifiDirectAuthType : int {
MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_TYPE_UNKNOWN = 0,
MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PASSWORD = 1,
MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PIN = 2,
MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PIN [[deprecated]] = 2,
MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_DEVICE_NAME = 3,
};
extern const uint32_t MediumMetadata_WifiDirectAuthType_internal_data_[];
inline constexpr MediumMetadata_WifiDirectAuthType MediumMetadata_WifiDirectAuthType_WifiDirectAuthType_MIN =
static_cast<MediumMetadata_WifiDirectAuthType>(0);
inline constexpr MediumMetadata_WifiDirectAuthType MediumMetadata_WifiDirectAuthType_WifiDirectAuthType_MAX =
static_cast<MediumMetadata_WifiDirectAuthType>(2);
static_cast<MediumMetadata_WifiDirectAuthType>(3);
inline bool MediumMetadata_WifiDirectAuthType_IsValid(int value) {
return 0 <= value && value <= 2;
return 0 <= value && value <= 3;
}
inline constexpr int MediumMetadata_WifiDirectAuthType_WifiDirectAuthType_ARRAYSIZE = 2 + 1;
inline constexpr int MediumMetadata_WifiDirectAuthType_WifiDirectAuthType_ARRAYSIZE = 3 + 1;
const ::std::string& MediumMetadata_WifiDirectAuthType_Name(MediumMetadata_WifiDirectAuthType value);
template <typename T>
const ::std::string& MediumMetadata_WifiDirectAuthType_Name(T value) {
@@ -4914,6 +4915,7 @@ class BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials fin
kIpV6AddressFieldNumber = 6,
kServiceNameFieldNumber = 7,
kPinFieldNumber = 8,
kDeviceNameFieldNumber = 9,
kPortFieldNumber = 3,
kFrequencyFieldNumber = 4,
};
@@ -4981,15 +4983,15 @@ class BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials fin
::std::string* PROTOBUF_NONNULL _internal_mutable_ip_v6_address();
public:
// optional string service_name = 7;
bool has_service_name() const;
void clear_service_name() ;
const ::std::string& service_name() const;
// optional string service_name = 7 [deprecated = true];
[[deprecated]] bool has_service_name() const;
[[deprecated]] void clear_service_name() ;
[[deprecated]] const ::std::string& service_name() const;
template <typename Arg_ = const ::std::string&, typename... Args_>
void set_service_name(Arg_&& arg, Args_... args);
::std::string* PROTOBUF_NONNULL mutable_service_name();
[[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_service_name();
void set_allocated_service_name(::std::string* PROTOBUF_NULLABLE value);
[[deprecated]] void set_service_name(Arg_&& arg, Args_... args);
[[deprecated]] ::std::string* PROTOBUF_NONNULL mutable_service_name();
[[deprecated]] [[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_service_name();
[[deprecated]] void set_allocated_service_name(::std::string* PROTOBUF_NULLABLE value);
private:
const ::std::string& _internal_service_name() const;
@@ -5012,6 +5014,22 @@ class BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials fin
PROTOBUF_ALWAYS_INLINE void _internal_set_pin(const ::std::string& value);
::std::string* PROTOBUF_NONNULL _internal_mutable_pin();
public:
// optional string device_name = 9;
bool has_device_name() const;
void clear_device_name() ;
const ::std::string& device_name() const;
template <typename Arg_ = const ::std::string&, typename... Args_>
void set_device_name(Arg_&& arg, Args_... args);
::std::string* PROTOBUF_NONNULL mutable_device_name();
[[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_device_name();
void set_allocated_device_name(::std::string* PROTOBUF_NULLABLE value);
private:
const ::std::string& _internal_device_name() const;
PROTOBUF_ALWAYS_INLINE void _internal_set_device_name(const ::std::string& value);
::std::string* PROTOBUF_NONNULL _internal_mutable_device_name();
public:
// optional int32 port = 3;
bool has_port() const;
@@ -5039,7 +5057,7 @@ class BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials fin
private:
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<3, 8,
static const ::google::protobuf::internal::TcParseTable<4, 9,
0, 0,
2>
_table_;
@@ -5068,6 +5086,7 @@ class BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials fin
::google::protobuf::internal::ArenaStringPtr ip_v6_address_;
::google::protobuf::internal::ArenaStringPtr service_name_;
::google::protobuf::internal::ArenaStringPtr pin_;
::google::protobuf::internal::ArenaStringPtr device_name_;
::int32_t port_;
::int32_t frequency_;
PROTOBUF_TSAN_DECLARE_MEMBER
@@ -7679,7 +7698,8 @@ class MediumMetadata final : public ::google::protobuf::MessageLite
using WifiDirectAuthType = MediumMetadata_WifiDirectAuthType;
static constexpr WifiDirectAuthType WIFI_DIRECT_TYPE_UNKNOWN = MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_TYPE_UNKNOWN;
static constexpr WifiDirectAuthType WIFI_DIRECT_WITH_PASSWORD = MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PASSWORD;
static constexpr WifiDirectAuthType WIFI_DIRECT_WITH_PIN = MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PIN;
[[deprecated]] static constexpr WifiDirectAuthType WIFI_DIRECT_WITH_PIN = MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_PIN;
static constexpr WifiDirectAuthType WIFI_DIRECT_WITH_DEVICE_NAME = MediumMetadata_WifiDirectAuthType_WIFI_DIRECT_WITH_DEVICE_NAME;
static inline bool WifiDirectAuthType_IsValid(int value) {
return MediumMetadata_WifiDirectAuthType_IsValid(value);
}
@@ -15574,14 +15594,14 @@ inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentia
// optional int32 port = 3;
inline bool BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::has_port() const {
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000040U);
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000080U);
return value;
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::clear_port() {
::google::protobuf::internal::TSanWrite(&_impl_);
_impl_.port_ = 0;
ClearHasBit(_impl_._has_bits_[0],
0x00000040U);
0x00000080U);
}
inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::port() const {
// @@protoc_insertion_point(field_get:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.port)
@@ -15589,7 +15609,7 @@ inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCred
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::set_port(::int32_t value) {
_internal_set_port(value);
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
SetHasBit(_impl_._has_bits_[0], 0x00000080U);
// @@protoc_insertion_point(field_set:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.port)
}
inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_internal_port() const {
@@ -15603,14 +15623,14 @@ inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentia
// optional int32 frequency = 4;
inline bool BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::has_frequency() const {
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000080U);
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000100U);
return value;
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::clear_frequency() {
::google::protobuf::internal::TSanWrite(&_impl_);
_impl_.frequency_ = 0;
ClearHasBit(_impl_._has_bits_[0],
0x00000080U);
0x00000100U);
}
inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::frequency() const {
// @@protoc_insertion_point(field_get:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.frequency)
@@ -15618,7 +15638,7 @@ inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCred
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::set_frequency(::int32_t value) {
_internal_set_frequency(value);
SetHasBit(_impl_._has_bits_[0], 0x00000080U);
SetHasBit(_impl_._has_bits_[0], 0x00000100U);
// @@protoc_insertion_point(field_set:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.frequency)
}
inline ::int32_t BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_internal_frequency() const {
@@ -15764,7 +15784,7 @@ inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentia
// @@protoc_insertion_point(field_set_allocated:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.ip_v6_address)
}
// optional string service_name = 7;
// optional string service_name = 7 [deprecated = true];
inline bool BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::has_service_name() const {
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000010U);
return value;
@@ -15833,6 +15853,75 @@ inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentia
// @@protoc_insertion_point(field_set_allocated:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.service_name)
}
// optional string device_name = 9;
inline bool BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::has_device_name() const {
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000040U);
return value;
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::clear_device_name() {
::google::protobuf::internal::TSanWrite(&_impl_);
_impl_.device_name_.ClearToEmpty();
ClearHasBit(_impl_._has_bits_[0],
0x00000040U);
}
inline const ::std::string& BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::device_name() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_get:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.device_name)
return _internal_device_name();
}
template <typename Arg_, typename... Args_>
PROTOBUF_ALWAYS_INLINE void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::set_device_name(Arg_&& arg, Args_... args) {
::google::protobuf::internal::TSanWrite(&_impl_);
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
_impl_.device_name_.Set(static_cast<Arg_&&>(arg), args..., GetArena());
// @@protoc_insertion_point(field_set:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.device_name)
}
inline ::std::string* PROTOBUF_NONNULL BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::mutable_device_name()
ABSL_ATTRIBUTE_LIFETIME_BOUND {
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
::std::string* _s = _internal_mutable_device_name();
// @@protoc_insertion_point(field_mutable:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.device_name)
return _s;
}
inline const ::std::string& BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_internal_device_name() const {
::google::protobuf::internal::TSanRead(&_impl_);
return _impl_.device_name_.Get();
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_internal_set_device_name(const ::std::string& value) {
::google::protobuf::internal::TSanWrite(&_impl_);
_impl_.device_name_.Set(value, GetArena());
}
inline ::std::string* PROTOBUF_NONNULL BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::_internal_mutable_device_name() {
::google::protobuf::internal::TSanWrite(&_impl_);
return _impl_.device_name_.Mutable( GetArena());
}
inline ::std::string* PROTOBUF_NULLABLE BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::release_device_name() {
::google::protobuf::internal::TSanWrite(&_impl_);
// @@protoc_insertion_point(field_release:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.device_name)
if (!CheckHasBit(_impl_._has_bits_[0], 0x00000040U)) {
return nullptr;
}
ClearHasBit(_impl_._has_bits_[0], 0x00000040U);
auto* released = _impl_.device_name_.Release();
if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) {
_impl_.device_name_.Set("", GetArena());
}
return released;
}
inline void BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::set_allocated_device_name(::std::string* PROTOBUF_NULLABLE value) {
::google::protobuf::internal::TSanWrite(&_impl_);
if (value != nullptr) {
SetHasBit(_impl_._has_bits_[0], 0x00000040U);
} else {
ClearHasBit(_impl_._has_bits_[0], 0x00000040U);
}
_impl_.device_name_.SetAllocated(value, GetArena());
if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.device_name_.IsDefault()) {
_impl_.device_name_.Set("", GetArena());
}
// @@protoc_insertion_point(field_set_allocated:location.nearby.connections.BandwidthUpgradeNegotiationFrame.UpgradePathInfo.WifiDirectCredentials.device_name)
}
// optional string pin = 8;
inline bool BandwidthUpgradeNegotiationFrame_UpgradePathInfo_WifiDirectCredentials::has_pin() const {
bool value = CheckHasBit(_impl_._has_bits_[0], 0x00000020U);
File diff suppressed because it is too large Load Diff
+44 -6
View File
@@ -324,18 +324,19 @@ bool Medium_Parse(
enum WifiDirectAuthType : int {
WIFI_DIRECT_TYPE_UNKNOWN = 0,
WIFI_DIRECT_WITH_PASSWORD = 1,
WIFI_DIRECT_WITH_PIN = 2,
WIFI_DIRECT_WITH_PIN [[deprecated]] = 2,
WIFI_DIRECT_WITH_DEVICE_NAME = 3,
};
extern const uint32_t WifiDirectAuthType_internal_data_[];
inline constexpr WifiDirectAuthType WifiDirectAuthType_MIN =
static_cast<WifiDirectAuthType>(0);
inline constexpr WifiDirectAuthType WifiDirectAuthType_MAX =
static_cast<WifiDirectAuthType>(2);
static_cast<WifiDirectAuthType>(3);
inline bool WifiDirectAuthType_IsValid(int value) {
return 0 <= value && value <= 2;
return 0 <= value && value <= 3;
}
inline constexpr int WifiDirectAuthType_ARRAYSIZE = 2 + 1;
inline constexpr int WifiDirectAuthType_ARRAYSIZE = 3 + 1;
const ::std::string& WifiDirectAuthType_Name(WifiDirectAuthType value);
template <typename T>
const ::std::string& WifiDirectAuthType_Name(T value) {
@@ -1272,17 +1273,54 @@ enum OperationResultCode : int {
DCT_ERROR_SERVICE_CANCELLED = 5022,
DCT_ERROR_UNVERIFIED_INTEGRITY = 5023,
DCT_ERROR_HTTP_SERVER_CLOSED = 5024,
DCT_ERROR_CHECKIN_FAILURE = 5025,
DCT_ERROR_REMOTE_ATTESTATION_TIMEOUT = 5026,
DCT_ERROR_REMOTE_ATTESTATION_NULL_PACKET = 5027,
DCT_ERROR_REMOTE_ATTESTATION_STATUS_NOT_AVAILABLE = 5028,
DCT_ERROR_REMOTE_ATTESTATION_HASH_TOO_SHORT = 5029,
DCT_ERROR_REMOTE_ATTESTATION_APPLE_INTEGRITY_UNAVAILABLE = 5030,
DCT_ERROR_LOCAL_ATTESTATION_PLAY_INTEGRITY_UNAVAILABLE = 5031,
DCT_ERROR_LOCAL_ATTESTATION_TIMEOUT = 5032,
DCT_ERROR_PARALLEL_ATTESTATION_TIMEOUT = 5033,
DCT_ERROR_REMOTE_MDNS_DISCOVERY_TIMEOUT = 5034,
DCT_ERROR_REMOTE_MDNS_REGISTER_SERVICE = 5035,
DCT_ERROR_REMOTE_REQUEST_FAILED = 5036,
DCT_ERROR_REMOTE_RESPONSE_FAILED = 5037,
DCT_ERROR_REMOTE_CONTROL_MESSAGE_EXCHANGE = 5038,
DCT_ERROR_REMOTE_CAPABILITY_MISMATCH = 5039,
DCT_ERROR_REMOTE_HIGH_SPEED_MEDIUM_UNAVAILABLE = 5040,
DCT_ERROR_REMOTE_WIFI_DISABLED = 5041,
DCT_ERROR_REMOTE_WIFI_DISCONNECTED = 5042,
DCT_ERROR_REMOTE_WIFI_CREDENTIAL_TRANSFER = 5043,
DCT_ERROR_REMOTE_WIFI_INTERNET_CONNECTION = 5044,
DCT_ERROR_REMOTE_UPGRADE_HIGH_SPEED_MEDIUM_FAILED = 5045,
DCT_ERROR_REMOTE_USER_CANCELLED = 5046,
DCT_ERROR_REMOTE_SERVICE_CANCELLED = 5047,
DCT_ERROR_REMOTE_UNVERIFIED_INTEGRITY = 5048,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_LOW_SPEED = 5049,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_CONNECTION = 5050,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_USB_NOT_PLUGGED = 5051,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_USB_NOT_HOST = 5052,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_MDNS_DISCOVERY_NOT_STARTED = 5053,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_NO_MEDIUM = 5054,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_USB_NETWORK_NOT_STARTED = 5055,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_MEDIUM_NEGOTIATION = 5056,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_HOST_NOT_STARTED = 5057,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_HOST_NETWORK_NOT_AVAILABLE = 5058,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_NO_INCOMING_HTTP_CONNECTION = 5059,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_USB_NO_CONNECTED_DEVICE = 5060,
DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_INTERRUPTED = 5061,
};
extern const uint32_t OperationResultCode_internal_data_[];
inline constexpr OperationResultCode OperationResultCode_MIN =
static_cast<OperationResultCode>(0);
inline constexpr OperationResultCode OperationResultCode_MAX =
static_cast<OperationResultCode>(5024);
static_cast<OperationResultCode>(5061);
inline bool OperationResultCode_IsValid(int value) {
return ::google::protobuf::internal::ValidateEnum(value, OperationResultCode_internal_data_);
}
inline constexpr int OperationResultCode_ARRAYSIZE = 5024 + 1;
inline constexpr int OperationResultCode_ARRAYSIZE = 5061 + 1;
const ::std::string& OperationResultCode_Name(OperationResultCode value);
template <typename T>
const ::std::string& OperationResultCode_Name(T value) {
+6 -3
View File
@@ -44,9 +44,11 @@ cc_library(
],
deps = [
":core_types",
"//connections/implementation:client_proxy",
"//connections/implementation:internal",
"//connections/implementation:service_id_constants",
"//connections/implementation/analytics",
"//connections/v3:v3_types",
"//internal/analytics:event_logger",
"//internal/interop:device",
"//internal/platform:base",
"//internal/platform:logging",
@@ -95,15 +97,15 @@ cc_library(
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/interop:authentication_status",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//internal/platform:types",
"//internal/platform:util",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/random",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:variant",
],
)
@@ -124,6 +126,7 @@ cc_test(
"//connections/implementation:internal_test",
"//connections/v3:v3_types",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
+7 -4
View File
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_apple//apple:apple.bzl", "apple_static_xcframework")
load("@rules_apple//apple:apple_xcframework.bzl", "apple_static_xcframework")
load("@rules_apple//apple:macos.bzl", "macos_dylib")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("//third_party/cpptoolchains/portable_llvm/build_defs:windows.bzl", "windows")
@@ -51,16 +51,18 @@ cc_library(
":nc_types",
"//connections:core",
"//connections:core_types",
"//connections/implementation/analytics:analytics_recorder_impl",
"//connections/implementation/flags:connections_flags",
"//internal/analytics:event_logger",
"//internal/flags:flag_reader",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//internal/platform:types",
"//internal/proto/analytics:connections_log_cc_proto",
"//sharing/proto/analytics:sharing_log_cc_proto",
"//location/nearby/analytics/cpp/logging:event_logger",
"//location/nearby/analytics/cpp/proto:connections_log_cc_proto",
"//location/nearby/analytics/cpp/proto:sharing_log_cc_proto",
"@com_google_absl//absl/base:no_destructor",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
@@ -73,6 +75,7 @@ cc_library(
],
"//conditions:default": [],
}),
alwayslink = True,
)
# iOS only.
+29 -5
View File
@@ -20,10 +20,16 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#if !defined(NC_OSS_BUILD)
#include "location/nearby/analytics/cpp/logging/event_logger.h"
#include "location/nearby/analytics/cpp/proto/connections_log.pb.h"
#include "location/nearby/analytics/cpp/proto/nearby_sharing_log.pb.h"
#endif // !defined(NC_OSS_BUILD)
#include "absl/base/no_destructor.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h"
@@ -34,6 +40,9 @@
#include "connections/connection_options.h"
#include "connections/core.h"
#include "connections/discovery_options.h"
#if !defined(NC_OSS_BUILD)
#include "connections/implementation/analytics/analytics_recorder_impl.h"
#endif // !defined(NC_OSS_BUILD)
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/out_of_band_connection_metadata.h"
@@ -41,7 +50,6 @@
#include "connections/payload.h"
#include "connections/status.h"
#include "connections/strategy.h"
#include "internal/analytics/event_logger.h"
#include "internal/flags/flag.h"
#include "internal/flags/flag_reader.h"
#include "internal/flags/nearby_flags.h"
@@ -49,8 +57,6 @@
#include "internal/platform/file.h"
#include "internal/platform/logging.h"
#include "internal/platform/mac_address.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "sharing/proto/analytics/nearby_sharing_log.pb.h"
#if TARGET_OS_IOS
#include "internal/platform/implementation/apple/nearby_logger.h"
#endif // TARGET_OS_IOS
@@ -118,6 +124,7 @@ class FlagReaderWrapper : public nearby::flags::FlagReader {
NC_PHENOTYPE_FLAG_READER phenotype_flag_reader_;
};
#if !defined(NC_OSS_BUILD)
// This is a bridging class between the C API and the C++ EventLogger interface.
class NcEventLogger : public ::nearby::analytics::EventLogger {
public:
@@ -145,6 +152,10 @@ class NcEventLogger : public ::nearby::analytics::EventLogger {
private:
const NC_EVENT_LOGGER* event_logger_;
};
#else // !defined(NC_OSS_BUILD)
class NcEventLogger;
#endif // !defined(NC_OSS_BUILD)
} // namespace
typedef struct NcContext {
@@ -244,6 +255,7 @@ NcContext* GetContext(NC_INSTANCE instance) {
return cpp_connection_request_info;
}
#if !defined(NC_OSS_BUILD)
NC_INSTANCE NcCreateService() {
return NcCreateServiceWithEventLogger(nullptr);
}
@@ -259,12 +271,24 @@ NcCreateServiceWithEventLogger(const NC_EVENT_LOGGER* event_logger) {
nc_context.router = new ::nearby::connections::ServiceControllerRouter();
nc_context.event_logger =
event_logger == nullptr ? nullptr : new NcEventLogger(event_logger);
nc_context.core = new ::nearby::connections::Core(nc_context.event_logger,
nc_context.router);
nc_context.core = new ::nearby::connections::Core(
std::make_unique<::nearby::analytics::AnalyticsRecorderImpl>(
nc_context.event_logger),
nc_context.router);
kNcContextMap->insert({nc_context.core, nc_context});
return nc_context.core;
}
#else // !defined(NC_OSS_BUILD)
NC_INSTANCE NcCreateService() {
NcContext nc_context;
nc_context.router = new ::nearby::connections::ServiceControllerRouter();
nc_context.core = new ::nearby::connections::Core(nc_context.router);
kNcContextMap->insert({nc_context.core, nc_context});
return nc_context.core;
}
#endif // !defined(NC_OSS_BUILD)
void NcCloseService(NC_INSTANCE instance) {
NcContext* nc_context = GetContext(instance);
+2
View File
@@ -27,11 +27,13 @@ extern "C" {
// Creates a new Nearby Connections service.
NC_API NC_INSTANCE NcCreateService();
#if !defined(NC_OSS_BUILD)
// Creates a new Nearby Connections service with an event logger.
// The passed-in |event_logger| must remain valid until NcCloseService() is
// called.
NC_API NC_INSTANCE
NcCreateServiceWithEventLogger(const NC_EVENT_LOGGER* event_logger);
#endif // !defined(NC_OSS_BUILD)
// Closes a Nearby Connections service.
NC_API void NcCloseService(NC_INSTANCE instance);
+3 -3
View File
@@ -25,6 +25,7 @@
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/service_controller_router.h"
#include "connections/listeners.h"
@@ -37,7 +38,6 @@
#include "connections/v3/discovery_options.h"
#include "connections/v3/listeners.h"
#include "connections/v3/listening_result.h"
#include "internal/analytics/event_logger.h"
#include "internal/interop/device.h"
#include "internal/interop/device_provider.h"
@@ -49,9 +49,9 @@ class Core {
public:
explicit Core(ServiceControllerRouter* router);
// Client needs to call this constructor if analytics logger is needed.
Core(::nearby::analytics::EventLogger* event_logger,
Core(std::unique_ptr<analytics::AnalyticsRecorder> analytics_recorder,
ServiceControllerRouter* router)
: client_(event_logger), router_(router) {}
: client_(std::move(analytics_recorder)), router_(router) {}
~Core();
Core(Core&&);
Core& operator=(Core&&);
+168 -109
View File
@@ -49,30 +49,143 @@ cc_library(
],
)
cc_library(
name = "service_id_constants",
hdrs = ["service_id_constants.h"],
visibility = ["//connections:__subpackages__"],
deps = [
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
],
)
cc_library(
name = "bwu_handler",
srcs = ["base_bwu_handler.cc"],
hdrs = [
"base_bwu_handler.h",
"bwu_handler.h",
],
visibility = ["//connections:__subpackages__"],
deps = [
":client_proxy",
":endpoint_channel",
":service_id_constants",
"//internal/platform:base",
"//internal/platform:logging",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/functional:any_invocable",
],
)
cc_library(
name = "offline_frames",
srcs = [
"offline_frames.cc",
"offline_frames_validator.cc",
],
hdrs = [
"internal_payload.h",
"offline_frames.h",
"offline_frames_validator.h",
],
visibility = ["//connections:__subpackages__"],
deps = [
"//connections:core_types",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:mac_address",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
],
)
cc_library(
name = "client_proxy",
srcs = ["client_proxy.cc"],
hdrs = ["client_proxy.h"],
visibility = ["//connections:__subpackages__"],
deps = [
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/mediums/advertisements:dct_advertisement",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//connections/v3:v3_types",
"//internal/base:file_path",
"//internal/base:files",
"//internal/flags:nearby_flags",
"//internal/interop:device",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:error_code_recorder",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//internal/platform:types",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/random",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
],
)
cc_library(
name = "endpoint_channel",
srcs = [
"base_endpoint_channel.cc",
"endpoint_channel_manager.cc",
],
hdrs = [
"base_endpoint_channel.h",
"endpoint_channel.h",
"endpoint_channel_manager.h",
],
visibility = ["//connections:__subpackages__"],
deps = [
":client_proxy",
":offline_frames",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation:types",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_ukey2//:ukey2",
],
)
cc_library(
name = "internal",
srcs = [
"awdl_bwu_handler.cc",
"awdl_endpoint_channel.cc",
"base_bwu_handler.cc",
"base_endpoint_channel.cc",
"base_pcp_handler.cc",
"ble_endpoint_channel.cc",
"ble_l2cap_endpoint_channel.cc",
"bluetooth_bwu_handler.cc",
"bluetooth_device_name.cc",
"bluetooth_endpoint_channel.cc",
"bwu_manager.cc",
"client_proxy.cc",
"connections_authentication_transport.cc",
"encryption_runner.cc",
"endpoint_channel_manager.cc",
"endpoint_manager.cc",
"injected_bluetooth_device_store.cc",
"internal_payload.cc",
"internal_payload_factory.cc",
"offline_frames.cc",
"offline_frames_validator.cc",
"offline_service_controller.cc",
"p2p_cluster_pcp_handler.cc",
"p2p_point_to_point_pcp_handler.cc",
@@ -80,41 +193,17 @@ cc_library(
"payload_manager.cc",
"pcp_manager.cc",
"service_controller_router.cc",
"webrtc_bwu_handler.cc",
"webrtc_bwu_handler_stub.cc",
"webrtc_endpoint_channel.cc",
"wifi_direct_bwu_handler.cc",
"wifi_direct_endpoint_channel.cc",
"wifi_hotspot_bwu_handler.cc",
"wifi_hotspot_endpoint_channel.cc",
"wifi_lan_bwu_handler.cc",
"wifi_lan_endpoint_channel.cc",
"wifi_lan_service_info.cc",
],
hdrs = [
"awdl_bwu_handler.h",
"awdl_endpoint_channel.h",
"base_bwu_handler.h",
"base_endpoint_channel.h",
"base_pcp_handler.h",
"ble_endpoint_channel.h",
"ble_l2cap_endpoint_channel.h",
"bluetooth_bwu_handler.h",
"bluetooth_device_name.h",
"bluetooth_endpoint_channel.h",
"bwu_handler.h",
"bwu_manager.h",
"client_proxy.h",
"connections_authentication_transport.h",
"encryption_runner.h",
"endpoint_channel.h",
"endpoint_channel_manager.h",
"endpoint_manager.h",
"injected_bluetooth_device_store.h",
"internal_payload.h",
"internal_payload_factory.h",
"offline_frames.h",
"offline_frames_validator.h",
"offline_service_controller.h",
"p2p_cluster_pcp_handler.h",
"p2p_point_to_point_pcp_handler.h",
@@ -124,49 +213,37 @@ cc_library(
"pcp_manager.h",
"service_controller.h",
"service_controller_router.h",
"service_id_constants.h",
"webrtc_bwu_handler.h",
"webrtc_bwu_handler_stub.h",
"webrtc_endpoint_channel.h",
"wifi_direct_bwu_handler.h",
"wifi_direct_endpoint_channel.h",
"wifi_hotspot_bwu_handler.h",
"wifi_hotspot_endpoint_channel.h",
"wifi_lan_bwu_handler.h",
"wifi_lan_endpoint_channel.h",
"wifi_lan_service_info.h",
],
copts = [
"-DCORE_ADAPTER_DLL",
"-DNO_WEBRTC",
],
copts = ["-DCORE_ADAPTER_DLL"],
visibility = [
"//chrome/chromeos/assistant/data_migration/lib:__pkg__",
"//connections:__pkg__",
"//connections:partners",
"//connections/implementation/fuzzers:__pkg__",
"//connections/implementation/mediums/multiplex:__pkg__",
"//sharing:__subpackages__",
],
deps = [
":ble_advertisement",
":bwu_handler",
":client_proxy",
":endpoint_channel",
":offline_frames",
":service_id_constants",
":types",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/mediums",
"//connections/implementation/mediums:utils",
"//connections/implementation/mediums:webrtc_utils",
"//connections/implementation/mediums:webrtc",
"//connections/implementation/mediums:webrtc_peer_id",
"//connections/implementation/mediums/advertisements:dct_advertisement",
"//connections/implementation/mediums/advertisements:util",
"//connections/implementation/mediums/ble:ble_advertisement_header",
"//connections/implementation/mediums/ble:ble_socket",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//connections/v3:v3_types",
"//internal/analytics:event_logger",
"//internal/base:file_path",
"//internal/base:files",
"//internal/base:masker",
"//internal/flags:nearby_flags",
"//internal/interop:authentication_status",
"//internal/interop:authentication_transport_interface",
@@ -175,7 +252,6 @@ cc_library(
"//internal/platform:cancellation_flag",
"//internal/platform:comm",
"//internal/platform:connection_info",
"//internal/platform:error_code_recorder",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//internal/platform:types",
@@ -184,7 +260,6 @@ cc_library(
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation:wifi_utils",
"//internal/proto/analytics:connections_log_cc_proto",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:btree",
@@ -192,7 +267,6 @@ cc_library(
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/random",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
@@ -214,6 +288,7 @@ cc_library(
"fake_bwu_handler.h",
"fake_endpoint_channel.h",
"mock_device.h",
"mock_endpoint_channel.h",
"mock_service_controller.h",
"mock_service_controller_router.h",
"offline_simulation_user.h",
@@ -223,7 +298,11 @@ cc_library(
"//connections:__subpackages__",
],
deps = [
":bwu_handler",
":client_proxy",
":endpoint_channel",
":internal",
":offline_frames",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
@@ -246,38 +325,30 @@ cc_library(
cc_test(
name = "bwu_test",
srcs = [
"awdl_bwu_handler_test.cc",
"base_bwu_handler_test.cc",
"bluetooth_bwu_test.cc",
"bwu_manager_test.cc",
"wifi_direct_bwu_test.cc",
"wifi_hotspot_bwu_test.cc",
],
deps = [
":bwu_handler",
":client_proxy",
":endpoint_channel",
":internal",
":internal_test",
":offline_frames",
":service_id_constants",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/mediums",
"//internal/analytics:mock_event_logger",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:mock_platform",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/flags:platform_flags",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform", # build_cleaner: keep
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/proto/analytics:connections_log_cc_proto",
"//proto:connections_enums_cc_proto",
"@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",
],
)
@@ -286,6 +357,7 @@ cc_test(
name = "pcp_manager_test",
srcs = ["pcp_manager_test.cc"],
deps = [
":endpoint_channel",
":internal",
":internal_test",
"//connections:core_types",
@@ -311,17 +383,20 @@ cc_test(
],
shard_count = 8,
deps = [
":client_proxy",
":endpoint_channel",
":internal",
":internal_test",
":offline_frames",
":types",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/analytics:mock_analytics_recorder",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/mediums",
"//connections/implementation/mediums:webrtc_utils",
"//connections/implementation/mediums:webrtc_peer_id",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//connections/v3:v3_types",
"//internal/analytics:mock_event_logger",
"//internal/flags:nearby_flags",
"//internal/interop:authentication_status",
"//internal/interop:authentication_transport_interface",
@@ -332,7 +407,6 @@ cc_test(
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/proto/analytics:connections_log_cc_proto",
"//proto:connections_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/base:core_headers",
@@ -369,7 +443,7 @@ cc_test(
name = "offline_frames_test",
srcs = ["offline_frames_validator_test.cc"],
deps = [
":internal",
":offline_frames",
"//connections:core_types",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
@@ -389,12 +463,11 @@ cc_test(
"client_proxy_test.cc",
],
deps = [
":internal",
"//base:casts",
":client_proxy",
"//connections:core_types",
"//connections/implementation/analytics:mock_analytics_recorder",
"//connections/implementation/flags:connections_flags",
"//connections/v3:v3_types",
"//internal/analytics:mock_event_logger",
"//internal/flags:nearby_flags",
"//internal/interop:device",
"//internal/platform:base",
@@ -418,6 +491,8 @@ cc_test(
"encryption_runner_test.cc",
],
deps = [
":client_proxy",
":endpoint_channel",
":internal",
"//connections/implementation/analytics",
"//internal/platform:base",
@@ -439,9 +514,12 @@ cc_test(
"endpoint_manager_test.cc",
],
deps = [
":client_proxy",
":endpoint_channel",
":internal",
":internal_test",
":offline_frames",
"//connections:core_types",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
@@ -466,14 +544,17 @@ cc_test(
"endpoint_channel_manager_test.cc",
],
deps = [
":client_proxy",
":endpoint_channel",
":internal",
":offline_frames",
"//connections/implementation/analytics",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/proto/analytics:connections_log_cc_proto",
"//proto:connections_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
@@ -491,13 +572,11 @@ cc_test(
],
deps = [
":internal",
"//connections/implementation/analytics",
":internal_test",
"//internal/platform:base",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//proto:connections_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
@@ -510,8 +589,8 @@ cc_test(
deps = [
":internal",
":internal_test",
":offline_frames",
"//connections:core_types",
"//connections/implementation/analytics",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:test_util",
@@ -532,6 +611,7 @@ cc_test(
"service_controller_router_test.cc",
],
deps = [
":client_proxy",
":internal",
":internal_test",
"//connections:core_types",
@@ -582,9 +662,11 @@ cc_test(
],
deps = [
":internal",
":offline_frames",
"//connections:core_types",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
@@ -593,26 +675,3 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "wifi_lan_bwu_handler_test",
srcs = [
"wifi_lan_bwu_handler_test.cc",
],
deps = [
":internal",
"//connections:core_types",
"//connections/implementation/mediums",
"//internal/analytics:mock_event_logger",
"//internal/platform:base",
"//internal/platform:mock_platform",
"//internal/platform:test_util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:platform_impl",
"//internal/proto/analytics:connections_log_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings:string_view",
"@com_google_googletest//:gtest_main",
],
)
+48 -15
View File
@@ -20,59 +20,92 @@ cc_library(
name = "analytics",
srcs = [
"analytics_recorder.cc",
"throughput_recorder.cc",
],
hdrs = [
"advertising_metadata_params.h",
"analytics_recorder.h",
"connection_attempt_metadata_params.h",
"discovery_metadata_params.h",
"packet_meta_data.h",
"throughput_recorder.h",
"operation_result_with_medium.h",
],
copts = ["-DCORE_ADAPTER_DLL"],
visibility = ["//connections:__subpackages__"],
deps = [
"//connections:core_types",
"//internal/analytics:event_logger",
"//internal/platform:error_code_recorder",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/time",
],
)
cc_library(
name = "analytics_recorder_impl",
srcs = [
"analytics_recorder_impl.cc",
],
hdrs = [
"analytics_recorder_impl.h",
],
copts = ["-DCORE_ADAPTER_DLL"],
visibility = [
"//connections/c:__pkg__",
"//sharing:__pkg__",
],
deps = [
":analytics",
"//connections:core_types",
"//internal/platform:error_code_recorder",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation:types",
"//internal/proto/analytics:connections_log_cc_proto",
"//location/nearby/analytics/cpp/logging:event_logger",
"//location/nearby/analytics/cpp/proto:connections_log_cc_proto",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/algorithm:container",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/meta:type_traits",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_protobuf//:protobuf_lite",
],
)
cc_library(
name = "mock_analytics_recorder",
testonly = True,
hdrs = [
"mock_analytics_recorder.h",
],
compatible_with = ["//buildenv/target:non_prod"],
visibility = ["//connections:__subpackages__"],
deps = [
":analytics",
"//connections:core_types",
"//internal/platform:error_code_recorder",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_for_library_testonly",
],
)
cc_test(
name = "analytics_test",
size = "small",
srcs = [
"analytics_recorder_test.cc",
"throughput_recorder_test.cc",
"analytics_recorder_impl_test.cc",
],
shard_count = 16,
deps = [
":analytics",
":analytics_recorder_impl",
"//connections:core_types",
"//internal/analytics:mock_event_logger",
"//internal/platform:base",
"//internal/platform:error_code_recorder",
"//internal/platform:logging",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//internal/proto/analytics:connections_log_cc_proto",
"//internal/test",
"//location/nearby/analytics/cpp/logging:mock_event_logger",
"//location/nearby/analytics/cpp/proto:connections_log_cc_proto",
"//net/proto2/contrib/parse_proto:parse_text_proto",
"//proto:connections_enums_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
@@ -17,7 +17,7 @@
#include <vector>
#include "internal/proto/analytics/connections_log.pb.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
namespace nearby {
@@ -26,8 +26,7 @@ struct AdvertisingMetadataParams {
bool is_extended_advertisement_supported = false;
int connected_ap_frequency = 0;
bool is_nfc_available = false;
std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>
std::vector<nearby::analytics::OperationResultWithMedium>
operation_result_with_mediums = {};
};
File diff suppressed because it is too large Load Diff
@@ -18,118 +18,98 @@
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/btree_map.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/advertising_metadata_params.h"
#include "connections/implementation/analytics/connection_attempt_metadata_params.h"
#include "connections/implementation/analytics/discovery_metadata_params.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
#include "connections/payload_type.h"
#include "connections/strategy.h"
#include "internal/analytics/event_logger.h"
#include "internal/platform/error_code_params.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/mutex.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace analytics {
namespace nearby::analytics {
enum class SafeDisconnectionResult {
kUnknown = 0,
kSafeDisconnection = 1,
kUnsafeDisconnection = 2,
};
class AnalyticsRecorder {
public:
explicit AnalyticsRecorder(::nearby::analytics::EventLogger* event_logger);
virtual ~AnalyticsRecorder();
AnalyticsRecorder() = default;
virtual ~AnalyticsRecorder() = default;
// Advertising phase
void OnStartAdvertising(
virtual void OnStartAdvertising(
connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>& mediums,
AdvertisingMetadataParams* advertising_metadata_params)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnStopAdvertising() ABSL_LOCKS_EXCLUDED(mutex_);
AdvertisingMetadataParams* advertising_metadata_params) = 0;
virtual void OnStopAdvertising() = 0;
// In case the client calls the {@link BasePcp#updateAdvertisingOptions()}
// multiple times, adds one index value to group the mediums results within
// the same UpdateAdvertisingOptions call, this API is to return the largest
// index value in current_advertising_phase.
int GetNextAdvertisingUpdateIndex() ABSL_LOCKS_EXCLUDED(mutex_);
virtual int GetNextAdvertisingUpdateIndex() = 0;
// Connection listening
void OnStartedIncomingConnectionListening(connections::Strategy strategy)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnStoppedIncomingConnectionListening() ABSL_LOCKS_EXCLUDED(mutex_);
virtual void OnStartedIncomingConnectionListening(
connections::Strategy strategy) = 0;
virtual void OnStoppedIncomingConnectionListening() = 0;
// Discovery phase
void OnStartDiscovery(
virtual void OnStartDiscovery(
connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>& mediums,
DiscoveryMetadataParams* discovery_metadata_params)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnStopDiscovery() ABSL_LOCKS_EXCLUDED(mutex_);
DiscoveryMetadataParams* discovery_metadata_params) = 0;
virtual void OnStopDiscovery() = 0;
// In case the client calls the {@link BasePcp#updateDiscoveryOptions()}
// multiple times, adds one index value to group the medium results within the
// same UpdateDiscoveryOptions call, this
// API is to return the latest index value in current_discovery_phase.
int GetNextDiscoveryUpdateIndex() ABSL_LOCKS_EXCLUDED(mutex_);
void OnEndpointFound(location::nearby::proto::connections::Medium medium)
ABSL_LOCKS_EXCLUDED(mutex_);
virtual int GetNextDiscoveryUpdateIndex() = 0;
virtual void OnEndpointFound(
location::nearby::proto::connections::Medium medium) = 0;
// Connection request
void OnRequestConnection(const connections::Strategy& strategy,
const std::string& endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
virtual void OnRequestConnection(const connections::Strategy& strategy,
const std::string& endpoint_id) = 0;
void OnConnectionRequestReceived(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnConnectionRequestSent(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnRemoteEndpointAccepted(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnLocalEndpointAccepted(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnRemoteEndpointRejected(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnLocalEndpointRejected(const std::string& remote_endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
virtual void OnConnectionRequestReceived(
const std::string& remote_endpoint_id) = 0;
virtual void OnConnectionRequestSent(
const std::string& remote_endpoint_id) = 0;
virtual void OnRemoteEndpointAccepted(
const std::string& remote_endpoint_id) = 0;
virtual void OnLocalEndpointAccepted(
const std::string& remote_endpoint_id) = 0;
virtual void OnRemoteEndpointRejected(
const std::string& remote_endpoint_id) = 0;
virtual void OnLocalEndpointRejected(
const std::string& remote_endpoint_id) = 0;
// Connection attempt
// Records an attempt with meta data at establishing an incoming physical
// connection.
void OnIncomingConnectionAttempt(
virtual void OnIncomingConnectionAttempt(
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
ABSL_LOCKS_EXCLUDED(mutex_);
// Records an attempt with meta data at establishing an outgoing physical
// connection.
void OnOutgoingConnectionAttempt(
ConnectionAttemptMetadataParams* connection_attempt_metadata_params) = 0;
virtual void OnOutgoingConnectionAttempt(
const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
ABSL_LOCKS_EXCLUDED(mutex_);
ConnectionAttemptMetadataParams* connection_attempt_metadata_params) = 0;
static std::unique_ptr<AdvertisingMetadataParams>
BuildAdvertisingMetadataParams(
bool is_extended_advertisement_supported = false,
int connected_ap_frequency = 0, bool is_nfc_available = false,
const std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>&
const std::vector<OperationResultWithMedium>&
operation_result_with_mediums = {});
static std::unique_ptr<DiscoveryMetadataParams> BuildDiscoveryMetadataParams(
bool is_extended_advertisement_supported = false,
int connected_ap_frequency = 0, bool is_nfc_available = false,
const std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>&
const std::vector<OperationResultWithMedium>&
operation_result_with_mediums = {});
static std::unique_ptr<ConnectionAttemptMetadataParams>
@@ -147,363 +127,78 @@ class AnalyticsRecorder {
GetChannelIoErrorResultCodeFromMedium(
location::nearby::proto::connections::Medium medium);
// Connection establishedSafeDisconnectionResult
void OnConnectionEstablished(
// Connection established
virtual void OnConnectionEstablished(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
const std::string& connection_token) ABSL_LOCKS_EXCLUDED(mutex_);
void OnConnectionClosed(
const std::string& connection_token) = 0;
virtual void OnConnectionClosed(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result)
ABSL_LOCKS_EXCLUDED(mutex_);
SafeDisconnectionResult result) = 0;
// Payload
void OnIncomingPayloadStarted(const std::string& endpoint_id,
std::int64_t payload_id,
connections::PayloadType type,
std::int64_t total_size_bytes)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnPayloadChunkReceived(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnIncomingPayloadDone(
virtual void OnIncomingPayloadStarted(const std::string& endpoint_id,
std::int64_t payload_id,
connections::PayloadType type,
std::int64_t total_size_bytes) = 0;
virtual void OnPayloadChunkReceived(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes) = 0;
virtual void OnIncomingPayloadDone(
const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_);
void OnOutgoingPayloadStarted(const std::vector<std::string>& endpoint_ids,
std::int64_t payload_id,
connections::PayloadType type,
std::int64_t total_size_bytes)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnPayloadChunkSent(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnOutgoingPayloadDone(
operation_result_code) = 0;
virtual void OnOutgoingPayloadStarted(
const std::vector<std::string>& endpoint_ids, std::int64_t payload_id,
connections::PayloadType type, std::int64_t total_size_bytes) = 0;
virtual void OnPayloadChunkSent(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes) = 0;
virtual void OnOutgoingPayloadDone(
const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_);
operation_result_code) = 0;
// BandwidthUpgrade
void OnBandwidthUpgradeStarted(
virtual void OnBandwidthUpgradeStarted(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium from_medium,
location::nearby::proto::connections::Medium to_medium,
location::nearby::proto::connections::ConnectionAttemptDirection
direction,
const std::string& connection_token) ABSL_LOCKS_EXCLUDED(mutex_);
void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id,
int num_interfaces,
int num_ipv6_only_interfaces)
ABSL_LOCKS_EXCLUDED(mutex_);
void OnBandwidthUpgradeError(
const std::string& connection_token) = 0;
virtual void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id,
int num_interfaces,
int num_ipv6_only_interfaces) = 0;
virtual void OnBandwidthUpgradeError(
const std::string& endpoint_id,
location::nearby::proto::connections::BandwidthUpgradeResult result,
location::nearby::proto::connections::BandwidthUpgradeErrorStage
error_stage,
location::nearby::proto::connections::OperationResultCode
operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_);
void OnBandwidthUpgradeSuccess(const std::string& endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
operation_result_code) = 0;
virtual void OnBandwidthUpgradeSuccess(const std::string& endpoint_id) = 0;
// Error Code
void OnErrorCode(const ErrorCodeParams& params);
virtual void OnErrorCode(const ErrorCodeParams& params) = 0;
// Log the start client session event with start client session logging
// resources setup (e.g. client_session_, started_client_session_time_)
void LogStartSession() ABSL_LOCKS_EXCLUDED(mutex_);
virtual void LogStartSession() = 0;
virtual void LogSession() = 0;
// Invokes event_logger_.Log() at the end of life of client. Log action is
// called in a separate thread to allow synchronous potentially lengthy
// execution.
void LogSession() ABSL_LOCKS_EXCLUDED(mutex_);
virtual bool IsSessionLogged() = 0;
bool IsSessionLogged();
location::nearby::proto::connections::OperationResultCategory
virtual location::nearby::proto::connections::OperationResultCategory
GetOperationResultCategory(
location::nearby::proto::connections::OperationResultCode result_code);
// Waits until all logs are sent to the backend.
// For testing only.
void Sync();
private:
// Tracks the chunks and duration of a Payload on a particular medium.
class PendingPayload {
public:
PendingPayload(location::nearby::proto::connections::PayloadType type,
std::int64_t total_size_bytes)
: PendingPayload(type, total_size_bytes,
location::nearby::proto::connections::
OperationResultCode::DETAIL_UNKNOWN) {}
PendingPayload(location::nearby::proto::connections::PayloadType type,
std::int64_t total_size_bytes,
location::nearby::proto::connections::OperationResultCode
operation_result_code)
: start_time_(SystemClock::ElapsedRealtime()),
type_(type),
total_size_bytes_(total_size_bytes),
num_bytes_transferred_(0),
num_chunks_(0),
operation_result_code_(operation_result_code) {}
~PendingPayload() = default;
void AddChunk(std::int64_t chunk_size_bytes);
location::nearby::analytics::proto::ConnectionsLog::Payload GetProtoPayload(
location::nearby::proto::connections::PayloadStatus status);
location::nearby::proto::connections::PayloadType type() const {
return type_;
}
std::int64_t total_size_bytes() const { return total_size_bytes_; }
void SetOperationResultCode(
location::nearby::proto::connections::OperationResultCode
operation_result_code) {
operation_result_code_ = operation_result_code;
}
private:
absl::Time start_time_;
location::nearby::proto::connections::PayloadType type_;
std::int64_t total_size_bytes_;
std::int64_t num_bytes_transferred_;
int num_chunks_;
location::nearby::proto::connections::OperationResultCode
operation_result_code_ = location::nearby::proto::connections::
OperationResultCode::DETAIL_UNKNOWN;
};
class LogicalConnection {
public:
LogicalConnection(
location::nearby::proto::connections::Medium initial_medium,
const std::string& connection_token) {
PhysicalConnectionEstablished(initial_medium, connection_token);
}
LogicalConnection(const LogicalConnection&) = delete;
LogicalConnection(LogicalConnection&& other)
: current_medium_(std::move(other.current_medium_)),
physical_connections_(std::move(other.physical_connections_)),
incoming_payloads_(std::move(other.incoming_payloads_)),
outgoing_payloads_(std::move(other.outgoing_payloads_)) {}
LogicalConnection& operator=(const LogicalConnection&) = delete;
LogicalConnection&& operator=(LogicalConnection&&) = delete;
~LogicalConnection() = default;
void PhysicalConnectionEstablished(
location::nearby::proto::connections::Medium medium,
const std::string& connection_token);
void PhysicalConnectionClosed(
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result);
void CloseAllPhysicalConnections();
void IncomingPayloadStarted(
std::int64_t payload_id,
location::nearby::proto::connections::PayloadType type,
std::int64_t total_size_bytes);
void ChunkReceived(std::int64_t payload_id, std::int64_t size_bytes);
void IncomingPayloadDone(
std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code);
void OutgoingPayloadStarted(
std::int64_t payload_id,
location::nearby::proto::connections::PayloadType type,
std::int64_t total_size_bytes);
void ChunkSent(std::int64_t payload_id, std::int64_t size_bytes);
void OutgoingPayloadDone(
std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code);
std::vector<location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection>
GetEstablisedConnections();
private:
void FinishPhysicalConnection(
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection* established_connection,
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result);
std::vector<location::nearby::analytics::proto::ConnectionsLog::Payload>
ResolvePendingPayloads(
absl::btree_map<std::int64_t, std::unique_ptr<PendingPayload>>&
pending_payloads,
location::nearby::proto::connections::DisconnectionReason reason);
location::nearby::proto::connections::OperationResultCode
GetPendingPayloadResultCodeFromReason(
location::nearby::proto::connections::DisconnectionReason reason);
location::nearby::proto::connections::Medium current_medium_ =
location::nearby::proto::connections::UNKNOWN_MEDIUM;
absl::btree_map<location::nearby::proto::connections::Medium,
std::unique_ptr<location::nearby::analytics::proto::
ConnectionsLog::EstablishedConnection>>
physical_connections_;
absl::btree_map<std::int64_t, std::unique_ptr<PendingPayload>>
incoming_payloads_;
absl::btree_map<std::int64_t, std::unique_ptr<PendingPayload>>
outgoing_payloads_;
};
bool CanRecordAnalyticsLocked(absl::string_view method_name)
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
// Callbacks the ConnectionsLog proto byte array data to the EventLogger with
// ClientSession sub-proto.
void LogClientSessionLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Callbacks the ConnectionsLog proto byte array data to the EventLogger.
void LogEvent(location::nearby::proto::connections::EventType event_type);
void UpdateStrategySessionLocked(
connections::Strategy strategy,
location::nearby::proto::connections::SessionRole role)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void RecordAdvertisingPhaseDurationAndReasonLocked(bool on_stop) const
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void FinishAdvertisingPhaseLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void RecordDiscoveryPhaseDurationAndReasonLocked(bool on_stop) const
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void FinishDiscoveryPhaseLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool UpdateAdvertiserConnectionRequestLocked(
location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest*
request) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
bool UpdateDiscovererConnectionRequestLocked(
location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest*
request) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
bool BothEndpointsRespondedLocked(
location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest*
request) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void LocalEndpointRespondedLocked(
const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionRequestResponse response)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void RemoteEndpointRespondedLocked(
const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionRequestResponse response)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void MarkConnectionRequestIgnoredLocked(
location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest*
request) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void OnIncomingConnectionAttemptLocked(
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void OnOutgoingConnectionAttemptLocked(
const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
ABSL_SHARED_LOCKS_REQUIRED(mutex_);
bool ConnectionAttemptResultCodeExistedLocked(
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptDirection
direction,
const std::string& connection_token,
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::OperationResultCode
operation_result_code) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
bool EraseIfBandwidthUpgradeRecordExistedLocked(
const std::string& endpoint_id,
location::nearby::proto::connections::BandwidthUpgradeResult result,
location::nearby::proto::connections::BandwidthUpgradeErrorStage
error_stage,
location::nearby::proto::connections::OperationResultCode
operation_result_code) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void FinishUpgradeAttemptLocked(
const std::string& endpoint_id,
location::nearby::proto::connections::BandwidthUpgradeResult result,
location::nearby::proto::connections::BandwidthUpgradeErrorStage
error_stage,
location::nearby::proto::connections::OperationResultCode
operation_result_code,
bool erase_item = true) ABSL_SHARED_LOCKS_REQUIRED(mutex_);
void FinishStrategySessionLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
result_code) = 0;
int GetLatestUpdateIndexLocked(
const std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>& list)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
location::nearby::proto::connections::ConnectionsStrategy
StrategyToConnectionStrategy(connections::Strategy strategy);
location::nearby::proto::connections::PayloadType
PayloadTypeToProtoPayloadType(connections::PayloadType type);
// Not owned by AnalyticsRecorder. Pointer must refer to a valid object
// that outlives the one constructed.
::nearby::analytics::EventLogger* event_logger_;
// Protects all sub-protos reading and writing in ConnectionLog.
Mutex mutex_;
// ClientSession
std::unique_ptr<
location::nearby::analytics::proto::ConnectionsLog::ClientSession>
client_session_;
absl::Time started_client_session_time_;
bool session_was_logged_ ABSL_GUARDED_BY(mutex_) = false;
bool start_client_session_was_logged_ ABSL_GUARDED_BY(mutex_) = false;
// Current StrategySession
connections::Strategy current_strategy_ ABSL_GUARDED_BY(mutex_) =
connections::Strategy::kNone;
std::unique_ptr<
location::nearby::analytics::proto::ConnectionsLog::StrategySession>
current_strategy_session_ ABSL_GUARDED_BY(mutex_);
absl::Time started_strategy_session_time_ ABSL_GUARDED_BY(mutex_);
// Current AdvertisingPhase
std::unique_ptr<
location::nearby::analytics::proto::ConnectionsLog::AdvertisingPhase>
current_advertising_phase_;
absl::Time started_advertising_phase_time_ = absl::InfinitePast();
// Current DiscoveryPhase
std::unique_ptr<
location::nearby::analytics::proto::ConnectionsLog::DiscoveryPhase>
current_discovery_phase_;
absl::Time started_discovery_phase_time_ = absl::InfinitePast();
absl::btree_map<std::string,
std::unique_ptr<location::nearby::analytics::proto::
ConnectionsLog::ConnectionRequest>>
incoming_connection_requests_ ABSL_GUARDED_BY(mutex_);
absl::btree_map<std::string,
std::unique_ptr<location::nearby::analytics::proto::
ConnectionsLog::ConnectionRequest>>
outgoing_connection_requests_ ABSL_GUARDED_BY(mutex_);
absl::btree_map<std::string, std::unique_ptr<LogicalConnection>>
active_connections_ ABSL_GUARDED_BY(mutex_);
absl::btree_map<std::string,
std::unique_ptr<location::nearby::analytics::proto::
ConnectionsLog::BandwidthUpgradeAttempt>>
bandwidth_upgrade_attempts_ ABSL_GUARDED_BY(mutex_);
virtual void Sync() = 0;
};
} // namespace analytics
} // namespace nearby
} // namespace nearby::analytics
#endif // ANALYTICS_ANALYTICS_RECORDER_H_
File diff suppressed because it is too large Load Diff
@@ -17,7 +17,7 @@
#include <vector>
#include "internal/proto/analytics/connections_log.pb.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
namespace nearby {
@@ -26,8 +26,7 @@ struct DiscoveryMetadataParams {
bool is_extended_advertisement_supported = false;
int connected_ap_frequency = 0;
bool is_nfc_available = false;
std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>
std::vector<nearby::analytics::OperationResultWithMedium>
operation_result_with_mediums = {};
};
@@ -0,0 +1,196 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ANALYTICS_MOCK_ANALYTICS_RECORDER_H_
#define ANALYTICS_MOCK_ANALYTICS_RECORDER_H_
#include <cstdint>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/advertising_metadata_params.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/connection_attempt_metadata_params.h"
#include "connections/implementation/analytics/discovery_metadata_params.h"
#include "connections/payload_type.h"
#include "connections/strategy.h"
#include "internal/platform/error_code_params.h"
#include "proto/connections_enums.pb.h"
namespace nearby::analytics {
class MockAnalyticsRecorder : public AnalyticsRecorder {
public:
MockAnalyticsRecorder() = default;
~MockAnalyticsRecorder() override = default;
// Advertising phase
MOCK_METHOD(void, OnStartAdvertising,
(connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>&
mediums,
AdvertisingMetadataParams* advertising_metadata_params),
(override));
MOCK_METHOD(void, OnStopAdvertising, (), (override));
MOCK_METHOD(int, GetNextAdvertisingUpdateIndex, (), (override));
// Connection listening
MOCK_METHOD(void, OnStartedIncomingConnectionListening,
(connections::Strategy strategy), (override));
MOCK_METHOD(void, OnStoppedIncomingConnectionListening, (), (override));
// Discovery phase
MOCK_METHOD(void, OnStartDiscovery,
(connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>&
mediums,
DiscoveryMetadataParams* discovery_metadata_params),
(override));
MOCK_METHOD(void, OnStopDiscovery, (), (override));
MOCK_METHOD(int, GetNextDiscoveryUpdateIndex, (), (override));
MOCK_METHOD(void, OnEndpointFound,
(location::nearby::proto::connections::Medium medium),
(override));
// Connection request
MOCK_METHOD(void, OnRequestConnection,
(const connections::Strategy& strategy,
const std::string& endpoint_id),
(override));
MOCK_METHOD(void, OnConnectionRequestReceived,
(const std::string& remote_endpoint_id), (override));
MOCK_METHOD(void, OnConnectionRequestSent,
(const std::string& remote_endpoint_id), (override));
MOCK_METHOD(void, OnRemoteEndpointAccepted,
(const std::string& remote_endpoint_id), (override));
MOCK_METHOD(void, OnLocalEndpointAccepted,
(const std::string& remote_endpoint_id), (override));
MOCK_METHOD(void, OnRemoteEndpointRejected,
(const std::string& remote_endpoint_id), (override));
MOCK_METHOD(void, OnLocalEndpointRejected,
(const std::string& remote_endpoint_id), (override));
// Connection attempt
MOCK_METHOD(
void, OnIncomingConnectionAttempt,
(location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params),
(override));
MOCK_METHOD(
void, OnOutgoingConnectionAttempt,
(const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params),
(override));
// Connection established
MOCK_METHOD(void, OnConnectionEstablished,
(const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
const std::string& connection_token),
(override));
MOCK_METHOD(void, OnConnectionClosed,
(const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::DisconnectionReason reason,
SafeDisconnectionResult result),
(override));
// Payload
MOCK_METHOD(void, OnIncomingPayloadStarted,
(const std::string& endpoint_id, std::int64_t payload_id,
connections::PayloadType type, std::int64_t total_size_bytes),
(override));
MOCK_METHOD(void, OnPayloadChunkReceived,
(const std::string& endpoint_id, std::int64_t payload_id,
std::int64_t chunk_size_bytes),
(override));
MOCK_METHOD(void, OnIncomingPayloadDone,
(const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code),
(override));
MOCK_METHOD(void, OnOutgoingPayloadStarted,
(const std::vector<std::string>& endpoint_ids,
std::int64_t payload_id, connections::PayloadType type,
std::int64_t total_size_bytes),
(override));
MOCK_METHOD(void, OnPayloadChunkSent,
(const std::string& endpoint_id, std::int64_t payload_id,
std::int64_t chunk_size_bytes),
(override));
MOCK_METHOD(void, OnOutgoingPayloadDone,
(const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code),
(override));
// BandwidthUpgrade
MOCK_METHOD(void, OnBandwidthUpgradeStarted,
(const std::string& endpoint_id,
location::nearby::proto::connections::Medium from_medium,
location::nearby::proto::connections::Medium to_medium,
location::nearby::proto::connections::ConnectionAttemptDirection
direction,
const std::string& connection_token),
(override));
MOCK_METHOD(void, UpdateBwUpgradeNetworkInfo,
(const std::string& endpoint_id, int num_interfaces,
int num_ipv6_only_interfaces),
(override));
MOCK_METHOD(void, OnBandwidthUpgradeError,
(const std::string& endpoint_id,
location::nearby::proto::connections::BandwidthUpgradeResult
result,
location::nearby::proto::connections::BandwidthUpgradeErrorStage
error_stage,
location::nearby::proto::connections::OperationResultCode
operation_result_code),
(override));
MOCK_METHOD(void, OnBandwidthUpgradeSuccess, (const std::string& endpoint_id),
(override));
// Error Code
MOCK_METHOD(void, OnErrorCode, (const ErrorCodeParams& params), (override));
MOCK_METHOD(void, LogStartSession, (), (override));
MOCK_METHOD(void, LogSession, (), (override));
MOCK_METHOD(bool, IsSessionLogged, (), (override));
MOCK_METHOD(
location::nearby::proto::connections::OperationResultCategory,
GetOperationResultCategory,
(location::nearby::proto::connections::OperationResultCode result_code),
(override));
MOCK_METHOD(void, Sync, (), (override));
};
} // namespace nearby::analytics
#endif // ANALYTICS_MOCK_ANALYTICS_RECORDER_H_
@@ -0,0 +1,55 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_
#define ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_
#include <optional>
#include "proto/connections_enums.pb.h"
namespace nearby::analytics {
struct OperationResultWithMedium {
location::nearby::proto::connections::Medium medium =
location::nearby::proto::connections::UNKNOWN_MEDIUM;
std::optional<int> update_index;
location::nearby::proto::connections::OperationResultCategory
result_category = location::nearby::proto::connections::CATEGORY_UNKNOWN;
location::nearby::proto::connections::OperationResultCode result_code =
location::nearby::proto::connections::DETAIL_UNKNOWN;
std::optional<location::nearby::proto::connections::ConnectionMode>
connection_mode;
void set_medium(location::nearby::proto::connections::Medium m) {
medium = m;
}
void set_update_index(int i) { update_index = i; }
void set_result_category(
location::nearby::proto::connections::OperationResultCategory c) {
result_category = c;
}
void set_result_code(
location::nearby::proto::connections::OperationResultCode c) {
result_code = c;
}
void set_connection_mode(
location::nearby::proto::connections::ConnectionMode m) {
connection_mode = m;
}
};
} // namespace nearby::analytics
#endif // ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_
@@ -1,102 +0,0 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_
#define NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_
#include <cstdint>
#include "absl/time/time.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/system_clock.h"
namespace nearby {
namespace analytics {
struct PacketMetaData {
int packet_size;
absl::Time file_io_start_time;
absl::Time file_io_end_time;
absl::Time encryption_start_time;
absl::Time encryption_end_time;
absl::Time socket_io_start_time;
absl::Time socket_io_end_time;
void Reset() {
file_io_start_time = SystemClock::ElapsedRealtime();
socket_io_start_time = SystemClock::ElapsedRealtime();
socket_io_start_time = SystemClock::ElapsedRealtime();
packet_size = 0;
}
void SetPacketSize(int packet_size) {
this->packet_size = packet_size;
}
int GetPacketSize() {
return packet_size;
}
void StartFileIo() {
file_io_start_time = SystemClock::ElapsedRealtime();
}
void StopFileIo() {
file_io_end_time = SystemClock::ElapsedRealtime();
}
void StartEncryption() {
encryption_start_time = SystemClock::ElapsedRealtime();
}
void StopEncryption() {
encryption_end_time = SystemClock::ElapsedRealtime();
}
void StartSocketIo() {
socket_io_start_time = SystemClock::ElapsedRealtime();
}
void StopSocketIo() {
socket_io_end_time = SystemClock::ElapsedRealtime();
}
int64_t GetEncryptionTimeInMillis() {
if (encryption_end_time > encryption_start_time) {
return absl::ToInt64Milliseconds(encryption_end_time -
encryption_start_time);
}
return 0L;
}
int64_t GetFileIoTimeInMillis() {
if (file_io_end_time > file_io_start_time) {
return absl::ToInt64Milliseconds(file_io_end_time - file_io_start_time);
}
return 0L;
}
int64_t GetSocketIoTimeInMillis() {
if (socket_io_end_time > socket_io_start_time) {
return absl::ToInt64Milliseconds(socket_io_end_time -
socket_io_start_time);
}
return 0L;
}
};
} // namespace analytics
} // namespace nearby
#endif // NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_
@@ -1,333 +0,0 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/analytics/throughput_recorder.h"
#include <stdint.h>
#include <new>
#include <ostream>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/str_format.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
namespace nearby {
namespace analytics {
namespace {
constexpr int kDefaultThroughoutKbps = 0;
constexpr int kKbInBytes = 1024;
constexpr int kSecInMs = 1000;
} // namespace
ThroughputRecorder::ThroughputRecorder(int64_t payload_id)
: payload_id_(payload_id) {}
ThroughputRecorderContainer& ThroughputRecorderContainer::GetInstance() {
alignas(ThroughputRecorderContainer) static char
storage[sizeof(ThroughputRecorderContainer)];
static ThroughputRecorderContainer* env =
new (&storage) ThroughputRecorderContainer();
return *env;
}
void ThroughputRecorder::Start(PayloadType payload_type,
PayloadDirection payload_direction) {
std::string direction =
(payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive"
: "; Send";
VLOG(1) << "Start TP profiling for payload_id:" << payload_id_ << direction;
if (payload_type == PayloadType::kUnknown) {
VLOG(1) << "Ignore ThroughputRecorder::start for Unknown Payload type";
return;
}
MutexLock lock(&mutex_);
start_timestamp_ = SystemClock::ElapsedRealtime();
payload_type_ = payload_type;
payload_direction_ = payload_direction;
// Add packetLostAlarm later
}
bool ThroughputRecorder::Stop() {
MutexLock lock(&mutex_);
VLOG(1) << "Stop TP profiling for payload_id:" << payload_id_;
if (payload_type_ == PayloadType::kUnknown) {
VLOG(1) << "Ignore ThroughputRecorder::stop as it never start";
return false;
}
{
// Add packetLostAlarm stop process later
absl::Time stop_timestamp = SystemClock::ElapsedRealtime();
int64_t total_byte_size = 0;
int medium_size = throughputs_.size();
// The worse case is the socket/connect blocking the write request, never
// got return when writing a frame out, it would get a very good data rate
// for this case. e.g. use 60 seconds to send a file and failed, the counter
// only get the duration as 30 seconds because the last write request
// blocked.
if (!success_) {
if (!throughputs_.empty()) {
for (auto& tp : throughputs_) {
tp.second.SetLastTimestamp(stop_timestamp);
}
}
}
// calculate throughput by medium
for (auto& tp : throughputs_) {
tp.second.dump();
total_byte_size += tp.second.GetTotalByteSize();
}
throughputs_.clear();
int64_t total_millis =
absl::ToInt64Milliseconds(stop_timestamp - start_timestamp_);
throughput_kbps_ = CalculateThroughputKBps(total_byte_size, total_millis);
int throughput_mbps = CalculateThroughputMBps(throughput_kbps_);
// calculate overall throughput if there are multiple mediums
if (medium_size > 1) {
if (throughput_kbps_ != kDefaultThroughoutKbps) {
std::string dump_content = absl::StrFormat(
"%s %s data(%d bytes) %s, overall used %d milliseconds, "
"throughput "
"is %d MB/s (%d KB/s), File IO takes %d ms, %s takes %d "
"ms, "
"Socket IO takes %d ms",
(payload_direction_ == PayloadDirection::INCOMING_PAYLOAD)
? "Received"
: "Sent",
ToString(payload_type_), total_byte_size,
success_ ? "SUCCEEDED" : "FAILED", total_millis, throughput_mbps,
throughput_kbps_, file_io_time_,
(payload_direction_ == PayloadDirection::INCOMING_PAYLOAD)
? "Decryption"
: "Encryption",
encryption_time_, socket_io_time_);
LOG(INFO) << dump_content;
}
}
}
return true;
}
void ThroughputRecorder::MarkAsSuccess() {
MutexLock lock(&mutex_);
success_ = true;
}
int ThroughputRecorder::CalculateThroughputKBps(int64_t total_byte_size,
int64_t total_millis) {
if (total_millis > 0) {
return (int)(total_byte_size * kSecInMs / kKbInBytes / total_millis);
}
return kDefaultThroughoutKbps;
}
int ThroughputRecorder::CalculateThroughputMBps(int throughputKBps) {
return throughputKBps / kKbInBytes;
}
void ThroughputRecorder::Throughput::Add(int frame_size, int64_t file_io_time,
int64_t encryption_time,
int64_t socket_io_time) {
total_byte_size_ += frame_size;
// reset the last timestamp
last_timestamp_ = SystemClock::ElapsedRealtime();
file_io_time_ += file_io_time;
encryption_time_ += encryption_time;
socket_io_time_ += socket_io_time;
}
bool ThroughputRecorder::Throughput::dump() {
int64_t total_millis =
absl::ToInt64Milliseconds(last_timestamp_ - start_timestamp_);
int throughput_kbps = CalculateThroughputKBps(total_byte_size_, total_millis);
if (throughput_kbps == kDefaultThroughoutKbps) {
return false;
}
int throughpu_mbps = CalculateThroughputMBps(throughput_kbps);
int64_t other =
total_millis - file_io_time_ - encryption_time_ - socket_io_time_;
std::string dump_content = absl::StrFormat(
"%s %s data(%ld bytes) via %s used %ld milliseconds, throughput is %d "
"MB/s (%d KB/s), File IO takes %ld ms, %s takes %ld ms, "
"Socket IO takes %ld ms, "
"Other takes %ld ms",
(payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) ? "Received"
: "Sent",
ToString(payload_type_), total_byte_size_,
location::nearby::proto::connections::Medium_Name(medium_), total_millis,
throughpu_mbps, throughput_kbps, file_io_time_,
(payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) ? "Decryption"
: "Encryption",
encryption_time_, socket_io_time_, other);
LOG(INFO) << dump_content;
return true;
}
ThroughputRecorder::Throughput& ThroughputRecorder::GetThroughput(
Medium medium, int64_t duration_millis) {
auto it = throughputs_.find(medium);
if (it == throughputs_.end()) {
auto throughput = new Throughput(
medium,
SystemClock::ElapsedRealtime() - absl::Milliseconds(duration_millis),
payload_type_, payload_direction_);
throughputs_.emplace(medium, std::move(*throughput));
delete throughput;
return throughputs_.find(medium)->second;
}
return it->second;
}
int ThroughputRecorder::GetThroughputsSize() {
MutexLock lock(&mutex_);
return throughputs_.size();
}
int ThroughputRecorder::GetThroughputKbps() { return throughput_kbps_; }
int64_t ThroughputRecorder::GetDurationMillis() { return duration_millis_; }
void ThroughputRecorder::OnFrameSent(Medium medium,
PacketMetaData& packetMetaData) {
MutexLock lock(&mutex_);
if (payload_type_ == PayloadType::kUnknown) {
VLOG(1) << "PayloadType is invalid, return";
return;
}
duration_millis_ = packetMetaData.GetEncryptionTimeInMillis() +
packetMetaData.GetFileIoTimeInMillis() +
packetMetaData.GetSocketIoTimeInMillis();
GetThroughput(medium, duration_millis_)
.Add(packetMetaData.packet_size, packetMetaData.GetFileIoTimeInMillis(),
packetMetaData.GetEncryptionTimeInMillis(),
packetMetaData.GetSocketIoTimeInMillis());
CalculateDurationTimes(packetMetaData);
}
void ThroughputRecorder::OnFrameReceived(Medium medium,
PacketMetaData& packetMetaData) {
MutexLock lock(&mutex_);
if (payload_type_ == PayloadType::kUnknown) {
VLOG(1) << "PayloadType is invalid, return";
return;
}
// Add packetLostAlarm process later
duration_millis_ = packetMetaData.GetEncryptionTimeInMillis() +
packetMetaData.GetFileIoTimeInMillis() +
packetMetaData.GetSocketIoTimeInMillis();
GetThroughput(medium, duration_millis_)
.Add(packetMetaData.packet_size, packetMetaData.GetFileIoTimeInMillis(),
packetMetaData.GetEncryptionTimeInMillis(),
packetMetaData.GetSocketIoTimeInMillis());
CalculateDurationTimes(packetMetaData);
}
void ThroughputRecorder::CalculateDurationTimes(PacketMetaData packetMetaData) {
encryption_time_ += packetMetaData.GetEncryptionTimeInMillis();
socket_io_time_ += packetMetaData.GetSocketIoTimeInMillis();
file_io_time_ += packetMetaData.GetFileIoTimeInMillis();
}
std::string ThroughputRecorder::ToString(PayloadType type) {
switch (type) {
case PayloadType::kBytes:
return std::string("Bytes");
case PayloadType::kStream:
return std::string("Stream");
case PayloadType::kFile:
return std::string("File");
case PayloadType::kUnknown:
return std::string("Unknown");
}
}
// Inplementation for ThroughputRecorderContainer
void ThroughputRecorderContainer::Shutdown() {
MutexLock lock(&mutex_);
VLOG(1) << __func__ << ". Num of Instance:" << throughput_recorders_.size();
for (auto& throughput_recorder : throughput_recorders_) {
VLOG(1) << "Stop instance: " << throughput_recorder.second;
throughput_recorder.second->Stop();
delete throughput_recorder.second;
}
throughput_recorders_.clear();
}
ThroughputRecorder* ThroughputRecorderContainer::GetTPRecorder(
const int64_t payload_id, PayloadDirection payload_direction) {
MutexLock lock(&mutex_);
auto it = throughput_recorders_.find(
std::pair<int64_t, PayloadDirection>(payload_id, payload_direction));
if (it == throughput_recorders_.end()) {
auto instance = new ThroughputRecorder(payload_id);
std::string direction =
(payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive"
: "; Send";
VLOG(1) << "Add ThroughputRecorder instance : " << instance
<< " for payload_id:" << payload_id << direction;
throughput_recorders_.emplace(
std::pair<int64_t, PayloadDirection>(payload_id, payload_direction),
instance);
return instance;
}
return it->second;
}
void ThroughputRecorderContainer::StopTPRecorder(
const int64_t payload_id, PayloadDirection payload_direction) {
MutexLock lock(&mutex_);
std::string direction =
(payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive"
: "; Send";
auto it = throughput_recorders_.find(
std::pair<int64_t, PayloadDirection>(payload_id, payload_direction));
if (it != throughput_recorders_.end()) {
VLOG(1) << "Found and stop/delete ThroughputRecorder instance : "
<< &(it->second) << " for payload_id:" << payload_id << direction;
it->second->Stop();
delete it->second;
throughput_recorders_.erase(
std::pair<int64_t, PayloadDirection>(payload_id, payload_direction));
return;
}
VLOG(1) << "No ThroughputRecorder found for :" << payload_id;
}
int ThroughputRecorderContainer::GetSize() {
MutexLock lock(&mutex_);
return throughput_recorders_.size();
}
} // namespace analytics
} // namespace nearby
@@ -1,144 +0,0 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_
#define NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_
#include <cstdint>
#include <string>
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/payload_type.h"
#include "internal/platform/mutex.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace analytics {
// The following aliases are only for users' convenience.
using ::location::nearby::proto::connections::Medium;
using ::nearby::connections::PayloadType;
// Enum to represent if a payload is incoming or outgoing.
using ::nearby::connections::PayloadDirection;
class ThroughputRecorder {
public:
explicit ThroughputRecorder(int64_t payload_id);
~ThroughputRecorder() = default;
void Start(PayloadType payload_type, PayloadDirection payload_direction);
bool Stop() ABSL_LOCKS_EXCLUDED(mutex_);
static int CalculateThroughputKBps(int64_t total_byte_size,
int64_t total_millis);
static int CalculateThroughputMBps(int throughputKBps);
class Throughput {
public:
Throughput() = default;
~Throughput() = default;
Throughput(Medium medium, absl::Time start_timestamp,
PayloadType payload_type, PayloadDirection payload_direction)
: medium_(medium),
start_timestamp_(start_timestamp),
payload_type_(payload_type),
payload_direction_(payload_direction) {}
void Add(int frame_size, int64_t file_io_time, int64_t encryption_time,
int64_t socket_io_time);
void SetLastTimestamp(absl::Time time_stamp) {
last_timestamp_ = time_stamp;
}
int64_t GetTotalByteSize() { return total_byte_size_; }
bool dump();
private:
Medium medium_;
absl::Time start_timestamp_;
PayloadType payload_type_;
int64_t total_byte_size_ = 0;
absl::Time last_timestamp_;
PayloadDirection payload_direction_ = PayloadDirection::INCOMING_PAYLOAD;
int64_t file_io_time_ = 0;
int64_t encryption_time_ = 0;
int64_t socket_io_time_ = 0;
};
Throughput& GetThroughput(Medium medium, int64_t duration_millis);
int GetThroughputsSize();
int GetThroughputKbps();
int64_t GetDurationMillis();
void OnFrameSent(Medium medium, PacketMetaData& packetMetaData);
void OnFrameReceived(Medium medium, PacketMetaData& packetMetaData);
void MarkAsSuccess();
private:
void CalculateDurationTimes(PacketMetaData packetMetaData);
static std::string ToString(PayloadType type);
Mutex mutex_;
int64_t payload_id_ = 0;
absl::Time start_timestamp_;
PayloadType payload_type_ = PayloadType::kUnknown;
PayloadDirection payload_direction_ = PayloadDirection::INCOMING_PAYLOAD;
absl::flat_hash_map<Medium, Throughput> throughputs_;
bool success_ = false;
int64_t file_io_time_ = 0;
int64_t encryption_time_ = 0;
int64_t socket_io_time_ = 0;
int64_t duration_millis_ = 0;
int throughput_kbps_ = 0;
};
class ThroughputRecorderContainer {
public:
ThroughputRecorderContainer(const ThroughputRecorderContainer&) = delete;
ThroughputRecorderContainer& operator=(const ThroughputRecorderContainer&) =
delete;
static ThroughputRecorderContainer& GetInstance();
void Shutdown() ABSL_LOCKS_EXCLUDED(mutex_);
ThroughputRecorder* GetTPRecorder(int64_t payload_id,
PayloadDirection payload_direction)
ABSL_LOCKS_EXCLUDED(mutex_);
void StopTPRecorder(int64_t payload_id, PayloadDirection payload_direction)
ABSL_LOCKS_EXCLUDED(mutex_);
int GetSize() ABSL_LOCKS_EXCLUDED(mutex_);
private:
// This is a singleton object, for which destructor will never be called.
// Constructor will be invoked once from Instance() static method.
// Object is create in-place (with a placement new) to guarantee that
// destructor is not scheduled for execution at exit.
ThroughputRecorderContainer() = default;
~ThroughputRecorderContainer() = default;
Mutex mutex_;
// std::pair<int64_t, PayloadDirection> for <payload id, payload direction>
absl::flat_hash_map<std::pair<int64_t, PayloadDirection>, ThroughputRecorder*>
throughput_recorders_ ABSL_GUARDED_BY(mutex_);
};
} // namespace analytics
} // namespace nearby
#endif // NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_
@@ -1,233 +0,0 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/analytics/throughput_recorder.h"
#include <stdint.h>
#include <ostream>
#include <string>
#include "gtest/gtest.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/logging.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace analytics {
namespace {
// TODO(b/246693797): Add unit tests coverage for throughput recorder code
constexpr int64_t kPayloadIdA = 123456789;
constexpr int64_t kPayloadIdB = 987654321;
constexpr int kFrameSize = 10 * 64 * 1024;
constexpr int64_t kTotalByteSize1GB = 1024 * 1024 * 1024;
constexpr int64_t kTotalMillis10Sec = 10 * 1000;
constexpr int kTPResultKBPerSec = 1024 * 1024 / 10;
constexpr int kTPKBPerSec = 100 * 1024;
constexpr int kTPResultMBPerSec = 100;
// class ThroughputRecorderTest : public testing::Test {
class ThroughputRecorderTest : public testing::TestWithParam<bool> {
protected:
ThroughputRecorderTest() = default;
~ThroughputRecorderTest() override {
ThroughputRecorderContainer::GetInstance().Shutdown();
}
ThroughputRecorderContainer& tp_recorder_container_ =
ThroughputRecorderContainer::GetInstance();
};
INSTANTIATE_TEST_SUITE_P(ParametrisedTestThroughputRecorderTest,
ThroughputRecorderTest, testing::Values(true, false));
TEST(ThroughputRecorder, CalculateThroughputKBps) {
EXPECT_EQ(ThroughputRecorder::CalculateThroughputKBps(kTotalByteSize1GB,
kTotalMillis10Sec),
kTPResultKBPerSec);
EXPECT_EQ(ThroughputRecorder::CalculateThroughputKBps(kTotalByteSize1GB, 0),
0);
}
TEST(ThroughputRecorder, CalculateThroughputMBps) {
EXPECT_EQ(ThroughputRecorder::CalculateThroughputMBps(kTPKBPerSec),
kTPResultMBPerSec);
}
TEST(ThroughputRecorderContainer, InstanceCreate_ContainerSize) {
ThroughputRecorderContainer& TPRecorderContainer =
ThroughputRecorderContainer::GetInstance();
TPRecorderContainer.GetTPRecorder(kPayloadIdA,
PayloadDirection::OUTGOING_PAYLOAD);
TPRecorderContainer.GetTPRecorder(kPayloadIdB,
PayloadDirection::INCOMING_PAYLOAD);
EXPECT_EQ(ThroughputRecorderContainer::GetInstance().GetSize(), 2);
ThroughputRecorderContainer::GetInstance().Shutdown();
EXPECT_EQ(ThroughputRecorderContainer::GetInstance().GetSize(), 0);
}
TEST_F(ThroughputRecorderTest, OnFrameSentSaveTransferredSize) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD);
TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD);
PacketMetaData packet_meta_data;
packet_meta_data.SetPacketSize(kFrameSize);
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
auto throughput =
TPRecorder->GetThroughput(location::nearby::proto::connections::BLE, 0);
EXPECT_EQ(throughput.GetTotalByteSize(), kFrameSize * 3);
}
TEST_F(ThroughputRecorderTest, OnIgnoreUnkownPaylaodType) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD);
TPRecorder->Start(PayloadType::kUnknown, PayloadDirection::OUTGOING_PAYLOAD);
PacketMetaData packet_meta_data;
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
EXPECT_EQ(TPRecorder->GetThroughputsSize(), 0);
TPRecorder->Start(PayloadType::kUnknown, PayloadDirection::INCOMING_PAYLOAD);
TPRecorder->OnFrameReceived(location::nearby::proto::connections::BLE,
packet_meta_data);
EXPECT_EQ(TPRecorder->GetThroughputsSize(), 0);
}
TEST_P(ThroughputRecorderTest, OnFrameSentStopAndDump) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD);
TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD);
PacketMetaData packet_meta_data;
packet_meta_data.SetPacketSize(kFrameSize);
packet_meta_data.StartFileIo();
absl::SleepFor(absl::Milliseconds(5));
packet_meta_data.StopFileIo();
packet_meta_data.StartEncryption();
absl::SleepFor(absl::Milliseconds(6));
packet_meta_data.StopEncryption();
packet_meta_data.StartSocketIo();
absl::SleepFor(absl::Milliseconds(7));
packet_meta_data.StopSocketIo();
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
EXPECT_EQ(TPRecorder->GetDurationMillis(),
packet_meta_data.GetEncryptionTimeInMillis() +
packet_meta_data.GetFileIoTimeInMillis() +
packet_meta_data.GetSocketIoTimeInMillis());
packet_meta_data.SetPacketSize(kFrameSize);
packet_meta_data.StartFileIo();
absl::SleepFor(absl::Milliseconds(15));
packet_meta_data.StopFileIo();
packet_meta_data.StartEncryption();
absl::SleepFor(absl::Milliseconds(16));
packet_meta_data.StopEncryption();
packet_meta_data.StartSocketIo();
absl::SleepFor(absl::Milliseconds(17));
packet_meta_data.StopSocketIo();
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data);
if (GetParam() == true) {
LOG(INFO) << "MarkAsSuccess";
TPRecorder->MarkAsSuccess();
}
EXPECT_TRUE(TPRecorder->Stop());
EXPECT_NE(TPRecorder->GetThroughputKbps(), 0);
}
TEST_F(ThroughputRecorderTest, OnFrameSentStopAndDumpForMultiMeadium) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD);
TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD);
PacketMetaData packet_meta_data1;
packet_meta_data1.SetPacketSize(kFrameSize);
packet_meta_data1.StartFileIo();
absl::SleepFor(absl::Milliseconds(5));
packet_meta_data1.StopFileIo();
packet_meta_data1.StartEncryption();
absl::SleepFor(absl::Milliseconds(6));
packet_meta_data1.StopEncryption();
packet_meta_data1.StartSocketIo();
absl::SleepFor(absl::Milliseconds(7));
packet_meta_data1.StopSocketIo();
TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE,
packet_meta_data1);
PacketMetaData packet_meta_data2;
packet_meta_data2.SetPacketSize(kFrameSize);
packet_meta_data2.StartFileIo();
absl::SleepFor(absl::Milliseconds(15));
packet_meta_data2.StopFileIo();
packet_meta_data2.StartEncryption();
absl::SleepFor(absl::Milliseconds(16));
packet_meta_data2.StopEncryption();
packet_meta_data2.StartSocketIo();
absl::SleepFor(absl::Milliseconds(17));
packet_meta_data2.StopSocketIo();
TPRecorder->OnFrameSent(location::nearby::proto::connections::WIFI_LAN,
packet_meta_data2);
TPRecorder->MarkAsSuccess();
EXPECT_TRUE(TPRecorder->Stop());
EXPECT_NE(TPRecorder->GetThroughputKbps(), 0);
}
TEST_F(ThroughputRecorderTest, OnFrameReceivedCheckDurationMillis) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::INCOMING_PAYLOAD);
TPRecorder->Start(PayloadType::kFile, PayloadDirection::INCOMING_PAYLOAD);
PacketMetaData packet_meta_data;
packet_meta_data.SetPacketSize(kFrameSize);
packet_meta_data.StartFileIo();
absl::SleepFor(absl::Milliseconds(5));
packet_meta_data.StopFileIo();
packet_meta_data.StartEncryption();
absl::SleepFor(absl::Milliseconds(6));
packet_meta_data.StopEncryption();
packet_meta_data.StartSocketIo();
absl::SleepFor(absl::Milliseconds(7));
packet_meta_data.StopSocketIo();
TPRecorder->OnFrameReceived(location::nearby::proto::connections::BLE,
packet_meta_data);
EXPECT_EQ(TPRecorder->GetDurationMillis(),
packet_meta_data.GetEncryptionTimeInMillis() +
packet_meta_data.GetFileIoTimeInMillis() +
packet_meta_data.GetSocketIoTimeInMillis());
}
TEST_F(ThroughputRecorderTest, OnTPRecorderNotStarted) {
auto TPRecorder = tp_recorder_container_.GetTPRecorder(
kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD);
auto throughput =
TPRecorder->GetThroughput(location::nearby::proto::connections::BLE, 0);
EXPECT_FALSE(throughput.dump());
}
} // namespace
} // namespace analytics
} // namespace nearby
@@ -20,7 +20,6 @@
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/service_id_constants.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/logging.h"
namespace nearby {
@@ -30,16 +29,16 @@ BaseBwuHandler::BaseBwuHandler(
IncomingConnectionCallback incoming_connection_callback)
: incoming_connection_callback_(std::move(incoming_connection_callback)) {}
ByteArray BaseBwuHandler::InitializeUpgradedMediumForEndpoint(
std::string BaseBwuHandler::InitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& service_id,
const std::string& endpoint_id) {
std::string upgrade_service_id = WrapInitiatorUpgradeServiceId(service_id);
// Perform any medium-specific handling in the child class.
ByteArray upgrade_path_available_frame =
std::string upgrade_path_available_frame =
HandleInitializeUpgradedMediumForEndpoint(client, upgrade_service_id,
endpoint_id);
if (!upgrade_path_available_frame.Empty()) {
if (!upgrade_path_available_frame.empty()) {
upgrade_service_id_to_active_endpoint_ids_[upgrade_service_id].insert(
endpoint_id);
}
@@ -22,7 +22,6 @@
#include "absl/container/flat_hash_set.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "internal/platform/byte_array.h"
namespace nearby {
namespace connections {
@@ -35,7 +34,7 @@ class BaseBwuHandler : public BwuHandler {
IncomingConnectionCallback incoming_connection_callback);
// BwuHandler implementation:
ByteArray InitializeUpgradedMediumForEndpoint(
std::string InitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& service_id,
const std::string& endpoint_id) final;
void RevertInitiatorState() final;
@@ -51,7 +50,7 @@ class BaseBwuHandler : public BwuHandler {
// respectively, to handle medium-specific logic.
// HandleRevertInitiatorStateForService is only invoked after the last
// endpoint for the service is reverted.
virtual ByteArray HandleInitializeUpgradedMediumForEndpoint(
virtual std::string HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) = 0;
virtual void HandleRevertInitiatorStateForService(
@@ -24,7 +24,6 @@
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/service_id_constants.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/expected.h"
namespace nearby {
@@ -55,8 +54,8 @@ class BwuHandlerImpl : public BaseBwuHandler {
const std::vector<InputData>& handle_revert_calls() const {
return handle_revert_calls_;
}
void set_handle_initialize_output(ByteArray bytes) {
handle_initialize_output_ = bytes;
void set_handle_initialize_output(absl::string_view bytes) {
handle_initialize_output_ = std::string(bytes);
}
private:
@@ -73,7 +72,7 @@ class BwuHandlerImpl : public BaseBwuHandler {
const std::string& endpoint_id) final {}
// BaseBwuHandler implementation:
ByteArray HandleInitializeUpgradedMediumForEndpoint(
std::string HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) final {
handle_initialize_calls_.push_back({.client = client,
@@ -86,7 +85,7 @@ class BwuHandlerImpl : public BaseBwuHandler {
handle_revert_calls_.push_back({.service_id = upgrade_service_id});
}
ByteArray handle_initialize_output_;
std::string handle_initialize_output_;
std::vector<InputData> handle_initialize_calls_;
std::vector<InputData> handle_revert_calls_;
};
@@ -95,7 +94,7 @@ TEST(BaseBwuHandlerTest, InitializeAndRevert) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{"not empty"};
absl::string_view expected_output{"not empty"};
handler.set_handle_initialize_output(expected_output);
// Initialize two upgrade endpoints for service A and one for service B.
@@ -150,7 +149,7 @@ TEST(BaseBwuHandlerTest, InitializeAndRevertAll) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{"not empty"};
absl::string_view expected_output{"not empty"};
handler.set_handle_initialize_output(expected_output);
handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A",
@@ -169,7 +168,7 @@ TEST(BaseBwuHandlerTest, Initialize_Failure_EmptyUpgradePathAvailableFrame) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{};
absl::string_view expected_output{};
handler.set_handle_initialize_output(expected_output);
handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A",
@@ -191,7 +190,7 @@ TEST(BaseBwuHandlerTest, Initialize_StillWorkWithUpgradeServiceIdSuffix) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{"not empty"};
absl::string_view expected_output{"not empty"};
handler.set_handle_initialize_output(expected_output);
// The method should be robust and not add _another_ upgrade suffix
@@ -208,7 +207,7 @@ TEST(BaseBwuHandlerTest, Revert_Failure_CantFindService) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{"not empty"};
absl::string_view expected_output{"not empty"};
handler.set_handle_initialize_output(expected_output);
handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A",
/*endpoint_id=*/"1");
@@ -222,7 +221,7 @@ TEST(BaseBwuHandlerTest, Revert_Failure_CantFindEndpoint) {
ClientProxy client;
BwuHandlerImpl handler;
ByteArray expected_output{"not empty"};
absl::string_view expected_output{"not empty"};
handler.set_handle_initialize_output(expected_output);
handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A",
/*endpoint_id=*/"1");
@@ -40,15 +40,13 @@
#include "internal/platform/mutex_lock.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::proto::connections::Medium::BLE;
using ::location::nearby::proto::connections::Medium::BLE_L2CAP;
using DisconnectionReason =
::location::nearby::proto::connections::DisconnectionReason;
using ::nearby::analytics::SafeDisconnectionResult;
using ::location::nearby::proto::connections::DisconnectionReason;
Exception WriteInt(OutputStream* writer, std::int32_t value) {
return Base64Utils::WriteInt(writer, value);
@@ -92,17 +90,10 @@ BaseEndpointChannel::BaseEndpointChannel(
try_count_(try_count) {}
ExceptionOr<ByteArray> BaseEndpointChannel::Read() {
PacketMetaData packet_meta_data;
return Read(packet_meta_data);
}
ExceptionOr<ByteArray> BaseEndpointChannel::Read(
PacketMetaData& packet_meta_data) {
ByteArray result;
{
MutexLock lock(&reader_mutex_);
packet_meta_data.StartSocketIo();
ExceptionOr<std::int32_t> read_int;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
@@ -133,8 +124,6 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read(
if (!read_bytes.ok()) {
return read_bytes;
}
packet_meta_data.StopSocketIo();
packet_meta_data.SetPacketSize(read_int.result() + sizeof(std::int32_t));
result = std::move(read_bytes.result());
}
@@ -144,7 +133,6 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read(
if (IsEncryptionEnabledLocked()) {
// If encryption is enabled, decode the message.
std::string input(std::move(result));
packet_meta_data.StartEncryption();
std::unique_ptr<std::string> decrypted_data =
crypto_context_->DecodeMessageFromPeer(input);
if (decrypted_data) {
@@ -157,7 +145,7 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read(
// and let it through if it is, otherwise message is erased.
// TODO(apolyudov): verify this happens at most once per session.
result = {};
auto parsed = parser::FromBytes(ByteArray(input));
auto parsed = parser::FromBytes(input);
if (parsed.ok()) {
if (parser::GetFrameType(parsed.result()) ==
location::nearby::connections::V1Frame::KEEP_ALIVE) {
@@ -175,7 +163,6 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read(
<< ": Unable to parse data as unencrypted message.";
}
}
packet_meta_data.StopEncryption();
if (result.Empty()) {
LOG(WARNING) << __func__ << ": Unable to parse read result.";
return ExceptionOr<ByteArray>(message_exception);
@@ -190,13 +177,7 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read(
return ExceptionOr<ByteArray>(result);
}
Exception BaseEndpointChannel::Write(const ByteArray& data) {
PacketMetaData packet_meta_data;
return Write(data.AsStringView(), packet_meta_data);
}
Exception BaseEndpointChannel::Write(absl::string_view data,
PacketMetaData& packet_meta_data) {
Exception BaseEndpointChannel::Write(absl::string_view data) {
{
MutexLock pause_lock(&is_paused_mutex_);
if (is_paused_) {
@@ -217,9 +198,7 @@ Exception BaseEndpointChannel::Write(absl::string_view data,
MutexLock crypto_lock(&crypto_mutex_);
if (IsEncryptionEnabledLocked()) {
// If encryption is enabled, encode the message.
packet_meta_data.StartEncryption();
encrypted = crypto_context_->EncodeMessageToPeer(data);
packet_meta_data.StopEncryption();
if (!encrypted) {
LOG(WARNING) << __func__ << ": Failed to encrypt data.";
return {Exception::kIo};
@@ -235,7 +214,6 @@ Exception BaseEndpointChannel::Write(absl::string_view data,
return {Exception::kIo};
}
packet_meta_data.StartSocketIo();
Exception write_exception;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
@@ -262,8 +240,6 @@ Exception BaseEndpointChannel::Write(absl::string_view data,
<< ": Failed to flush writer: " << flush_exception.value;
return flush_exception;
}
packet_meta_data.StopSocketIo();
packet_meta_data.SetPacketSize(data_size + sizeof(std::uint32_t));
}
{
@@ -326,7 +302,7 @@ void BaseEndpointChannel::SetAnalyticsRecorder(
void BaseEndpointChannel::Close(
location::nearby::proto::connections::DisconnectionReason reason) {
Close(reason, ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
Close(reason, SafeDisconnectionResult::kSafeDisconnection);
}
void BaseEndpointChannel::Close(
@@ -490,5 +466,4 @@ std::unique_ptr<std::string> BaseEndpointChannel::EncodeMessageForTests(
return crypto_context_->EncodeMessageToPeer(data);
}
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
@@ -23,7 +23,6 @@
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/implementation/endpoint_channel.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/condition_variable.h"
@@ -32,10 +31,7 @@
#include "internal/platform/mutex.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace connections {
using analytics::PacketMetaData;
namespace nearby::connections {
class BaseEndpointChannel : public EndpointChannel {
public:
@@ -51,20 +47,16 @@ class BaseEndpointChannel : public EndpointChannel {
~BaseEndpointChannel() override = default;
// EndpointChannel:
ExceptionOr<ByteArray> Read() override;
ExceptionOr<ByteArray> Read(PacketMetaData& packet_meta_data)
ExceptionOr<ByteArray> Read()
ABSL_LOCKS_EXCLUDED(reader_mutex_, crypto_mutex_,
last_read_mutex_) override;
Exception Write(const ByteArray& data) override;
Exception Write(absl::string_view data, PacketMetaData& packet_meta_data)
Exception Write(absl::string_view data)
ABSL_LOCKS_EXCLUDED(writer_mutex_, crypto_mutex_) override;
void Close() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override;
void Close(location::nearby::proto::connections::DisconnectionReason reason)
override;
void Close(
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result) override;
void Close(location::nearby::proto::connections::DisconnectionReason reason,
nearby::analytics::SafeDisconnectionResult result) override;
bool IsClosed() const ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override;
std::string GetType() const override;
std::string GetServiceId() const override;
@@ -176,7 +168,6 @@ class BaseEndpointChannel : public EndpointChannel {
std::string endpoint_id_ = "";
};
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
#endif // CORE_INTERNAL_BASE_ENDPOINT_CHANNEL_H_
@@ -108,20 +108,26 @@ std::function<void(const ByteArray&)> MakeDataMonitor(const std::string& label,
std::pair<std::shared_ptr<EncryptionContext>,
std::shared_ptr<EncryptionContext>>
DoDhKeyExchange(BaseEndpointChannel* channel_a,
BaseEndpointChannel* channel_b) {
DoDhKeyExchange(std::shared_ptr<TestEndpointChannel> channel_a,
std::shared_ptr<TestEndpointChannel> channel_b) {
std::shared_ptr<EncryptionContext> context_a;
std::shared_ptr<EncryptionContext> context_b;
EncryptionRunner crypto_a;
EncryptionRunner crypto_b;
ClientProxy proxy_a;
ClientProxy proxy_b;
CountDownLatch latch(2);
std::shared_ptr<EndpointChannel> shared_channel_a = channel_a;
std::shared_ptr<EndpointChannel> shared_channel_b = channel_b;
// Create a shared_ptr for the latch to prevent Use-After-Free if the
// negotiation times out and this function returns early.
auto latch = std::make_shared<CountDownLatch>(2);
crypto_a.StartClient(
&proxy_a, "endpoint_id", channel_a,
&proxy_a, "endpoint_id", shared_channel_a,
{
.on_success_cb =
[&latch, &context_a](
[latch, &context_a](
const std::string& endpoint_id,
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token,
@@ -131,20 +137,19 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
auto context = ukey2->ToConnectionContext();
EXPECT_NE(context, nullptr);
context_a = std::move(context);
latch.CountDown();
latch->CountDown();
},
.on_failure_cb =
[&latch](const std::string& endpoint_id,
EndpointChannel* channel) {
[latch](const std::string& endpoint_id) {
LOG(INFO) << "client-A side key negotiation failed";
latch.CountDown();
latch->CountDown();
},
});
crypto_b.StartServer(
&proxy_b, "endpoint_id", channel_b,
&proxy_b, "endpoint_id", shared_channel_b,
{
.on_success_cb =
[&latch, &context_b](
[latch, &context_b](
const std::string& endpoint_id,
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token,
@@ -154,16 +159,15 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
auto context = ukey2->ToConnectionContext();
EXPECT_NE(context, nullptr);
context_b = std::move(context);
latch.CountDown();
latch->CountDown();
},
.on_failure_cb =
[&latch](const std::string& endpoint_id,
EndpointChannel* channel) {
[latch](const std::string& endpoint_id) {
LOG(INFO) << "client-B side key negotiation failed";
latch.CountDown();
latch->CountDown();
},
});
EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result());
EXPECT_TRUE(latch->Await(absl::Milliseconds(5000)).result());
return std::make_pair(std::move(context_a), std::move(context_b));
}
@@ -174,7 +178,7 @@ class BaseEndpointChannelTest : public ::testing::Test {
NearbyFlags::GetInstance().ResetOverridedValues();
}
const ByteArray kTestData{"test_data"};
const absl::string_view kTestData = "test_data";
};
TEST_F(BaseEndpointChannelTest, ReadSucceedsWhenFlagDisabled) {
@@ -189,7 +193,7 @@ TEST_F(BaseEndpointChannelTest, ReadSucceedsWhenFlagDisabled) {
channel_a.Write(kTestData);
ByteArray rx_message = std::move(channel_b.Read().result());
EXPECT_EQ(rx_message, kTestData);
EXPECT_EQ(rx_message.AsStringView(), kTestData);
}
TEST_F(BaseEndpointChannelTest, ReadCallsDispatchPacketWhenFlagEnabled) {
@@ -203,13 +207,14 @@ TEST_F(BaseEndpointChannelTest, ReadCallsDispatchPacketWhenFlagEnabled) {
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
EXPECT_CALL(channel_b, DispatchPacket)
.WillOnce(::testing::Return(ExceptionOr<ByteArray>(kTestData)));
.WillOnce(::testing::Return(
ExceptionOr<ByteArray>(ByteArray(std::string(kTestData)))));
channel_a.Write(kTestData);
auto read_byte = channel_b.Read();
EXPECT_TRUE(read_byte.ok());
EXPECT_EQ(read_byte.result(), kTestData);
EXPECT_EQ(read_byte.result().AsStringView(), kTestData);
}
TEST_F(BaseEndpointChannelTest,
@@ -243,10 +248,10 @@ TEST_F(BaseEndpointChannelTest, ReadWrite) {
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
ByteArray tx_message{"data message"};
absl::string_view tx_message = "data message";
channel_a.Write(tx_message);
ByteArray rx_message = std::move(channel_b.Read().result());
EXPECT_EQ(rx_message, tx_message);
EXPECT_EQ(rx_message.AsStringView(), tx_message);
}
TEST_F(BaseEndpointChannelTest, ChannelUnencryptedByDefault) {
@@ -264,20 +269,22 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) {
absl::string_view kMessage = "message";
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
pipe_a.second.get());
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
pipe_b.second.get());
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context_a, nullptr);
ASSERT_NE(context_b, nullptr);
channel_a.EnableEncryption(context_a);
channel_b.EnableEncryption(context_b);
channel_a->EnableEncryption(context_a);
channel_b->EnableEncryption(context_b);
std::unique_ptr<std::string> encrypted_message =
channel_a.EncodeMessageForTests(kMessage);
channel_a->EncodeMessageForTests(kMessage);
ExceptionOr<ByteArray> decrypted_message =
channel_b.TryDecrypt(ByteArray(*encrypted_message));
channel_b->TryDecrypt(ByteArray(*encrypted_message));
EXPECT_TRUE(channel_b.IsEncrypted());
EXPECT_TRUE(channel_b->IsEncrypted());
EXPECT_TRUE(decrypted_message.ok());
EXPECT_EQ(decrypted_message.result().AsStringView(), kMessage);
}
@@ -285,16 +292,18 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) {
TEST_F(BaseEndpointChannelTest, TryDecryptFailsWhenDecryptionFails) {
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
pipe_a.second.get());
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
pipe_b.second.get());
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context_a, nullptr);
channel_a.EnableEncryption(context_a);
channel_a->EnableEncryption(context_a);
ExceptionOr<ByteArray> result =
channel_a.TryDecrypt(ByteArray("invalid message"));
channel_a->TryDecrypt(ByteArray("invalid message"));
EXPECT_TRUE(channel_a.IsEncrypted());
EXPECT_TRUE(channel_a->IsEncrypted());
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kExecution);
}
@@ -332,12 +341,12 @@ TEST_F(BaseEndpointChannelTest, NotEncryptedReadWriteCanBeIntercepted) {
EXPECT_EQ(channel_b.GetType(), "BLE");
// Start data transfer
ByteArray tx_message{"data message"};
absl::string_view tx_message = "data message";
channel_a.Write(tx_message);
ByteArray rx_message = std::move(channel_b.Read().result());
// Verify expectations.
EXPECT_EQ(rx_message, tx_message);
EXPECT_EQ(rx_message.AsStringView(), tx_message);
{
absl::MutexLock lock(mutex);
std::string message{tx_message};
@@ -365,13 +374,15 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
// to server "b".
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
// to server "a".
TestEndpointChannel channel_a(server_a.first.get(), client_a.second.get());
TestEndpointChannel channel_b(server_b.first.get(), client_b.second.get());
auto channel_a = std::make_shared<TestEndpointChannel>(server_a.first.get(),
client_a.second.get());
auto channel_b = std::make_shared<TestEndpointChannel>(server_b.first.get(),
client_b.second.get());
ON_CALL(channel_a, GetMedium).WillByDefault([]() {
ON_CALL(*channel_a, GetMedium).WillByDefault([]() {
return Medium::BLUETOOTH;
});
ON_CALL(channel_b, GetMedium).WillByDefault([]() {
ON_CALL(*channel_b, GetMedium).WillByDefault([]() {
return Medium::BLUETOOTH;
});
@@ -384,24 +395,24 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
MakeDataMonitor("monitor_b", &capture_b, &mutex)));
// Run DH key exchange; setup encryption contexts for channels.
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context_a, nullptr);
ASSERT_NE(context_b, nullptr);
channel_a.EnableEncryption(context_a);
channel_b.EnableEncryption(context_b);
channel_a->EnableEncryption(context_a);
channel_b->EnableEncryption(context_b);
EXPECT_EQ(channel_a.GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_TRUE(channel_a.IsEncrypted());
EXPECT_TRUE(channel_b.IsEncrypted());
EXPECT_EQ(channel_a->GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_TRUE(channel_a->IsEncrypted());
EXPECT_TRUE(channel_b->IsEncrypted());
// Start data transfer
ByteArray tx_message{"data message"};
channel_a.Write(tx_message);
ByteArray rx_message = std::move(channel_b.Read().result());
absl::string_view tx_message = "data message";
channel_a->Write(tx_message);
ByteArray rx_message = std::move(channel_b->Read().result());
// Verify expectations.
EXPECT_EQ(rx_message, tx_message);
EXPECT_EQ(rx_message.AsStringView(), tx_message);
{
absl::MutexLock lock(mutex);
std::string message{tx_message};
@@ -410,8 +421,8 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
}
// Shutdown test environment.
channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION);
channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION);
}
TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) {
@@ -432,8 +443,8 @@ TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) {
EXPECT_EQ(channel_b.GetType(), "WIFI_LAN");
// Start data transfer
ByteArray tx_message{"data message"};
ByteArray more_message{"more data"};
absl::string_view tx_message = "data message";
absl::string_view more_message = "more data";
channel_a.Write(tx_message);
ByteArray rx_message = std::move(channel_b.Read().result());
@@ -459,7 +470,7 @@ TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) {
// Resume; verify that data transfer comepleted.
channel_a.Resume();
EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result());
EXPECT_EQ(read_more, more_message);
EXPECT_EQ(read_more.AsStringView(), more_message);
// Shutdown test environment.
channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION);
@@ -485,43 +496,45 @@ TEST_F(BaseEndpointChannelTest, ReadUnencryptedFrameOnEncryptedChannel) {
// Setup test communication environment.
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
pipe_a.second.get());
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
pipe_b.second.get());
ON_CALL(channel_a, GetMedium).WillByDefault([]() {
ON_CALL(*channel_a, GetMedium).WillByDefault([]() {
return Medium::BLUETOOTH;
});
ON_CALL(channel_b, GetMedium).WillByDefault([]() {
ON_CALL(*channel_b, GetMedium).WillByDefault([]() {
return Medium::BLUETOOTH;
});
// Run DH key exchange; setup encryption contexts for channels. But only
// encrypt |channel_b|.
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context_a, nullptr);
ASSERT_NE(context_b, nullptr);
channel_b.EnableEncryption(context_b);
channel_b->EnableEncryption(context_b);
EXPECT_EQ(channel_a.GetType(), "BLUETOOTH");
EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_EQ(channel_a->GetType(), "BLUETOOTH");
EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH");
// An unencrypted KeepAlive should succeed.
ByteArray keep_alive_message = parser::ForKeepAlive();
channel_a.Write(keep_alive_message);
ExceptionOr<ByteArray> result = channel_b.Read();
std::string keep_alive_message = parser::ForKeepAlive();
channel_a->Write(keep_alive_message);
ExceptionOr<ByteArray> result = channel_b->Read();
EXPECT_TRUE(result.ok());
EXPECT_EQ(result.result(), keep_alive_message);
EXPECT_EQ(result.result().AsStringView(), keep_alive_message);
// An unencrypted data frame should fail.
ByteArray tx_message{"data message"};
channel_a.Write(tx_message);
result = channel_b.Read();
absl::string_view tx_message = "data message";
channel_a->Write(tx_message);
result = channel_b->Read();
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.exception(), Exception::kInvalidProtocolBuffer);
// Shutdown test environment.
channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION);
channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION);
}
} // namespace
+220 -163
View File
@@ -36,7 +36,9 @@
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/connection_attempt_metadata_params.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
#include "connections/implementation/bwu_manager.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/connections_authentication_transport.h"
@@ -51,7 +53,6 @@
#include "connections/implementation/mediums/webrtc_peer_id.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "connections/implementation/webrtc_state.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
@@ -84,11 +85,24 @@
#include "internal/platform/runnable.h"
#include "internal/platform/wifi.h"
#include "internal/platform/wifi_lan_connection_info.h"
#include "proto/connections_enums.pb.h"
namespace nearby::connections {
namespace {
using ::location::nearby::connections::ConnectionRequestFrame;
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;
using ::location::nearby::proto::connections::WifiDirectAuthType;
using ::nearby::analytics::AnalyticsRecorder;
using ::nearby::analytics::OperationResultWithMedium;
using ::securegcm::UKey2Handshake;
constexpr int kEndpointCancelAlarmTimeout = 10;
std::string AuthenticationStatusToString(nearby::AuthenticationStatus status) {
@@ -101,20 +115,8 @@ std::string AuthenticationStatusToString(nearby::AuthenticationStatus status) {
return "failure";
}
}
} // namespace
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::ConnectionRequestFrame;
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;
using ::location::nearby::proto::connections::WifiDirectAuthType;
using ::securegcm::UKey2Handshake;
} // namespace
BasePcpHandler::BasePcpHandler(Mediums* mediums,
EndpointManager* endpoint_manager,
@@ -212,8 +214,7 @@ std::vector<ConnectionInfoVariant> BasePcpHandler::GetConnectionInfoFromResult(
}
WifiLanConnectionInfo info(
std::string(ip_address.begin(), ip_address.end()),
absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "",
{});
absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "", {});
connection_infos.push_back(info);
}
}
@@ -279,11 +280,10 @@ Status BasePcpHandler::StartAdvertising(
// Save the advertising options for local reference in later process
// like upgrading bandwidth.
advertising_listener_ = info.listener;
client->StartedAdvertising(
service_id, GetStrategy(), info.listener,
absl::MakeSpan(result.mediums),
std::move(result.operation_result_with_mediums),
compatible_advertising_options);
client->StartedAdvertising(service_id, GetStrategy(), info.listener,
absl::MakeSpan(result.mediums),
result.operation_result_with_mediums,
compatible_advertising_options);
client->UpdateLocalEndpointInfo(info.endpoint_info.string_data());
response.Set({Status::kSuccess});
});
@@ -424,25 +424,25 @@ BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums(
pending_connection_info.connection_options.connection_info
.supported_wifi_direct_auth_types;
LOG(INFO) << "Remote supported WifiDirect auth types: "
<< absl::StrJoin(
remote_supported_wifi_direct_auth_types, ", ",
[](std::string* out, int auth_type) {
absl::StrAppend(
out,
WifiDirectAuthType_Name(
static_cast<WifiDirectAuthType>(auth_type)));
});
<< absl::StrJoin(
remote_supported_wifi_direct_auth_types, ", ",
[](std::string* out, int auth_type) {
absl::StrAppend(
out,
WifiDirectAuthType_Name(
static_cast<WifiDirectAuthType>(auth_type)));
});
auto local_supported_wifi_direct_auth_types =
mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes();
LOG(INFO) << "Local supported WifiDirect auth types: "
<< absl::StrJoin(
local_supported_wifi_direct_auth_types, ", ",
[](std::string* out, int auth_type) {
absl::StrAppend(
out,
WifiDirectAuthType_Name(
static_cast<WifiDirectAuthType>(auth_type)));
});
<< absl::StrJoin(
local_supported_wifi_direct_auth_types, ", ",
[](std::string* out, int auth_type) {
absl::StrAppend(
out,
WifiDirectAuthType_Name(
static_cast<WifiDirectAuthType>(auth_type)));
});
bool found_common_auth_type = false;
for (const auto& auth_type : local_supported_wifi_direct_auth_types) {
if (auth_type == WifiDirectAuthType::WIFI_DIRECT_TYPE_UNKNOWN) {
@@ -510,11 +510,11 @@ Status BasePcpHandler::StartDiscovery(ClientProxy* client,
MutexLock lock(&discovered_endpoint_mutex_);
discovered_endpoints_.clear();
}
client->StartedDiscovery(
service_id, GetStrategy(), std::move(listener),
absl::MakeSpan(result.mediums),
std::move(result.operation_result_with_mediums),
stripped_discovery_options);
client->StartedDiscovery(service_id, GetStrategy(),
std::move(listener),
absl::MakeSpan(result.mediums),
result.operation_result_with_mediums,
stripped_discovery_options);
response.Set({Status::kSuccess});
});
return WaitForResult(absl::StrCat("StartDiscovery(", service_id, ")"),
@@ -587,34 +587,50 @@ void BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
serial_executor_.Execute(name, std::move(runnable));
}
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() {
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener(
std::shared_ptr<EndpointChannel> endpoint_channel) {
std::weak_ptr<EndpointChannel> weak_channel = endpoint_channel;
return {
.on_success_cb =
[this](const std::string& endpoint_id,
std::unique_ptr<UKey2Handshake> ukey2,
const std::string& auth_token,
const ByteArray& raw_auth_token) {
[this, weak_channel](const std::string& endpoint_id,
std::unique_ptr<UKey2Handshake> ukey2,
const std::string& auth_token,
const ByteArray& raw_auth_token) {
auto channel = weak_channel.lock();
if (!channel) return;
RunOnPcpHandlerThread(
"encryption-success",
[this, endpoint_id, raw_ukey2 = ukey2.release(), auth_token,
raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable {
OnEncryptionSuccessRunnable(
endpoint_id, std::unique_ptr<UKey2Handshake>(raw_ukey2),
auth_token, raw_auth_token);
});
[this, endpoint_id, weak_channel, raw_ukey2 = ukey2.release(),
auth_token, raw_auth_token]()
RUN_ON_PCP_HANDLER_THREAD() mutable {
std::unique_ptr<UKey2Handshake> ukey2(raw_ukey2);
auto channel = weak_channel.lock();
if (!channel) return;
OnEncryptionSuccessRunnable(endpoint_id, std::move(ukey2),
auth_token, raw_auth_token,
channel);
});
},
.on_failure_cb =
[this](const std::string& endpoint_id, EndpointChannel* channel) {
[this, weak_channel](const std::string& endpoint_id) {
auto channel = weak_channel.lock();
if (!channel) return;
RunOnPcpHandlerThread(
"encryption-failure",
[this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() {
LOG(ERROR)
<< "Encryption failed for endpoint_id=" << endpoint_id
<< " on medium="
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium());
OnEncryptionFailureRunnable(endpoint_id, channel);
});
[this, endpoint_id, weak_channel]()
RUN_ON_PCP_HANDLER_THREAD() {
auto channel = weak_channel.lock();
if (!channel) return;
LOG(ERROR)
<< "Encryption failed for endpoint_id=" << endpoint_id
<< " on medium="
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium());
OnEncryptionFailureRunnable(endpoint_id, channel);
});
},
};
}
@@ -622,36 +638,49 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() {
EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3(
const NearbyDeviceProvider& device_provider,
const NearbyDevice& remote_device,
const EndpointChannel& endpoint_channel) {
std::shared_ptr<EndpointChannel> endpoint_channel) {
std::weak_ptr<EndpointChannel> weak_channel = endpoint_channel;
return {
.on_success_cb =
[this, &device_provider, &remote_device, &endpoint_channel](
[this, &device_provider, &remote_device, weak_channel](
const std::string& endpoint_id,
std::unique_ptr<UKey2Handshake> ukey2,
const std::string& auth_token, const ByteArray& raw_auth_token) {
auto channel = weak_channel.lock();
if (!channel) return;
RunOnPcpHandlerThread(
"encryption-success",
[this, &device_provider, &remote_device, &endpoint_channel,
raw_ukey2 = ukey2.release(), auth_token,
raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable {
OnEncryptionSuccessRunnableV3(
remote_device, std::unique_ptr<UKey2Handshake>(raw_ukey2),
auth_token, raw_auth_token, endpoint_channel,
device_provider);
});
[this, &device_provider, &remote_device, weak_channel,
raw_ukey2 = ukey2.release(), auth_token, raw_auth_token]()
RUN_ON_PCP_HANDLER_THREAD() mutable {
std::unique_ptr<UKey2Handshake> ukey2(raw_ukey2);
auto channel = weak_channel.lock();
if (!channel) return;
OnEncryptionSuccessRunnableV3(
remote_device, std::move(ukey2), auth_token,
raw_auth_token, channel, device_provider);
});
},
.on_failure_cb =
[this](const std::string& endpoint_id, EndpointChannel* channel) {
[this, weak_channel](const std::string& endpoint_id) {
auto channel = weak_channel.lock();
if (!channel) return;
RunOnPcpHandlerThread(
"encryption-failure",
[this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() {
LOG(ERROR)
<< "Encryption failed for endpoint_id=" << endpoint_id
<< " on medium="
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium());
OnEncryptionFailureRunnable(endpoint_id, channel);
});
[this, endpoint_id, weak_channel]()
RUN_ON_PCP_HANDLER_THREAD() {
auto channel = weak_channel.lock();
if (!channel) return;
LOG(ERROR)
<< "Encryption failed for endpoint_id=" << endpoint_id
<< " on medium="
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium());
OnEncryptionFailureRunnable(endpoint_id, channel);
});
},
};
}
@@ -659,7 +688,7 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3(
void BasePcpHandler::OnEncryptionSuccessRunnableV3(
const NearbyDevice& remote_device, std::unique_ptr<UKey2Handshake> ukey2,
absl::string_view auth_token, const ByteArray& raw_auth_token,
const EndpointChannel& endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
const NearbyDeviceProvider& device_provider) {
// Quick fail if we've been removed from pending connections while we were
// busy running UKEY2.
@@ -674,7 +703,11 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3(
}
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
// Verify pointer equality to avoid accidental action on superseded
// channels.
if (endpoint_channel != pending_connection_info.channel) {
return;
}
// TODO(b/300149127): Add test coverage.
if (!ukey2) {
// Fail early, if there is no crypto context.
@@ -697,8 +730,15 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3(
//
// TODO(b/305004353): Authenticate the connection in the responder role for
// outgoing connections.
if (!pending_connection_info.is_incoming) {
if (pending_connection_info.is_incoming) {
LOG(ERROR) << __func__ << ": only outgoing connections are supported";
ProcessPreConnectionInitiationFailure(
pending_connection_info.client, pending_connection_info.medium,
remote_device.GetEndpointId(), pending_connection_info.channel.get(),
pending_connection_info.is_incoming, /*log_failure=*/true,
pending_connection_info.start_time, {Status::kConnectionRejected},
OperationResultCode::DETAIL_UNKNOWN,
pending_connection_info.result.lock().get());
return;
}
@@ -724,7 +764,8 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3(
void BasePcpHandler::OnEncryptionSuccessRunnable(
const std::string& endpoint_id, std::unique_ptr<UKey2Handshake> ukey2,
const std::string& auth_token, const ByteArray& raw_auth_token) {
const std::string& auth_token, const ByteArray& raw_auth_token,
std::shared_ptr<EndpointChannel> endpoint_channel) {
// Quick fail if we've been removed from pending connections while we were
// busy running UKEY2.
// TODO(b/316421187): Add test coverage
@@ -738,6 +779,12 @@ void BasePcpHandler::OnEncryptionSuccessRunnable(
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
// Verify pointer equality to avoid accidental action on superseded
// channels.
if (endpoint_channel != pending_connection_info.channel) {
return;
}
if (!ukey2) {
// Fail early, if there is no crypto context.
ProcessPreConnectionInitiationFailure(
@@ -801,24 +848,21 @@ void BasePcpHandler::RegisterDeviceAfterEncryptionSuccess(
}
void BasePcpHandler::OnEncryptionFailureRunnable(
const std::string& endpoint_id, EndpointChannel* endpoint_channel) {
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel) {
auto it = pending_connections_.find(endpoint_id);
if (it == pending_connections_.end()) {
LOG(INFO)
<< "Connection not found on UKEY negotination complete; endpoint_id="
<< "Connection not found on UKEY negotiation complete; endpoint_id="
<< endpoint_id;
return;
}
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
// We had a bug here, caused by a race with EncryptionRunner. We now verify
// the EndpointChannel to avoid it. In a simultaneous connection, we clean
// up one of the two EndpointChannels and then update our pendingConnections
// with the winning channel's state. Closing a channel that was in the
// middle of EncryptionRunner would trigger onEncryptionFailed, and, since
// the map had already updated with the winning EndpointChannel, we closed
// it too by accident.
if (*endpoint_channel != *pending_connection_info.channel) {
// Verify pointer equality to avoid accidental action on superseded
// channels.
if (endpoint_channel != pending_connection_info.channel) {
LOG(INFO) << "Not destroying channel [mismatch]: passed="
<< endpoint_channel->GetName()
<< "; expected=" << pending_connection_info.channel->GetName();
@@ -871,8 +915,8 @@ ConnectionInfo BasePcpHandler::FillConnectionInfo(
connection_info.supported_wifi_direct_auth_types =
mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes();
VLOG(1) << "Set SupportedWifiDirectAuthTypes for WIFI_DIRECT: "
<< absl::StrJoin(connection_info.supported_wifi_direct_auth_types,
",");
<< absl::StrJoin(connection_info.supported_wifi_direct_auth_types,
",");
} else {
connection_info.supported_wifi_direct_auth_types = {};
}
@@ -975,8 +1019,8 @@ Status BasePcpHandler::RequestConnection(
client, channel_medium, endpoint_id, channel.get(),
/*is_incoming=*/false, /*log_failure=*/true, start_time,
{Status::kEndpointIoError},
client->GetAnalyticsRecorder()
.GetChannelIoErrorResultCodeFromMedium(channel_medium),
AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium(
channel_medium),
result.get());
return;
}
@@ -1005,17 +1049,32 @@ Status BasePcpHandler::RequestConnection(
pending_connection_info.medium = channel->GetMedium();
pending_connection_info.channel = std::move(channel);
EndpointChannel* endpoint_channel =
pending_connections_
.emplace(endpoint_id, std::move(pending_connection_info))
.first->second.channel.get();
std::shared_ptr<EndpointChannel> channel_to_close_on_failure =
pending_connection_info.channel;
auto [it, inserted] = pending_connections_.emplace(
endpoint_id, std::move(pending_connection_info));
if (!inserted) {
LOG(ERROR) << "Failed to add outgoing connection to pending set; "
"endpoint_id="
<< endpoint_id
<< ". Likely a collision with an existing pending "
"connection.";
if (channel_to_close_on_failure) {
channel_to_close_on_failure->Close(
location::nearby::proto::connections::DisconnectionReason::
IO_ERROR);
}
result->Set({Status::kEndpointIoError});
return;
}
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
LOG(INFO) << "Initiating secure connection: endpoint_id="
<< endpoint_id;
// Next, we'll set up encryption. When it's done, our future will return
// and RequestConnection() will finish.
encryption_runner_.StartClient(client, endpoint_id, endpoint_channel,
GetResultListener());
GetResultListener(endpoint_channel));
});
LOG(INFO) << "Waiting for connection to complete: endpoint_id="
<< endpoint_id;
@@ -1122,8 +1181,8 @@ Status BasePcpHandler::RequestConnectionV3(
client, channel_medium, endpoint_id, channel.get(),
/*is_incoming=*/false, /*log_failure=*/true, start_time,
{Status::kEndpointIoError},
client->GetAnalyticsRecorder()
.GetChannelIoErrorResultCodeFromMedium(channel_medium),
AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium(
channel_medium),
result.get());
return;
}
@@ -1144,7 +1203,7 @@ Status BasePcpHandler::RequestConnectionV3(
pending_connection_info.client = client;
pending_connection_info.remote_endpoint_info = endpoint->endpoint_info;
pending_connection_info.nonce = connection_info.nonce;
pending_connection_info.is_incoming = true;
pending_connection_info.is_incoming = false;
pending_connection_info.start_time = start_time;
pending_connection_info.listener = info.listener;
pending_connection_info.connection_options = connection_options;
@@ -1152,10 +1211,25 @@ Status BasePcpHandler::RequestConnectionV3(
pending_connection_info.medium = channel->GetMedium();
pending_connection_info.channel = std::move(channel);
EndpointChannel* endpoint_channel =
pending_connections_
.emplace(endpoint_id, std::move(pending_connection_info))
.first->second.channel.get();
std::shared_ptr<EndpointChannel> channel_to_close_on_failure =
pending_connection_info.channel;
auto [it, inserted] = pending_connections_.emplace(
endpoint_id, std::move(pending_connection_info));
if (!inserted) {
LOG(ERROR) << "Failed to add outgoing connection to pending set; "
"endpoint_id="
<< endpoint_id
<< ". Likely a collision with an existing pending "
"connection.";
if (channel_to_close_on_failure) {
channel_to_close_on_failure->Close(
location::nearby::proto::connections::DisconnectionReason::
IO_ERROR);
}
result->Set({Status::kEndpointIoError});
return;
}
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
LOG(INFO) << "Initiating secure connection: endpoint_id="
<< endpoint_id;
@@ -1165,7 +1239,7 @@ Status BasePcpHandler::RequestConnectionV3(
encryption_runner_.StartClient(
client, endpoint_id, endpoint_channel,
GetResultListenerV3(*(client->GetLocalDeviceProvider()),
remote_device, *endpoint_channel));
remote_device, endpoint_channel));
});
LOG(INFO) << "Waiting for connection to complete: endpoint_id="
<< endpoint_id;
@@ -1231,22 +1305,21 @@ void BasePcpHandler::StripOutUnavailableMediums(
}
}
std::unique_ptr<ConnectionsLog::OperationResultWithMedium>
OperationResultWithMedium
BasePcpHandler::GetOperationResultWithMediumByResultCode(
ClientProxy* client, location::nearby::proto::connections::Medium medium,
int update_index,
location::nearby::proto::connections::OperationResultCode
operation_result_code,
location::nearby::proto::connections::ConnectionMode connection_mode) {
auto operation_result_with_medium =
std::make_unique<ConnectionsLog::OperationResultWithMedium>();
operation_result_with_medium->set_medium(medium);
operation_result_with_medium->set_result_code(operation_result_code);
operation_result_with_medium->set_result_category(
OperationResultWithMedium operation_result_with_medium;
operation_result_with_medium.set_medium(medium);
operation_result_with_medium.set_result_code(operation_result_code);
operation_result_with_medium.set_result_category(
client->GetAnalyticsRecorder().GetOperationResultCategory(
operation_result_code));
operation_result_with_medium->set_connection_mode(connection_mode);
operation_result_with_medium->set_update_index(update_index);
operation_result_with_medium.set_connection_mode(connection_mode);
operation_result_with_medium.set_update_index(update_index);
return operation_result_with_medium;
}
@@ -1512,8 +1585,7 @@ Status BasePcpHandler::AcceptConnection(ClientProxy* client,
Exception write_exception =
channel->Write(parser::ForConnectionResponse(
Status::kSuccess, client->GetLocalOsInfo(),
client->GetLocalMultiplexSocketBitmask()));
Status::kSuccess, client->GetLocalOsInfo()));
if (!write_exception.Ok()) {
LOG(INFO) << "AcceptConnection: failed to send response: endpoint_id="
<< endpoint_id;
@@ -1574,8 +1646,7 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client,
Exception write_exception =
channel->Write(parser::ForConnectionResponse(
Status::kConnectionRejected, client->GetLocalOsInfo(),
client->GetLocalMultiplexSocketBitmask()));
Status::kConnectionRejected, client->GetLocalOsInfo()));
if (!write_exception.Ok()) {
LOG(INFO) << "RejectConnection: failed to send response: endpoint_id="
<< endpoint_id;
@@ -1600,8 +1671,7 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client,
void BasePcpHandler::OnIncomingFrame(
OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client,
location::nearby::proto::connections::Medium medium,
PacketMetaData& packet_meta_data) {
location::nearby::proto::connections::Medium medium) {
CountDownLatch latch(1);
RunOnPcpHandlerThread(
"incoming-frame",
@@ -1967,8 +2037,7 @@ Exception BasePcpHandler::OnIncomingConnection(
/*is_incoming=*/true,
/*log_failure=*/wrapped_frame.exception() != Exception::kNoData,
start_time, {Status::kError},
client->GetAnalyticsRecorder().GetChannelIoErrorResultCodeFromMedium(
medium),
AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium(medium),
nullptr);
}
return wrapped_frame.GetException();
@@ -2133,14 +2202,23 @@ Exception BasePcpHandler::OnIncomingConnection(
pending_connection_info.medium = channel->GetMedium();
pending_connection_info.channel = std::move(channel);
auto* owned_channel = pending_connections_
.emplace(connection_request.endpoint_id(),
std::move(pending_connection_info))
.first->second.channel.get();
auto [it, inserted] = pending_connections_.emplace(
connection_request.endpoint_id(), std::move(pending_connection_info));
// This should not happen since BreakTie() above should have checked that
// the endpoint_id is not already in pending_connections_.
if (!inserted) {
LOG(ERROR) << "Failed to add incoming connection to pending set; "
"endpoint_id="
<< connection_request.endpoint_id()
<< ". Likely a collision with an existing pending connection.";
return {Exception::kIo};
}
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
// Next, we'll set up encryption.
encryption_runner_.StartServer(client, connection_request.endpoint_id(),
owned_channel, GetResultListener());
endpoint_channel,
GetResultListener(endpoint_channel));
return {Exception::kSuccess};
}
@@ -2383,26 +2461,6 @@ void BasePcpHandler::EvaluateConnectionResult(ClientProxy* client,
std::move(context))) {
response_code = {Status::kEndpointUnknown};
}
std::shared_ptr<EndpointChannel> channel =
channel_manager_->GetChannelForEndpoint(endpoint_id);
if (channel != nullptr) {
if (client->IsMultiplexSocketSupported(endpoint_id,
channel->GetMedium())) {
if (!channel->EnableMultiplexSocket()) {
LOG(INFO) << "MultiplexSocket is not implemented for Medium: "
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium());
} else {
LOG(INFO) << "MultiplexSocket is supported for Medium: "
<< location::nearby::proto::connections::Medium_Name(
channel->GetMedium())
<< " on both sides.";
}
}
} else {
LOG(INFO) << "channel is null";
}
} else {
LOG(INFO) << "Pending connection rejected; endpoint_id=" << endpoint_id;
response_code = {Status::kConnectionRejected};
@@ -2477,8 +2535,8 @@ ExceptionOr<OfflineFrame> BasePcpHandler::ReadConnectionRequestFrame(
return ExceptionOr<OfflineFrame>(wrapped_bytes.exception());
}
ByteArray bytes = std::move(wrapped_bytes.result());
ExceptionOr<OfflineFrame> wrapped_frame = parser::FromBytes(bytes);
ExceptionOr<OfflineFrame> wrapped_frame =
parser::FromBytes(wrapped_bytes.result().AsStringView());
if (wrapped_frame.GetException().Raised(Exception::kInvalidProtocolBuffer)) {
return ExceptionOr<OfflineFrame>(Exception::kIo);
}
@@ -2510,7 +2568,7 @@ void BasePcpHandler::LogConnectionAttemptFailure(
connections_attempt_metadata_params;
if (endpoint_channel != nullptr) {
connections_attempt_metadata_params =
client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams(
AnalyticsRecorder::BuildConnectionAttemptMetadataParams(
endpoint_channel->GetTechnology(), endpoint_channel->GetBand(),
endpoint_channel->GetFrequency(), endpoint_channel->GetTryCount());
connections_attempt_metadata_params->operation_result_code =
@@ -2536,12 +2594,11 @@ void BasePcpHandler::LogConnectionAttemptSuccess(
connections_attempt_metadata_params;
if (pending_connection_info.channel != nullptr) {
connections_attempt_metadata_params =
pending_connection_info.client->GetAnalyticsRecorder()
.BuildConnectionAttemptMetadataParams(
pending_connection_info.channel->GetTechnology(),
pending_connection_info.channel->GetBand(),
pending_connection_info.channel->GetFrequency(),
pending_connection_info.channel->GetTryCount());
AnalyticsRecorder::BuildConnectionAttemptMetadataParams(
pending_connection_info.channel->GetTechnology(),
pending_connection_info.channel->GetBand(),
pending_connection_info.channel->GetFrequency(),
pending_connection_info.channel->GetTryCount());
connections_attempt_metadata_params->operation_result_code =
OperationResultCode::DETAIL_SUCCESS;
} else {
+21 -20
View File
@@ -31,7 +31,7 @@
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
#include "connections/implementation/bwu_manager.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/encryption_runner.h"
@@ -158,10 +158,10 @@ class BasePcpHandler : public PcpHandler,
const std::string& endpoint_id) override;
// @EndpointManagerReaderThread
void OnIncomingFrame(location::nearby::connections::OfflineFrame& frame,
const std::string& endpoint_id, ClientProxy* client,
location::nearby::proto::connections::Medium medium,
analytics::PacketMetaData& packet_meta_data) override;
void OnIncomingFrame(
location::nearby::connections::OfflineFrame& frame,
const std::string& endpoint_id, ClientProxy* client,
location::nearby::proto::connections::Medium medium) override;
// Called when an endpoint disconnects while we're waiting for both sides to
// approve/reject the connection.
@@ -190,8 +190,7 @@ class BasePcpHandler : public PcpHandler,
// If success, the mediums on which we are now advertising/discovering, for
// analytics.
std::vector<location::nearby::proto::connections::Medium> mediums;
std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>
std::vector<nearby::analytics::OperationResultWithMedium>
operation_result_with_mediums;
};
@@ -413,8 +412,7 @@ class BasePcpHandler : public PcpHandler,
void StripOutWifiHotspotMedium(ConnectionInfo& connection_info);
std::unique_ptr<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>
nearby::analytics::OperationResultWithMedium
GetOperationResultWithMediumByResultCode(
ClientProxy* client, location::nearby::proto::connections::Medium medium,
int update_index,
@@ -476,11 +474,11 @@ class BasePcpHandler : public PcpHandler,
// Only (possibly) vector for incoming connections.
std::vector<location::nearby::proto::connections::Medium> supported_mediums;
// Keep track of a channel before we pass it to EndpointChannelManager. This
// is owned until the call to OnEncryptionSuccessRunnableV3 or
// OnEncryptionSuccessRunnable when ownership is transferred to the
// EndpointManager.
std::unique_ptr<EndpointChannel> channel;
// Keep track of a channel before it is registered with the
// EndpointManager. This reference is held during the handshake phase and
// passed to the EndpointManager upon successful encryption
// (OnEncryptionSuccessRunnableV3 or OnEncryptionSuccessRunnable).
std::shared_ptr<EndpointChannel> channel;
// Crypto context; initially empty; established first thing after channel
// creation by running UKey2 session. While it is in progress, we keep track
@@ -509,24 +507,27 @@ class BasePcpHandler : public PcpHandler,
void OnEncryptionFailureImpl(const std::string& endpoint_id,
EndpointChannel* channel);
EncryptionRunner::ResultListener GetResultListener();
EncryptionRunner::ResultListener GetResultListener(
std::shared_ptr<EndpointChannel> endpoint_channel);
EncryptionRunner::ResultListener GetResultListenerV3(
const NearbyDeviceProvider& device_provider,
const NearbyDevice& remote_device,
const EndpointChannel& endpoint_channel);
std::shared_ptr<EndpointChannel> endpoint_channel);
void OnEncryptionSuccessRunnable(
const std::string& endpoint_id,
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token, const ByteArray& raw_auth_token);
const std::string& auth_token, const ByteArray& raw_auth_token,
std::shared_ptr<EndpointChannel> endpoint_channel);
void OnEncryptionSuccessRunnableV3(
const NearbyDevice& remote_device,
std::unique_ptr<::securegcm::UKey2Handshake> ukey2,
absl::string_view auth_token, const ByteArray& raw_auth_token,
const EndpointChannel& endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
const NearbyDeviceProvider& device_provider);
void OnEncryptionFailureRunnable(const std::string& endpoint_id,
EndpointChannel* endpoint_channel);
void OnEncryptionFailureRunnable(
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel);
void RegisterDeviceAfterEncryptionSuccess(
std::string_view endpoint_id,
std::unique_ptr<::securegcm::UKey2Handshake> ukey2,
@@ -32,7 +32,8 @@
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/mock_analytics_recorder.h"
#include "connections/implementation/base_endpoint_channel.h"
#include "connections/implementation/bwu_manager.h"
#include "connections/implementation/client_proxy.h"
@@ -55,8 +56,6 @@
#include "connections/status.h"
#include "connections/strategy.h"
#include "connections/v3/connection_listening_options.h"
#include "internal/analytics/mock_event_logger.h"
#include "internal/analytics/sharing_log_matchers.h"
#include "internal/flags/nearby_flags.h"
#include "internal/interop/authentication_status.h"
#include "internal/interop/authentication_transport.h"
@@ -72,29 +71,21 @@
#include "internal/platform/medium_environment.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/pipe.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
#include "proto/connections_enums.proto.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::proto::connections::EventType;
using ::location::nearby::proto::connections::Medium;
using ::nearby::analytics::HasEventType;
using ::testing::_;
using ::testing::AtLeast;
using ::protobuf_matchers::EqualsProto;
using ::testing::Invoke;
using ::testing::Matcher;
using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::proto::Partially;
constexpr absl::string_view kTestEndpointId = "REMOTETEST";
@@ -171,7 +162,7 @@ class MockEndpointChannel : public BaseEndpointChannel {
output_stream_(std::move(writer)) {}
ExceptionOr<ByteArray> DoRead() { return BaseEndpointChannel::Read(); }
Exception DoWrite(const ByteArray& data) {
Exception DoWrite(absl::string_view data) {
if (broken_write_) {
return {Exception::kFailed};
}
@@ -182,7 +173,7 @@ class MockEndpointChannel : public BaseEndpointChannel {
}
MOCK_METHOD(ExceptionOr<ByteArray>, Read, (), (override));
MOCK_METHOD(Exception, Write, (const ByteArray& data), (override));
MOCK_METHOD(Exception, Write, (absl::string_view data), (override));
MOCK_METHOD(void, CloseImpl, (), (override));
MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (),
(const, override));
@@ -454,15 +445,20 @@ class BasePcpHandlerTest
};
BasePcpHandlerTest() {
client_ = std::make_unique<ClientProxy>(&mock_event_logger_);
client_ = std::make_unique<ClientProxy>(CreateAnalyticsRecorder());
}
void SetUp() override {
MacAddress::FromString("12:34:56:78:9a:bc", remote_mac_address_);
}
void TearDown() override {
env_.Stop();
void TearDown() override { env_.Stop(); }
std::unique_ptr<analytics::AnalyticsRecorder> CreateAnalyticsRecorder() {
auto recorder =
std::make_unique<analytics::MockAnalyticsRecorder>();
mock_analytics_recorder_ptr_ = recorder.get();
return recorder;
}
void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler,
@@ -576,26 +572,26 @@ class BasePcpHandlerTest
// the peer channel. The rest of the exchange must happen for the benefit of
// DH key exchange.
EXPECT_CALL(*channel_a, Read())
.WillRepeatedly(Invoke(
[channel = channel_a.get()]() { return channel->DoRead(); }));
.WillRepeatedly(
[channel = channel_a.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_a, Write(_))
.WillOnce(Return(Exception{Exception::kSuccess}))
.WillRepeatedly(
Invoke([channel = channel_a.get()](const ByteArray& data) {
[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()));
EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false));
EXPECT_CALL(*channel_b, Read())
.WillRepeatedly(Invoke(
[channel = channel_b.get()]() { return channel->DoRead(); }));
.WillRepeatedly(
[channel = channel_b.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_b, Write(_))
.WillRepeatedly(
Invoke([channel = channel_b.get()](const ByteArray& data) {
[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()));
@@ -622,20 +618,20 @@ class BasePcpHandlerTest
// the peer channel. The rest of the exchange must happen for the benefit of
// DH key exchange.
EXPECT_CALL(*channel_a, Read())
.WillRepeatedly(Invoke(
[channel = channel_a.get()]() { return channel->DoRead(); }));
.WillRepeatedly(
[channel = channel_a.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_a, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false));
EXPECT_CALL(*channel_b, Read())
.WillRepeatedly(Invoke(
[channel = channel_b.get()]() { return channel->DoRead(); }));
.WillRepeatedly(
[channel = channel_b.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_b, Write(_))
.WillRepeatedly(
Invoke([channel = channel_b.get()](const ByteArray& data) {
[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()));
@@ -646,7 +642,7 @@ class BasePcpHandlerTest
void RequestConnection(
const std::string& endpoint_id,
std::unique_ptr<MockEndpointChannel> channel_a,
MockEndpointChannel* channel_b, ClientProxy* client,
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
MockPcpHandler* pcp_handler,
location::nearby::proto::connections::Medium connect_medium,
std::atomic_int* flag = nullptr,
@@ -675,15 +671,15 @@ class BasePcpHandlerTest
auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client);
EXPECT_CALL(*pcp_handler, ConnectImpl)
.WillOnce(Invoke([&channel_a, connect_medium](
ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
.WillOnce([&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(
@@ -716,7 +712,7 @@ class BasePcpHandlerTest
void RequestConnectionV3(
const NearbyDevice& remote_device,
std::unique_ptr<MockEndpointChannel> channel_a,
MockEndpointChannel* channel_b, ClientProxy* client,
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
MockPcpHandler* pcp_handler,
location::nearby::proto::connections::Medium connect_medium,
FakePresenceDeviceProvider* fake_presence_device_provider,
@@ -756,15 +752,15 @@ class BasePcpHandlerTest
EXPECT_CALL(*pcp_handler, ConnectImpl)
.WillRepeatedly(
Invoke([&channel_a, connect_medium](
ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
[&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(
@@ -796,7 +792,7 @@ class BasePcpHandlerTest
void RequestConnectionWifiLanFail(
const std::string& endpoint_id,
std::unique_ptr<MockEndpointChannel> channel_a,
MockEndpointChannel* channel_b, ClientProxy* client,
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
MockPcpHandler* pcp_handler, std::atomic_int* flag = nullptr,
Status expected_result = {Status::kSuccess}) {
ConnectionRequestInfo info{
@@ -824,8 +820,8 @@ class BasePcpHandlerTest
EXPECT_CALL(*pcp_handler, ConnectImpl)
.WillRepeatedly(
Invoke([&channel_a](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
[&channel_a](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
if (endpoint->medium ==
location::nearby::proto::connections::WIFI_LAN) {
LOG(INFO) << "Connect with Medium WIFI_LAN failed.";
@@ -844,7 +840,7 @@ class BasePcpHandlerTest
.endpoint_channel = std::move(channel_a),
};
}
}));
});
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler->OnEndpointFound(
@@ -900,7 +896,7 @@ class BasePcpHandlerTest
MediumEnvironment& env_ = MediumEnvironment::Instance();
NiceMock<MockNearbyDevice> mock_device_;
MacAddress remote_mac_address_;
nearby::analytics::MockEventLogger mock_event_logger_;
nearby::analytics::MockAnalyticsRecorder* mock_analytics_recorder_ptr_;
std::unique_ptr<ClientProxy> client_;
};
@@ -1137,12 +1133,13 @@ TEST_F(BasePcpHandlerTest, WifiMediumFailFallBackToBT) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a),
channel_b.get(), client_.get(), &pcp_handler);
RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a), channel_b,
client_.get(), &pcp_handler);
LOG(INFO) << "RequestConnection complete";
channel_b->Close();
bwu.Shutdown();
@@ -1162,12 +1159,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnection("1234", std::move(channel_a), channel_b.get(),
client_.get(), &pcp_handler, connect_medium);
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium);
LOG(INFO) << "RequestConnection complete";
EXPECT_TRUE(pcp_handler.HasOutgoingConnections(client_.get()));
EXPECT_FALSE(pcp_handler.HasIncomingConnections(client_.get()));
@@ -1208,12 +1206,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnection("1234", std::move(channel_a), channel_b.get(),
client_.get(), &pcp_handler, connect_medium);
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium);
LOG(INFO) << "RequestConnection complete";
channel_b->Close();
bwu.Shutdown();
@@ -1237,12 +1236,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnection("1234", std::move(channel_a), channel_b.get(),
client_.get(), &pcp_handler, connect_medium);
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium);
LOG(INFO) << "RequestConnection complete";
channel_b->Close();
bwu.Shutdown();
@@ -1267,11 +1267,12 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
const auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b,
client_.get(), &pcp_handler, connect_medium, &provider);
LOG(INFO) << "RequestConnectionV3 complete";
channel_b->Close();
@@ -1298,12 +1299,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_AuthenticationFailure) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
const auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionV3(
mock_device_, std::move(channel_a), channel_b.get(), client_.get(),
mock_device_, std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium, &provider, /*flag=*/nullptr,
/*expected_result=*/{Status::kSuccess},
/*expected_authentication_status=*/AuthenticationStatus::kFailure);
@@ -1329,7 +1331,8 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) {
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
const auto& channel_b = channel_pair.second;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
ConnectionRequestInfo info{
@@ -1353,7 +1356,7 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) {
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get());
EXPECT_CALL(pcp_handler, ConnectImpl)
.WillRepeatedly(Invoke(
.WillRepeatedly(
[connect_medium](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
@@ -1361,7 +1364,7 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) {
.status = {Status::kError},
.endpoint_channel = nullptr,
};
}));
});
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler.OnEndpointFound(
@@ -1404,7 +1407,8 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) {
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
const auto& channel_b = channel_pair.second;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
ConnectionRequestInfo info{
@@ -1428,7 +1432,7 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) {
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get());
EXPECT_CALL(pcp_handler, ConnectImpl)
.WillRepeatedly(Invoke(
.WillRepeatedly(
[connect_medium](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
@@ -1436,7 +1440,7 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) {
.status = {Status::kError},
.endpoint_channel = nullptr,
};
}));
});
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler.OnEndpointFound(
@@ -1476,12 +1480,13 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionV3Fails) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1));
EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1));
channel_b->broken_write_ = true;
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b,
client_.get(), &pcp_handler, connect_medium, nullptr,
nullptr, {Status::kEndpointIoError});
LOG(INFO) << "RequestConnectionV3 complete";
@@ -1504,13 +1509,14 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1));
EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1));
channel_b->broken_write_ = true;
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(),
client_.get(), &pcp_handler, connect_medium, nullptr,
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium, nullptr,
{Status::kEndpointIoError});
LOG(INFO) << "RequestConnection complete";
channel_b->Close();
@@ -1532,11 +1538,12 @@ TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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.get(),
client_.get(), &pcp_handler, connect_medium);
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_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}),
Status{Status::kSuccess});
@@ -1560,9 +1567,10 @@ TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) {
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_b = channel_pair.second;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1);
RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b.get(),
RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b,
client_.get(), &pcp_handler, connect_medium);
LOG(INFO) << "Attempting to reject connection: id=" << endpoint_id;
EXPECT_EQ(pcp_handler.RejectConnection(client_.get(), endpoint_id),
@@ -1582,17 +1590,17 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
analytics::PacketMetaData packet_meta_data;
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;
auto& channel_b = channel_pair.second;
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.get(),
client_.get(), &pcp_handler, connect_medium);
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)
@@ -1601,11 +1609,11 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
Status{Status::kSuccess});
LOG(INFO) << "Simulating remote accept: id=" << endpoint_id;
OsInfo os_info;
auto frame = parser::FromBytes(parser::ForConnectionResponse(
Status::kSuccess, os_info, /*multiplex_socket_bitmask=*/0));
auto frame = parser::FromBytes(
parser::ForConnectionResponse(Status::kSuccess, os_info));
EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1);
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
connect_medium, packet_meta_data);
connect_medium);
LOG(INFO) << "Closing connection: id=" << endpoint_id;
channel_b->Close();
bwu.Shutdown();
@@ -1629,10 +1637,11 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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.get(),
RequestConnection(endpoint_id, std::move(channel_a), channel_b,
client_.get(), &pcp_handler, connect_medium,
&destroyed_flag);
mediums_count = mediums.size();
@@ -1671,11 +1680,12 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) {
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
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);
EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call).Times(1);
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(),
RequestConnection(endpoint_id, std::move(channel_a), channel_b,
client_.get(), &pcp_handler, connect_medium,
&destroyed_flag);
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get());
@@ -1787,7 +1797,7 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) {
EXPECT_TRUE(client_->IsDiscovering());
EXPECT_CALL(pcp_handler, InjectEndpointImpl(client_.get(), service_id, _))
.WillOnce(Invoke([&pcp_handler, &endpoint_id](
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
@@ -1803,7 +1813,7 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) {
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
});
pcp_handler.InjectEndpoint(
client_.get(), service_id,
OutOfBandConnectionMetadata{
@@ -1851,30 +1861,30 @@ TEST_F(BasePcpHandlerTest,
::testing::InSequence seq;
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
.WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id,
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
const ByteArray& endpoint_info,
const std::string& service_id) {
EXPECT_EQ(endpoint_id, id);
EXPECT_EQ(endpoint_info, ByteArray{"ABCD"});
}));
});
EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call)
.WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id) {
.WillOnce([id = endpoint_id](const std::string& endpoint_id) {
EXPECT_EQ(endpoint_id, id);
}));
});
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
.WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id,
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
const ByteArray& endpoint_info,
const std::string& service_id) {
EXPECT_EQ(endpoint_id, id);
EXPECT_EQ(endpoint_info, ByteArray{"ABCDEF"});
}));
});
EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call)
.WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id) {
.WillOnce([id = endpoint_id](const std::string& endpoint_id) {
EXPECT_EQ(endpoint_id, id);
}));
});
// Found endpoint on Bluetooth
pcp_handler.OnEndpointFound(
@@ -1964,7 +1974,7 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) {
EXPECT_TRUE(client_->IsDiscovering());
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce(Invoke([&pcp_handler, &endpoint_id](
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
@@ -1980,7 +1990,7 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) {
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
});
pcp_handler.InjectEndpoint(
client_.get(), service_id,
OutOfBandConnectionMetadata{
@@ -2027,7 +2037,7 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) {
EXPECT_TRUE(client_->IsDiscovering());
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce(Invoke([&pcp_handler, &endpoint_id](
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
@@ -2043,7 +2053,7 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) {
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
});
pcp_handler.InjectEndpoint(
client_.get(), service_id,
OutOfBandConnectionMetadata{
@@ -2094,7 +2104,7 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) {
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.Times(2)
.WillRepeatedly(
Invoke([&pcp_handler, &endpoint_id, &first_call](
[&pcp_handler, &endpoint_id, &first_call](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ByteArray endpoint_info;
@@ -2117,7 +2127,7 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) {
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
});
pcp_handler.InjectEndpoint(
client_.get(), service_id,
OutOfBandConnectionMetadata{
@@ -2271,20 +2281,20 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithUnknown) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()->mutable_connection_request()->clear_connections_device();
frame.mutable_v1()->mutable_connection_request()->clear_presence_device();
ASSERT_FALSE(frame.v1().connection_request().has_connections_device());
ASSERT_FALSE(frame.v1().connection_request().has_presence_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_TRUE(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2321,20 +2331,20 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithUnknown) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()->mutable_connection_request()->clear_connections_device();
frame.mutable_v1()->mutable_connection_request()->clear_presence_device();
ASSERT_FALSE(frame.v1().connection_request().has_connections_device());
ASSERT_FALSE(frame.v1().connection_request().has_presence_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_EQ(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2370,21 +2380,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithConnections) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()
->mutable_connection_request()
->mutable_connections_device()
->set_endpoint_id("ABCD");
ASSERT_TRUE(frame.v1().connection_request().has_connections_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_EQ(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2420,21 +2430,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithPresence) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()
->mutable_connection_request()
->mutable_presence_device()
->set_endpoint_id("ABCD");
ASSERT_TRUE(frame.v1().connection_request().has_presence_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_TRUE(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2469,21 +2479,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithConnections) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()
->mutable_connection_request()
->mutable_connections_device()
->set_endpoint_id("ABCD");
ASSERT_TRUE(frame.v1().connection_request().has_connections_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_TRUE(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2518,21 +2528,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "ABCD",
.local_endpoint_info = ByteArray("local endpoint"),
});
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()
->mutable_connection_request()
->mutable_presence_device()
->set_endpoint_id("ABCD");
ASSERT_TRUE(frame.v1().connection_request().has_presence_device());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_EQ(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2544,7 +2554,8 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) {
}
TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
env_.Start();
env_.Start({.use_simulated_clock = true});
client_ = std::make_unique<ClientProxy>(CreateAnalyticsRecorder());
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
@@ -2561,6 +2572,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}}));
EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection)
.WillRepeatedly(Return(true));
EXPECT_CALL(*mock_analytics_recorder_ptr_,
OnStartedIncomingConnectionListening(_));
EXPECT_TRUE(pcp_handler
.StartListeningForIncomingConnections(client_.get(),
"service", options, {})
@@ -2568,7 +2581,7 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
ASSERT_TRUE(client_->IsListeningForIncomingConnections());
ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get()));
auto channel_pair = SetupConnection(Medium::BLUETOOTH);
ByteArray serialized_frame = parser::ForConnectionRequestConnections(
std::string serialized_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "",
.local_endpoint_info = ByteArray("local endpoint"),
@@ -2576,53 +2589,19 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
// At this point the connection request doesn't have an endpoint ID field
// set, so we do that here.
location::nearby::connections::OfflineFrame frame;
frame.ParseFromString(serialized_frame.AsStringView());
frame.ParseFromString(serialized_frame);
frame.mutable_v1()->mutable_connection_request()->set_endpoint_id("");
ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id());
// do a dummy write to get to the actual write.
channel_pair.first->Write(ByteArray());
channel_pair.first->Write(ByteArray(frame.SerializeAsString()));
absl::string_view expected_log = R"pb(
event_type: CLIENT_SESSION
client_session {
strategy_session {
connection_attempt {
type: INITIAL
direction: INCOMING
medium: BLUETOOTH
attempt_result: RESULT_ERROR
operation_result {
result_category: CATEGORY_CONNECTIVITY_ERROR
result_code: CONNECTIVITY_CHANNEL_IO_ERROR_ON_BT
}
}
}
}
)pb";
absl::string_view client_session_log = R"pb(
event_type: CLIENT_SESSION
client_session { duration_millis: 0 }
version: "v1.5.0"
)pb";
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::STOP_STRATEGY_SESSION))))
.Times(1);
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::STOP_CLIENT_SESSION))))
.Times(3);
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::START_CLIENT_SESSION))))
.Times(3);
channel_pair.first->Write("");
channel_pair.first->Write(frame.SerializeAsString());
EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3);
EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3);
EXPECT_CALL(
mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(EqualsProto(client_session_log))))
.Times(2);
EXPECT_CALL(mock_event_logger_, Log(Matcher<const ConnectionsLog&>(
Partially(EqualsProto(expected_log)))));
*mock_analytics_recorder_ptr_,
OnIncomingConnectionAttempt(
location::nearby::proto::connections::INITIAL, Medium::BLUETOOTH,
location::nearby::proto::connections::RESULT_ERROR, _, _, _));
EXPECT_EQ(pcp_handler
.OnIncomingConnection(
client_.get(), ByteArray("remote endpoint"),
@@ -2636,7 +2615,7 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) {
env_.Start({.use_simulated_clock = true});
// Recreate ClientProxy so that AnalyticRecorder uses simulated clock.
client_ = std::make_unique<ClientProxy>(&mock_event_logger_);
client_ = std::make_unique<ClientProxy>(CreateAnalyticsRecorder());
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
@@ -2653,6 +2632,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) {
MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}}));
EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection)
.WillRepeatedly(Return(true));
EXPECT_CALL(*mock_analytics_recorder_ptr_,
OnStartedIncomingConnectionListening(_));
EXPECT_TRUE(pcp_handler
.StartListeningForIncomingConnections(client_.get(),
"service", options, {})
@@ -2664,59 +2645,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) {
std::move(input_a), std::move(output_a));
EXPECT_CALL(*input_channel, Read())
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kNoData)));
absl::string_view expected_log = R"pb(
event_type: CLIENT_SESSION
client_session {
strategy_session {
connection_attempt {
type: INITIAL
direction: INCOMING
attempt_result: RESULT_ERROR
}
}
}
)pb";
absl::string_view client_session_log = R"pb(
event_type: CLIENT_SESSION
client_session { duration_millis: 0 }
version: "v1.5.0"
)pb";
absl::string_view client_session_log2 = R"pb(
event_type: CLIENT_SESSION
client_session {
duration_millis: 0
strategy_session {
duration_millis: 0
strategy: UNKNOWN_STRATEGY
role: ADVERTISER
}
}
version: "v1.5.0"
)pb";
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::STOP_STRATEGY_SESSION))))
.Times(1);
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::STOP_CLIENT_SESSION))))
.Times(3);
EXPECT_CALL(mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(
HasEventType(EventType::START_CLIENT_SESSION))))
.Times(3);
EXPECT_CALL(
mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(EqualsProto(client_session_log))))
.Times(2);
EXPECT_CALL(
mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(EqualsProto(client_session_log2))));
EXPECT_CALL(
mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(Partially(EqualsProto(expected_log)))))
.Times(0);
EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3);
EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3);
EXPECT_EQ(
pcp_handler
.OnIncomingConnection(client_.get(), ByteArray("remote endpoint"),
@@ -3020,5 +2950,4 @@ TEST_F(BasePcpHandlerTest, TestForceUpdateEndpointIdAdvertisingOption) {
}
} // namespace
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
+1 -2
View File
@@ -21,7 +21,6 @@
#include "absl/functional/any_invocable.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/expected.h"
namespace nearby {
@@ -53,7 +52,7 @@ class BwuHandler {
// that hasn't already been done), and returns a serialized UpgradePathInfo
// that can be sent to the Responder.
// @BwuHandlerThread
virtual ByteArray InitializeUpgradedMediumForEndpoint(
virtual std::string InitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& service_id,
const std::string& endpoint_id) = 0;
+45 -37
View File
@@ -25,9 +25,8 @@
#include "absl/functional/bind_front.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/connection_attempt_metadata_params.h"
#include "connections/implementation/awdl_bwu_handler.h"
#include "connections/implementation/bluetooth_bwu_handler.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
@@ -38,16 +37,7 @@
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/service_id_constants.h"
#include "internal/flags/nearby_flags.h"
#ifdef NO_WEBRTC
#include "connections/implementation/webrtc_bwu_handler_stub.h"
#else
#include "connections/implementation/webrtc_bwu_handler.h"
#endif
#include "connections/implementation/wifi_direct_bwu_handler.h"
#include "connections/implementation/wifi_hotspot_bwu_handler.h"
#include "connections/implementation/wifi_lan_bwu_handler.h"
#include "connections/medium_selector.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancelable_alarm.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/expected.h"
@@ -72,6 +62,8 @@ using ::location::nearby::proto::connections::ConnectionAttemptResult;
using ::location::nearby::proto::connections::ConnectionAttemptType;
using ::location::nearby::proto::connections::DisconnectionReason;
using ::location::nearby::proto::connections::OperationResultCode;
using ::nearby::analytics::AnalyticsRecorder;
} // namespace
BwuManager::BwuManager(
@@ -135,43 +127,37 @@ void BwuManager::InitBwuHandlers() {
if (config_.allow_upgrade_to.awdl) {
handlers_.emplace(
Medium::AWDL,
std::make_unique<AwdlBwuHandler>(
*mediums_,
mediums_->GetAwdl().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
if (config_.allow_upgrade_to.wifi_hotspot) {
handlers_.emplace(
Medium::WIFI_HOTSPOT,
std::make_unique<WifiHotspotBwuHandler>(
*mediums_,
mediums_->GetWifiHotspot().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
if (config_.allow_upgrade_to.wifi_direct) {
handlers_.emplace(
Medium::WIFI_DIRECT,
std::make_unique<WifiDirectBwuHandler>(
*mediums_,
mediums_->GetWifiDirect().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
if (config_.allow_upgrade_to.wifi_lan) {
handlers_.emplace(
Medium::WIFI_LAN,
std::make_unique<WifiLanBwuHandler>(
*mediums_,
mediums_->GetWifiLan().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
if (config_.allow_upgrade_to.web_rtc) {
handlers_.emplace(
Medium::WEB_RTC,
std::make_unique<WebrtcBwuHandler>(
*mediums_,
mediums_->GetWebRtc().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
if (config_.allow_upgrade_to.bluetooth) {
handlers_.emplace(
Medium::BLUETOOTH,
std::make_unique<BluetoothBwuHandler>(
*mediums_,
mediums_->GetBluetoothClassic().CreateBwuHandler(
absl::bind_front(&BwuManager::OnIncomingConnection, this)));
}
}
@@ -197,8 +183,9 @@ void BwuManager::Shutdown() {
medium_ = Medium::UNKNOWN_MEDIUM;
endpoint_id_to_bwu_medium_.clear();
for (auto& medium_handler_pair : handlers_) {
assert(medium_handler_pair.second);
medium_handler_pair.second->RevertInitiatorState();
if (medium_handler_pair.second != nullptr) {
medium_handler_pair.second->RevertInitiatorState();
}
}
handlers_.clear();
@@ -341,12 +328,12 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client,
}
std::string service_id = channel->GetServiceId();
ByteArray bytes = handler->InitializeUpgradedMediumForEndpoint(
std::string bytes = handler->InitializeUpgradedMediumForEndpoint(
client, service_id, endpoint_id);
// Because we grab the endpointChannel first thing, it is possible the
// endpointChannel is stale by the time we attempt to write over it.
if (bytes.Empty()) {
if (bytes.empty()) {
LOG(ERROR) << "BwuManager couldn't complete the upgrade for endpoint "
<< endpoint_id << " to medium "
<< location::nearby::proto::connections::Medium_Name(
@@ -401,8 +388,7 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client,
void BwuManager::OnIncomingFrame(OfflineFrame& frame,
const std::string& endpoint_id,
ClientProxy* client, Medium medium,
PacketMetaData& packet_meta_data) {
ClientProxy* client, Medium medium) {
V1Frame::FrameType frame_type = parser::GetFrameType(frame);
if (frame_type != V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION) return;
@@ -549,7 +535,7 @@ BwuHandler* BwuManager::GetHandlerForMedium(Medium medium) const {
}
void BwuManager::OnBwuNegotiationFrame(
ClientProxy* client, const BandwidthUpgradeNegotiationFrame frame,
ClientProxy* client, const BandwidthUpgradeNegotiationFrame& frame,
const std::string& endpoint_id) {
LOG(INFO) << "OnBwuNegotiationFrame: processing incoming "
<< BandwidthUpgradeNegotiationFrame::EventType_Name(
@@ -586,9 +572,19 @@ void BwuManager::OnBwuNegotiationFrame(
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
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 "
<< endpoint_id << " but no upgrade is in progress.";
return;
}
ProcessLastWriteToPriorChannelEvent(client, endpoint_id);
break;
case BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL:
if (!in_progress_upgrades_.contains(endpoint_id)) {
LOG(ERROR) << "Received SAFE_TO_CLOSE_PRIOR_CHANNEL for endpoint "
<< endpoint_id << " but no upgrade is in progress.";
return;
}
ProcessSafeToClosePriorChannelEvent(client, endpoint_id);
break;
default:
@@ -680,7 +676,7 @@ void BwuManager::OnIncomingConnection(
connections_attempt_metadata_params;
if (channel != nullptr) {
connections_attempt_metadata_params =
client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams(
AnalyticsRecorder::BuildConnectionAttemptMetadataParams(
channel->GetTechnology(), channel->GetBand(),
channel->GetFrequency(), channel->GetTryCount());
connections_attempt_metadata_params->operation_result_code =
@@ -891,7 +887,7 @@ void BwuManager::ProcessBwuPathAvailableEvent(
if (channel != nullptr) {
std::unique_ptr<ConnectionAttemptMetadataParams>
connections_attempt_metadata_params =
client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams(
AnalyticsRecorder::BuildConnectionAttemptMetadataParams(
channel->GetTechnology(), channel->GetBand(),
channel->GetFrequency(), channel->GetTryCount());
connections_attempt_metadata_params->operation_result_code =
@@ -1138,7 +1134,7 @@ bool BwuManager::ReadClientIntroductionFrame(
auto data = channel->Read();
timeout_alarm.Cancel();
if (!data.ok()) return false;
auto transfer(parser::FromBytes(data.result()));
auto transfer(parser::FromBytes(data.result().AsStringView()));
if (!transfer.ok()) {
LOG(ERROR) << "In ReadClientIntroductionFrame, attempted to read a "
"ClientIntroductionFrame from EndpointChannel "
@@ -1189,7 +1185,7 @@ bool BwuManager::ReadClientIntroductionAckFrame(EndpointChannel* channel) {
auto data = channel->Read();
timeout_alarm.Cancel();
if (!data.ok()) return false;
auto transfer(parser::FromBytes(data.result()));
auto transfer(parser::FromBytes(data.result().AsStringView()));
if (!transfer.ok()) return false;
OfflineFrame frame = transfer.result();
if (!frame.has_v1() || !frame.v1().has_bandwidth_upgrade_negotiation())
@@ -1219,9 +1215,8 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent(
// loss). But now that we've received this definitive final write over that
// prior EndpointChannel, we can let the remote device that they can safely
// close their end of this now-dormant EndpointChannel.
EndpointChannel* previous_endpoint_channel =
previous_endpoint_channels_[endpoint_id].get();
if (!previous_endpoint_channel) {
auto it = previous_endpoint_channels_.find(endpoint_id);
if (it == previous_endpoint_channels_.end()) {
LOG(ERROR)
<< "BwuManager received a BWU_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL "
"OfflineFrame for unknown endpoint "
@@ -1229,6 +1224,12 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent(
successfully_upgraded_endpoints_.emplace(endpoint_id);
return;
}
EndpointChannel* previous_endpoint_channel = it->second.get();
if (!previous_endpoint_channel) {
LOG(ERROR) << "previous_endpoint_channel is null for endpoint "
<< endpoint_id;
return;
}
LOG(INFO) << "ProcessLastWriteToPriorChannelEvent: service_id="
<< previous_endpoint_channel->GetServiceId()
@@ -1281,6 +1282,13 @@ void BwuManager::ProcessSafeToClosePriorChannelEvent(
// or not (as is the case with Android's Bluetooth sockets, where closing
// instantly throws an IOException on the remote device).
auto item = previous_endpoint_channels_.extract(endpoint_id);
if (item.empty()) {
LOG(ERROR)
<< "BwuManager received a BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL "
"OfflineFrame for unknown endpoint "
<< endpoint_id << ", can't complete the upgrade protocol.";
return;
}
auto& previous_endpoint_channel = item.mapped();
if (previous_endpoint_channel == nullptr) {
LOG(ERROR)
+2 -3
View File
@@ -92,8 +92,7 @@ class BwuManager : public EndpointManager::FrameProcessor {
// @EndpointManagerReaderThread
void OnIncomingFrame(location::nearby::connections::OfflineFrame& frame,
const std::string& endpoint_id, ClientProxy* client,
Medium medium,
PacketMetaData& packet_meta_data) override;
Medium medium) override;
// Cleans up in-progress upgrades after endpoint disconnection.
// @EndpointManagerReaderThread
@@ -144,7 +143,7 @@ class BwuManager : public EndpointManager::FrameProcessor {
// upgrade.
void OnBwuNegotiationFrame(
ClientProxy* client,
const location::nearby::connections::BandwidthUpgradeNegotiationFrame
const location::nearby::connections::BandwidthUpgradeNegotiationFrame&
frame,
const string& endpoint_id);
+132 -50
View File
@@ -22,6 +22,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "connections/connection_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
@@ -41,19 +42,17 @@
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/service_address.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame;
using ::location::nearby::connections::MediumRole;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::connections::V1Frame;
using ::location::nearby::proto::connections::DisconnectionReason;
using ::nearby::analytics::SafeDisconnectionResult;
constexpr absl::string_view kServiceIdA = "ServiceA";
constexpr absl::string_view kServiceIdB = "ServiceB";
@@ -148,7 +147,7 @@ class BwuManagerTest : public ::testing::Test {
void UnRegisterChannelForEndpoint(absl::string_view endpoint_id) {
ecm_.UnregisterChannelForEndpoint(
std::string(endpoint_id), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
}
// Upgrade from |initial_medium| to |upgrade_medium|, close down the BLUETOOTH
@@ -188,12 +187,12 @@ class BwuManagerTest : public ::testing::Test {
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(endpoint_id), &client_,
initial_medium, packet_meta_data_);
initial_medium);
ExceptionOr<OfflineFrame> safe_to_close_frame =
parser::FromBytes(parser::ForBwuSafeToClose());
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
std::string(endpoint_id), &client_,
initial_medium, packet_meta_data_);
initial_medium);
return upgraded_channel;
}
@@ -209,7 +208,6 @@ class BwuManagerTest : public ::testing::Test {
FakeBwuHandler* fake_wifi_direct_bwu_handler_ = nullptr;
FakeBwuHandler* fake_wifi_hotspot_bwu_handler_ = nullptr;
std::unique_ptr<BwuManager> bwu_manager_;
PacketMetaData packet_meta_data_;
};
TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
@@ -233,9 +231,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
Medium::WIFI_LAN);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
ecm.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel2 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
@@ -244,9 +242,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2),
Medium::WIFI_HOTSPOT);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2)));
ecm.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId2),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel3 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
@@ -255,9 +253,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3),
Medium::WIFI_DIRECT);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3)));
ecm.UnregisterChannelForEndpoint(
std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId3),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel4 = std::make_unique<FakeEndpointChannel>(
Medium::WEB_RTC, std::string(kServiceIdA));
@@ -266,9 +264,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4),
Medium::BLUETOOTH);
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4)));
ecm.UnregisterChannelForEndpoint(
std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId4),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
}
@@ -308,9 +306,9 @@ TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) {
Medium::WIFI_HOTSPOT);
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
ecm.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
@@ -370,12 +368,12 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Success) {
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH, packet_meta_data_);
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, packet_meta_data_);
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
@@ -501,7 +499,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id, std::string(kEndpointId1), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -515,7 +513,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id, std::string(kEndpointId2), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -549,7 +547,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id, std::string(kEndpointId1), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -569,7 +567,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id, std::string(kEndpointId2), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -606,7 +604,7 @@ TEST_F(BwuManagerTest,
EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount());
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount());
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_A, std::string(kEndpointId1), latch,
@@ -626,7 +624,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount());
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_B, std::string(kEndpointId2), latch,
@@ -660,7 +658,7 @@ TEST_F(BwuManagerTest,
EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount());
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount());
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_A, std::string(kEndpointId1), latch,
@@ -680,7 +678,7 @@ TEST_F(BwuManagerTest,
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount());
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_B, std::string(kEndpointId2), latch,
@@ -736,7 +734,7 @@ TEST_F(
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_A, std::string(kEndpointId1), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -761,7 +759,7 @@ TEST_F(
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_A, std::string(kEndpointId2), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -782,7 +780,7 @@ TEST_F(
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_B, std::string(kEndpointId3), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -803,7 +801,7 @@ TEST_F(
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_B, std::string(kEndpointId4), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -826,7 +824,7 @@ TEST_F(
CountDownLatch latch(1);
ecm_.UnregisterChannelForEndpoint(
std::string(kEndpointId5), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION);
SafeDisconnectionResult::kUnsafeDisconnection);
bwu_manager_->OnEndpointDisconnect(
&client_, upgrade_service_id_B, std::string(kEndpointId5), latch,
DisconnectionReason::LOCAL_DISCONNECTION);
@@ -871,7 +869,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagEnabled) {
parser::FromBytes(parser::ForBwuFailure(info));
bwu_manager_->OnIncomingFrame(upgrade_failure.result(),
std::string(kEndpointId3), &client_,
Medium::WEB_RTC, packet_meta_data_);
Medium::WEB_RTC);
// With the flag enabled, we can safely revert WebRTC just for service B
// because service B has no active WebRTC endpoints.
@@ -908,7 +906,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) {
parser::FromBytes(parser::ForBwuFailure(info));
bwu_manager_->OnIncomingFrame(upgrade_failure.result(),
std::string(kEndpointId3), &client_,
Medium::WEB_RTC, packet_meta_data_);
Medium::WEB_RTC);
// With the flag disabled, we don't revert if there are still connected
// endpoints for _any_ service. We don't have service-level bookkeeping; we
@@ -924,12 +922,12 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) {
OfflineFrame frame;
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
ByteArray bytes = parser::ForBwuWifiDirectPathAvailable(
std::string bytes = parser::ForBwuWifiDirectPathAvailable(
/*ssid=*/"", /*password=*/"", /*port=*/2143,
/*frequency=*/2412, /*supports_disabling_encryption=*/false,
/*gateway=*/"123.234.23.1", /*service_name=*/"NC-WifiDirectTest",
/*gateway=*/"123.234.23.1", /*device_name=*/"NC-WifiDirectTest",
/*pin=*/"b592f7d3");
frame.ParseFromString(std::string(bytes));
frame.ParseFromString(bytes);
::nearby::connections::V1Frame* v1_frame = frame.mutable_v1();
::nearby::connections::BandwidthUpgradeNegotiationFrame* sub_frame =
@@ -938,7 +936,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) {
upgrade_path_info = sub_frame->mutable_upgrade_path_info();
upgrade_path_info->set_supports_client_introduction_ack(false);
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH, packet_meta_data_);
Medium::BLUETOOTH);
CountDownLatch latch(1);
bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA,
std::string(kEndpointId1), latch,
@@ -973,7 +971,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) {
upgrade_path_info->set_supports_client_introduction_ack(false);
upgrade_path_info->set_supports_disabling_encryption(true);
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH, packet_meta_data_);
Medium::BLUETOOTH);
CountDownLatch latch(1);
bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA,
std::string(kEndpointId1), latch,
@@ -1001,7 +999,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Wlan) {
upgrade_path_info->set_supports_client_introduction_ack(false);
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH, packet_meta_data_);
Medium::BLUETOOTH);
CountDownLatch latch(1);
bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA,
std::string(kEndpointId1), latch,
@@ -1040,7 +1038,7 @@ TEST_F(BwuManagerTest, BlockBwuFrameBeforeAccept) {
upgrade_path_info2->set_supports_client_introduction_ack(false);
upgrade_path_info2->set_supports_disabling_encryption(true);
bwu_manager_->OnIncomingFrame(frame2, std::string(kEndpointId2), &client_,
Medium::BLUETOOTH, packet_meta_data_);
Medium::BLUETOOTH);
CountDownLatch latch2(1);
// The BWU frame should be drop, so the inProgressUpgrades should be empty.
ASSERT_EQ(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)), false);
@@ -1084,16 +1082,100 @@ TEST_F(BwuManagerTest, BlockBwuFrameFromAdvertiser) {
EXPECT_TRUE(client_.IsConnectedToEndpoint(std::string(kEndpointId2)));
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId2), &client_,
Medium::BLUETOOTH, packet_meta_data_);
Medium::BLUETOOTH);
CountDownLatch latch2(1);
// The BWU frame should be drop, so the IsUpgradeOngoing should be empty.
ASSERT_EQ(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)), false);
UnRegisterChannelForEndpoint(kEndpointId2);
}
TEST_F(BwuManagerTest, ReceiveUnexpectedSafeToClose_NoCrash) {
ExceptionOr<OfflineFrame> safe_to_close_frame =
parser::FromBytes(parser::ForBwuSafeToClose());
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
}
TEST_F(BwuManagerTest, ReceiveUnexpectedLastWrite_NoCrashOrWedge) {
ExceptionOr<OfflineFrame> last_write_frame =
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
}
TEST_F(BwuManagerTest, ReceiveEarlyLastWrite_Success) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
std::shared_ptr<EndpointChannel> shared_initial_channel =
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
ASSERT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1)));
ExceptionOr<OfflineFrame> last_write_frame =
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
ExceptionOr<OfflineFrame> safe_to_close_frame =
parser::FromBytes(parser::ForBwuSafeToClose());
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
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_F(BwuManagerTest, ReceiveUnexpectedLastWriteBeforeUpgrade_NoWedge) {
ExceptionOr<OfflineFrame> last_write_frame =
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
std::shared_ptr<EndpointChannel> shared_initial_channel =
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
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);
auto old_channel =
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
EXPECT_FALSE(upgraded_channel->IsPaused());
EXPECT_TRUE(old_channel->is_closed());
UnRegisterChannelForEndpoint(kEndpointId1);
}
INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam,
testing::Bool());
} // namespace
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
+207 -88
View File
@@ -38,12 +38,15 @@
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/advertising_metadata_params.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/connection_attempt_metadata_params.h"
#include "connections/implementation/analytics/discovery_metadata_params.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/advertisements/dct_advertisement.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/payload.h"
#include "connections/payload_type.h"
#include "connections/status.h"
#include "connections/strategy.h"
#include "connections/v3/bandwidth_info.h"
@@ -52,7 +55,6 @@
#include "connections/v3/connections_device.h"
#include "connections/v3/connections_device_provider.h"
#include "connections/v3/listeners.h"
#include "internal/analytics/event_logger.h"
#include "internal/base/file_path.h"
#include "internal/base/files.h"
#include "internal/flags/nearby_flags.h"
@@ -60,7 +62,9 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/cancelable_alarm.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/device_info_impl.h"
#ifndef NEARBY_CHROMIUM
#include "internal/platform/implementation/device_info.h"
#endif
#include "internal/platform/error_code_params.h"
#include "internal/platform/error_code_recorder.h"
#include "internal/platform/feature_flags.h"
@@ -77,9 +81,9 @@
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::MediumRole;
using ::location::nearby::connections::OsInfo;
using ::nearby::analytics::AnalyticsRecorder;
constexpr char kEndpointIdChars[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
@@ -95,11 +99,154 @@ constexpr absl::string_view kAdvertisingTimestamp = "nc.advertising.timestamp";
constexpr absl::Duration kAdvertisingKeepAliveDuration = absl::Seconds(30);
class NoOpAnalyticsRecorder : public AnalyticsRecorder {
public:
NoOpAnalyticsRecorder() = default;
~NoOpAnalyticsRecorder() override = default;
// Advertising phase
void OnStartAdvertising(
connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>& mediums,
AdvertisingMetadataParams* advertising_metadata_params) override {}
void OnStopAdvertising() override {}
int GetNextAdvertisingUpdateIndex() override { return 0; }
// Connection listening
void OnStartedIncomingConnectionListening(
connections::Strategy strategy) override {}
void OnStoppedIncomingConnectionListening() override {}
// Discovery phase
void OnStartDiscovery(
connections::Strategy strategy,
const std::vector<location::nearby::proto::connections::Medium>& mediums,
DiscoveryMetadataParams* discovery_metadata_params) override {}
void OnStopDiscovery() override {}
int GetNextDiscoveryUpdateIndex() override { return 0; }
void OnEndpointFound(
location::nearby::proto::connections::Medium medium) override {}
// Connection request
void OnRequestConnection(const connections::Strategy& strategy,
const std::string& endpoint_id) override {}
void OnConnectionRequestReceived(
const std::string& remote_endpoint_id) override {}
void OnConnectionRequestSent(
const std::string& remote_endpoint_id) override {}
void OnRemoteEndpointAccepted(
const std::string& remote_endpoint_id) override {}
void OnLocalEndpointAccepted(
const std::string& remote_endpoint_id) override {}
void OnRemoteEndpointRejected(
const std::string& remote_endpoint_id) override {}
void OnLocalEndpointRejected(
const std::string& remote_endpoint_id) override {}
// Connection attempt
void OnIncomingConnectionAttempt(
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
override {}
void OnOutgoingConnectionAttempt(
const std::string& remote_endpoint_id,
location::nearby::proto::connections::ConnectionAttemptType type,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::ConnectionAttemptResult result,
absl::Duration duration, const std::string& connection_token,
ConnectionAttemptMetadataParams* connection_attempt_metadata_params)
override {}
// Connection established
void OnConnectionEstablished(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
const std::string& connection_token) override {}
void OnConnectionClosed(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium medium,
location::nearby::proto::connections::DisconnectionReason reason,
nearby::analytics::SafeDisconnectionResult result) override {}
// Payload
void OnIncomingPayloadStarted(const std::string& endpoint_id,
std::int64_t payload_id,
connections::PayloadType type,
std::int64_t total_size_bytes) override {}
void OnPayloadChunkReceived(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes) override {}
void OnIncomingPayloadDone(
const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code) override {}
void OnOutgoingPayloadStarted(
const std::vector<std::string>& endpoint_ids, std::int64_t payload_id,
connections::PayloadType type, std::int64_t total_size_bytes) override {}
void OnPayloadChunkSent(const std::string& endpoint_id,
std::int64_t payload_id,
std::int64_t chunk_size_bytes) override {}
void OnOutgoingPayloadDone(
const std::string& endpoint_id, std::int64_t payload_id,
location::nearby::proto::connections::PayloadStatus status,
location::nearby::proto::connections::OperationResultCode
operation_result_code) override {}
// BandwidthUpgrade
void OnBandwidthUpgradeStarted(
const std::string& endpoint_id,
location::nearby::proto::connections::Medium from_medium,
location::nearby::proto::connections::Medium to_medium,
location::nearby::proto::connections::ConnectionAttemptDirection
direction,
const std::string& connection_token) override {}
void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id,
int num_interfaces,
int num_ipv6_only_interfaces) override {}
void OnBandwidthUpgradeError(
const std::string& endpoint_id,
location::nearby::proto::connections::BandwidthUpgradeResult result,
location::nearby::proto::connections::BandwidthUpgradeErrorStage
error_stage,
location::nearby::proto::connections::OperationResultCode
operation_result_code) override {}
void OnBandwidthUpgradeSuccess(const std::string& endpoint_id) override {}
// Error Code
void OnErrorCode(const ErrorCodeParams& params) override {}
void LogStartSession() override {}
void LogSession() override {}
bool IsSessionLogged() override { return false; }
location::nearby::proto::connections::OperationResultCategory
GetOperationResultCategory(
location::nearby::proto::connections::OperationResultCode result_code)
override {
return location::nearby::proto::connections::OperationResultCategory::
CATEGORY_UNKNOWN;
}
void Sync() override {}
};
} // namespace
ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger)
: client_id_(Prng().NextInt64()) {
VLOG(1) << "ClientProxy ctor event_logger=" << event_logger;
ClientProxy::ClientProxy(std::unique_ptr<AnalyticsRecorder> analytics_recorder)
: client_id_(Prng().NextInt64()),
analytics_recorder_(std::move(analytics_recorder)) {
if (analytics_recorder_ == nullptr) {
analytics_recorder_ = std::make_unique<NoOpAnalyticsRecorder>();
}
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableNearbyConnectionsPreferences)) {
@@ -108,8 +255,6 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger)
is_dct_enabled_ = NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableDct);
analytics_recorder_ =
std::make_unique<analytics::AnalyticsRecorder>(event_logger);
error_code_recorder_ = std::make_unique<ErrorCodeRecorder>(
[this](const ErrorCodeParams& params) {
analytics_recorder_->OnErrorCode(params);
@@ -186,6 +331,7 @@ const NearbyDevice* ClientProxy::GetLocalDevice() {
}
std::string ClientProxy::GetConnectionToken(const std::string& endpoint_id) {
MutexLock lock(&mutex_);
ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
return item->first.connection_token;
@@ -216,6 +362,7 @@ std::string ClientProxy::GetSavePath(
std::optional<MacAddress> ClientProxy::GetBluetoothMacAddress(
const std::string& endpoint_id) {
MutexLock lock(&mutex_);
auto item = bluetooth_mac_addresses_.find(endpoint_id);
if (item != bluetooth_mac_addresses_.end()) return item->second;
return std::nullopt;
@@ -223,6 +370,7 @@ std::optional<MacAddress> ClientProxy::GetBluetoothMacAddress(
void ClientProxy::SetBluetoothMacAddress(const std::string& endpoint_id,
MacAddress bluetooth_mac_address) {
MutexLock lock(&mutex_);
bluetooth_mac_addresses_[endpoint_id] = bluetooth_mac_address;
}
@@ -260,7 +408,7 @@ void ClientProxy::StartedAdvertising(
const std::string& service_id, Strategy strategy,
const ConnectionListener& listener,
absl::Span<location::nearby::proto::connections::Medium> mediums,
const std::vector<ConnectionsLog::OperationResultWithMedium>&
const std::vector<analytics::OperationResultWithMedium>&
operation_result_with_mediums,
const AdvertisingOptions& advertising_options) {
MutexLock lock(&mutex_);
@@ -281,9 +429,9 @@ void ClientProxy::StartedAdvertising(
mediums.begin(), mediums.end());
std::unique_ptr<AdvertisingMetadataParams> advertising_metadata_params;
advertising_metadata_params =
GetAnalyticsRecorder().BuildAdvertisingMetadataParams();
AnalyticsRecorder::BuildAdvertisingMetadataParams();
advertising_metadata_params->operation_result_with_mediums =
std::move(operation_result_with_mediums);
operation_result_with_mediums;
analytics_recorder_->OnStartAdvertising(strategy, medium_vector,
advertising_metadata_params.get());
}
@@ -399,7 +547,7 @@ void ClientProxy::StartedDiscovery(
const std::string& service_id, Strategy strategy,
DiscoveryListener listener,
absl::Span<location::nearby::proto::connections::Medium> mediums,
const std::vector<ConnectionsLog::OperationResultWithMedium>&
const std::vector<analytics::OperationResultWithMedium>&
operation_result_with_mediums,
const DiscoveryOptions& discovery_options) {
MutexLock lock(&mutex_);
@@ -409,10 +557,9 @@ void ClientProxy::StartedDiscovery(
const std::vector<location::nearby::proto::connections::Medium> medium_vector(
mediums.begin(), mediums.end());
std::unique_ptr<DiscoveryMetadataParams> discovery_metadata_params;
discovery_metadata_params =
GetAnalyticsRecorder().BuildDiscoveryMetadataParams();
discovery_metadata_params = AnalyticsRecorder::BuildDiscoveryMetadataParams();
discovery_metadata_params->operation_result_with_mediums =
std::move(operation_result_with_mediums);
operation_result_with_mediums;
analytics_recorder_->OnStartDiscovery(strategy, medium_vector,
discovery_metadata_params.get());
}
@@ -875,16 +1022,19 @@ bool ClientProxy::IsConnectionRejected(const std::string& endpoint_id) const {
}
bool ClientProxy::LocalConnectionIsAccepted(std::string endpoint_id) const {
MutexLock lock(&mutex_);
return ConnectionStatusesContains(
endpoint_id, ClientProxy::Connection::kLocalEndpointAccepted);
}
bool ClientProxy::RemoteConnectionIsAccepted(std::string endpoint_id) const {
MutexLock lock(&mutex_);
return ConnectionStatusesContains(
endpoint_id, ClientProxy::Connection::kRemoteEndpointAccepted);
}
bool ClientProxy::AutoUpgradeBandwidth() const {
MutexLock lock(&mutex_);
bool result = false;
if (IsAdvertising() && (GetAdvertisingOptions().strategy.IsNone() ||
GetAdvertisingOptions().auto_upgrade_bandwidth)) {
@@ -899,6 +1049,7 @@ bool ClientProxy::AutoUpgradeBandwidth() const {
}
bool ClientProxy::ShouldEnforceTopologyConstraints() const {
MutexLock lock(&mutex_);
bool result = false;
if (IsAdvertising() &&
(GetAdvertisingOptions().strategy.IsNone() ||
@@ -919,6 +1070,7 @@ void ClientProxy::AddCancellationFlag(const std::string& endpoint_id) {
return;
}
MutexLock lock(&mutex_);
auto item = cancellation_flags_.find(endpoint_id);
if (item != cancellation_flags_.end()) {
// A new flag may be added to the map with the same endpoint, even if a
@@ -933,19 +1085,21 @@ void ClientProxy::AddCancellationFlag(const std::string& endpoint_id) {
return;
}
cancellation_flags_.emplace(endpoint_id,
std::make_unique<CancellationFlag>());
std::make_shared<CancellationFlag>());
}
CancellationFlag* ClientProxy::GetCancellationFlag(
std::shared_ptr<CancellationFlag> ClientProxy::GetCancellationFlag(
const std::string& endpoint_id) {
MutexLock lock(&mutex_);
const auto item = cancellation_flags_.find(endpoint_id);
if (item == cancellation_flags_.end()) {
return default_cancellation_flag_.get();
return default_cancellation_flag_;
}
return item->second.get();
return item->second;
}
void ClientProxy::CancelEndpoint(const std::string& endpoint_id) {
MutexLock lock(&mutex_);
const auto item = cancellation_flags_.find(endpoint_id);
if (item != cancellation_flags_.end()) {
item->second->Cancel();
@@ -956,6 +1110,7 @@ const OsInfo& ClientProxy::GetLocalOsInfo() const { return local_os_info_; }
std::optional<OsInfo> ClientProxy::GetRemoteOsInfo(
absl::string_view endpoint_id) const {
MutexLock lock(&mutex_);
const ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
return item->first.os_info;
@@ -965,11 +1120,13 @@ std::optional<OsInfo> ClientProxy::GetRemoteOsInfo(
void ClientProxy::SetLocalOsType(
const location::nearby::connections::OsInfo::OsType& os_type) {
MutexLock lock(&mutex_);
local_os_info_.set_type(os_type);
}
void ClientProxy::SetRemoteOsInfo(absl::string_view endpoint_id,
const OsInfo& remote_os_info) {
MutexLock lock(&mutex_);
ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
item->first.os_info.emplace(remote_os_info);
@@ -1016,8 +1173,9 @@ bool ClientProxy::IsPayloadReceivedAckEnabled(absl::string_view endpoint_id) {
}
void ClientProxy::CancelAllEndpoints() {
MutexLock lock(&mutex_);
for (const auto& item : cancellation_flags_) {
CancellationFlag* cancellation_flag = item.second.get();
std::shared_ptr<CancellationFlag> cancellation_flag = item.second;
if (cancellation_flag->Cancelled()) {
continue;
}
@@ -1120,14 +1278,17 @@ void ClientProxy::AppendConnectionStatus(const std::string& endpoint_id,
}
AdvertisingOptions ClientProxy::GetAdvertisingOptions() const {
MutexLock lock(&mutex_);
return advertising_options_;
}
DiscoveryOptions ClientProxy::GetDiscoveryOptions() const {
MutexLock lock(&mutex_);
return discovery_options_;
}
v3::ConnectionListeningOptions ClientProxy::GetListeningOptions() const {
MutexLock lock(&mutex_);
return listening_options_;
}
@@ -1204,30 +1365,9 @@ OsInfo::OsType ClientProxy::OSNameToOsInfoType(api::OSName osName) {
}
}
std::int32_t ClientProxy::GetLocalMultiplexSocketBitmask() const {
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplex)) {
std::int32_t multiplex_bitmask =
(NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth)
? kBtMultiplexEnabled
: 0) |
(NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexWifiLan)
? kWifiLanMultiplexEnabled
: 0);
LOG(INFO) << "ClientProxy [GetLocalMultiplexSocketBitmask]: "
<< multiplex_bitmask;
return multiplex_bitmask;
}
return 0;
}
void ClientProxy::SetRemoteMultiplexSocketBitmask(
absl::string_view endpoint_id, int remote_multiplex_socket_bitmask) {
MutexLock lock(&mutex_);
ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
item->first.remote_multiplex_socket_bitmask =
@@ -1237,62 +1377,31 @@ void ClientProxy::SetRemoteMultiplexSocketBitmask(
}
}
bool ClientProxy::IsLocalMultiplexSocketSupported(Medium medium) {
int bitmask = GetLocalMultiplexSocketBitmask();
switch (medium) {
case Medium::BLUETOOTH:
LOG(INFO) << "ClientProxy [IsLocalMultiplexSocketSupported]: "
<< (bitmask & kBtMultiplexEnabled);
return (bitmask & kBtMultiplexEnabled) != 0;
case Medium::WIFI_LAN:
return (bitmask & kWifiLanMultiplexEnabled) != 0;
default:
return false;
}
bool ClientProxy::GetWebRtcNonCellular() {
MutexLock lock(&mutex_);
return webrtc_non_cellular_;
}
std::optional<std::int32_t> ClientProxy::GetRemoteMultiplexSocketBitmask(
absl::string_view endpoint_id) const {
const ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
return item->first.remote_multiplex_socket_bitmask;
}
return std::nullopt;
}
bool ClientProxy::IsMultiplexSocketSupported(absl::string_view endpoint_id,
Medium medium) {
ConnectionPair* item = LookupConnection(endpoint_id);
if (item == nullptr) {
return false;
}
int combined_result = GetLocalMultiplexSocketBitmask() &
item->first.remote_multiplex_socket_bitmask;
switch (medium) {
case Medium::BLUETOOTH:
return (combined_result & kBtMultiplexEnabled) != 0;
case Medium::WIFI_LAN:
return (combined_result & kWifiLanMultiplexEnabled) != 0;
default:
return false;
}
}
bool ClientProxy::GetWebRtcNonCellular() { return webrtc_non_cellular_; }
void ClientProxy::SetWebRtcNonCellular(bool webrtc_non_cellular) {
MutexLock lock(&mutex_);
VLOG(1) << "ClientProxy: client=" << GetClientId()
<< (webrtc_non_cellular ? " disallow" : " allow")
<< " to use mobile data.";
webrtc_non_cellular_ = webrtc_non_cellular;
}
bool ClientProxy::IsDctEnabled() const { return is_dct_enabled_; }
bool ClientProxy::IsDctEnabled() const {
MutexLock lock(&mutex_);
return is_dct_enabled_;
}
uint8_t ClientProxy::GetDctDedup() const { return dct_dedup_; }
uint8_t ClientProxy::GetDctDedup() const {
MutexLock lock(&mutex_);
return dct_dedup_;
}
void ClientProxy::UpdateDctDeviceName(absl::string_view device_name) {
MutexLock lock(&mutex_);
if (!dct_device_name_.empty() && dct_device_name_ != device_name) {
// Need to update dedup value if device name is changed.
absl::BitGen bitgen;
@@ -1314,6 +1423,7 @@ void ClientProxy::UpdateDctDeviceName(absl::string_view device_name) {
std::optional<MediumRole> ClientProxy::GetMediumRole(
absl::string_view endpoint_id) const {
MutexLock lock(&mutex_);
const ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
return item->first.connection_options.connection_info.medium_role;
@@ -1322,6 +1432,7 @@ std::optional<MediumRole> ClientProxy::GetMediumRole(
}
std::optional<std::string> ClientProxy::GetEndpointIdForDct() const {
MutexLock lock(&mutex_);
if (dct_endpoint_id_.empty()) {
return std::nullopt;
}
@@ -1329,13 +1440,20 @@ std::optional<std::string> ClientProxy::GetEndpointIdForDct() const {
return dct_endpoint_id_;
}
#ifdef NEARBY_CHROMIUM
void ClientProxy::InitializePreferencesManager() {
// This method is not currently used by Chromium.
NOTREACHED();
}
#else
void ClientProxy::InitializePreferencesManager() {
LOG(INFO) << "ClientProxy [InitializePreferencesManager]: client="
<< GetClientId();
auto device_info_ = std::make_unique<nearby::DeviceInfoImpl>();
std::unique_ptr<nearby::api::DeviceInfo> device_info_ =
nearby::api::ImplementationPlatform::CreateDeviceInfo();
FilePath preferences_path =
device_info_->GetAppDataPath().append(FilePath(kPreferencesFilePath));
device_info_->GetLocalAppDataPath(FilePath(kPreferencesFilePath));
if (!Files::FileExists(preferences_path)) {
Files::CreateDirectories(preferences_path);
@@ -1350,6 +1468,7 @@ void ClientProxy::InitializePreferencesManager() {
<< GetClientId();
}
}
#endif
void ClientProxy::SaveClientInfoToPreferences() {
MutexLock lock(&mutex_);
+10 -34
View File
@@ -32,6 +32,7 @@
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/operation_result_with_medium.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
@@ -41,7 +42,6 @@
#include "connections/v3/connection_listening_options.h"
#include "connections/v3/connections_device_provider.h"
#include "connections/v3/listeners.h"
#include "internal/analytics/event_logger.h"
#include "internal/interop/device.h"
#include "internal/interop/device_provider.h"
#include "internal/platform/byte_array.h"
@@ -54,7 +54,6 @@
#include "internal/platform/mutex.h"
#include "internal/platform/os_name.h"
#include "internal/platform/scheduled_executor.h"
#include "internal/proto/analytics/connections_log.pb.h"
namespace nearby::connections {
@@ -66,8 +65,8 @@ class ClientProxy final {
static constexpr absl::Duration
kHighPowerAdvertisementEndpointIdCacheTimeout = absl::Seconds(30);
explicit ClientProxy(
::nearby::analytics::EventLogger* event_logger = nullptr);
explicit ClientProxy(std::unique_ptr<nearby::analytics::AnalyticsRecorder>
analytics_recorder = nullptr);
~ClientProxy();
ClientProxy(ClientProxy&&) = default;
ClientProxy& operator=(ClientProxy&&) = default;
@@ -109,8 +108,7 @@ class ClientProxy final {
const std::string& service_id, Strategy strategy,
const ConnectionListener& connection_lifecycle_listener,
absl::Span<location::nearby::proto::connections::Medium> mediums,
const std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>&
const std::vector<analytics::OperationResultWithMedium>&
operation_result_with_medium,
const AdvertisingOptions& advertising_options = AdvertisingOptions{});
// Marks this client as not advertising.
@@ -134,8 +132,7 @@ class ClientProxy final {
const std::string& service_id, Strategy strategy,
DiscoveryListener discovery_listener,
absl::Span<location::nearby::proto::connections::Medium> mediums,
const std::vector<location::nearby::analytics::proto::ConnectionsLog::
OperationResultWithMedium>&
const std::vector<analytics::OperationResultWithMedium>&
operation_result_with_medium,
const DiscoveryOptions& discovery_options = DiscoveryOptions{});
// Marks this client as not discovering at all.
@@ -264,7 +261,8 @@ class ClientProxy final {
// Adds a CancellationFlag for endpoint id.
void AddCancellationFlag(const std::string& endpoint_id);
// Returns the CancellationFlag for endpoint id,
CancellationFlag* GetCancellationFlag(const std::string& endpoint_id);
std::shared_ptr<CancellationFlag> GetCancellationFlag(
const std::string& endpoint_id);
// Sets the CancellationFlag to true for endpoint id.
void CancelEndpoint(const std::string& endpoint_id);
// Cancels all CancellationFlags.
@@ -311,19 +309,9 @@ class ClientProxy final {
bool IsSafeToDisconnectEnabled(absl::string_view endpoint_id);
bool IsPayloadReceivedAckEnabled(absl::string_view endpoint_id);
// Returns the multiplex socket supports status for local device.
std::int32_t GetLocalMultiplexSocketBitmask() const;
// Sets the multiplex socket supports status for remote device.
void SetRemoteMultiplexSocketBitmask(absl::string_view endpoint_id,
int remote_multiplex_socket_bitmask);
// Returns true if the multiplex socket is supported for the given medium.
bool IsLocalMultiplexSocketSupported(Medium medium);
// Gets the multiplex socket supports status for remote device.
std::optional<std::int32_t> GetRemoteMultiplexSocketBitmask(
absl::string_view endpoint_id) const;
// Returns true if the multiplex socket is supported for the given medium.
bool IsMultiplexSocketSupported(absl::string_view endpoint_id, Medium medium);
// Gets the WebRTC non cellular network status.
bool GetWebRtcNonCellular();
@@ -345,18 +333,6 @@ class ClientProxy final {
std::optional<location::nearby::connections::MediumRole> GetMediumRole(
absl::string_view endpoint_id) const;
/** Bitmask for bt multiplex connection support. */
// Note. Deprecates the first and second bit of BT_MULTIPLEX_ENABLED and
// WIFI_LAN_MULTIPLEX_ENABLED and shift them to the third and the forth bit.
// The reason is we need to escape the (0, 1) bit which has been set in some
// devices without salt enabled. If accompany with the devices with salted
// enabled, the frames passed cannot be decrypted and the connection shall be
// failed. Please refer to b/295925531#comment#14 for the details.
enum MultiplexSocketBitmask : uint32_t {
kBtMultiplexEnabled = 1 << 2,
kWifiLanMultiplexEnabled = 1 << 3,
};
// Forces client to regenerate a new local endpoint id.
void ClearCachedLocalEndpointId();
@@ -519,11 +495,11 @@ class ClientProxy final {
// Maps endpoint_id to CancellationFlag. CancellationFlags are passed around
// as raw pointers to other classes in Nearby Connections, so it is important
// that objects in this map are not cleared, even if they are cancelled.
absl::flat_hash_map<std::string, std::unique_ptr<CancellationFlag>>
absl::flat_hash_map<std::string, std::shared_ptr<CancellationFlag>>
cancellation_flags_;
// A default cancellation flag with isCancelled set be true.
std::unique_ptr<CancellationFlag> default_cancellation_flag_ =
std::make_unique<CancellationFlag>(true);
std::shared_ptr<CancellationFlag> default_cancellation_flag_ =
std::make_shared<CancellationFlag>(true);
// An app lifecycle monitor for monitoring the app lifecycle state.
std::unique_ptr<api::AppLifecycleMonitor> app_lifecycle_monitor_;
+93 -157
View File
@@ -14,6 +14,7 @@
#include "connections/implementation/client_proxy.h"
#include <atomic>
#include <cstdint>
#include <memory>
#include <optional>
@@ -32,17 +33,18 @@
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
#include "connections/discovery_options.h"
#include "connections/implementation/analytics/mock_analytics_recorder.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/payload.h"
#include "connections/status.h"
#include "connections/strategy.h"
#include "connections/v3/bandwidth_info.h"
#include "connections/v3/connection_listening_options.h"
#include "connections/v3/connection_result.h"
#include "connections/v3/connections_device_provider.h"
#include "connections/v3/listeners.h"
#include "internal/analytics/mock_event_logger.h"
#include "internal/flags/nearby_flags.h"
#include "internal/interop/device.h"
#include "internal/interop/device_provider.h"
@@ -51,19 +53,15 @@
#include "internal/platform/count_down_latch.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/single_thread_executor.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::proto::connections::CLIENT_SESSION;
using ::location::nearby::proto::connections::START_CLIENT_SESSION;
using ::location::nearby::proto::connections::STOP_CLIENT_SESSION;
using ::testing::_;
using ::testing::IsEmpty;
using ::testing::MockFunction;
using ::testing::StrictMock;
@@ -77,46 +75,6 @@ constexpr FeatureFlags::Flags kTestCases[] = {
},
};
class FakeEventLogger : public ::nearby::analytics::MockEventLogger {
public:
explicit FakeEventLogger() = default;
void Log(const ConnectionsLog& message) override {
MutexLock lock(&mutex_);
logs_.push_back(message);
}
int GetCompleteClientSessionCount() {
MutexLock lock(&mutex_);
bool has_start_client_session = false;
bool has_client_session = false;
int session_count = 0;
// We expect series of START_CLIENT_SESSION, CLIENT_SESSION and
// STOP_CLIENT_SESSION events, possibly interleaved with other events.
for (const auto& log : logs_) {
if (log.event_type() == START_CLIENT_SESSION) {
EXPECT_FALSE(has_start_client_session);
EXPECT_FALSE(has_client_session);
has_start_client_session = true;
} else if (log.event_type() == CLIENT_SESSION) {
EXPECT_TRUE(has_start_client_session);
EXPECT_FALSE(has_client_session);
has_client_session = true;
} else if (log.event_type() == STOP_CLIENT_SESSION) {
EXPECT_TRUE(has_start_client_session);
EXPECT_TRUE(has_client_session);
has_start_client_session = false;
has_client_session = false;
++session_count;
}
}
return session_count;
}
Mutex mutex_;
std::vector<ConnectionsLog> logs_;
};
class MockDeviceProvider : public nearby::NearbyDeviceProvider {
public:
MOCK_METHOD((const NearbyDevice*), GetLocalDevice, (), (override));
@@ -165,8 +123,14 @@ class ClientProxyTest : public ::testing::TestWithParam<FeatureFlags::Flags> {
/*use_simulated_clock=*/true,
/*use_temporary_directory_for_app_path=*/true};
env_.Start(config);
client1_ = std::make_unique<ClientProxy>(&event_logger1_);
client2_ = std::make_unique<ClientProxy>(&event_logger2_);
auto analytics_recorder1 =
std::make_unique<analytics::MockAnalyticsRecorder>();
mock_analytics_recorder1_ptr_ = analytics_recorder1.get();
client1_ = std::make_unique<ClientProxy>(std::move(analytics_recorder1));
auto analytics_recorder2 =
std::make_unique<analytics::MockAnalyticsRecorder>();
mock_analytics_recorder2_ptr_ = analytics_recorder2.get();
client2_ = std::make_unique<ClientProxy>(std::move(analytics_recorder2));
}
void TearDown() override {
@@ -360,10 +324,7 @@ class ClientProxyTest : public ::testing::TestWithParam<FeatureFlags::Flags> {
ClientProxy* client2() { return client2_.get(); }
void FastForward(absl::Duration duration) {
(*env_.GetSimulatedClock())
->FastForward(
ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout +
absl::Milliseconds(100));
env_.FastForward(duration);
// make sure the timer based callback is executed.
absl::SleepFor(absl::Milliseconds(100));
}
@@ -383,8 +344,8 @@ class ClientProxyTest : public ::testing::TestWithParam<FeatureFlags::Flags> {
MediumEnvironment& env_ = MediumEnvironment::Instance();
Strategy strategy_{Strategy::kP2pPointToPoint};
const std::string service_id_{"service"};
FakeEventLogger event_logger1_;
FakeEventLogger event_logger2_;
analytics::MockAnalyticsRecorder* mock_analytics_recorder1_ptr_;
analytics::MockAnalyticsRecorder* mock_analytics_recorder2_ptr_;
std::unique_ptr<ClientProxy> client1_;
std::unique_ptr<ClientProxy> client2_;
std::string auth_token_ = "auth_token";
@@ -437,7 +398,7 @@ TEST_P(ClientProxyTest, CanCancelEndpoint) {
// `CancellationFlag` pointers are passed to other classes in Nearby
// Connections, and by using the pointers directly, we test their
// consumption of `CancellationFlag` pointers.
CancellationFlag* cancellation_flag =
std::shared_ptr<CancellationFlag> cancellation_flag =
client2()->GetCancellationFlag(advertising_endpoint.id);
EXPECT_FALSE(
@@ -473,7 +434,7 @@ TEST_P(ClientProxyTest, CanCancelAllEndpoints) {
// `CancellationFlag` pointers are passed to other classes in Nearby
// Connections, and by using the pointers directly, we test their
// consumption of `CancellationFlag` pointers.
CancellationFlag* cancellation_flag =
std::shared_ptr<CancellationFlag> cancellation_flag =
client2()->GetCancellationFlag(advertising_endpoint.id);
EXPECT_FALSE(
@@ -540,6 +501,26 @@ TEST_P(ClientProxyTest, CanCancelAllEndpointsWithDifferentEndpoint) {
}
}
TEST_P(ClientProxyTest, GetCancellationFlagRace) {
std::string endpoint_id = "test_endpoint";
client1()->AddCancellationFlag(endpoint_id);
std::atomic<bool> run{true};
SingleThreadExecutor executor;
executor.Execute([&]() {
while (run) {
client1()->GetCancellationFlag(endpoint_id);
}
});
for (int i = 0; i < 10000; ++i) {
client1()->Reset();
client1()->AddCancellationFlag(endpoint_id);
}
run = false;
}
INSTANTIATE_TEST_SUITE_P(ParametrisedClientProxyTest, ClientProxyTest,
::testing::ValuesIn(kTestCases));
@@ -1161,11 +1142,13 @@ TEST_F(ClientProxyTest, NotLogSessionForStoppedAdvertisingWithConnection) {
// After
StopAdvertising(client1()); // No Advertising
EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0);
EXPECT_CALL(*mock_analytics_recorder1_ptr_, LogSession()).Times(1);
}
TEST_F(ClientProxyTest,
LogSessionForStoppedAdvertisingWhenNoConnectionsAndNoDiscovering) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
@@ -1174,36 +1157,47 @@ TEST_F(ClientProxyTest,
advertising_endpoint.id)); // No Connections
EXPECT_FALSE(client1()->IsDiscovering()); // No Discovery
EXPECT_TRUE(client1()->IsAdvertising()); // Advertising
EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0);
// After
EXPECT_CALL(*mock_analytics_recorder1_ptr_, OnStopAdvertising());
StopAdvertising(client1());
EXPECT_GT(event_logger1_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest, NotLogSessionForStoppedDiscoveryWithConnection) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartDiscovery(strategy_, mediums_, _));
StartDiscovery(client2(), GetDiscoveryListener());
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnEndpointFound(Medium::BLUETOOTH));
OnDiscoveryEndpointFound(client2(), advertising_endpoint);
// Before
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnConnectionRequestReceived(advertising_endpoint.id));
OnDiscoveryConnectionInitiated(
client2(), advertising_endpoint); // Connections are available
EXPECT_FALSE(client2()->IsAdvertising()); // No Advertising
EXPECT_TRUE(client2()->IsDiscovering()); // Discovering
// After
EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery());
StopDiscovery(client2());
EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest,
NotLogSessionForStoppedDiscoveryWithoutConnectionsAndAdvertising) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartDiscovery(strategy_, mediums_, _));
StartDiscovery(client2(), GetDiscoveryListener());
// Before
@@ -1213,30 +1207,40 @@ TEST_F(ClientProxyTest,
advertising_endpoint.id)); // No Connections
// After
EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery());
StopDiscovery(client2());
EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest, LogSessionOnDisconnectedWithOneConnection) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartDiscovery(strategy_, mediums_, _));
StartDiscovery(client2(), GetDiscoveryListener());
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnEndpointFound(Medium::BLUETOOTH));
OnDiscoveryEndpointFound(client2(), advertising_endpoint);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnConnectionRequestReceived(advertising_endpoint.id));
OnDiscoveryConnectionInitiated(client2(), advertising_endpoint);
// Before
EXPECT_FALSE(client2()->IsAdvertising()); // No Advertising
EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery());
StopDiscovery(client2()); // No Discovery
EXPECT_TRUE(client2()->HasPendingConnectionToEndpoint(
advertising_endpoint.id)); // One Connection
// After
OnDiscoveryConnectionDisconnected(client2(), advertising_endpoint);
EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest,
NotLogSessionOnDisconnectedWithoutConnectionsDiscoveringAdvertising) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
@@ -1248,13 +1252,16 @@ TEST_F(ClientProxyTest,
// After
client2()->OnDisconnected(advertising_endpoint.id, /*notify=*/false);
EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedWhenMoreThanOneConnection) {
ClientProxy client3;
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint_1 =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint_2 =
StartAdvertising(client2(), advertising_connection_listener_);
StartDiscovery(&client3, GetDiscoveryListener());
@@ -1275,15 +1282,22 @@ TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedWhenMoreThanOneConnection) {
// After
client2()->OnDisconnected(advertising_endpoint_1.id, /*notify=*/false);
EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest,
NotLogSessionOnDisconnectedForDiscoveringWithOnlyOneConnection) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartDiscovery(strategy_, mediums_, _));
StartDiscovery(client2(), GetDiscoveryListener());
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnEndpointFound(Medium::BLUETOOTH));
OnDiscoveryEndpointFound(client2(), advertising_endpoint);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnConnectionRequestReceived(advertising_endpoint.id));
OnDiscoveryConnectionInitiated(client2(), advertising_endpoint);
// Before
@@ -1294,26 +1308,27 @@ TEST_F(ClientProxyTest,
// After
OnDiscoveryConnectionDisconnected(client2(), advertising_endpoint);
// Since we are no longer checking IsDiscovering(), we complete sessions now
// solely based on advertising.
EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 1);
}
TEST_F(ClientProxyTest, LogSessionForResetClientProxy) {
EXPECT_CALL(*mock_analytics_recorder1_ptr_,
OnStartAdvertising(strategy_, mediums_, _));
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnStartDiscovery(strategy_, mediums_, _));
StartDiscovery(client2(), GetDiscoveryListener());
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnEndpointFound(Medium::BLUETOOTH));
OnDiscoveryEndpointFound(client2(), advertising_endpoint);
EXPECT_CALL(*mock_analytics_recorder2_ptr_,
OnConnectionRequestReceived(advertising_endpoint.id));
OnDiscoveryConnectionInitiated(client2(), advertising_endpoint);
EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0);
EXPECT_CALL(*mock_analytics_recorder1_ptr_, OnStopAdvertising());
client1()->Reset();
// TODO(b/290936886): Why are there more than one complete sessions?
EXPECT_GT(event_logger1_.GetCompleteClientSessionCount(), 0);
EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0);
EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery());
client2()->Reset();
EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0);
}
TEST_F(ClientProxyTest, GetLocalInfoCorrect) {
@@ -1483,91 +1498,12 @@ TEST_F(ClientProxyTest, TestAutoBwuWhenListeningWithAutoBwu) {
EXPECT_TRUE(client1()->AutoUpgradeBandwidth());
}
TEST_F(ClientProxyTest, TestMultiplexSocketBitmask) {
if (!NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplex)) {
EXPECT_EQ(client1()->GetLocalMultiplexSocketBitmask(), 0);
}
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableMultiplex,
true);
EXPECT_EQ(client1()->GetLocalMultiplexSocketBitmask(), 0);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth,
true);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexWifiLan,
true);
EXPECT_EQ(
client1()->GetLocalMultiplexSocketBitmask(),
ClientProxy::kBtMultiplexEnabled | ClientProxy::kWifiLanMultiplexEnabled);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableMultiplex,
false);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth,
false);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexWifiLan,
false);
}
TEST_F(ClientProxyTest, TestRemoteMultiplexSocketBitmask) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableMultiplex,
true);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth,
true);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexWifiLan,
true);
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), advertising_endpoint);
client1()->SetRemoteMultiplexSocketBitmask(
advertising_endpoint.id,
ClientProxy::kBtMultiplexEnabled | ClientProxy::kWifiLanMultiplexEnabled);
ASSERT_TRUE(client1()
->GetRemoteMultiplexSocketBitmask(advertising_endpoint.id)
.has_value());
EXPECT_EQ(
client1()
->GetRemoteMultiplexSocketBitmask(advertising_endpoint.id)
.value(),
ClientProxy::kBtMultiplexEnabled | ClientProxy::kWifiLanMultiplexEnabled);
EXPECT_TRUE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id,
Medium::BLUETOOTH));
EXPECT_TRUE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id,
Medium::WIFI_LAN));
EXPECT_FALSE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id,
Medium::WIFI_AWARE));
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableMultiplex,
false);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth,
false);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexWifiLan,
false);
}
TEST_F(ClientProxyTest, SaveClientInfoFromPreferences) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableNearbyConnectionsPreferences,
true);
client1_ = std::make_unique<ClientProxy>(&event_logger1_);
client1_ = std::make_unique<ClientProxy>();
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
std::string endpoint_id = advertising_endpoint.id;
@@ -1575,7 +1511,7 @@ TEST_F(ClientProxyTest, SaveClientInfoFromPreferences) {
// Destroy the client and create a new one.
client1_.reset();
client1_ = std::make_unique<ClientProxy>(&event_logger1_);
client1_ = std::make_unique<ClientProxy>();
// The new client should load the same endpoint ID.
EXPECT_EQ(client1()->GetLocalEndpointId(), endpoint_id);
@@ -1590,7 +1526,7 @@ TEST_F(ClientProxyTest, NotLoadClientInfoFromPreferencesOnExpired) {
config_package_nearby::nearby_connections_feature::
kEnableNearbyConnectionsPreferences,
true);
client1_ = std::make_unique<ClientProxy>(&event_logger1_);
client1_ = std::make_unique<ClientProxy>();
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
std::string endpoint_id = advertising_endpoint.id;
@@ -1600,7 +1536,7 @@ TEST_F(ClientProxyTest, NotLoadClientInfoFromPreferencesOnExpired) {
client1_.reset();
FastForward(absl::Hours(25));
client1_ = std::make_unique<ClientProxy>(&event_logger1_);
client1_ = std::make_unique<ClientProxy>();
// The new client should load the same endpoint ID.
EXPECT_NE(client1()->GetLocalEndpointId(), endpoint_id);
@@ -14,30 +14,30 @@
#include "connections/implementation/connections_authentication_transport.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "connections/implementation/endpoint_channel.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace connections {
ConnectionsAuthenticationTransport::ConnectionsAuthenticationTransport(
const EndpointChannel& channel) {
channel_ = const_cast<EndpointChannel*>(&channel);
}
std::shared_ptr<EndpointChannel> channel)
: channel_(std::move(channel)) {}
void ConnectionsAuthenticationTransport::WriteMessage(
absl::string_view message) const {
// channel_ should never be null.
// channel_ is guaranteed valid by shared_ptr ownership
CHECK(channel_ != nullptr);
channel_->Write(ByteArray(message.data(), message.size()));
channel_->Write(message);
}
std::string ConnectionsAuthenticationTransport::ReadMessage() const {
// channel_ should never be null.
// channel_ is guaranteed valid by shared_ptr ownership
CHECK(channel_ != nullptr);
auto response = channel_->Read();
if (response.ok()) {
@@ -15,6 +15,7 @@
#ifndef THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_
#define THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
@@ -30,12 +31,13 @@ namespace connections {
class ConnectionsAuthenticationTransport
: public nearby::AuthenticationTransport {
public:
explicit ConnectionsAuthenticationTransport(const EndpointChannel& channel);
explicit ConnectionsAuthenticationTransport(
std::shared_ptr<EndpointChannel> channel);
void WriteMessage(absl::string_view message) const override;
std::string ReadMessage() const override;
private:
EndpointChannel* channel_;
std::shared_ptr<EndpointChannel> channel_;
};
} // namespace connections
@@ -14,7 +14,6 @@
#include "connections/implementation/connections_authentication_transport.h"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
@@ -23,12 +22,9 @@
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mock_endpoint_channel.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
@@ -36,84 +32,40 @@ namespace {
using ::testing::_;
class MockEndpointChannel : public EndpointChannel {
public:
MOCK_METHOD(ExceptionOr<ByteArray>, Read, (), (override));
MOCK_METHOD(ExceptionOr<ByteArray>, Read, (PacketMetaData&), (override));
MOCK_METHOD(Exception, Write, (const ByteArray& data), (override));
MOCK_METHOD(Exception, Write, (absl::string_view data, PacketMetaData&),
(override));
MOCK_METHOD(void, Close, (), (override));
MOCK_METHOD(
void, Close,
(location::nearby::proto::connections::DisconnectionReason reason),
(override));
MOCK_METHOD(void, Close,
(location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result),
(override));
MOCK_METHOD(bool, IsClosed, (), (const, override));
MOCK_METHOD(std::string, GetType, (), (const, override));
MOCK_METHOD(std::string, GetServiceId, (), (const, override));
MOCK_METHOD(std::string, GetName, (), (const, override));
MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (),
(const, override));
MOCK_METHOD(location::nearby::proto::connections::ConnectionTechnology,
GetTechnology, (), (const, override));
MOCK_METHOD(location::nearby::proto::connections::ConnectionBand, GetBand, (),
(const, override));
MOCK_METHOD(int, GetFrequency, (), (const, override));
MOCK_METHOD(int, GetTryCount, (), (const, override));
MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const, override));
MOCK_METHOD(void, EnableEncryption, (std::shared_ptr<EncryptionContext>),
(override));
MOCK_METHOD(void, DisableEncryption, (), (override));
MOCK_METHOD(bool, IsEncrypted, (), (override));
MOCK_METHOD(ExceptionOr<ByteArray>, TryDecrypt, (const ByteArray& data),
(override));
MOCK_METHOD(bool, IsPaused, (), (const, override));
MOCK_METHOD(void, Pause, (), (override));
MOCK_METHOD(void, Resume, (), (override));
MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override));
MOCK_METHOD(absl::Time, GetLastWriteTimestamp, (), (const, override));
MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override));
MOCK_METHOD(void, SetAnalyticsRecorder,
(analytics::AnalyticsRecorder*, const std::string&), (override));
std::vector<std::string> messages_;
};
TEST(ConnectionsAuthenticationTransportTest, TestWriteMessage) {
MockEndpointChannel channel;
std::vector<std::string> messages;
auto channel = std::make_shared<MockEndpointChannel>();
ConnectionsAuthenticationTransport transport(channel);
EXPECT_CALL(channel, Write(_)).WillOnce([&channel](const ByteArray& data) {
channel.messages_.push_back(data.string_data());
return Exception{
.value = Exception::Value::kSuccess,
};
});
EXPECT_CALL(*channel, Write(_))
.WillOnce([&messages](absl::string_view data) {
messages.push_back(std::string(data));
return Exception{
.value = Exception::Value::kSuccess,
};
});
transport.WriteMessage("hello world");
EXPECT_THAT(channel.messages_, testing::ElementsAre("hello world"));
EXPECT_THAT(messages, testing::ElementsAre("hello world"));
}
TEST(ConnectionsAuthenticationTransportTest, TestReadMessage) {
MockEndpointChannel channel;
std::vector<std::string> messages;
auto channel = std::make_shared<MockEndpointChannel>();
ConnectionsAuthenticationTransport transport(channel);
channel.messages_.push_back("hello world");
EXPECT_CALL(channel, Read()).WillOnce([&channel]() {
std::string ret = channel.messages_[0];
channel.messages_.erase(channel.messages_.begin());
messages.push_back("hello world");
EXPECT_CALL(*channel, Read()).WillOnce([&messages]() {
std::string ret = messages[0];
messages.erase(messages.begin());
return ExceptionOr<ByteArray>(ByteArray(ret));
});
EXPECT_EQ(transport.ReadMessage(), "hello world");
}
TEST(ConnectionsAuthenticationTransportTest, TestReadMessageFail) {
MockEndpointChannel channel;
std::vector<std::string> messages;
auto channel = std::make_shared<MockEndpointChannel>();
ConnectionsAuthenticationTransport transport(channel);
channel.messages_.push_back("hello world");
EXPECT_CALL(channel, Read()).WillOnce([]() {
messages.push_back("hello world");
EXPECT_CALL(*channel, Read()).WillOnce([]() {
return ExceptionOr<ByteArray>(Exception::Value::kIo);
});
EXPECT_EQ(transport.ReadMessage(), "");
+65 -42
View File
@@ -14,7 +14,6 @@
#include "connections/implementation/encryption_runner.h"
#include <cinttypes>
#include <cstdint>
#include <memory>
#include <string>
@@ -22,7 +21,6 @@
#include "securegcm/ukey2_handshake.h"
#include "absl/strings/ascii.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
@@ -70,9 +68,9 @@ bool HandleEncryptionSuccess(const std::string& endpoint_id,
return true;
}
void CancelableAlarmRunnable(ClientProxy* client,
const std::string& endpoint_id,
EndpointChannel* endpoint_channel) {
void CancelableAlarmRunnable(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel) {
LOG(INFO) << "Timing out encryption for client " << client->GetClientId()
<< " to endpoint_id=" << endpoint_id << " after "
<< absl::FormatDuration(kTimeout);
@@ -82,18 +80,31 @@ void CancelableAlarmRunnable(ClientProxy* client,
class ServerRunnable final {
public:
ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor,
const std::string& endpoint_id, EndpointChannel* channel,
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> channel,
EncryptionRunner::ResultListener listener)
: client_(client),
alarm_executor_(alarm_executor),
endpoint_id_(endpoint_id),
channel_(channel),
weak_channel_(channel),
listener_(std::move(listener)) {}
void operator()() {
// Lock the weak pointer. If it fails, the channel was freed.
auto channel = weak_channel_.lock();
// The IsClosed() check is to provide an early exit if channel has been
// closed. Otherwise the Read() and Write() calls on the channel below will
// return error and exit.
if (!channel || channel->IsClosed()) {
return;
}
CancelableAlarm timeout_alarm(
"EncryptionRunner.StartServer() timeout",
[this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); },
[this, weak_channel = weak_channel_]() {
if (auto channel = weak_channel.lock()) {
CancelableAlarmRunnable(client_, endpoint_id_, channel);
}
},
kTimeout, alarm_executor_);
std::unique_ptr<securegcm::UKey2Handshake> server =
@@ -105,7 +116,7 @@ class ServerRunnable final {
}
// Message 1 (Client Init)
ExceptionOr<ByteArray> client_init = channel_->Read();
ExceptionOr<ByteArray> client_init = channel->Read();
if (!client_init.ok()) {
LogException();
HandleHandshakeOrIoException(&timeout_alarm);
@@ -119,7 +130,7 @@ class ServerRunnable final {
if (!parse_result.success) {
LogException();
if (parse_result.alert_to_send != nullptr) {
HandleAlertException(parse_result);
HandleAlertException(parse_result, channel);
}
HandleHandshakeOrIoException(&timeout_alarm);
return;
@@ -139,8 +150,7 @@ class ServerRunnable final {
return;
}
Exception write_exception =
channel_->Write(ByteArray(std::move(*server_init)));
Exception write_exception = channel->Write(*server_init);
if (!write_exception.Ok()) {
LogException();
HandleHandshakeOrIoException(&timeout_alarm);
@@ -151,7 +161,7 @@ class ServerRunnable final {
<< endpoint_id_ << ").";
// Message 3 (Client Finish)
ExceptionOr<ByteArray> client_finish = channel_->Read();
ExceptionOr<ByteArray> client_finish = channel->Read();
if (!client_finish.ok()) {
LogException();
@@ -166,7 +176,7 @@ class ServerRunnable final {
if (!parse_result.success) {
LogException();
if (parse_result.alert_to_send != nullptr) {
HandleAlertException(parse_result);
HandleAlertException(parse_result, channel);
}
HandleHandshakeOrIoException(&timeout_alarm);
return;
@@ -192,13 +202,13 @@ class ServerRunnable final {
void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) {
timeout_alarm->Cancel();
listener_.CallFailureCallback(endpoint_id_, channel_);
listener_.CallFailureCallback(endpoint_id_);
}
void HandleAlertException(
const securegcm::UKey2Handshake::ParseResult& parse_result) const {
Exception write_exception =
channel_->Write(ByteArray(*parse_result.alert_to_send));
const securegcm::UKey2Handshake::ParseResult& parse_result,
std::shared_ptr<EndpointChannel> channel) const {
Exception write_exception = channel->Write(*parse_result.alert_to_send);
if (!write_exception.Ok()) {
LOG(WARNING) << "In StartServer(), client " << client_->GetClientId()
<< " failed to pass the alert error message to endpoint(id="
@@ -209,25 +219,39 @@ class ServerRunnable final {
ClientProxy* client_;
ScheduledExecutor* alarm_executor_;
const std::string endpoint_id_;
EndpointChannel* channel_;
std::weak_ptr<EndpointChannel> weak_channel_;
EncryptionRunner::ResultListener listener_;
};
class ClientRunnable final {
public:
ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor,
const std::string& endpoint_id, EndpointChannel* channel,
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> channel,
EncryptionRunner::ResultListener listener)
: client_(client),
alarm_executor_(alarm_executor),
endpoint_id_(endpoint_id),
channel_(channel),
weak_channel_(channel),
listener_(std::move(listener)) {}
void operator()() {
// Lock the weak pointer. If it fails, the channel was freed.
auto channel = weak_channel_.lock();
// The IsClosed() check is to provide an early exit if channel has been
// closed. Otherwise the Read() and Write() calls on the channel below will
// return error and exit.
if (!channel || channel->IsClosed()) {
return;
}
CancelableAlarm timeout_alarm(
"EncryptionRunner.StartClient() timeout",
[this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); },
[this, weak_channel = weak_channel_]() {
if (auto channel = weak_channel.lock()) {
CancelableAlarmRunnable(client_, endpoint_id_, channel);
}
},
kTimeout, alarm_executor_);
std::unique_ptr<securegcm::UKey2Handshake> crypto =
@@ -251,7 +275,7 @@ class ClientRunnable final {
return;
}
Exception write_init_exception = channel_->Write(ByteArray(*client_init));
Exception write_init_exception = channel->Write(*client_init);
if (!write_init_exception.Ok()) {
LogException();
HandleHandshakeOrIoException(&timeout_alarm);
@@ -262,7 +286,7 @@ class ClientRunnable final {
<< endpoint_id_ << ").";
// Message 2 (Server Init)
ExceptionOr<ByteArray> server_init = channel_->Read();
ExceptionOr<ByteArray> server_init = channel->Read();
if (!server_init.ok()) {
LogException();
@@ -277,7 +301,7 @@ class ClientRunnable final {
if (!parse_result.success) {
LogException();
if (parse_result.alert_to_send != nullptr) {
HandleAlertException(parse_result);
HandleAlertException(parse_result, channel);
}
HandleHandshakeOrIoException(&timeout_alarm);
return;
@@ -297,8 +321,7 @@ class ClientRunnable final {
return;
}
Exception write_finish_exception =
channel_->Write(ByteArray(*client_finish));
Exception write_finish_exception = channel->Write(*client_finish);
if (!write_finish_exception.Ok()) {
LogException();
HandleHandshakeOrIoException(&timeout_alarm);
@@ -325,13 +348,13 @@ class ClientRunnable final {
void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) {
timeout_alarm->Cancel();
listener_.CallFailureCallback(endpoint_id_, channel_);
listener_.CallFailureCallback(endpoint_id_);
}
void HandleAlertException(
const securegcm::UKey2Handshake::ParseResult& parse_result) const {
Exception write_exception =
channel_->Write(ByteArray(*parse_result.alert_to_send));
const securegcm::UKey2Handshake::ParseResult& parse_result,
std::shared_ptr<EndpointChannel> channel) const {
Exception write_exception = channel->Write(*parse_result.alert_to_send);
if (!write_exception.Ok()) {
LOG(WARNING) << "In StartClient(), client " << client_->GetClientId()
<< " failed to pass the alert error message to endpoint(id="
@@ -342,7 +365,7 @@ class ClientRunnable final {
ClientProxy* client_;
ScheduledExecutor* alarm_executor_;
const std::string endpoint_id_;
EndpointChannel* channel_;
std::weak_ptr<EndpointChannel> weak_channel_;
EncryptionRunner::ResultListener listener_;
};
@@ -350,19 +373,19 @@ class ClientRunnable final {
EncryptionRunner::~EncryptionRunner() { Shutdown(); }
void EncryptionRunner::StartServer(ClientProxy* client,
const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
EncryptionRunner::ResultListener listener) {
void EncryptionRunner::StartServer(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel,
EncryptionRunner::ResultListener listener) {
ServerRunnable runnable(client, &alarm_executor_, endpoint_id,
endpoint_channel, std::move(listener));
server_executor_.Execute("encryption-server", std::move(runnable));
}
void EncryptionRunner::StartClient(ClientProxy* client,
const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
EncryptionRunner::ResultListener listener) {
void EncryptionRunner::StartClient(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel,
EncryptionRunner::ResultListener listener) {
ClientRunnable runnable(client, &alarm_executor_, endpoint_id,
endpoint_channel, std::move(listener));
client_executor_.Execute("encryption-client", std::move(runnable));
@@ -391,9 +414,9 @@ void EncryptionRunner::ResultListener::CallSuccessCallback(
}
void EncryptionRunner::ResultListener::CallFailureCallback(
const std::string& endpoint_id, EndpointChannel* channel) {
const std::string& endpoint_id) {
if (on_failure_cb) {
std::move(on_failure_cb)(endpoint_id, channel);
std::move(on_failure_cb)(endpoint_id);
}
Reset();
}
+5 -14
View File
@@ -45,8 +45,7 @@ class EncryptionRunner {
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token,
const ByteArray& raw_auth_token);
void CallFailureCallback(const std::string& endpoint_id,
EndpointChannel* channel);
void CallFailureCallback(const std::string& endpoint_id);
void Reset();
// @EncryptionRunnerThread
@@ -56,27 +55,19 @@ class EncryptionRunner {
const ByteArray& raw_auth_token) &&>
on_success_cb;
// Encryption has failed. The remote_endpoint_id and channel are given so
// that any pending state can be cleaned up.
//
// We return the EndpointChannel because, at this stage, simultaneous
// connections are a possibility. Use this channel to verify that the state
// you're cleaning up is for this EndpointChannel, and not state for another
// channel to the same endpoint.
// Encryption has failed.
//
// @EncryptionRunnerThread
absl::AnyInvocable<void(const std::string& endpoint_id,
EndpointChannel* channel) &&>
on_failure_cb;
absl::AnyInvocable<void(const std::string& endpoint_id)> on_failure_cb;
};
// @AnyThread
void StartServer(ClientProxy* client, const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
ResultListener result_listener);
// @AnyThread
void StartClient(ClientProxy* client, const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
ResultListener result_listener);
// @AnyThread
@@ -35,8 +35,7 @@
#include "proto/connections_enums.pb.h"
#include "third_party/ukey2/src/main/cpp/include/securegcm/ukey2_handshake.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::proto::connections::Medium;
@@ -52,16 +51,8 @@ class FakeEndpointChannel : public EndpointChannel {
read_timestamp_ = SystemClock::ElapsedRealtime();
return in_ ? in_->Read(kChunkSize) : ExceptionOr<ByteArray>{Exception::kIo};
}
ExceptionOr<ByteArray> Read(PacketMetaData& packet_meta_data) override {
read_timestamp_ = SystemClock::ElapsedRealtime();
return in_ ? in_->Read(kChunkSize) : ExceptionOr<ByteArray>{Exception::kIo};
}
Exception Write(const ByteArray& data) override {
write_timestamp_ = SystemClock::ElapsedRealtime();
return out_ ? out_->Write(data.AsStringView()) : Exception{Exception::kIo};
}
Exception Write(absl::string_view data,
PacketMetaData& packet_meta_data) override {
Exception Write(absl::string_view data) override {
write_timestamp_ = SystemClock::ElapsedRealtime();
return out_ ? out_->Write(data) : Exception{Exception::kIo};
}
@@ -73,10 +64,8 @@ class FakeEndpointChannel : public EndpointChannel {
override {
Close();
}
void Close(
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result) override {
void Close(location::nearby::proto::connections::DisconnectionReason reason,
nearby::analytics::SafeDisconnectionResult result) override {
Close();
}
bool IsClosed() const override { return false; }
@@ -124,21 +113,24 @@ class FakeEndpointChannel : public EndpointChannel {
};
struct User {
User(InputStream* reader, OutputStream* writer) : channel(reader, writer) {}
User(InputStream* reader, OutputStream* writer)
: channel(std::make_shared<FakeEndpointChannel>(reader, writer)) {}
FakeEndpointChannel channel;
std::shared_ptr<FakeEndpointChannel> channel;
EncryptionRunner crypto;
ClientProxy client;
};
struct Response {
Response() : latch(2) {}
explicit Response(int count) : latch(count) {}
enum class Status {
kUnknown = 0,
kDone = 1,
kFailed = 2,
};
CountDownLatch latch{2};
CountDownLatch latch;
Status server_status = Status::kUnknown;
Status client_status = Status::kUnknown;
};
@@ -155,7 +147,7 @@ TEST(EncryptionRunnerTest, ReadWrite) {
Response response;
user_a.crypto.StartServer(
&user_a.client, "endpoint_id", &user_a.channel,
&user_a.client, "endpoint_id", user_a.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -166,15 +158,14 @@ TEST(EncryptionRunnerTest, ReadWrite) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_a](const std::string& endpoint_id) {
user_a.channel->Close();
response.server_status = Response::Status::kFailed;
response.latch.CountDown();
},
});
user_b.crypto.StartClient(
&user_b.client, "endpoint_id", &user_b.channel,
&user_b.client, "endpoint_id", user_b.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -185,9 +176,8 @@ TEST(EncryptionRunnerTest, ReadWrite) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_b](const std::string& endpoint_id) {
user_b.channel->Close();
response.client_status = Response::Status::kFailed;
response.latch.CountDown();
},
@@ -204,14 +194,13 @@ TEST(EncryptionRunnerTest, ClientWriteFails) {
/*writer=*/from_a_to_b.second.get());
User user_b(/*reader=*/from_a_to_b.first.get(),
/*writer=*/from_b_to_a.second.get());
Response response;
response.latch = CountDownLatch(1);
Response response(1);
// Close server's input stream, so client can't write to it.
from_b_to_a.first->Close();
user_b.crypto.StartClient(
&user_b.client, "endpoint_id", &user_b.channel,
&user_b.client, "endpoint_id", user_b.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -222,9 +211,8 @@ TEST(EncryptionRunnerTest, ClientWriteFails) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_a](const std::string& endpoint_id) {
user_a.channel->Close();
response.client_status = Response::Status::kFailed;
response.latch.CountDown();
},
@@ -240,14 +228,13 @@ TEST(EncryptionRunnerTest, ServerWriteFails) {
/*writer=*/from_a_to_b.second.get());
User user_b(/*reader=*/from_a_to_b.first.get(),
/*writer=*/from_b_to_a.second.get());
Response response;
response.latch = CountDownLatch(1);
Response response(1);
// Close client's input stream, so server can't write to it.
from_a_to_b.first->Close();
user_a.crypto.StartServer(
&user_a.client, "endpoint_id", &user_a.channel,
&user_a.client, "endpoint_id", user_a.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -258,24 +245,22 @@ TEST(EncryptionRunnerTest, ServerWriteFails) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_a](const std::string& endpoint_id) {
user_a.channel->Close();
response.server_status = Response::Status::kFailed;
response.latch.CountDown();
},
});
user_b.crypto.StartClient(
&user_b.client, "endpoint_id", &user_b.channel,
&user_b.client, "endpoint_id", user_b.channel,
{
.on_success_cb =
[](const std::string& endpoint_id,
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token,
const ByteArray& raw_auth_token) {},
.on_success_cb = [](const std::string& endpoint_id,
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
const std::string& auth_token,
const ByteArray& raw_auth_token) {},
.on_failure_cb =
[](const std::string& endpoint_id, EndpointChannel* channel) {
channel->Close();
[&user_b](const std::string& endpoint_id) {
user_b.channel->Close();
},
});
EXPECT_TRUE(response.latch.Await(absl::Milliseconds(5000)).result());
@@ -287,11 +272,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) {
auto from_client_to_server = CreatePipe();
User user_a(/*reader=*/from_client_to_server.first.get(),
/*writer=*/from_server_to_client.second.get());
Response response;
response.latch = CountDownLatch(1);
Response response(1);
user_a.crypto.StartServer(
&user_a.client, "endpoint_id", &user_a.channel,
&user_a.client, "endpoint_id", user_a.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -302,9 +286,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_a](const std::string& endpoint_id) {
user_a.channel->Close();
response.server_status = Response::Status::kFailed;
response.latch.CountDown();
},
@@ -328,11 +311,10 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) {
auto from_client_to_server = CreatePipe();
User user_b(/*reader=*/from_server_to_client.first.get(),
/*writer=*/from_client_to_server.second.get());
Response response;
response.latch = CountDownLatch(1);
Response response(1);
user_b.crypto.StartClient(
&user_b.client, "endpoint_id", &user_b.channel,
&user_b.client, "endpoint_id", user_b.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -343,9 +325,8 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_b](const std::string& endpoint_id) {
user_b.channel->Close();
response.client_status = Response::Status::kFailed;
response.latch.CountDown();
},
@@ -374,11 +355,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
/*writer=*/from_server_to_client.second.get());
User user_b(/*reader=*/from_server_to_client.first.get(),
/*writer=*/from_client_to_server.second.get());
Response response;
response.latch = CountDownLatch(1);
Response response(1);
user_a.crypto.StartServer(
&user_a.client, "endpoint_id", &user_a.channel,
&user_a.client, "endpoint_id", user_a.channel,
{
.on_success_cb =
[&response](const std::string& endpoint_id,
@@ -389,9 +369,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
response.latch.CountDown();
},
.on_failure_cb =
[&response](const std::string& endpoint_id,
EndpointChannel* channel) {
channel->Close();
[&response, &user_a](const std::string& endpoint_id) {
user_a.channel->Close();
response.server_status = Response::Status::kFailed;
response.latch.CountDown();
},
@@ -411,7 +390,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
EXPECT_TRUE(server_init.ok());
// Client crypto parses message 2.
client_crypto->ParseHandshakeMessage(std::string(server_init.result()));
client_crypto->ParseHandshakeMessage(
std::string(server_init.result().data(), server_init.result().size()));
// Client sends garbage instead of message 3
from_client_to_server.second->Write("Garbage");
@@ -427,5 +407,4 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
}
} // namespace
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
+4 -16
View File
@@ -23,14 +23,10 @@
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
namespace nearby {
namespace connections {
using analytics::PacketMetaData;
namespace nearby::connections {
class EndpointChannel {
public:
@@ -41,15 +37,9 @@ class EndpointChannel {
virtual ExceptionOr<ByteArray>
Read() = 0; // throws Exception::IO, Exception::INTERRUPTED
virtual ExceptionOr<ByteArray> Read(PacketMetaData& packet_meta_data) = 0;
virtual Exception Write(absl::string_view data) = 0; // throws Exception::IO
virtual Exception Write(const ByteArray& data) = 0; // throws Exception::IO
virtual Exception Write(
absl::string_view data,
PacketMetaData& packet_meta_data) = 0; // throws Exception::IO
// Closes this EndpointChannel, without tracking the closure in analytics.
virtual void Close() = 0;
// Closes this EndpointChannel and records the closure with the given reason.
@@ -60,8 +50,7 @@ class EndpointChannel {
// and safe disconnection result.
virtual void Close(
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result) = 0;
nearby::analytics::SafeDisconnectionResult result) = 0;
// True if the EndpointChannel is currently closed.
virtual bool IsClosed() const = 0;
@@ -150,7 +139,6 @@ inline bool operator!=(const EndpointChannel& lhs, const EndpointChannel& rhs) {
return !(lhs == rhs);
}
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
#endif // CORE_INTERNAL_ENDPOINT_CHANNEL_H_
@@ -29,10 +29,7 @@
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
namespace nearby {
namespace connections {
using ::location::nearby::analytics::proto::ConnectionsLog;
namespace nearby::connections {
namespace {
const absl::Duration kDataTransferDelay = absl::Milliseconds(500);
}
@@ -46,7 +43,7 @@ EndpointChannelManager::~EndpointChannelManager() {
void EndpointChannelManager::RegisterChannelForEndpoint(
ClientProxy* client, const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel) {
std::shared_ptr<EndpointChannel> channel) {
MutexLock lock(&mutex_);
LOG(INFO) << "EndpointChannelManager registered channel of type "
@@ -59,7 +56,7 @@ void EndpointChannelManager::RegisterChannelForEndpoint(
void EndpointChannelManager::ReplaceChannelForEndpoint(
ClientProxy* client, const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel, bool enable_encryption) {
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
MutexLock lock(&mutex_);
if (client->IsSafeToDisconnectEnabled(endpoint_id) &&
channel_state_.IsWaitingForSafeToDisconnectTimeout(endpoint_id)) {
@@ -106,7 +103,7 @@ std::shared_ptr<EndpointChannel> EndpointChannelManager::GetChannelForEndpoint(
void EndpointChannelManager::SetActiveEndpointChannel(
ClientProxy* client, const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel, bool enable_encryption) {
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);
@@ -183,13 +180,13 @@ void EndpointChannelManager::ChannelState::DestroyAll() {
for (auto& item : endpoints_) {
RemoveEndpoint(item.first, DisconnectionReason::SHUTDOWN,
/* safe_to_disconnect_enabled */ false,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
}
endpoints_.clear();
}
void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint(
const std::string& endpoint_id, std::unique_ptr<EndpointChannel> channel) {
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);
}
@@ -365,5 +362,4 @@ bool EndpointChannelManager::UnregisterChannelForEndpoint(
return true;
}
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
@@ -21,18 +21,16 @@
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "internal/platform/mutex.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
using DisconnectionReason =
::location::nearby::proto::connections::DisconnectionReason;
using SafeDisconnectionResult = ::location::nearby::analytics::proto::
ConnectionsLog::EstablishedConnection::SafeDisconnectionResult;
using SafeDisconnectionResult = nearby::analytics::SafeDisconnectionResult;
// NOTE(std::string):
// All the strings in internal class public interfaces should be exchanged as
@@ -59,7 +57,7 @@ class EndpointChannelManager final {
// be closed before continuing the registration.
void RegisterChannelForEndpoint(ClientProxy* client,
const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel)
std::shared_ptr<EndpointChannel> channel)
ABSL_LOCKS_EXCLUDED(mutex_);
// Replaces the EndpointChannel to be associated with an endpoint from here on
@@ -67,7 +65,7 @@ class EndpointChannelManager final {
// to the newly-provided EndpointChannel.
void ReplaceChannelForEndpoint(ClientProxy* client,
const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel,
std::shared_ptr<EndpointChannel> channel,
bool enable_encryption)
ABSL_LOCKS_EXCLUDED(mutex_);
@@ -168,7 +166,7 @@ class EndpointChannelManager final {
// Stores a new EndpointChannel for the endpoint.
// Prevoius one is destroyed, if it existed.
void UpdateChannelForEndpoint(const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel);
std::shared_ptr<EndpointChannel> channel);
// Stores a new EncryptionContext for the endpoint.
// Prevoius one is destroyed, if it existed.
@@ -207,7 +205,7 @@ class EndpointChannelManager final {
void SetActiveEndpointChannel(ClientProxy* client,
const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> channel,
std::shared_ptr<EndpointChannel> channel,
bool enable_encryption)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
@@ -215,7 +213,6 @@ class EndpointChannelManager final {
ChannelState channel_state_;
};
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
#endif // CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_
@@ -27,6 +27,7 @@
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/base_endpoint_channel.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/encryption_runner.h"
@@ -39,16 +40,14 @@
#include "internal/platform/multi_thread_executor.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/pipe.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::proto::connections::DisconnectionReason;
using ::location::nearby::proto::connections::Medium;
using ::nearby::analytics::SafeDisconnectionResult;
using EncryptionContext = BaseEndpointChannel::EncryptionContext;
constexpr size_t kChunkSize = 64 * 1024;
@@ -110,8 +109,8 @@ std::function<void(const ByteArray&)> MakeDataMonitor(absl::string_view label,
std::pair<std::unique_ptr<EncryptionContext>,
std::unique_ptr<EncryptionContext>>
DoDhKeyExchange(BaseEndpointChannel* channel_a,
BaseEndpointChannel* channel_b) {
DoDhKeyExchange(std::shared_ptr<EndpointChannel> channel_a,
std::shared_ptr<EndpointChannel> channel_b) {
std::unique_ptr<EncryptionContext> context_a;
std::unique_ptr<EncryptionContext> context_b;
EncryptionRunner crypto_a;
@@ -136,8 +135,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
latch.CountDown();
},
.on_failure_cb =
[&latch](const std::string& endpoint_id,
EndpointChannel* channel) {
[&latch](const std::string& endpoint_id) {
LOG(INFO) << "client-A side key negotiation failed";
latch.CountDown();
},
@@ -159,8 +157,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
latch.CountDown();
},
.on_failure_cb =
[&latch](const std::string& endpoint_id,
EndpointChannel* channel) {
[&latch](const std::string& endpoint_id) {
LOG(INFO) << "client-B side key negotiation failed";
latch.CountDown();
},
@@ -185,9 +182,9 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
// to server "b".
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
// to server "a".
auto channel_a = std::make_unique<MockEndpointChannel>(server_a.first.get(),
auto channel_a = std::make_shared<MockEndpointChannel>(server_a.first.get(),
client_a.second.get());
auto channel_b = std::make_unique<MockEndpointChannel>(server_b.first.get(),
auto channel_b = std::make_shared<MockEndpointChannel>(server_b.first.get(),
client_b.second.get());
auto channel_a_raw = channel_a.get();
auto channel_b_raw = channel_b.get();
@@ -208,7 +205,7 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
MakeDataMonitor(kMonitorB, &capture_b, &mutex)));
// Run DH key exchange; setup encryption contexts for channels.
auto context = DoDhKeyExchange(channel_a.get(), channel_b.get());
auto context = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context.first, nullptr);
ASSERT_NE(context.second, nullptr);
@@ -227,12 +224,12 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
EXPECT_EQ(channel_a_raw->GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_EQ(channel_b_raw->GetType(), "ENCRYPTED_BLUETOOTH");
ByteArray tx_message{"data message"};
absl::string_view tx_message = "data message";
channel_a_raw->Write(tx_message);
ByteArray rx_message = std::move(channel_b_raw->Read().result());
// Verify expectations.
EXPECT_EQ(rx_message, tx_message);
EXPECT_EQ(rx_message.AsStringView(), tx_message);
{
absl::MutexLock lock(mutex);
std::string message{tx_message};
@@ -245,10 +242,10 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
ecm_a.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
ecm_b.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
}
TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
@@ -266,9 +263,9 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
// to server "b".
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
// to server "a".
auto channel_a = std::make_unique<MockEndpointChannel>(server_a.first.get(),
auto channel_a = std::make_shared<MockEndpointChannel>(server_a.first.get(),
client_a.second.get());
auto channel_b = std::make_unique<MockEndpointChannel>(server_b.first.get(),
auto channel_b = std::make_shared<MockEndpointChannel>(server_b.first.get(),
client_b.second.get());
auto channel_a_raw = channel_a.get();
auto channel_b_raw = channel_b.get();
@@ -289,7 +286,7 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
MakeDataMonitor(kMonitorB, &capture_b, &mutex)));
// Run DH key exchange; setup encryption contexts for channels.
auto context = DoDhKeyExchange(channel_a.get(), channel_b.get());
auto context = DoDhKeyExchange(channel_a, channel_b);
ASSERT_NE(context.first, nullptr);
ASSERT_NE(context.second, nullptr);
@@ -313,12 +310,11 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
ecm_a.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
ecm_b.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
}
} // namespace
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
+105 -130
View File
@@ -24,8 +24,7 @@
#include "absl/functional/any_invocable.h"
#include "absl/time/time.h"
#include "connections/connection_options.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/implementation/analytics/throughput_recorder.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/endpoint_channel_manager.h"
@@ -34,7 +33,6 @@
#include "connections/implementation/service_id_constants.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/payload_type.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
@@ -45,20 +43,17 @@
#include "internal/platform/mutex_lock.h"
#include "internal/platform/runnable.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/proto/analytics/connections_log.pb.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
namespace {
using ::location::nearby::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::KeepAliveFrame;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::PayloadTransferFrame;
using ::location::nearby::connections::V1Frame;
using ::location::nearby::proto::connections::DisconnectionReason;
using ::nearby::analytics::PacketMetaData;
using ::nearby::analytics::SafeDisconnectionResult;
// We set this to 11s to provide sufficient time for an in-progress WebRTC
// bandwidth upgrade to resolve. This is chosen to be slightly longer than the
@@ -207,7 +202,7 @@ ExceptionOr<OfflineFrame> EndpointManager::TryDecryptFrame(
if (decrypted.ok()) {
VLOG(1) << "Message decrypted after "
<< SystemClock::ElapsedRealtime() - start_time;
return parser::FromBytes(decrypted.result());
return parser::FromBytes(decrypted.result().AsStringView());
}
if (decrypted.exception() == Exception::kExecution) {
return decrypted.exception();
@@ -235,8 +230,7 @@ ExceptionOr<bool> EndpointManager::HandleData(
// a replacement for this endpoint since we last checked with the
// EndpointChannelManager.
while (true) {
PacketMetaData packet_meta_data;
ExceptionOr<ByteArray> bytes = endpoint_channel->Read(packet_meta_data);
ExceptionOr<ByteArray> bytes = endpoint_channel->Read();
if (!bytes.ok()) {
LOG(INFO) << "Stop reading on read-time exception: " << bytes.exception();
// Treat kNoData as kIo.
@@ -245,7 +239,8 @@ ExceptionOr<bool> EndpointManager::HandleData(
}
return ExceptionOr<bool>(bytes.exception());
}
ExceptionOr<OfflineFrame> wrapped_frame = parser::FromBytes(bytes.result());
ExceptionOr<OfflineFrame> wrapped_frame =
parser::FromBytes(bytes.result().AsStringView());
if (!wrapped_frame.ok() && try_decrypting) {
// Workaround for a race condition where the remote party has sent an
// encrypted message but our end was still configured as unencrypted when
@@ -316,8 +311,7 @@ ExceptionOr<bool> EndpointManager::HandleData(
}
frame_processor->OnIncomingFrame(frame, endpoint_id, client,
endpoint_channel->GetMedium(),
packet_meta_data);
endpoint_channel->GetMedium());
}
}
@@ -456,7 +450,6 @@ EndpointManager::~EndpointManager() {
MutexLock lock(&mutex_);
is_shutdown_ = true;
}
analytics::ThroughputRecorderContainer::GetInstance().Shutdown();
CountDownLatch latch(1);
RunOnEndpointManagerThread("bring-down-endpoints", [this, &latch]() {
LOG(INFO) << "Bringing down endpoints";
@@ -539,103 +532,94 @@ void EndpointManager::RegisterEndpoint(
ClientProxy* client, const std::string& endpoint_id,
const ConnectionResponseInfo& info,
const ConnectionOptions& connection_options,
std::unique_ptr<EndpointChannel> channel,
std::shared_ptr<EndpointChannel> channel,
const ConnectionListener& listener, const std::string& connection_token) {
CountDownLatch latch(1);
// NOTE (unique_ptr<> capture):
// std::unique_ptr<> is not copyable, so we can not pass it to
// lambda capture, because lambda eventually is converted to
// std::function<>. Instead, we release() a pointer, and pass a raw pointer,
// which is copyalbe. We ignore the risk of job not scheduled (and an
// associated risk of memory leak), because this may only happen during
// service shutdown.
RunOnEndpointManagerThread(
"register-endpoint",
[this, client, channel = channel.release(), &endpoint_id, &info,
&connection_options, &listener, &connection_token, &latch]() {
if (endpoints_.contains(endpoint_id)) {
LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id;
// We must remove old endpoint state before registering a new one
// for the same endpoint_id.
RemoveEndpointState(endpoint_id);
}
RunOnEndpointManagerThread("register-endpoint", [this, client, channel,
&endpoint_id, &info,
&connection_options,
&listener, &connection_token,
&latch]() {
if (endpoints_.contains(endpoint_id)) {
LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id;
// We must remove old endpoint state before registering a new one
// for the same endpoint_id.
RemoveEndpointState(endpoint_id);
}
absl::Duration keep_alive_interval =
absl::Milliseconds(connection_options.keep_alive_interval_millis);
absl::Duration keep_alive_timeout =
absl::Milliseconds(connection_options.keep_alive_timeout_millis);
LOG(INFO) << "Registering endpoint " << endpoint_id << " for client "
<< client->GetClientId()
<< " with keep-alive frame as interval="
<< absl::FormatDuration(keep_alive_interval)
<< ", timeout=" << absl::FormatDuration(keep_alive_timeout);
absl::Duration keep_alive_interval =
absl::Milliseconds(connection_options.keep_alive_interval_millis);
absl::Duration keep_alive_timeout =
absl::Milliseconds(connection_options.keep_alive_timeout_millis);
LOG(INFO) << "Registering endpoint " << endpoint_id << " for client "
<< client->GetClientId() << " with keep-alive frame as interval="
<< absl::FormatDuration(keep_alive_interval)
<< ", timeout=" << absl::FormatDuration(keep_alive_timeout);
// Pass ownership of channel to EndpointChannelManager
LOG(INFO) << "Registering endpoint with channel manager: endpoint "
<< endpoint_id;
channel_manager_->RegisterChannelForEndpoint(
client, endpoint_id, std::unique_ptr<EndpointChannel>(channel));
// Pass ownership of channel to EndpointChannelManager
LOG(INFO) << "Registering endpoint with channel manager: endpoint "
<< endpoint_id;
channel_manager_->RegisterChannelForEndpoint(client, endpoint_id, channel);
EndpointState& endpoint_state =
endpoints_
.emplace(endpoint_id,
EndpointState(endpoint_id, channel_manager_))
.first->second;
EndpointState& endpoint_state =
endpoints_
.emplace(endpoint_id, EndpointState(endpoint_id, channel_manager_))
.first->second;
LOG(INFO) << "Starting workers: endpoint " << endpoint_id;
// For every endpoint, there's normally only one Read handler instance
// running on a dedicated thread. This instance reads data from the
// endpoint and delegates incoming frames to various FrameProcessors.
// Once the frame has been properly handled, it starts reading again
// for the next frame. If the handler fails its read and no other
// EndpointChannels are available for this endpoint, a disconnection
// will be initiated.
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
LOG(INFO) << "Starting workers: endpoint " << endpoint_id;
// For every endpoint, there's normally only one Read handler instance
// running on a dedicated thread. This instance reads data from the
// endpoint and delegates incoming frames to various FrameProcessors.
// Once the frame has been properly handled, it starts reading again
// for the next frame. If the handler fails its read and no other
// EndpointChannels are available for this endpoint, a disconnection
// will be initiated.
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
EndpointChannelLoopRunnable(
"Read", client, endpoint_id,
[this, client, endpoint_id](EndpointChannel* channel) {
return HandleData(endpoint_id, client, channel);
});
});
// For every endpoint, there's only one KeepAliveManager instance
// running on a dedicated thread. This instance will periodically send
// out a ping* to the endpoint while listening for an incoming pong**.
// If it fails to send the ping, or if no pong is heard within
// keep_alive_timeout, it initiates a disconnection.
//
// (*) Bluetooth requires a constant outgoing stream of messages. If
// there's silence, Android will break the socket. This is why we
// ping.
// (**) Wifi Hotspots can fail to notice a connection has been lost,
// and they will happily keep writing to /dev/null. This is why we
// listen for the pong.
VLOG(1) << "EndpointManager enabling KeepAlive for endpoint "
<< endpoint_id;
endpoint_state.StartEndpointKeepAliveManager(
[this, client, endpoint_id, keep_alive_interval, keep_alive_timeout](
Mutex* keep_alive_waiter_mutex,
ConditionVariable* keep_alive_waiter) {
EndpointChannelLoopRunnable(
"Read", client, endpoint_id,
[this, client, endpoint_id](EndpointChannel* channel) {
return HandleData(endpoint_id, client, channel);
"KeepAliveManager", client, endpoint_id,
[this, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex,
keep_alive_waiter](EndpointChannel* channel) {
return HandleKeepAlive(
channel, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex, keep_alive_waiter);
});
});
LOG(INFO) << "Registering endpoint " << endpoint_id
<< ", workers started and notifying client.";
// For every endpoint, there's only one KeepAliveManager instance
// running on a dedicated thread. This instance will periodically send
// out a ping* to the endpoint while listening for an incoming pong**.
// If it fails to send the ping, or if no pong is heard within
// keep_alive_timeout, it initiates a disconnection.
//
// (*) Bluetooth requires a constant outgoing stream of messages. If
// there's silence, Android will break the socket. This is why we
// ping.
// (**) Wifi Hotspots can fail to notice a connection has been lost,
// and they will happily keep writing to /dev/null. This is why we
// listen for the pong.
VLOG(1) << "EndpointManager enabling KeepAlive for endpoint "
<< endpoint_id;
endpoint_state.StartEndpointKeepAliveManager(
[this, client, endpoint_id, keep_alive_interval,
keep_alive_timeout](Mutex* keep_alive_waiter_mutex,
ConditionVariable* keep_alive_waiter) {
EndpointChannelLoopRunnable(
"KeepAliveManager", client, endpoint_id,
[this, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex,
keep_alive_waiter](EndpointChannel* channel) {
return HandleKeepAlive(
channel, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex, keep_alive_waiter);
});
});
LOG(INFO) << "Registering endpoint " << endpoint_id
<< ", workers started and notifying client.";
// It's now time to let the client know of this new connection so that
// they can accept or reject it.
client->OnConnectionInitiated(endpoint_id, info, connection_options,
listener, connection_token);
latch.CountDown();
});
// It's now time to let the client know of this new connection so that
// they can accept or reject it.
client->OnConnectionInitiated(endpoint_id, info, connection_options,
listener, connection_token);
latch.CountDown();
});
latch.Await();
}
@@ -666,17 +650,15 @@ int EndpointManager::GetMaxTransmitPacketSize(const std::string& endpoint_id) {
std::vector<std::string> EndpointManager::SendPayloadChunk(
const PayloadTransferFrame::PayloadHeader& payload_header,
const PayloadTransferFrame::PayloadChunk& payload_chunk,
const std::vector<std::string>& endpoint_ids,
PacketMetaData& packet_meta_data) {
ByteArray bytes =
const std::vector<std::string>& endpoint_ids) {
std::string bytes =
parser::ForDataPayloadTransfer(payload_header, payload_chunk);
return SendTransferFrameBytes(
endpoint_ids, bytes, payload_header.id(),
/*offset=*/payload_chunk.offset(),
/*packet_type=*/
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::DATA),
packet_meta_data);
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::DATA));
}
// Designed to run asynchronously. It is called from IO thread pools, and
@@ -722,7 +704,7 @@ void EndpointManager::DiscardEndpoint(ClientProxy* client,
// of `serial_executor_` and will still have access to a valid
// `is_shutdown_`.
//
// TODO(b/280653613): Develop a more robost solution to prevent
// TODO(b/280653613): Develop a more robust solution to prevent
// accessing an already destroyed `ClientProxy` during destruction.
{
MutexLock lock(&mutex_);
@@ -743,15 +725,13 @@ std::vector<std::string> EndpointManager::SendControlMessage(
const PayloadTransferFrame::PayloadHeader& header,
const PayloadTransferFrame::ControlMessage& control,
const std::vector<std::string>& endpoint_ids) {
ByteArray bytes = parser::ForControlPayloadTransfer(header, control);
PacketMetaData packet_meta_data;
std::string bytes = parser::ForControlPayloadTransfer(header, control);
return SendTransferFrameBytes(
endpoint_ids, bytes, header.id(),
/*offset=*/control.offset(),
/*packet_type=*/
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::CONTROL),
packet_meta_data);
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::CONTROL));
}
// @EndpointManagerThread
@@ -762,7 +742,7 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
<< ", reason: " << reason;
SafeDisconnectionResult safe_disconnect_result =
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION;
SafeDisconnectionResult::kSafeDisconnection;
// Grab the service ID before we destroy the channel.
EndpointChannel* channel =
@@ -775,11 +755,13 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
bool is_safe_disconnection =
ApplySafeToDisconnect(endpoint_id, channel, reason);
safe_disconnect_result =
is_safe_disconnection
? ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION
: ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION;
is_safe_disconnection ? SafeDisconnectionResult::kSafeDisconnection
: SafeDisconnectionResult::kUnsafeDisconnection;
LOG(INFO) << "[safe-to-disconnect] safe_disconnect_result:"
<< (safe_disconnect_result ? "true" : "false");
<< (safe_disconnect_result ==
SafeDisconnectionResult::kSafeDisconnection
? "true"
: "false");
}
}
@@ -920,21 +902,19 @@ CountDownLatch EndpointManager::NotifyFrameProcessorsOnEndpointDisconnect(
std::vector<std::string> EndpointManager::SendPayloadAck(
std::int64_t payload_id, const std::vector<std::string>& endpoint_ids) {
ByteArray bytes = parser::ForPayloadAckPayloadTransfer(payload_id);
PacketMetaData packet_meta_data;
std::string bytes = parser::ForPayloadAckPayloadTransfer(payload_id);
return SendTransferFrameBytes(
endpoint_ids, bytes, payload_id,
/* offset= */ -1,
/*packet_type=*/
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::PAYLOAD_ACK),
packet_meta_data);
PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::PAYLOAD_ACK));
}
std::vector<std::string> EndpointManager::SendTransferFrameBytes(
const std::vector<std::string>& endpoint_ids, const ByteArray& bytes,
const std::vector<std::string>& endpoint_ids, const std::string& bytes,
std::int64_t payload_id, std::int64_t offset,
const std::string& packet_type, PacketMetaData& packet_meta_data) {
const std::string& packet_type) {
std::vector<std::string> failed_endpoint_ids;
for (const std::string& endpoint_id : endpoint_ids) {
std::shared_ptr<EndpointChannel> channel =
@@ -953,16 +933,12 @@ std::vector<std::string> EndpointManager::SendTransferFrameBytes(
continue;
}
Exception write_exception =
channel->Write(bytes.AsStringView(), packet_meta_data);
Exception write_exception = channel->Write(bytes);
if (!write_exception.Ok()) {
failed_endpoint_ids.push_back(endpoint_id);
LOG(INFO) << "Failed to send packet; endpoint_id=" << endpoint_id;
continue;
}
analytics::ThroughputRecorderContainer::GetInstance()
.GetTPRecorder(payload_id, PayloadDirection::OUTGOING_PAYLOAD)
->OnFrameSent(channel->GetMedium(), packet_meta_data);
}
return failed_endpoint_ids;
@@ -978,7 +954,7 @@ EndpointManager::EndpointState::~EndpointState() {
VLOG(1) << "EndpointState destructor " << endpoint_id_;
channel_manager_->UnregisterChannelForEndpoint(
endpoint_id_, DisconnectionReason::SHUTDOWN,
ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION);
SafeDisconnectionResult::kSafeDisconnection);
}
// Make sure the KeepAlive thread isn't blocking shutdown.
@@ -1007,5 +983,4 @@ void EndpointManager::RunOnEndpointManagerThread(const std::string& name,
serial_executor_->Execute(name, std::move(runnable));
}
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
+8 -11
View File
@@ -16,7 +16,6 @@
#define CORE_INTERNAL_ENDPOINT_MANAGER_H_
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
@@ -24,10 +23,9 @@
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/functional/any_invocable.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/packet_meta_data.h"
#include "connections/connection_options.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/endpoint_channel_manager.h"
@@ -36,6 +34,8 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/condition_variable.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/mutex.h"
#include "internal/platform/runnable.h"
#include "internal/platform/single_thread_executor.h"
@@ -79,8 +79,7 @@ class EndpointManager {
virtual void OnIncomingFrame(
location::nearby::connections::OfflineFrame& offline_frame,
const std::string& from_endpoint_id, ClientProxy* to_client,
location::nearby::proto::connections::Medium current_medium,
analytics::PacketMetaData& packet_meta_data) = 0;
location::nearby::proto::connections::Medium current_medium) = 0;
// Implementations must call barrier.CountDown() once
// they're done. This parallelizes the disconnection event across all frame
@@ -114,7 +113,7 @@ class EndpointManager {
void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id,
const ConnectionResponseInfo& info,
const ConnectionOptions& connection_options,
std::unique_ptr<EndpointChannel> channel,
std::shared_ptr<EndpointChannel> channel,
const ConnectionListener& listener,
const std::string& connection_token);
// Called when a client explicitly asks to disconnect from this endpoint. In
@@ -133,8 +132,7 @@ class EndpointManager {
payload_header,
const location::nearby::connections::PayloadTransferFrame::PayloadChunk&
payload_chunk,
const std::vector<std::string>& endpoint_ids,
analytics::PacketMetaData& packet_meta_data);
const std::vector<std::string>& endpoint_ids);
std::vector<std::string> SendControlMessage(
const location::nearby::connections::PayloadTransferFrame::PayloadHeader&
payload_header,
@@ -283,9 +281,8 @@ class EndpointManager {
std::vector<std::string> SendTransferFrameBytes(
const std::vector<std::string>& endpoint_ids,
const ByteArray& payload_transfer_frame_bytes, std::int64_t payload_id,
std::int64_t offset, const std::string& packet_type,
analytics::PacketMetaData& packet_meta_data);
const std::string& payload_transfer_frame_bytes, std::int64_t payload_id,
std::int64_t offset, const std::string& packet_type);
// Executes all jobs sequentially, on a serial_executor_.
void RunOnEndpointManagerThread(const std::string& name, Runnable runnable);
@@ -29,11 +29,10 @@
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/connection_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#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/mock_endpoint_channel.h"
#include "connections/implementation/offline_frames.h"
#include "connections/listeners.h"
#include "connections/status.h"
@@ -63,68 +62,12 @@ using ::testing::MockFunction;
using ::testing::Return;
using ::testing::StrictMock;
class MockEndpointChannel : public EndpointChannel {
public:
MOCK_METHOD(ExceptionOr<ByteArray>, Read, (), (override));
MOCK_METHOD(ExceptionOr<ByteArray>, Read, (PacketMetaData & packet_meta_data),
(override));
MOCK_METHOD(Exception, Write, (const ByteArray& data), (override));
MOCK_METHOD(Exception, Write,
(absl::string_view data, PacketMetaData& packet_meta_data),
(override));
MOCK_METHOD(void, Close, (), (override));
MOCK_METHOD(void, Close, (DisconnectionReason reason), (override));
MOCK_METHOD(void, Close,
(DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result),
(override));
MOCK_METHOD(location::nearby::proto::connections::ConnectionTechnology,
GetTechnology, (), (const, override));
MOCK_METHOD(location::nearby::proto::connections::ConnectionBand, GetBand, (),
(const, override));
MOCK_METHOD(int, GetFrequency, (), (const, override));
MOCK_METHOD(int, GetTryCount, (), (const, override));
MOCK_METHOD(std::string, GetType, (), (const, override));
MOCK_METHOD(std::string, GetServiceId, (), (const, override));
MOCK_METHOD(std::string, GetName, (), (const, override));
MOCK_METHOD(Medium, GetMedium, (), (const, override));
MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const, override));
MOCK_METHOD(void, EnableEncryption,
(std::shared_ptr<EncryptionContext> context), (override));
MOCK_METHOD(void, DisableEncryption, (), (override));
MOCK_METHOD(bool, IsPaused, (), (const, override));
MOCK_METHOD(bool, IsEncrypted, (), (override));
MOCK_METHOD(ExceptionOr<ByteArray>, TryDecrypt, (const ByteArray& data),
(override));
MOCK_METHOD(void, Pause, (), (override));
MOCK_METHOD(void, Resume, (), (override));
MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override));
MOCK_METHOD(absl::Time, GetLastWriteTimestamp, (), (const, override));
MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override));
MOCK_METHOD(void, SetAnalyticsRecorder,
(analytics::AnalyticsRecorder*, const std::string&), (override));
bool IsClosed() const override {
absl::MutexLock lock(mutex_);
return closed_;
}
void DoClose() {
absl::MutexLock lock(mutex_);
closed_ = true;
}
private:
mutable absl::Mutex mutex_;
bool closed_ = false;
};
class MockFrameProcessor : public EndpointManager::FrameProcessor {
public:
MOCK_METHOD(void, OnIncomingFrame,
(OfflineFrame & offline_frame,
const std::string& from_endpoint_id, ClientProxy* to_client,
Medium current_medium, PacketMetaData& packet_meta_data),
Medium current_medium),
(override));
MOCK_METHOD(void, OnEndpointDisconnect,
@@ -277,11 +220,12 @@ TEST_F(EndpointManagerTest, RegisterFrameProcessorWorks) {
0 /*keep_alive_interval_millis*/,
0 /*keep_alive_timeout_millis*/};
auto read_data = parser::ForConnectionRequestConnections({}, connection_info);
std::string read_data =
parser::ForConnectionRequestConnections({}, connection_info);
EXPECT_CALL(*connect_request, OnIncomingFrame);
EXPECT_CALL(*connect_request, OnEndpointDisconnect);
EXPECT_CALL(*endpoint_channel, Read(_))
.WillOnce(Return(ExceptionOr<ByteArray>(read_data)))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(ByteArray(read_data))))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, Write(_))
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
@@ -318,6 +262,8 @@ TEST_F(EndpointManagerTest, UnregisterFrameProcessorWorks) {
TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) {
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
absl::Mutex close_mutex;
bool closed = false;
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::ControlMessage control;
header.set_id(12345);
@@ -326,22 +272,24 @@ TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) {
control.set_offset(150);
control.set_event(PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED);
ON_CALL(*endpoint_channel, Read(_))
.WillByDefault([channel = endpoint_channel.get()]() {
if (channel->IsClosed()) return ExceptionOr<ByteArray>(Exception::kIo);
ON_CALL(*endpoint_channel, Read())
.WillByDefault([&, channel = endpoint_channel.get()]() {
absl::MutexLock lock(close_mutex);
if (closed) return ExceptionOr<ByteArray>(Exception::kIo);
LOG(INFO) << "Simulate read delay: wait";
absl::SleepFor(absl::Milliseconds(100));
LOG(INFO) << "Simulate read delay: done";
if (channel->IsClosed()) return ExceptionOr<ByteArray>(Exception::kIo);
if (closed) return ExceptionOr<ByteArray>(Exception::kIo);
return ExceptionOr<ByteArray>(ByteArray{});
});
ON_CALL(*endpoint_channel, Close(_))
.WillByDefault(
[channel = endpoint_channel.get()](DisconnectionReason reason) {
channel->DoClose();
[&, channel = endpoint_channel.get()](DisconnectionReason reason) {
absl::MutexLock lock(close_mutex);
closed = true;
LOG(INFO) << "Channel closed";
});
EXPECT_CALL(*endpoint_channel, Write(_, _))
EXPECT_CALL(*endpoint_channel, Write(_))
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
RegisterEndpoint(std::move(endpoint_channel), false);
@@ -358,7 +306,7 @@ TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) {
TEST_F(EndpointManagerTest, SingleReadOnReadError) {
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
EXPECT_CALL(*endpoint_channel, Read(_))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(
Return(ExceptionOr<ByteArray>(Exception::kInvalidProtocolBuffer)));
EXPECT_CALL(*endpoint_channel, Write(_))
@@ -376,7 +324,7 @@ TEST_F(EndpointManagerTest, ReadInvalidUnencryptedPayloadIgnoresFrame) {
CountDownLatch latch(1);
const ByteArray payload("not a valid frame");
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
EXPECT_CALL(*endpoint_channel, Read(_))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(payload)))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload)))
@@ -400,7 +348,7 @@ class EndpointManagerFuzzTest
// too.
// 4. Invalid frame is ignored. No bad side effects.
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
EXPECT_CALL(*endpoint_channel, Read(_))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(payload)))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload)))
@@ -416,7 +364,7 @@ class EndpointManagerFuzzTest
// 2. EndpointManager receives an invalid encrypted frame.
// 3. No calls to TryDecrypt.
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
EXPECT_CALL(*endpoint_channel, Read(_))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(payload)))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, IsEncrypted()).WillRepeatedly(Return(true));
@@ -429,7 +377,9 @@ class EndpointManagerFuzzTest
auto InvalidPayloadDomain() {
return Filter(
[](ByteArray payload) { return !parser::FromBytes(payload).ok(); },
[](ByteArray payload) {
return !parser::FromBytes(payload.AsStringView()).ok();
},
Map([](std::string payloadString) { return ByteArray(payloadString); },
String()));
}
@@ -461,16 +411,16 @@ TEST_F(EndpointManagerTest, TryDecrypt) {
std::vector<Medium>{Medium::BLE} /*supported_mediums*/,
0 /*keep_alive_interval_millis*/,
0 /*keep_alive_timeout_millis*/};
ByteArray decrypted_data =
std::string decrypted_data =
parser::ForConnectionRequestConnections({}, connection_info);
EXPECT_CALL(*connect_request, OnIncomingFrame);
EXPECT_CALL(*connect_request, OnEndpointDisconnect);
EXPECT_CALL(*endpoint_channel, Read(_))
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(payload)))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload)))
.WillOnce(Return(ExceptionOr<ByteArray>(Exception::kFailed)))
.WillOnce(Return(ExceptionOr<ByteArray>(decrypted_data)));
.WillOnce(Return(ExceptionOr<ByteArray>(ByteArray(decrypted_data))));
EXPECT_CALL(*endpoint_channel, Write(_))
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
em_.RegisterFrameProcessor(V1Frame::CONNECTION_REQUEST,
@@ -87,9 +87,9 @@ class FakeBwuHandler : public BaseBwuHandler {
medium_, *handle_initialize_calls_[initialize_call_index].service_id);
FakeEndpointChannel* upgraded_channel_raw = upgraded_channel.get();
upgraded_channel->set_read_output(
ExceptionOr<ByteArray>(parser::ForBwuIntroduction(
ExceptionOr<ByteArray>(ByteArray(parser::ForBwuIntroduction(
*handle_initialize_calls_[initialize_call_index].endpoint_id,
false /* supports_disabling_encryption */)));
false /* supports_disabling_encryption */))));
auto connection = std::make_unique<IncomingSocketConnection>();
connection->channel = std::move(upgraded_channel);
@@ -133,7 +133,7 @@ class FakeBwuHandler : public BaseBwuHandler {
}
// BaseBwuHandler:
ByteArray HandleInitializeUpgradedMediumForEndpoint(
std::string HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) final {
handle_initialize_calls_.push_back({.client = client,
@@ -178,7 +178,7 @@ class FakeBwuHandler : public BaseBwuHandler {
return parser::ForBwuWifiDirectPathAvailable(
/*ssid=*/"", /*password=*/"", /*port=*/2143,
/*frequency=*/2412, /*supports_disabling_encryption=*/false,
/*gateway=*/"123.234.23.1", /*service_name=*/"NC-WifiDirectTest",
/*gateway=*/"123.234.23.1", /*device_name=*/"NC-WifiDirectTest",
/*pin=*/"b592f7d3");
case location::nearby::proto::connections::UNKNOWN_MEDIUM:
case location::nearby::proto::connections::MDNS:
@@ -188,7 +188,7 @@ class FakeBwuHandler : public BaseBwuHandler {
case location::nearby::proto::connections::BLE_L2CAP:
case location::nearby::proto::connections::USB:
case location::nearby::proto::connections::AWDL:
return ByteArray{};
return {};
}
}
@@ -27,8 +27,7 @@
#include "internal/platform/exception.h"
#include "internal/platform/implementation/system_clock.h"
namespace nearby {
namespace connections {
namespace nearby::connections {
// An endpoint channel implementation used for testing. The read and write
// output can be set.
@@ -46,16 +45,7 @@ class FakeEndpointChannel : public EndpointChannel {
read_timestamp_ = SystemClock::ElapsedRealtime();
return read_output_;
}
ExceptionOr<ByteArray> Read(PacketMetaData& packet_meta_data) override {
read_timestamp_ = SystemClock::ElapsedRealtime();
return read_output_;
}
Exception Write(const ByteArray& data) override {
write_timestamp_ = SystemClock::ElapsedRealtime();
return write_output_;
}
Exception Write(absl::string_view data,
PacketMetaData& packet_meta_data) override {
Exception Write(absl::string_view data) override {
write_timestamp_ = SystemClock::ElapsedRealtime();
return write_output_;
}
@@ -65,10 +55,8 @@ class FakeEndpointChannel : public EndpointChannel {
is_closed_ = true;
disconnection_reason_ = reason;
}
void Close(
location::nearby::proto::connections::DisconnectionReason reason,
location::nearby::analytics::proto::ConnectionsLog::
EstablishedConnection::SafeDisconnectionResult result) override {
void Close(location::nearby::proto::connections::DisconnectionReason reason,
nearby::analytics::SafeDisconnectionResult result) override {
Close(reason);
}
bool IsClosed() const override { return is_closed_; }
@@ -128,7 +116,6 @@ class FakeEndpointChannel : public EndpointChannel {
mutable uint32_t next_keep_alive_seq_no_ = 0;
};
} // namespace connections
} // namespace nearby
} // namespace nearby::connections
#endif // NEARBY_CONNECTIONS_IMPLEMENTATION_FAKE_ENDPOINT_CHANNEL_H_
+10 -23
View File
@@ -31,9 +31,6 @@ namespace nearby_connections_feature {
// The timeout in millis to report peripheral device lost.
constexpr auto kBlePeripheralLostTimeoutMillis =
flags::Flag<int64_t>(kConfigPackage, "45411439", 12000);
// Disable instant on lost on BLE without extended feature.
constexpr auto kDisableInstantOnLostOnBleWithoutExtended =
flags::Flag<bool>(kConfigPackage, "45687098", true);
// When true, enable advertising for instant on lost feature.
constexpr auto kEnableAdvertisingForInstantOnLost =
flags::Flag<bool>(kConfigPackage, "45708614", true);
@@ -55,34 +52,25 @@ constexpr auto kEnableDynamicRoleSwitch =
// Enable/Disable GATT client disconnection.
constexpr auto kEnableGattClientDisconnection =
flags::Flag<bool>(kConfigPackage, "45698964", false);
// When true, enable instant on lost feature.
// When true, enable multiplexing in NC.
constexpr auto kEnableMultiplex =
flags::Flag<bool>(kConfigPackage, "45647946", false);
// Enable/disable multiplex in NC for AWDL.
constexpr auto kEnableMultiplexAwdl =
flags::Flag<bool>(kConfigPackage, "45690761", false);
// When true, enable multiplexing in NC for Bluetooth.
constexpr auto kEnableMultiplexBluetooth =
flags::Flag<bool>(kConfigPackage, "45676646", false);
// When true, enable multiplexing in NC for Wifi.
constexpr auto kEnableMultiplexWifiLan =
flags::Flag<bool>(kConfigPackage, "45676647", false);
// Enable/Disable preferences for Nearby Connections.
constexpr auto kEnableNearbyConnectionsPreferences =
flags::Flag<bool>(kConfigPackage, "45732423", false);
// Enable/Disable payload manager to skip chunk update.
constexpr auto kEnablePayloadManagerToSkipChunkUpdate =
flags::Flag<bool>(kConfigPackage, "45415729", true);
// Enable/Disable payload-received-ack feature.
constexpr auto kEnablePayloadReceivedAck =
flags::Flag<bool>(kConfigPackage, "45425840", false);
// Enable/Disable safe-to-disconnect feature.
constexpr auto kEnableSafeToDisconnect =
flags::Flag<bool>(kConfigPackage, "45425789", false);
// When true, enable scanning for instant on lost feature.
constexpr auto kEnableScanningForInstantOnLost =
flags::Flag<bool>(kConfigPackage, "45708613", true);
// Enable/Disable usage of shared CBPeripheralManager for GATT and L2CAP
// servers.
constexpr auto kEnableSharedPeripheralManager =
flags::Flag<bool>(kConfigPackage, "45770787", false);
// Enable/Disable single copy read/write for input/output buffers.
constexpr auto kEnableSingleCopy =
flags::Flag<bool>(kConfigPackage, "45782646", true);
// Stop BLE_V2 scanning when upgrading to WIFI Hotspot or WFD.
constexpr auto kEnableStopBleScanningOnWifiUpgrade =
flags::Flag<bool>(kConfigPackage, "45687902", false);
@@ -92,6 +80,9 @@ constexpr auto kEnableWifiDirect =
// by default, enable Wi-Fi Hotspot client.
constexpr auto kEnableWifiHotspotClient =
flags::Flag<bool>(kConfigPackage, "45648734", true);
// When true, fix the BleServerSocket deadlock/use-after-free (b/494335036).
constexpr auto kFixBleServerSocketDeadlock =
flags::Flag<bool>(kConfigPackage, "45782647", true);
// Default max transmit packet size for medium.
constexpr auto kMediumDefaultMaxTransmitPacketSize =
flags::Flag<int64_t>(kConfigPackage, "45669529", 65536);
@@ -101,10 +92,6 @@ constexpr auto kMediumMaxAllowedReadBytes =
// Disable/Enable refactor of BLE/L2CAP in Nearby Connections SDK.
constexpr auto kRefactorBleL2cap =
flags::Flag<bool>(kConfigPackage, "45737079", false);
// Enable/Disable usage of shared CBPeripheralManager for GATT and L2CAP
// servers.
constexpr auto kEnableSharedPeripheralManager =
flags::Flag<bool>(kConfigPackage, "45770787", false);
// Set the safe-to-disconnect version.
// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3.
// auto-reconnect(deprecated)
+2 -3
View File
@@ -24,11 +24,10 @@ cc_test(
],
tags = ["componentid:148515"],
deps = [
"//connections/implementation:internal",
"//internal/platform:base",
"//connections/implementation:offline_frames",
"//internal/platform/implementation/g3",
"//testing/fuzzing:fuzztest",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings:string_view",
"@com_google_googletest//:gtest_main",
],
)
@@ -12,13 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/string_view.h"
#include "connections/implementation/offline_frames.h"
#include "internal/platform/byte_array.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
nearby::ByteArray byte_array;
byte_array.SetData(reinterpret_cast<const char*>(data), size);
absl::string_view byte_array(reinterpret_cast<const char*>(data), size);
nearby::connections::parser::FromBytes(byte_array);
return 0;
+110 -30
View File
@@ -21,46 +21,75 @@ cc_library(
name = "mediums",
srcs = [
"awdl.cc",
"awdl_bwu_handler.cc",
"awdl_endpoint_channel.cc",
"ble.cc",
"ble_endpoint_channel.cc",
"ble_l2cap_endpoint_channel.cc",
"bluetooth_bwu_handler.cc",
"bluetooth_classic.cc",
"bluetooth_endpoint_channel.cc",
"bluetooth_radio.cc",
"mediums.cc",
"webrtc.cc",
"webrtc_stub.cc",
"wifi_direct.cc",
"wifi_direct_bwu_handler.cc",
"wifi_direct_endpoint_channel.cc",
"wifi_hotspot.cc",
"wifi_hotspot_bwu_handler.cc",
"wifi_hotspot_endpoint_channel.cc",
"wifi_lan.cc",
"wifi_lan_bwu_handler.cc",
"wifi_lan_endpoint_channel.cc",
],
hdrs = [
"awdl.h",
"awdl_bwu_handler.h",
"awdl_endpoint_channel.h",
"ble.h",
"ble_endpoint_channel.h",
"ble_l2cap_endpoint_channel.h",
"bluetooth_bwu_handler.h",
"bluetooth_classic.h",
"bluetooth_endpoint_channel.h",
"bluetooth_radio.h",
"mediums.h",
"webrtc.h",
"webrtc_stub.h",
"wifi.h",
"wifi_direct.h",
"wifi_direct_bwu_handler.h",
"wifi_direct_endpoint_channel.h",
"wifi_hotspot.h",
"wifi_hotspot_bwu_handler.h",
"wifi_hotspot_endpoint_channel.h",
"wifi_lan.h",
"wifi_lan_bwu_handler.h",
"wifi_lan_endpoint_channel.h",
],
copts = ["-DNO_WEBRTC"],
local_defines = select({
"//:webrtc_enabled": [],
"//conditions:default": ["NO_WEBRTC"],
}),
visibility = [
"//connections/implementation:__subpackages__",
],
deps = [
":utils",
":webrtc_utils",
":webrtc",
":webrtc_peer_id",
":webrtc_socket",
"//connections:core_types",
"//connections/implementation:bwu_handler",
"//connections/implementation:client_proxy",
"//connections/implementation:endpoint_channel",
"//connections/implementation:offline_frames",
"//connections/implementation:service_id_constants",
"//connections/implementation:types",
"//connections/implementation/flags:connections_flags",
"//connections/implementation/mediums/ble",
"//connections/implementation/mediums/ble:ble_advertisement_header",
"//connections/implementation/mediums/ble:ble_socket",
"//connections/implementation/mediums/ble:bloom_filter",
"//connections/implementation/mediums/multiplex",
"//connections/implementation/mediums/webrtc",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/base:masker",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
@@ -73,10 +102,8 @@ cc_library(
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:wifi_utils",
"//proto/mediums:web_rtc_signaling_frames_cc_proto",
# "//third_party/webrtc/files/stable/webrtc/api:create_peerconnection_factory", # buildcleaner: keep
# "//third_party/webrtc/files/stable/webrtc/api:jsep",
"@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/container:flat_hash_set",
@@ -87,21 +114,18 @@ cc_library(
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:optional",
],
] + select({
"//:webrtc_enabled": [
"//connections/implementation/mediums/webrtc:webrtc_impl",
],
"//conditions:default": [],
}),
)
cc_library(
name = "webrtc_utils",
srcs = [
"webrtc_peer_id.cc",
"webrtc_peer_id_stub.cc",
],
hdrs = [
"webrtc_peer_id.h",
"webrtc_peer_id_stub.h",
"webrtc_socket.h",
"webrtc_socket_stub.h",
],
name = "webrtc_peer_id",
srcs = ["webrtc_peer_id.cc"],
hdrs = ["webrtc_peer_id.h"],
visibility = [
"//connections/implementation:__pkg__",
"//connections/implementation/mediums:__pkg__",
@@ -109,7 +133,6 @@ cc_library(
],
deps = [
":utils",
"//connections/implementation/mediums/webrtc:data_types",
"//internal/platform:base",
"@com_google_absl//absl/strings",
],
@@ -131,12 +154,10 @@ cc_library(
name = "utils",
srcs = ["utils.cc"],
hdrs = ["utils.h"],
copts = ["-DNO_WEBRTC"],
visibility = [
"//connections/implementation:__pkg__",
"//connections/implementation/mediums/advertisements:__pkg__",
"//connections/implementation/mediums/ble:__subpackages__",
"//connections/implementation/mediums/multiplex:__pkg__",
"//internal/platform/implementation/windows:__pkg__",
],
deps = [
@@ -145,6 +166,31 @@ cc_library(
],
)
cc_library(
name = "webrtc_socket",
hdrs = ["webrtc_socket.h"],
visibility = ["//connections/implementation:__subpackages__"],
deps = [
"//internal/platform:base",
"@com_google_absl//absl/strings:string_view",
],
)
cc_library(
name = "webrtc",
hdrs = ["webrtc.h"],
visibility = ["//connections/implementation:__subpackages__"],
deps = [
":webrtc_peer_id",
":webrtc_socket",
"//connections/implementation:bwu_handler",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"@com_google_absl//absl/functional:any_invocable",
],
)
cc_test(
name = "core_internal_mediums_test",
size = "small",
@@ -180,19 +226,53 @@ cc_test(
"//internal/platform/implementation:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@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",
],
)
cc_test(
name = "bwu_handler_test",
size = "small",
srcs = [
"awdl_bwu_handler_test.cc",
"bluetooth_bwu_handler_test.cc",
"wifi_direct_bwu_handler_test.cc",
"wifi_hotspot_bwu_handler_test.cc",
"wifi_lan_bwu_handler_test.cc",
],
deps = [
":mediums",
"//connections/implementation:bwu_handler",
"//connections/implementation:client_proxy",
"//connections/implementation:endpoint_channel",
"//connections/implementation:offline_frames",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:mock_platform",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/flags:platform_flags",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "core_internal_mediums_webrtc_test",
size = "small",
srcs = [
"webrtc_peer_id_test.cc",
"webrtc_test.cc",
],
shard_count = 16,
tags = [
@@ -200,8 +280,8 @@ cc_test(
"requires-net:external",
],
deps = [
":mediums",
":webrtc_utils",
":webrtc_peer_id",
":webrtc_socket",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:comm",
+8 -7
View File
@@ -23,28 +23,23 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/mediums/awdl_bwu_handler.h"
#include "connections/implementation/mediums/utils.h"
#include "connections/medium_selector.h"
#include "internal/platform/awdl.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/implementation/wifi_utils.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/socket.h"
#include "internal/platform/types.h"
namespace nearby {
namespace connections {
namespace {
using MultiplexSocket = mediums::multiplex::MultiplexSocket;
using location::nearby::proto::connections::OperationResultCode;
constexpr absl::string_view kAwdlServiceIdSuffixForServiceType = "_AWDL";
@@ -479,5 +474,11 @@ ErrorOr<AwdlSocket> Awdl::InternalConnect(
return socket;
}
std::unique_ptr<BwuHandler> Awdl::CreateBwuHandler(
BwuHandler::IncomingConnectionCallback incoming_connection_callback) {
return std::make_unique<AwdlBwuHandler>(
this, std::move(incoming_connection_callback));
}
} // namespace connections
} // namespace nearby
+5 -4
View File
@@ -16,6 +16,7 @@
#define CORE_INTERNAL_MEDIUMS_AWDL_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
@@ -24,12 +25,9 @@
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/functional/any_invocable.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include "internal/flags/nearby_flags.h"
#include "connections/implementation/bwu_handler.h"
#include "internal/platform/awdl.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/multi_thread_executor.h"
@@ -133,6 +131,9 @@ class Awdl {
AwdlCredential GetCredentials(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<BwuHandler> CreateBwuHandler(
BwuHandler::IncomingConnectionCallback incoming_connection_callback);
private:
struct AdvertisingInfo {
bool Empty() const { return nsd_service_infos.empty(); }
@@ -12,29 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/awdl_bwu_handler.h"
#include "connections/implementation/mediums/awdl_bwu_handler.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/base/nullability.h"
#include "absl/functional/bind_front.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/awdl_endpoint_channel.h"
#include "connections/implementation/base_bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/mediums/awdl_endpoint_channel.h"
#include "connections/implementation/mediums/utils.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/service_id_constants.h"
#include "internal/base/masker.h"
#include "internal/platform/awdl.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
@@ -56,9 +57,10 @@ constexpr absl::string_view kAwdlServiceIdSuffixForServiceType = "_AWDL";
} // namespace
AwdlBwuHandler::AwdlBwuHandler(
Mediums& mediums, IncomingConnectionCallback incoming_connection_callback)
Awdl* absl_nonnull awdl_medium,
IncomingConnectionCallback incoming_connection_callback)
: BaseBwuHandler(std::move(incoming_connection_callback)),
mediums_(mediums) {}
awdl_medium_(*awdl_medium) {}
// Called by BWU target. Retrieves a new medium info from incoming message,
// and establishes connection over AWDL using this info.
@@ -148,9 +150,10 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
<< service_name << ", service_type:" << service_type
<< ") for endpoint " << endpoint_id;
ErrorOr<AwdlSocket> socket_result =
awdl_medium_.Connect(upgrade_service_id, nsd_service_info, psk_info,
client->GetCancellationFlag(endpoint_id));
std::shared_ptr<CancellationFlag> cancellation_flag =
client->GetCancellationFlag(endpoint_id);
ErrorOr<AwdlSocket> socket_result = awdl_medium_.Connect(
upgrade_service_id, nsd_service_info, psk_info, cancellation_flag.get());
if (socket_result.has_error()) {
LOG(ERROR) << "Failed to connect to the AWDL service (service_name:"
<< service_name << ", service_type:" << service_type
@@ -185,7 +188,7 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
// Called by BWU initiator. Set up AWDL upgraded medium for this endpoint,
// and returns a upgrade path info (service_name, port) for remote party to
// perform discovery.
ByteArray AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
std::string AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) {
if (!awdl_medium_.IsAcceptingConnections(upgrade_service_id)) {
@@ -12,21 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_AWDL_BWU_HANDLER_H_
#define CORE_INTERNAL_AWDL_BWU_HANDLER_H_
#ifndef CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_
#define CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_
#include <memory>
#include <string>
#include <utility>
#include "absl/base/nullability.h"
#include "connections/implementation/base_bwu_handler.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/mediums.h"
#include "internal/platform/awdl.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/expected.h"
#include "internal/platform/nsd_service_info.h"
@@ -37,8 +35,8 @@ namespace connections {
// per-Medium-specific operations needed to upgrade an EndpointChannel.
class AwdlBwuHandler : public BaseBwuHandler {
public:
explicit AwdlBwuHandler(
Mediums& mediums,
AwdlBwuHandler(
Awdl* absl_nonnull awdl_medium,
IncomingConnectionCallback incoming_connection_callback);
private:
@@ -68,7 +66,7 @@ class AwdlBwuHandler : public BaseBwuHandler {
const std::string& endpoint_id) final {}
// BaseBwuHandler implementation:
ByteArray HandleInitializeUpgradedMediumForEndpoint(
std::string HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) final;
void HandleRevertInitiatorStateForService(
@@ -82,12 +80,11 @@ class AwdlBwuHandler : public BaseBwuHandler {
std::string GenerateServiceName();
std::string GeneratePassword();
Mediums& mediums_;
Awdl& awdl_medium_{mediums_.GetAwdl()};
Awdl& awdl_medium_;
NsdServiceInfo nsd_service_info_;
};
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_AWDL_BWU_HANDLER_H_
#endif // CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_
@@ -0,0 +1,495 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/awdl_bwu_handler.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/awdl_endpoint_channel.h"
#include "connections/implementation/mediums/mediums.h"
#include "internal/platform/awdl.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/awdl.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/medium_environment.h"
#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"
namespace nearby {
class MockAwdlSocket : public api::AwdlSocket {
public:
MOCK_METHOD(InputStream&, GetInputStream, (), (override));
MOCK_METHOD(OutputStream&, GetOutputStream, (), (override));
MOCK_METHOD(Exception, Close, (), (override));
};
class MockAwdlServerSocket : public api::AwdlServerSocket {
public:
MOCK_METHOD(std::string, GetIPAddress, (), (const, override));
MOCK_METHOD(int, GetPort, (), (const, override));
MOCK_METHOD(std::unique_ptr<api::AwdlSocket>, Accept, (), (override));
MOCK_METHOD(Exception, Close, (), (override));
};
class MockAwdlMedium : public api::AwdlMedium {
public:
MOCK_METHOD(bool, IsNetworkConnected, (), (const, override));
MOCK_METHOD(bool, StartAdvertising, (const NsdServiceInfo& nsd_service_info),
(override));
MOCK_METHOD(bool, StopAdvertising, (const NsdServiceInfo& nsd_service_info),
(override));
MOCK_METHOD(bool, StartDiscovery,
(const std::string& service_type,
DiscoveredServiceCallback callback),
(override));
MOCK_METHOD(bool, StopDiscovery, (const std::string& service_type),
(override));
MOCK_METHOD(std::unique_ptr<api::AwdlSocket>, ConnectToService,
(const NsdServiceInfo& remote_service_info,
CancellationFlag* cancellation_flag),
(override));
MOCK_METHOD(std::unique_ptr<api::AwdlSocket>, ConnectToService,
(const NsdServiceInfo& remote_service_info,
const api::PskInfo& psk_info,
CancellationFlag* cancellation_flag),
(override));
MOCK_METHOD(std::unique_ptr<api::AwdlServerSocket>, ListenForService,
(int port), (override));
MOCK_METHOD(std::unique_ptr<api::AwdlServerSocket>, ListenForService,
(const api::PskInfo& psk_info, int port), (override));
MOCK_METHOD((std::optional<std::pair<std::int32_t, std::int32_t>>),
GetDynamicPortRange, (), (override));
};
MockAwdlMedium* awdl_medium_mock = nullptr;
namespace connections {
namespace {
using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::V1Frame;
using ::location::nearby::proto::connections::OperationResultCode;
using ::testing::_;
using ::testing::ByMove;
using ::protobuf_matchers::EqualsProto;
using ::testing::MockFunction;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::StrictMock;
constexpr absl::string_view kServiceId{"service_id"};
constexpr absl::string_view kEndpointId{"endpoint_id"};
constexpr absl::string_view kServiceName{"awdl_srv"};
constexpr absl::string_view kServiceType{"_awdl._tcp"};
constexpr absl::string_view kPassword{"password123"};
constexpr absl::string_view kChannelName{"channel_name"};
class AwdlBwuHandlerTest : public ::testing::Test {
protected:
AwdlBwuHandlerTest()
: handler_(&mediums_.GetAwdl(),
incoming_connection_callback_.AsStdFunction()) {}
void SetUp() override {
// By default, network is connected.
ON_CALL(*awdl_medium_mock, IsNetworkConnected())
.WillByDefault(Return(true));
}
Mediums mediums_;
MockFunction<void(ClientProxy*,
std::unique_ptr<BwuHandler::IncomingSocketConnection>)>
incoming_connection_callback_;
AwdlBwuHandler handler_;
MockInputStream mock_input_stream_;
MockOutputStream mock_output_stream_;
};
TEST_F(AwdlBwuHandlerTest,
CreateUpgradedEndpointChannel_InvalidCredentials_Fails) {
ClientProxy client;
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
path_info.mutable_awdl_credentials(); // Empty credentials
auto result =
static_cast<BwuHandler*>(&handler_)->CreateUpgradedEndpointChannel(
&client, "service_id", "endpoint_id", path_info);
ASSERT_TRUE(result.has_error());
EXPECT_EQ(result.error().operation_result_code().value(),
OperationResultCode::CONNECTIVITY_AWDL_INVALID_CREDENTIAL);
}
TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
MockInputStream input_stream;
MockOutputStream output_stream;
auto awdl_socket = std::make_unique<MockAwdlSocket>();
EXPECT_CALL(*awdl_socket, GetInputStream())
.WillRepeatedly(ReturnRef(input_stream));
EXPECT_CALL(*awdl_socket, GetOutputStream())
.WillRepeatedly(ReturnRef(output_stream));
EXPECT_CALL(*awdl_medium_mock, StartDiscovery(_, _))
.WillOnce([](const std::string& service_type,
api::AwdlMedium::DiscoveredServiceCallback callback) {
NsdServiceInfo service_info;
service_info.SetServiceName(std::string(kServiceName));
service_info.SetServiceType(service_type);
if (callback.service_discovered_cb) {
NsdServiceInfo service_info_copy = service_info;
callback.service_discovered_cb(service_info_copy);
}
return true;
});
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*awdl_medium_mock, ConnectToService(_, _, _))
.WillOnce(Return(ByMove(std::move(awdl_socket))));
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
auto* credentials = path_info.mutable_awdl_credentials();
credentials->set_service_name(kServiceName);
credentials->set_service_type(kServiceType);
credentials->set_password(kPassword);
auto result =
static_cast<BwuHandler*>(&handler_)->CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId),
path_info);
EXPECT_TRUE(result.has_value());
}
TEST_F(AwdlBwuHandlerTest,
InitializeUpgradedMediumForEndpoint_StartAcceptingConnectionsFails) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(nullptr)));
std::string result = handler_.InitializeUpgradedMediumForEndpoint(
&client, std::string(kServiceId), std::string(kEndpointId));
EXPECT_TRUE(result.empty());
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
// The reason for putting ClientProxy inside a C++ { } block so it destructs
// before the simulated clock is restored. Otherwise, the simulated clock
// would stopped before ClientProxy went out of scope, causing its destructor
// to log the session duration using the real system clock. If 1 or more
// real-world milliseconds elapsed between the test start and test end, this
// duration evaluated to something > 0.
{
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
auto awdl_server_socket = std::make_unique<MockAwdlServerSocket>();
auto* awdl_server_socket_ptr = awdl_server_socket.get();
EXPECT_CALL(*awdl_server_socket_ptr, GetPort())
.WillRepeatedly(Return(8080));
EXPECT_CALL(*awdl_server_socket_ptr, Accept())
.WillOnce(Return(ByMove(nullptr)));
EXPECT_CALL(*awdl_server_socket_ptr, Close())
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(std::move(awdl_server_socket))));
std::string captured_service_name;
std::string captured_service_type;
EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_))
.WillOnce([&](const NsdServiceInfo& nsd_service_info) {
captured_service_name = nsd_service_info.GetServiceName();
captured_service_type = nsd_service_info.GetServiceType();
return true;
});
std::string result = handler_.InitializeUpgradedMediumForEndpoint(
&client, std::string(kServiceId), std::string(kEndpointId));
EXPECT_FALSE(result.empty());
OfflineFrame expected_frame;
expected_frame.set_version(OfflineFrame::V1);
expected_frame.mutable_v1()->set_type(
V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
auto* bwu_frame =
expected_frame.mutable_v1()->mutable_bandwidth_upgrade_negotiation();
bwu_frame->set_event_type(
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
auto* upgrade_path_info = bwu_frame->mutable_upgrade_path_info();
upgrade_path_info->set_medium(
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::AWDL);
upgrade_path_info->set_supports_client_introduction_ack(true);
upgrade_path_info->set_supports_disabling_encryption(true);
auto* awdl_credentials = upgrade_path_info->mutable_awdl_credentials();
awdl_credentials->set_service_name(captured_service_name);
awdl_credentials->set_service_type(captured_service_type);
// The password is automatically generated and set in the handle start, we
// can obtain it from the credential Since we mock StartAcceptingConnections
// instead of using real awdl, GetPskInfo won't work perfectly. However
// InitializeUpgradedMediumForEndpoint internally calls
// parser::ForBwuAwdlPathAvailable which puts the generated password. We
// will extract it from result directly to build expected frame.
OfflineFrame result_frame;
EXPECT_TRUE(result_frame.ParseFromString(result));
awdl_credentials->set_password(result_frame.v1()
.bandwidth_upgrade_negotiation()
.upgrade_path_info()
.awdl_credentials()
.password());
EXPECT_THAT(result_frame, EqualsProto(expected_frame));
handler_.RevertInitiatorState();
}
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, OnIncomingAwdlConnection_Success) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
auto awdl_server_socket = std::make_unique<MockAwdlServerSocket>();
auto* awdl_server_socket_ptr = awdl_server_socket.get();
EXPECT_CALL(*awdl_server_socket_ptr, Close())
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(*awdl_server_socket_ptr, Accept())
.WillOnce([this]() {
auto awdl_socket = std::make_unique<MockAwdlSocket>();
EXPECT_CALL(*awdl_socket, GetInputStream())
.WillRepeatedly(ReturnRef(mock_input_stream_));
EXPECT_CALL(*awdl_socket, GetOutputStream())
.WillRepeatedly(ReturnRef(mock_output_stream_));
return awdl_socket;
})
.WillRepeatedly([]() {
absl::SleepFor(absl::Seconds(5));
return nullptr;
});
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(std::move(awdl_server_socket))));
EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true));
CountDownLatch latch(1);
EXPECT_CALL(incoming_connection_callback_, Call(&client, _))
.WillOnce([&latch](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
connection) { latch.CountDown(); });
std::string result = handler_.InitializeUpgradedMediumForEndpoint(
&client, std::string(kServiceId), std::string(kEndpointId));
EXPECT_FALSE(result.empty());
auto await_result = latch.Await(absl::Seconds(5));
EXPECT_TRUE(await_result.ok());
handler_.RevertInitiatorState();
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, AwdlIncomingSocket_ToStringAndClose) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
auto awdl_server_socket = std::make_unique<MockAwdlServerSocket>();
auto* awdl_server_socket_ptr = awdl_server_socket.get();
EXPECT_CALL(*awdl_server_socket_ptr, Close())
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(*awdl_server_socket_ptr, Accept())
.WillOnce([this]() {
auto awdl_socket = std::make_unique<MockAwdlSocket>();
EXPECT_CALL(*awdl_socket, GetInputStream())
.WillRepeatedly(ReturnRef(mock_input_stream_));
EXPECT_CALL(*awdl_socket, GetOutputStream())
.WillRepeatedly(ReturnRef(mock_output_stream_));
EXPECT_CALL(*awdl_socket, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
return awdl_socket;
})
.WillRepeatedly([]() {
absl::SleepFor(absl::Seconds(5));
return nullptr;
});
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(std::move(awdl_server_socket))));
EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true));
CountDownLatch latch(1);
EXPECT_CALL(incoming_connection_callback_, Call(&client, _))
.WillOnce([&latch](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
connection) {
EXPECT_FALSE(connection->socket->ToString().empty());
connection->socket->Close();
latch.CountDown();
});
std::string result = handler_.InitializeUpgradedMediumForEndpoint(
&client, std::string(kServiceId), std::string(kEndpointId));
EXPECT_FALSE(result.empty());
auto await_result = latch.Await(absl::Seconds(5));
EXPECT_TRUE(await_result.ok());
handler_.RevertInitiatorState();
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, HandleRevertInitiatorStateForService_Success) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
auto awdl_server_socket = std::make_unique<MockAwdlServerSocket>();
auto* awdl_server_socket_ptr = awdl_server_socket.get();
EXPECT_CALL(*awdl_server_socket_ptr, Close())
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(*awdl_server_socket_ptr, Accept()).WillRepeatedly([]() {
absl::SleepFor(absl::Seconds(10));
return nullptr;
});
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(std::move(awdl_server_socket))));
EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true));
EXPECT_CALL(*awdl_medium_mock, StopAdvertising(_)).WillOnce(Return(true));
handler_.InitializeUpgradedMediumForEndpoint(&client, std::string(kServiceId),
std::string(kEndpointId));
handler_.RevertInitiatorState();
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, GetUpgradeMedium_ReturnsAwdl) {
auto* bwu_handler = static_cast<BwuHandler*>(&handler_);
EXPECT_EQ(bwu_handler->GetUpgradeMedium(),
location::nearby::proto::connections::Medium::AWDL);
}
TEST_F(AwdlBwuHandlerTest, OnEndpointDisconnect_DoesNotCrash) {
ClientProxy client;
auto* bwu_handler = static_cast<BwuHandler*>(&handler_);
// This method is a no-op, just verifying it doesn't crash.
bwu_handler->OnEndpointDisconnect(&client, std::string(kEndpointId));
}
class AwdlEndpointChannelTest : public ::testing::Test {
protected:
void SetUp() override {
ON_CALL(*awdl_medium_mock, IsNetworkConnected())
.WillByDefault(Return(true));
mock_socket_ = std::make_unique<StrictMock<MockAwdlSocket>>();
EXPECT_CALL(*mock_socket_, GetInputStream())
.WillRepeatedly(ReturnRef(mock_input_stream_));
EXPECT_CALL(*mock_socket_, GetOutputStream())
.WillRepeatedly(ReturnRef(mock_output_stream_));
}
std::unique_ptr<StrictMock<MockAwdlSocket>> mock_socket_;
StrictMock<MockInputStream> mock_input_stream_;
StrictMock<MockOutputStream> mock_output_stream_;
Awdl awdl_medium_;
};
TEST_F(AwdlEndpointChannelTest, CloseImpl_StopsDiscoveryIfOutgoing) {
EXPECT_CALL(*mock_socket_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(mock_input_stream_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(mock_output_stream_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(*awdl_medium_mock, StartDiscovery(_, _)).WillOnce(Return(true));
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillOnce(Return(true));
awdl_medium_.StartDiscovery(std::string(kServiceId), {});
AwdlEndpointChannel channel(
std::string(kServiceId), std::string(kChannelName),
AwdlSocket(std::move(mock_socket_)), &awdl_medium_,
/*is_outgoing=*/true);
channel.Close(location::nearby::proto::connections::DisconnectionReason::
UNKNOWN_DISCONNECTION_REASON);
}
TEST_F(AwdlEndpointChannelTest, CloseImpl_DoesNotStopDiscoveryIfIncoming) {
EXPECT_CALL(*mock_socket_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(mock_input_stream_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
EXPECT_CALL(mock_output_stream_, Close())
.WillOnce(Return(Exception{Exception::kSuccess}));
AwdlEndpointChannel channel(
std::string(kServiceId), std::string(kChannelName),
AwdlSocket(std::move(mock_socket_)), &awdl_medium_,
/*is_outgoing=*/false);
channel.Close(location::nearby::proto::connections::DisconnectionReason::
UNKNOWN_DISCONNECTION_REASON);
}
TEST_F(AwdlEndpointChannelTest, EnableMultiplexSocket_CallsSocket) {
AwdlEndpointChannel channel(
std::string(kServiceId), std::string(kChannelName),
AwdlSocket(std::move(mock_socket_)), &awdl_medium_,
/*is_outgoing=*/true);
EXPECT_TRUE(channel.EnableMultiplexSocket());
}
} // namespace
} // namespace connections
namespace api {
std::unique_ptr<AwdlMedium> ImplementationPlatform::CreateAwdlMedium() {
auto medium = std::make_unique<MockAwdlMedium>();
awdl_medium_mock = medium.get();
return medium;
}
} // namespace api
} // namespace nearby
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/awdl_endpoint_channel.h"
#include "connections/implementation/mediums/awdl_endpoint_channel.h"
#include <string>
#include <utility>
@@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_
#ifndef CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_
#include <string>
#include "connections/implementation/base_endpoint_channel.h"
#include "connections/implementation/mediums/awdl.h"
#include "internal/platform/awdl.h"
namespace nearby {
namespace connections {
@@ -48,4 +49,4 @@ class AwdlEndpointChannel final : public BaseEndpointChannel {
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_
#endif // CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_
@@ -70,7 +70,6 @@ cc_library(
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/synchronization",
],
)
@@ -207,22 +207,28 @@ Medium BleSocket::GetMediumLocked() const {
}
ExceptionOr<ByteArray> BleSocket::DispatchPacket() {
MutexLock lock(&mutex_);
if (!ble_input_stream_) {
return Exception::kFailed;
std::shared_ptr<BleInputStream> input_stream;
{
MutexLock lock(&mutex_);
if (!ble_input_stream_) {
return Exception::kFailed;
}
input_stream = ble_input_stream_;
}
ExceptionOr<ByteArray> read_bytes =
ble_input_stream_->Read(BlePacket::kServiceIdHashLength);
input_stream->Read(BlePacket::kServiceIdHashLength);
while (read_bytes.ok()) {
ByteArray read_bytes_result = read_bytes.result();
if (BlePacket::IsControlPacketBytes(read_bytes_result)) {
ExceptionOr<ByteArray> handle_result = ProcessBleControlPacketLocked();
ExceptionOr<ByteArray> handle_result =
ProcessBleControlPacket(input_stream);
if (!handle_result.ok()) {
return handle_result;
}
read_bytes = ble_input_stream_->Read(BlePacket::kServiceIdHashLength);
read_bytes = input_stream->Read(BlePacket::kServiceIdHashLength);
} else {
MutexLock lock(&mutex_);
if (read_bytes_result != service_id_hash_) {
LOG(WARNING)
<< "Received data packet with incorrect service ID hash. Expected: "
@@ -239,20 +245,22 @@ ExceptionOr<ByteArray> BleSocket::DispatchPacket() {
ExceptionOr<std::int32_t> BleSocket::ReadPayloadLength() {
int payload_length = 0;
std::shared_ptr<BleInputStream> input_stream;
{
MutexLock lock(&mutex_);
if (!ble_input_stream_) {
return {Exception::kIo};
}
ExceptionOr<ByteArray> read_bytes =
ble_input_stream_->Read(sizeof(std::int32_t));
if (!read_bytes.ok()) {
return read_bytes.exception();
}
payload_length = byte_utils::BytesToInt(std::move(read_bytes.result()));
input_stream = ble_input_stream_;
}
ExceptionOr<ByteArray> read_bytes = input_stream->Read(sizeof(std::int32_t));
if (!read_bytes.ok()) {
return read_bytes.exception();
}
payload_length = byte_utils::BytesToInt(std::move(read_bytes.result()));
Exception send_ack_result = SendPacketAcknowledgement(payload_length);
if (!send_ack_result.Ok()) {
LOG(WARNING) << "Failed to send packet acknowledgement.";
@@ -268,9 +276,10 @@ Exception BleSocket::WritePayloadLength(int payload_length) {
return ble_output_stream_->WritePayloadLength(payload_length);
}
ExceptionOr<ByteArray> BleSocket::ProcessBleControlPacketLocked() {
ExceptionOr<ByteArray> BleSocket::ProcessBleControlPacket(
std::shared_ptr<BleInputStream> input_stream) {
// Read the first 4 bytes (packet block 1).
ExceptionOr<ByteArray> read_bytes = ble_input_stream_->Read(4);
ExceptionOr<ByteArray> read_bytes = input_stream->Read(4);
if (!read_bytes.ok()) {
return read_bytes;
}
@@ -282,7 +291,7 @@ ExceptionOr<ByteArray> BleSocket::ProcessBleControlPacketLocked() {
// Read the length from the 3rd byte of the packet block (0-indexed).
int packet_block_2_size = packet_block_1.data()[3];
// Read the left bytes for the packet block 2).
read_bytes = ble_input_stream_->Read(packet_block_2_size);
read_bytes = input_stream->Read(packet_block_2_size);
if (!read_bytes.ok()) {
return read_bytes;
}
@@ -375,8 +375,8 @@ class BleSocket final {
* payload, the `ByteArray` may be empty. Returns an `Exception` if a
* protocol error occurs or the read operation fails.
*/
ExceptionOr<ByteArray> ProcessBleControlPacketLocked()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
ExceptionOr<ByteArray> ProcessBleControlPacket(
std::shared_ptr<BleInputStream> input_stream);
/**
* Sends a raw L2CAP packet over the socket.
@@ -407,9 +407,9 @@ class BleSocket final {
SingleThreadExecutor serial_executor_;
const ByteArray service_id_hash_;
std::unique_ptr<mediums::BleInputStream> ble_input_stream_
std::shared_ptr<mediums::BleInputStream> ble_input_stream_
ABSL_GUARDED_BY(mutex_) = nullptr;
std::unique_ptr<mediums::BleOutputStream> ble_output_stream_
std::shared_ptr<mediums::BleOutputStream> ble_output_stream_
ABSL_GUARDED_BY(mutex_) = nullptr;
nearby::BleSocket ble_socket_ ABSL_GUARDED_BY(mutex_) = nearby::BleSocket();
nearby::BleL2capSocket l2cap_socket_ ABSL_GUARDED_BY(mutex_) =
@@ -228,6 +228,7 @@ bool DiscoveredPeripheralTracker::HandleOnLostAdvertisementLocked(
return false;
}
std::vector<BleAdvertisement> advertisements_to_clear;
for (const auto& hash : on_lost_advertisement->hashes()) {
for (const auto& it : gatt_advertisement_infos_) {
if (it.second.instant_on_lost_hash.string_data() == hash) {
@@ -247,30 +248,25 @@ bool DiscoveredPeripheralTracker::HandleOnLostAdvertisementLocked(
BlePeripheral lost_peripheral = it.second.peripheral;
lost_peripheral.SetId(ByteArray(gatt_advertisement));
if (gatt_advertisement.IsValid()) {
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableScanningForInstantOnLost)) {
AddInstantLostAdvertisement(it.second.advertisement_header);
discovery_cb_it->second.discovered_peripheral_callback
.instant_lost_cb(lost_peripheral, it.second.service_id,
gatt_advertisement.GetData(),
gatt_advertisement.IsFastAdvertisement());
} else {
discovery_cb_it->second.discovered_peripheral_callback
.peripheral_lost_cb(lost_peripheral, it.second.service_id,
gatt_advertisement.GetData(),
gatt_advertisement.IsFastAdvertisement());
}
AddInstantLostAdvertisement(it.second.advertisement_header);
discovery_cb_it->second.discovered_peripheral_callback
.instant_lost_cb(lost_peripheral, it.second.service_id,
gatt_advertisement.GetData(),
gatt_advertisement.IsFastAdvertisement());
LOG(INFO) << __func__ << ": OnLost triggered for service_id "
<< it.second.service_id;
}
ClearGattAdvertisement(gatt_advertisement);
advertisements_to_clear.push_back(gatt_advertisement);
}
break;
}
}
}
for (const auto& advertisement : advertisements_to_clear) {
ClearGattAdvertisement(advertisement);
}
return true;
}
@@ -17,7 +17,6 @@
#include <atomic>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -53,7 +52,6 @@
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/uuid.h"
#include "internal/test/fake_clock.h"
namespace nearby {
namespace connections {
@@ -225,6 +223,42 @@ class DiscoveredPeripheralTrackerTest
adapter_peripheral_->GetAddress().address());
}
void SetupMultipleAdvertisementsState(
const BleAdvertisementHeader& header,
const BleAdvertisement& advertisement_1,
const BleAdvertisement& advertisement_2) {
MutexLock lock(&discovered_peripheral_tracker_->mutex_);
ByteArray advertisement_bytes_1 = advertisement_1.ByteArrayWithExtraField();
ByteArray advertisement_bytes_2 = advertisement_2.ByteArrayWithExtraField();
std::vector<const ByteArray*> gatt_advertisement_bytes_list = {
&advertisement_bytes_1, &advertisement_bytes_2};
discovered_peripheral_tracker_->HandleRawGattAdvertisements(
CreateBlePeripheral(), header, gatt_advertisement_bytes_list,
/*service_uuid=*/{});
}
void RegisterServiceIdCallback(const std::string& service_id,
CountDownLatch& lost_latch) {
discovered_peripheral_tracker_->StartTracking(
service_id, /*include_dct_advertisement=*/false, Pcp::kP2pPointToPoint,
{
.instant_lost_cb =
[&lost_latch](
BlePeripheral peripheral, const std::string& service_id,
const ByteArray& advertisement_bytes,
bool fast_advertisement) { lost_latch.CountDown(); },
},
/*fast_advertisement_service_uuid=*/{});
}
bool CallHandleOnLostAdvertisementLocked(
const api::ble::BleAdvertisementData& advertisement_data) {
MutexLock lock(&discovered_peripheral_tracker_->mutex_);
return discovered_peripheral_tracker_->HandleOnLostAdvertisementLocked(
advertisement_data);
}
// Simulates to see a fast advertisement.
void FindFastAdvertisement(
const api::ble::BleAdvertisementData& advertisement_data,
@@ -1269,6 +1303,58 @@ TEST_P(DiscoveredPeripheralTrackerTest, InstantLostPeripheralForInstantOnLost) {
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
}
TEST_P(DiscoveredPeripheralTrackerTest,
InstantLostPeripheralForInstantOnLost_MultipleAdvertisements) {
ByteArray advertisement_hash = GenerateRandomAdvertisementHash();
BleAdvertisementHeader header(BleAdvertisementHeader::Version::kV2,
/*extended_advertisement=*/false,
/*num_slots=*/1, ByteArray{}, // bloom filter
advertisement_hash,
BleAdvertisementHeader::kDefaultPsmValue);
ByteArray advertisement_bytes_1 = CreateBleAdvertisement(
std::string(kServiceIdA), ByteArray(std::string(kData)),
ByteArray(std::string(kDeviceToken)));
ByteArray advertisement_bytes_2 = CreateBleAdvertisement(
std::string(kServiceIdB), ByteArray(std::string(kData2)),
ByteArray(std::string(kDeviceToken)));
auto adv_status_or_1 =
BleAdvertisement::CreateBleAdvertisement(advertisement_bytes_1);
ASSERT_OK(adv_status_or_1);
BleAdvertisement advertisement_1 = adv_status_or_1.value();
auto adv_status_or_2 =
BleAdvertisement::CreateBleAdvertisement(advertisement_bytes_2);
ASSERT_OK(adv_status_or_2);
BleAdvertisement advertisement_2 = adv_status_or_2.value();
// Register callbacks for both Service A and Service B.
CountDownLatch lost_latch(2);
RegisterServiceIdCallback(std::string(kServiceIdA), lost_latch);
RegisterServiceIdCallback(std::string(kServiceIdB), lost_latch);
// Use helper method to set up state manually.
SetupMultipleAdvertisementsState(header, advertisement_1, advertisement_2);
// Create OnLost advertisement for advertisement_1's hash.
auto advertisement = InstantOnLostAdvertisement::CreateFromHashes(
std::list<std::string>({std::string(bleutils::GenerateAdvertisementHash(
advertisement_1.ByteArrayWithExtraField()))}));
ASSERT_OK(advertisement);
api::ble::BleAdvertisementData loss_advertisement_data{};
loss_advertisement_data.service_data.insert(
{bleutils::kCopresenceServiceUuid, ByteArray(advertisement->ToBytes())});
// Call HandleOnLostAdvertisementLocked using helper.
bool result = CallHandleOnLostAdvertisementLocked(loss_advertisement_data);
EXPECT_TRUE(result);
// Verify that both are lost (callback triggered twice).
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
}
TEST_P(DiscoveredPeripheralTrackerTest,
IgnoreFoundAdvertisementForInstantOnLost) {
std::vector<std::string> service_ids = {std::string(kServiceIdA)};
@@ -1628,9 +1714,6 @@ TEST_P(DiscoveredPeripheralTrackerTest,
TEST_P(DiscoveredPeripheralTrackerTest,
OnlyGattAdvertisementReceivedOnDeviceWithExtended) {
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
std::vector<std::string> service_ids = {std::string(kServiceIdA)};
ByteArray advertisement_hash = GenerateRandomAdvertisementHash();
ByteArray advertisement_header_bytes =
@@ -1668,7 +1751,7 @@ TEST_P(DiscoveredPeripheralTrackerTest,
// 2. Receive GATT advertisement data again after 4 seconds, it should access
// GATT server.
(*fake_clock)->FastForward(absl::Seconds(4));
MediumEnvironment::Instance().FastForward(absl::Seconds(4));
FindAdvertisement(advertisement_data, {advertisement_bytes}, fetch_latch);
// We should receive a client callback of a peripheral discovery.
@@ -1678,9 +1761,6 @@ TEST_P(DiscoveredPeripheralTrackerTest,
}
TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) {
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
std::vector<std::string> service_ids = {std::string(kServiceIdA)};
ByteArray advertisement_hash = GenerateRandomAdvertisementHash();
ByteArray advertisement_header_bytes =
@@ -1718,7 +1798,7 @@ TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) {
// 2. The GATT advertisement is already queued and will be skipped.
FindAdvertisement(advertisement_data, {advertisement_bytes}, fetch_latch);
(*fake_clock)->FastForward(absl::Seconds(20));
MediumEnvironment::Instance().FastForward(absl::Seconds(20));
discovered_peripheral_tracker_->StartFetchExecutorForTesting();
// We should not receive a client callback of a peripheral discovery.
@@ -1729,9 +1809,6 @@ TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) {
TEST_P(DiscoveredPeripheralTrackerTest,
DiscoveredOnceWhenGattAndExtendedAdvertisementReceived) {
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
std::vector<std::string> service_ids = {std::string(kServiceIdA)};
ByteArray advertisement_hash = GenerateRandomAdvertisementHash();
ByteArray advertisement_header_bytes =
@@ -1756,7 +1833,7 @@ TEST_P(DiscoveredPeripheralTrackerTest,
},
},
bleutils::kCopresenceServiceUuid);
(*fake_clock)->FastForward(absl::Seconds(4));
MediumEnvironment::Instance().FastForward(absl::Seconds(4));
discovered_peripheral_tracker_->StartFetchExecutorForTesting();
// 1. Received extended advertisement.
@@ -1784,8 +1861,6 @@ TEST_P(DiscoveredPeripheralTrackerTest,
TEST_P(DiscoveredPeripheralTrackerTest,
FindGattAdvertisementInHigherPriorityThanExtendedGattAdvertisement) {
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
std::vector<std::string> service_ids = {std::string(kServiceIdA)};
ByteArray advertisement_hash_a = GenerateRandomAdvertisementHash();
ByteArray advertisement_header_a =
@@ -1823,7 +1898,7 @@ TEST_P(DiscoveredPeripheralTrackerTest,
},
},
bleutils::kCopresenceServiceUuid);
(*fake_clock)->FastForward(absl::Seconds(4));
MediumEnvironment::Instance().FastForward(absl::Seconds(4));
discovered_peripheral_tracker_->StartFetchExecutorForTesting();
// 1. Find peripheral A with GATT advertisement.
@@ -206,10 +206,7 @@ bool InstantOnLostManager::StartInstantOnLostAdvertisement() {
StopOnLostAdvertising();
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kDisableInstantOnLostOnBleWithoutExtended) &&
!ble_medium_.IsExtendedAdvertisementsAvailable()) {
if (!ble_medium_.IsExtendedAdvertisementsAvailable()) {
LOG(WARNING)
<< __func__
<< ": Disabling instant on lost on BLE without extended advertising.";
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/ble_endpoint_channel.h"
#include "connections/implementation/mediums/ble_endpoint_channel.h"
#include <memory>
#include <string>
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_
#define CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_
#ifndef CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_
#include <memory>
#include <string>
@@ -57,4 +57,4 @@ class BleEndpointChannel final : public BaseEndpointChannel {
} // namespace connections
} // namespace nearby
#endif // CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_
#endif // CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/ble_l2cap_endpoint_channel.h"
#include "connections/implementation/mediums/ble_l2cap_endpoint_channel.h"
#include <cstdint>
#include <memory>
@@ -22,11 +22,11 @@
#include "connections/implementation/base_endpoint_channel.h"
#include "connections/implementation/mediums/ble/ble_socket.h"
#include "internal/platform/ble.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/byte_array.h"
namespace nearby {
namespace connections {
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#ifndef CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#include <cstdint>
#include <memory>
@@ -60,4 +60,4 @@ class BleL2capEndpointChannel final : public BaseEndpointChannel {
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_
#endif // CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_
@@ -12,22 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/bluetooth_bwu_handler.h"
#include "connections/implementation/mediums/bluetooth_bwu_handler.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/base/nullability.h"
#include "absl/functional/bind_front.h"
#include "connections/implementation/base_bwu_handler.h"
#include "connections/implementation/bluetooth_endpoint_channel.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/mediums/bluetooth_classic.h"
#include "connections/implementation/mediums/bluetooth_endpoint_channel.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#include "connections/implementation/offline_frames.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/expected.h"
#include "internal/platform/logging.h"
#include "internal/platform/mac_address.h"
@@ -44,9 +46,12 @@ using ::location::nearby::proto::connections::OperationResultCode;
} // namespace
BluetoothBwuHandler::BluetoothBwuHandler(
Mediums& mediums, IncomingConnectionCallback incoming_connection_callback)
BluetoothRadio* absl_nonnull bluetooth_radio,
BluetoothClassic* absl_nonnull bluetooth_medium,
IncomingConnectionCallback incoming_connection_callback)
: BaseBwuHandler(std::move(incoming_connection_callback)),
mediums_(mediums) {}
bluetooth_radio_(*bluetooth_radio),
bluetooth_medium_(*bluetooth_medium) {}
// Called by BWU target. Retrieves a new medium info from incoming message,
// and establishes connection over BT using this info.
@@ -85,8 +90,10 @@ BluetoothBwuHandler::CreateUpgradedEndpointChannel(
OperationResultCode::CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE)};
}
ErrorOr<BluetoothSocket> socket_result = bluetooth_medium_.Connect(
device, service_id, client->GetCancellationFlag(endpoint_id));
std::shared_ptr<CancellationFlag> cancellation_flag =
client->GetCancellationFlag(endpoint_id);
ErrorOr<BluetoothSocket> socket_result =
bluetooth_medium_.Connect(device, service_name, cancellation_flag.get());
if (socket_result.has_error()) {
LOG(ERROR)
<< "BluetoothBwuHandler failed to connect to the Bluetooth device ("
@@ -116,7 +123,7 @@ BluetoothBwuHandler::CreateUpgradedEndpointChannel(
return {std::move(channel)};
}
ByteArray BluetoothBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
std::string BluetoothBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) {
MacAddress mac_address = bluetooth_medium_.GetAddress();
@@ -12,21 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_
#define CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_
#ifndef CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_
#define CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_
#include <memory>
#include <string>
#include "absl/base/nullability.h"
#include "connections/implementation/base_bwu_handler.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mediums/bluetooth_classic.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/medium_selector.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/expected.h"
namespace nearby {
@@ -36,8 +36,9 @@ namespace connections {
// per-Medium-specific operations needed to upgrade an EndpointChannel.
class BluetoothBwuHandler : public BaseBwuHandler {
public:
explicit BluetoothBwuHandler(
Mediums& mediums,
BluetoothBwuHandler(
BluetoothRadio* absl_nonnull bluetooth_radio,
BluetoothClassic* absl_nonnull bluetooth_medium,
IncomingConnectionCallback incoming_connection_callback);
private:
@@ -66,7 +67,7 @@ class BluetoothBwuHandler : public BaseBwuHandler {
const std::string& endpoint_id) final {}
// BaseBwuHandler implementation:
ByteArray HandleInitializeUpgradedMediumForEndpoint(
std::string HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) final;
void HandleRevertInitiatorStateForService(
@@ -76,12 +77,11 @@ class BluetoothBwuHandler : public BaseBwuHandler {
const std::string& upgrade_service_id,
BluetoothSocket socket);
Mediums& mediums_;
BluetoothRadio& bluetooth_radio_{mediums_.GetBluetoothRadio()};
BluetoothClassic& bluetooth_medium_{mediums_.GetBluetoothClassic()};
BluetoothRadio& bluetooth_radio_;
BluetoothClassic& bluetooth_medium_;
};
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_
#endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_
@@ -12,18 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/bluetooth_bwu_handler.h"
#include <memory>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/time/time.h"
#include "connections/implementation/bluetooth_bwu_handler.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/offline_frames.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
@@ -43,17 +44,27 @@ constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
class BluetoothBwuTest : public testing::Test {
protected:
BluetoothBwuTest() { env_.Start(); }
~BluetoothBwuTest() override { env_.Stop(); }
BluetoothBwuTest() {
original_flags_ = FeatureFlags::GetInstance().GetFlags();
env_.Start();
}
~BluetoothBwuTest() override {
FeatureFlags::GetMutableInstanceForTesting().SetFlags(original_flags_);
env_.Stop();
}
void RunSTACreateEndpointChannelTest(bool enable_cancellation);
MediumEnvironment& env_{MediumEnvironment::Instance()};
FeatureFlags::Flags original_flags_;
};
TEST_F(BluetoothBwuTest, CanCreateBwuHandler) {
ClientProxy client;
Mediums mediums;
auto handler = std::make_unique<BluetoothBwuHandler>(mediums, nullptr);
auto handler = std::make_unique<BluetoothBwuHandler>(
&mediums.GetBluetoothRadio(), &mediums.GetBluetoothClassic(), nullptr);
handler->InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"B",
/*endpoint_id=*/"2");
@@ -62,7 +73,12 @@ TEST_F(BluetoothBwuTest, CanCreateBwuHandler) {
handler.reset();
}
TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
void BluetoothBwuTest::RunSTACreateEndpointChannelTest(
bool enable_cancellation) {
FeatureFlags::Flags flags = original_flags_;
flags.enable_cancellation_flag = enable_cancellation;
FeatureFlags::GetMutableInstanceForTesting().SetFlags(flags);
CountDownLatch start_latch(1);
CountDownLatch accept_latch(1);
CountDownLatch end_latch(1);
@@ -71,10 +87,14 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
Mediums mediums_1, mediums_2;
ExceptionOr<OfflineFrame> upgrade_frame;
EXPECT_TRUE(mediums_1.GetBluetoothRadio().Enable());
EXPECT_TRUE(mediums_2.GetBluetoothRadio().Enable());
auto handler_1 = std::make_unique<BluetoothBwuHandler>(
mediums_1, [&](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
mutable_connection) {
&mediums_1.GetBluetoothRadio(), &mediums_1.GetBluetoothClassic(),
[&](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
mutable_connection) {
LOG(WARNING) << "Server socket connection accept call back";
accept_latch.CountDown();
EXPECT_TRUE(end_latch.Await(kWaitDuration).result());
@@ -83,11 +103,11 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
// client_1 works as Bluetooth Server Device
SingleThreadExecutor server_executor;
server_executor.Execute([&]() {
ByteArray upgrade_path_available_frame =
std::string upgrade_path_available_frame =
handler_1->InitializeUpgradedMediumForEndpoint(&client_1,
/*service_id=*/"A",
/*endpoint_id=*/"1");
EXPECT_FALSE(upgrade_path_available_frame.Empty());
EXPECT_FALSE(upgrade_path_available_frame.empty());
upgrade_frame = parser::FromBytes(upgrade_path_available_frame);
start_latch.CountDown();
@@ -98,7 +118,9 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
// Wait till client_1 started as Bluetooth and then connect to it
EXPECT_TRUE(start_latch.Await(kWaitDuration).result());
std::unique_ptr<BwuHandler> handler_2 =
std::make_unique<BluetoothBwuHandler>(mediums_2, nullptr);
std::make_unique<BluetoothBwuHandler>(
&mediums_2.GetBluetoothRadio(), &mediums_2.GetBluetoothClassic(),
nullptr);
client_executor.Execute([&]() {
auto bwu_frame =
@@ -108,7 +130,7 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
handler_2->CreateUpgradedEndpointChannel(&client_2, /*service_id=*/"A",
/*endpoint_id=*/"1",
bwu_frame.upgrade_path_info());
if (!FeatureFlags::GetInstance().GetFlags().enable_cancellation_flag) {
if (!enable_cancellation) {
ASSERT_TRUE(result.has_value());
std::unique_ptr<EndpointChannel> new_channel = std::move(result.value());
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
@@ -117,9 +139,9 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
} else {
EXPECT_FALSE(result.has_value());
EXPECT_TRUE(result.has_error());
EXPECT_EQ(
result.error().operation_result_code(),
OperationResultCode::CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE);
EXPECT_EQ(result.error().operation_result_code(),
OperationResultCode::
CLIENT_CANCELLATION_CANCEL_BT_OUTGOING_CONNECTION);
accept_latch.CountDown();
}
EXPECT_TRUE(mediums_2.GetBluetoothClassic().GetAddress().IsSet());
@@ -131,5 +153,15 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) {
EXPECT_TRUE(end_latch.Await(kWaitDuration).result());
}
TEST_F(BluetoothBwuTest,
SoftAPBWUInit_STACreateEndpointChannel_WithCancellation) {
RunSTACreateEndpointChannelTest(true);
}
TEST_F(BluetoothBwuTest,
SoftAPBWUInit_STACreateEndpointChannel_NoCancellation) {
RunSTACreateEndpointChannelTest(false);
}
} // namespace connections
} // namespace nearby
@@ -18,11 +18,9 @@
#include <string>
#include <utility>
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include "connections/medium_selector.h"
#include "internal/flags/nearby_flags.h"
#include "connections/implementation/mediums/bluetooth_bwu_handler.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/cancellation_flag.h"
@@ -30,8 +28,6 @@
#include "internal/platform/logging.h"
#include "internal/platform/mac_address.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/socket.h"
#include "internal/platform/types.h"
#include "internal/platform/uuid.h"
namespace nearby {
@@ -54,8 +50,6 @@ std::string ScanModeToString(BluetoothAdapter::ScanMode mode) {
}
} // namespace
using MultiplexSocket = mediums::multiplex::MultiplexSocket;
BluetoothClassic::BluetoothClassic(BluetoothRadio& radio)
: BluetoothClassic(radio, std::make_unique<BluetoothClassicMedium>(
radio.GetBluetoothAdapter())) {}
@@ -64,15 +58,7 @@ BluetoothClassic::BluetoothClassic(
BluetoothRadio& radio, std::unique_ptr<BluetoothClassicMedium> medium)
: radio_(radio),
adapter_(radio_.GetBluetoothAdapter()),
medium_(std::move(medium)) {
is_multiplex_enabled_ =
NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplex) &&
NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableMultiplexBluetooth);
}
medium_(std::move(medium)) {}
BluetoothClassic::~BluetoothClassic() {
// Destructor is not taking locks, but methods it is calling are.
@@ -82,20 +68,6 @@ BluetoothClassic::~BluetoothClassic() {
}
TurnOffDiscoverability();
{
MutexLock lock(&mutex_);
LOG(INFO) << "Closing multiplex sockets for " << multiplex_sockets_.size()
<< " devices";
if (is_multiplex_enabled_) {
for (auto& [bt_mac, multiplex_socket] : multiplex_sockets_) {
LOG(INFO) << "Closing multiplex sockets for "
<< GetRemoteDevice(bt_mac).GetName();
multiplex_socket->Shutdown();
}
}
multiplex_sockets_.clear();
}
// All the AcceptLoopRunnable objects in here should already have gotten an
// opportunity to shut themselves down cleanly in the calls to
// StopAcceptingConnections() above.
@@ -384,24 +356,13 @@ ErrorOr<bool> BluetoothClassic::StartAcceptingConnections(
auto owned_socket =
server_sockets_.emplace(service_id, std::move(socket)).first->second;
if (is_multiplex_enabled_) {
MultiplexSocket::ListenForIncomingConnection(
service_id, Medium::BLUETOOTH,
[&callback](const std::string& listening_service_id,
MediumSocket* virtual_socket) mutable {
if (callback) {
callback(listening_service_id,
*(down_cast<BluetoothSocket*>(virtual_socket)));
}
});
}
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections()
// is invoked.
accept_loops_runner_.Execute("bt-accept", [callback = std::move(callback),
server_socket =
std::move(owned_socket),
service_id, this]() mutable {
service_id]() mutable {
while (true) {
BluetoothSocket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
@@ -411,34 +372,6 @@ ErrorOr<bool> BluetoothClassic::StartAcceptingConnections(
}
LOG(INFO) << "Accepted connection for " << service_id;
bool callback_called = false;
{
MutexLock lock(&mutex_);
if (is_multiplex_enabled_) {
BluetoothSocket client_socket_bak = client_socket;
auto physical_socket_ptr =
std::make_shared<BluetoothSocket>(client_socket_bak);
MultiplexSocket* multiplex_socket =
MultiplexSocket::CreateIncomingSocket(physical_socket_ptr,
service_id, 0);
if (multiplex_socket != nullptr &&
multiplex_socket->GetVirtualSocket(service_id)) {
multiplex_sockets_.emplace(
client_socket.GetRemoteDevice().GetAddress(),
multiplex_socket);
MultiplexSocket::StopListeningForIncomingConnection(
service_id, Medium::BLUETOOTH);
LOG(INFO) << "Multiplex virtaul socket created for "
<< client_socket.GetRemoteDevice().GetName();
if (callback) {
callback(service_id,
*(down_cast<BluetoothSocket*>(
multiplex_socket->GetVirtualSocket(service_id))));
callback_called = true;
}
}
}
}
if (callback && !callback_called) {
LOG(INFO) << "Call back triggered for physical socket.";
callback(service_id, std::move(client_socket));
@@ -475,10 +408,6 @@ bool BluetoothClassic::StopAcceptingConnections(const std::string& service_id) {
<< " because it was never started.";
return false;
}
if (is_multiplex_enabled_) {
MultiplexSocket::StopListeningForIncomingConnection(service_id,
Medium::BLUETOOTH);
}
// Closing the BluetoothServerSocket will kick off the suicide of the thread
// in accept_loops_thread_pool_ that blocks on
@@ -507,29 +436,6 @@ bool BluetoothClassic::StopAcceptingConnections(const std::string& service_id) {
ErrorOr<BluetoothSocket> BluetoothClassic::Connect(
BluetoothDevice& bluetooth_device, const std::string& service_id,
CancellationFlag* cancellation_flag) {
{
MutexLock lock(&mutex_);
if (is_multiplex_enabled_) {
LOG(INFO) << "multiplex_sockets_ size:" << multiplex_sockets_.size();
auto it = multiplex_sockets_.find(bluetooth_device.GetAddress());
if (it != multiplex_sockets_.end()) {
MultiplexSocket* multiplex_socket = it->second;
if (multiplex_socket->IsEnabled()) {
auto* virtual_socket =
multiplex_socket->EstablishVirtualSocket(service_id);
// Should not happen.
auto* bluetooth_socket = down_cast<BluetoothSocket*>(virtual_socket);
if (bluetooth_socket == nullptr) {
LOG(INFO) << "Failed to cast to BluetoothSocket for " << service_id
<< " with " << bluetooth_device.GetName();
return {Error(OperationResultCode::
NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE)};
}
return *bluetooth_socket;
}
}
}
}
service_id_to_connect_attempts_count_map_[service_id] = 1;
while (service_id_to_connect_attempts_count_map_[service_id] <=
kConnectAttemptsLimit) {
@@ -605,29 +511,6 @@ ErrorOr<BluetoothSocket> BluetoothClassic::AttemptToConnect(
return {Error(
OperationResultCode::CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE)};
}
if (is_multiplex_enabled_) {
// New MultiplexSocket but default disabled, should be enabled after
// negotiated
auto physical_socket_ptr = std::make_shared<BluetoothSocket>(socket);
MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket(
std::move(physical_socket_ptr), service_id);
auto* virtual_socket = multiplex_socket->GetVirtualSocket(service_id);
// Should not happen.
auto* bluetooth_socket = down_cast<BluetoothSocket*>(virtual_socket);
if (bluetooth_socket == nullptr) {
LOG(INFO) << "Failed to cast to BluetoothSocket for " << service_id
<< " with " << bluetooth_device.GetName();
return {Error(
OperationResultCode::NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE)};
}
LOG(INFO) << "Multiplex socket created for " << bluetooth_device.GetName();
multiplex_sockets_.emplace(bluetooth_device.GetAddress(),
multiplex_socket);
return *bluetooth_socket;
}
return socket;
}
@@ -684,5 +567,12 @@ std::string BluetoothClassic::GenerateUuidFromString(const std::string& data) {
return std::string(Uuid(data));
}
std::unique_ptr<BwuHandler> BluetoothClassic::CreateBwuHandler(
BwuHandler::IncomingConnectionCallback incoming_connection_callback) {
MutexLock lock(&mutex_);
return std::make_unique<BluetoothBwuHandler>(
&radio_, this, std::move(incoming_connection_callback));
}
} // namespace connections
} // namespace nearby
@@ -22,10 +22,8 @@
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/cancellation_flag.h"
@@ -129,6 +127,9 @@ class BluetoothClassic {
bool IsDiscovering(const std::string& serviceId) const
ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<BwuHandler> CreateBwuHandler(
BwuHandler::IncomingConnectionCallback incoming_connection_callback);
protected:
// Use for unit tests only to inject a BluetoothClassicMedium.
BluetoothClassic(BluetoothRadio& radio,
@@ -234,14 +235,6 @@ class BluetoothClassic {
mutable Mutex discovery_callbacks_mutex_;
absl::flat_hash_map<std::string, DiscoveredDeviceCallback>
discovery_callbacks_ ABSL_GUARDED_BY(discovery_callbacks_mutex_);
// Whether the multiplex feature is enabled.
bool is_multiplex_enabled_ = NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableMultiplex);
// A map of Bluetooth MacAddress -> MultiplexSocket.
absl::flat_hash_map<MacAddress, mediums::multiplex::MultiplexSocket*>
multiplex_sockets_ ABSL_GUARDED_BY(mutex_);
};
} // namespace connections
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/bluetooth_endpoint_channel.h"
#include "connections/implementation/mediums/bluetooth_endpoint_channel.h"
#include <string>
#include <utility>
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_
#ifndef CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_
#define CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_
#include <string>
@@ -46,4 +46,4 @@ class BluetoothEndpointChannel final : public BaseEndpointChannel {
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_
#endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_
+14 -1
View File
@@ -14,10 +14,15 @@
#include "connections/implementation/mediums/mediums.h"
#include <memory>
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/ble.h"
#include "connections/implementation/mediums/bluetooth_classic.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#ifndef NO_WEBRTC
#include "connections/implementation/mediums/webrtc/webrtc_impl.h"
#endif
#include "connections/implementation/mediums/webrtc.h"
#include "connections/implementation/mediums/wifi.h"
#include "connections/implementation/mediums/wifi_direct.h"
@@ -27,6 +32,14 @@
namespace nearby {
namespace connections {
Mediums::Mediums() {
#ifndef NO_WEBRTC
webrtc_ = std::make_unique<mediums::WebRtcImpl>();
#else
webrtc_ = std::make_unique<mediums::WebRtc>();
#endif
}
BluetoothRadio& Mediums::GetBluetoothRadio() { return bluetooth_radio_; }
BluetoothClassic& Mediums::GetBluetoothClassic() { return bluetooth_classic_; }
@@ -41,7 +54,7 @@ WifiHotspot& Mediums::GetWifiHotspot() { return wifi_hotspot_; }
WifiDirect& Mediums::GetWifiDirect() { return wifi_direct_; }
mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; }
mediums::WebRtc& Mediums::GetWebRtc() { return *webrtc_; }
Awdl& Mediums::GetAwdl() { return awdl_; }
+4 -6
View File
@@ -15,15 +15,13 @@
#ifndef CORE_INTERNAL_MEDIUMS_MEDIUMS_H_
#define CORE_INTERNAL_MEDIUMS_MEDIUMS_H_
#include <memory>
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/ble.h"
#include "connections/implementation/mediums/bluetooth_classic.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#ifdef NO_WEBRTC
#include "connections/implementation/mediums/webrtc_stub.h"
#else
#include "connections/implementation/mediums/webrtc.h"
#endif
#include "connections/implementation/mediums/wifi.h"
#include "connections/implementation/mediums/wifi_direct.h"
#include "connections/implementation/mediums/wifi_hotspot.h"
@@ -35,7 +33,7 @@ namespace connections {
// Facilitates convenient and reliable usage of various wireless mediums.
class Mediums {
public:
Mediums() = default;
Mediums();
~Mediums() = default;
// Returns a handle to the Bluetooth radio.
@@ -81,7 +79,7 @@ class Mediums {
WifiLan wifi_lan_;
WifiHotspot wifi_hotspot_;
WifiDirect wifi_direct_;
mediums::WebRtc webrtc_;
std::unique_ptr<mediums::WebRtc> webrtc_;
Awdl awdl_;
};
@@ -1,72 +0,0 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
# Copyright 2024 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.
licenses(["notice"])
cc_library(
name = "multiplex",
srcs = [
"multiplex_frames.cc",
"multiplex_output_stream.cc",
"multiplex_socket.cc",
],
hdrs = [
"multiplex_frames.h",
"multiplex_output_stream.h",
"multiplex_socket.h",
],
visibility = [
"//connections/implementation:__subpackages__",
],
deps = [
"//connections:core_types",
"//connections/implementation/mediums:utils",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:types",
"//proto:connections_enums_cc_proto",
"//proto/mediums:multiplex_frames_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
)
cc_test(
name = "multiplex_test",
srcs = [
"multiplex_frames_test.cc",
"multiplex_output_stream_test.cc",
"multiplex_socket_test.cc",
],
deps = [
":multiplex",
"//connections/implementation:internal",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform/implementation/g3", # buildcleaner: keep
"//proto:connections_enums_cc_proto",
"//proto/mediums:multiplex_frames_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
@@ -1,215 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "connections/implementation/mediums/utils.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
using ::location::nearby::mediums::ConnectionResponseFrame;
using ::location::nearby::mediums::MultiplexControlFrame;
using ::location::nearby::mediums::MultiplexFrame;
ByteArray GenerateServiceIdHash(const std::string& service_id) {
return Utils::Sha256Hash(service_id, kServiceIdHashLength);
}
ByteArray GenerateServiceIdHashWithSalt(const std::string& service_id,
std::string salt) {
if (salt.empty()) {
return GenerateServiceIdHash(service_id);
}
return Utils::Sha256Hash(service_id + salt, kServiceIdHashLength);
}
std::string GenerateServiceIdHashKey(const ByteArray& service_id_hash) {
return Base64Utils::Encode(service_id_hash);
}
std::string GenerateServiceIdHashKey(const std::string& service_id) {
return GenerateServiceIdHashKey(GenerateServiceIdHash(service_id));
}
std::string GenerateServiceIdHashKeyWithSalt(const std::string& service_id,
std::string salt) {
return GenerateServiceIdHashKey(
GenerateServiceIdHashWithSalt(service_id, salt));
}
ByteArray ToBytes(MultiplexFrame&& frame) {
ByteArray bytes(frame.ByteSizeLong());
frame.SerializeToArray(bytes.data(), bytes.size());
return bytes;
}
ByteArray ForConnectionRequest(const std::string& service_id,
const std::string& service_id_hash_salt) {
MultiplexFrame frame;
frame.set_frame_type(MultiplexFrame::CONTROL_FRAME);
auto* header = frame.mutable_header();
header->set_salted_service_id_hash(std::string(
GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt)));
header->set_service_id_hash_salt(service_id_hash_salt);
auto* control_frame = frame.mutable_control_frame();
control_frame->set_control_frame_type(
MultiplexControlFrame::CONNECTION_REQUEST);
return ToBytes(std::move(frame));
}
ByteArray ForConnectionResponse(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
ConnectionResponseFrame::ConnectionResponseCode response_code) {
MultiplexFrame frame;
frame.set_frame_type(MultiplexFrame::CONTROL_FRAME);
auto* header = frame.mutable_header();
header->set_salted_service_id_hash(std::string(salted_service_id_hash));
header->set_service_id_hash_salt(service_id_hash_salt);
auto* control_frame = frame.mutable_control_frame();
control_frame->set_control_frame_type(
MultiplexControlFrame::CONNECTION_RESPONSE);
auto* response_frame = control_frame->mutable_connection_response_frame();
response_frame->set_connection_response_code(response_code);
return ToBytes(std::move(frame));
}
ByteArray ForDisconnection(const std::string& service_id,
const std::string& service_id_hash_salt) {
MultiplexFrame frame;
frame.set_frame_type(MultiplexFrame::CONTROL_FRAME);
auto* header = frame.mutable_header();
header->set_salted_service_id_hash(std::string(
GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt)));
header->set_service_id_hash_salt(service_id_hash_salt);
auto* control_frame = frame.mutable_control_frame();
control_frame->set_control_frame_type(MultiplexControlFrame::DISCONNECTION);
return ToBytes(std::move(frame));
}
ByteArray ForData(const std::string& service_id,
const std::string& service_id_hash_salt,
bool should_pass_salt, absl::string_view data) {
MultiplexFrame frame;
frame.set_frame_type(MultiplexFrame::DATA_FRAME);
auto* header = frame.mutable_header();
header->set_salted_service_id_hash(std::string(
GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt)));
if (should_pass_salt) {
header->set_service_id_hash_salt(service_id_hash_salt);
}
auto* data_frame = frame.mutable_data_frame();
data_frame->set_data(data);
return ToBytes(std::move(frame));
}
ExceptionOr<MultiplexFrame> FromBytes(const ByteArray& multiplex_frame_bytes) {
MultiplexFrame frame;
if (frame.ParseFromString(std::string(multiplex_frame_bytes))) {
if (!IsValid(frame)) {
return ExceptionOr<MultiplexFrame>(Exception::kInvalidProtocolBuffer);
}
return ExceptionOr<MultiplexFrame>(std::move(frame));
} else {
return ExceptionOr<MultiplexFrame>(Exception::kInvalidProtocolBuffer);
}
}
bool IsControlFrame(MultiplexFrame::MultiplexFrameType frame_type) {
return frame_type == MultiplexFrame::CONTROL_FRAME;
}
bool IsDataFrame(MultiplexFrame::MultiplexFrameType frame_type) {
return frame_type == MultiplexFrame::DATA_FRAME;
}
bool IsValid(const MultiplexFrame& frame) {
switch (frame.frame_type()) {
case MultiplexFrame::CONTROL_FRAME:
return IsValidControlFrame(frame);
case MultiplexFrame::DATA_FRAME:
return IsValidDataFrame(frame);
default:
return false;
}
}
bool IsValidControlFrame(const MultiplexFrame& frame) {
if (!frame.has_control_frame()) {
return false;
}
switch (frame.control_frame().control_frame_type()) {
case MultiplexControlFrame::CONNECTION_REQUEST:
case MultiplexControlFrame::CONNECTION_RESPONSE:
case MultiplexControlFrame::DISCONNECTION:
if (frame.header().salted_service_id_hash().size() ==
kServiceIdHashLength) {
return true;
}
break;
default:
break;
}
return false;
}
bool IsValidDataFrame(const MultiplexFrame& frame) {
return frame.has_data_frame() &&
frame.header().salted_service_id_hash().size() == kServiceIdHashLength;
}
bool IsMultiplexFrame(const ByteArray& data) {
ExceptionOr<MultiplexFrame> frame = FromBytes(data);
if (!frame.ok()) {
return false;
} else {
LOG(INFO) << "Checked data is a multiplex frame. Is Control ? "
<< frame.result().has_control_frame() << ", is data ? "
<< frame.result().has_data_frame();
return true;
}
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,112 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_
#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "proto/mediums/multiplex_frames.pb.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
constexpr int kServiceIdHashLength = 4;
// Serialize/Deserialize MultiplexFrame messages.
// Parses incoming MultiplexFrame message.
// Returns MultiplexFrame if parser was able to understand it, or
// Exception::kInvalidProtocolBuffer, if parser failed.
// Generates a service ID hash bytes with {@link
// MultiplexFrames#SERVICE_ID_HASH_LENGTH}.
ByteArray GenerateServiceIdHash(const std::string& service_id);
// Generates a service ID hash bytes with salt and {@link
// MultiplexFrames#SERVICE_ID_HASH_LENGTH}.
ByteArray GenerateServiceIdHashWithSalt(const std::string& service_id,
std::string salt);
// Converts the service Id hash bytes to a Base64 encoded string to be used as a
// {@code Map} key.
std::string GenerateServiceIdHashKey(const ByteArray& service_id_hash);
// Generates a service ID hash bytes with {@link
// MultiplexFrames#SERVICE_ID_HASH_LENGTH} and converts to a Base64 encoded
// string to be used as a {@code Map} key.
std::string GenerateServiceIdHashKey(const std::string& service_id);
// Generates a service ID hash bytes with salt and {@link
// MultiplexFrames#SERVICE_ID_HASH_LENGTH} and converts to a Base64 encoded
// string to be used as a { @code Map } key.
std::string GenerateServiceIdHashKeyWithSalt(const std::string& service_id,
std::string salt);
// Build a MultiplexFrame Connection Request frame Bytes stream.
// @param service_id The service ID of the connection.
// @param service_id_hash_salt The salt used to generate the service ID hash.
ByteArray ForConnectionRequest(const std::string& service_id,
const std::string& service_id_hash_salt);
// Build a MultiplexFrame Connection Response frame Bytes stream.
// @param salted_service_id_hash The salted service ID hash.
// @param service_id_hash_salt The salt used to generate the service ID hash.
// @param response_code The response code of the connection.
ByteArray ForConnectionResponse(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
location::nearby::mediums::ConnectionResponseFrame::ConnectionResponseCode
response_code);
// Build a MultiplexFrame Disconnection frame Bytes stream.
// @param service_id The service ID of the connection.
// @param service_id_hash_salt The salt used to generate the service ID hash.
ByteArray ForDisconnection(const std::string& service_id,
const std::string& service_id_hash_salt);
// Build a MultiplexFrame Data frame Bytes stream.
// @param service_id The service ID of the connection.
// @param service_id_hash_salt The salt used to generate the service ID hash.
// @param should_pass_salt Whether to pass the salt in the data frame.
// @param data The data to send.
ByteArray ForData(const std::string& service_id,
const std::string& service_id_hash_salt,
bool should_pass_salt, absl::string_view data);
ExceptionOr<location::nearby::mediums::MultiplexFrame> FromBytes(
const ByteArray& multiplex_frame_bytes);
bool IsControlFrame(
location::nearby::mediums::MultiplexFrame::MultiplexFrameType frame_type);
bool IsDataFrame(
location::nearby::mediums::MultiplexFrame::MultiplexFrameType frame_type);
bool IsValid(const location::nearby::mediums::MultiplexFrame& frame);
bool IsValidControlFrame(
const location::nearby::mediums::MultiplexFrame& frame);
bool IsValidDataFrame(const location::nearby::mediums::MultiplexFrame& frame);
bool IsMultiplexFrame(const ByteArray& data);
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_
@@ -1,170 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
using ::location::nearby::mediums::MultiplexFrame;
using ::location::nearby::mediums::MultiplexControlFrame;
using ::location::nearby::mediums::ConnectionResponseFrame;
constexpr absl::string_view kServiceId_1 = "serviceId_1";
constexpr absl::string_view kServiceId_2 = "serviceId_2";
TEST(MultiplexFrameTest, FrameValidation) {
const ByteArray data("abcdefghijklmnopqrstuvwxyz");
MultiplexFrame frame;
EXPECT_FALSE(IsValid(frame));
frame.set_frame_type(MultiplexFrame::CONTROL_FRAME);
EXPECT_FALSE(IsValidControlFrame(frame));
auto* control_frame = frame.mutable_control_frame();
control_frame->set_control_frame_type(
MultiplexControlFrame::UNKNOWN_CONTROL_FRAME_TYPE);
EXPECT_FALSE(IsValidControlFrame(frame));
auto* header = frame.mutable_header();
header->set_salted_service_id_hash(std::string(
GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "1234")));
control_frame->set_control_frame_type(
MultiplexControlFrame::CONNECTION_REQUEST);
EXPECT_TRUE(IsValidControlFrame(frame));
EXPECT_TRUE(IsValid(frame));
control_frame->set_control_frame_type(
MultiplexControlFrame::CONNECTION_RESPONSE);
EXPECT_TRUE(IsValidControlFrame(frame));
EXPECT_TRUE(IsValid(frame));
control_frame->set_control_frame_type(
MultiplexControlFrame::DISCONNECTION);
EXPECT_TRUE(IsValidControlFrame(frame));
EXPECT_TRUE(IsValid(frame));
EXPECT_FALSE(IsValidDataFrame(frame));
frame.set_frame_type(MultiplexFrame::DATA_FRAME);
auto* data_frame = frame.mutable_data_frame();
data_frame->set_data(std::string(std::move(data)));
EXPECT_TRUE(IsValidDataFrame(frame));
EXPECT_TRUE(IsValid(frame));
frame.set_frame_type(MultiplexFrame::UNKNOWN_FRAME_TYPE);
EXPECT_FALSE(IsValid(frame));
frame.set_frame_type(MultiplexFrame::DATA_FRAME);
auto serialized_bytes = ByteArray(frame.SerializeAsString());
EXPECT_TRUE(IsMultiplexFrame(std::move(serialized_bytes)));
EXPECT_TRUE(IsControlFrame(MultiplexFrame::CONTROL_FRAME));
EXPECT_FALSE(IsControlFrame(MultiplexFrame::DATA_FRAME));
EXPECT_TRUE(IsDataFrame(MultiplexFrame::DATA_FRAME));
EXPECT_FALSE(IsDataFrame(MultiplexFrame::UNKNOWN_FRAME_TYPE));
}
TEST(MultiplexFrameTest, HashValidtion) {
auto service_id_hash_1 = GenerateServiceIdHash(std::string(kServiceId_1));
EXPECT_EQ(service_id_hash_1.size(), kServiceIdHashLength);
auto service_id_hash_2 = GenerateServiceIdHash(std::string(kServiceId_2));
EXPECT_NE(service_id_hash_1, service_id_hash_2);
auto hash_key_1 = GenerateServiceIdHashKey(service_id_hash_1);
auto hash_key_2 = GenerateServiceIdHashKey(service_id_hash_2);
EXPECT_NE(hash_key_1, hash_key_2);
auto service_id_hash_with_salt_1 =
GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "1234");
EXPECT_EQ(service_id_hash_with_salt_1.size(), kServiceIdHashLength);
auto service_id_hash_with_salt_2 =
GenerateServiceIdHashWithSalt(std::string(kServiceId_2), "1234");
EXPECT_NE(service_id_hash_with_salt_1, service_id_hash_with_salt_2);
service_id_hash_with_salt_2 =
GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "abcd");
EXPECT_NE(service_id_hash_with_salt_1, service_id_hash_with_salt_2);
auto hash_key_with_salt_1 =
GenerateServiceIdHashKeyWithSalt(std::string(kServiceId_1), "1234");
auto hash_key_with_salt_2 =
GenerateServiceIdHashKeyWithSalt(std::string(kServiceId_2), "1234");
EXPECT_NE(hash_key_with_salt_1, hash_key_with_salt_2);
}
TEST(MultiplexFrameTest, CanGenerateConnectionRequest) {
ByteArray bytes = ForConnectionRequest(std::string(kServiceId_1), "1234");
auto request = FromBytes(bytes);
ASSERT_TRUE(request.ok());
auto frame = request.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::CONNECTION_REQUEST);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
"1234")));
}
TEST(MultiplexFrameTest, CanGenerateConnectionRespons) {
auto service_id_hash_with_salt_2 =
GenerateServiceIdHashWithSalt(std::string(kServiceId_2), "1234");
ByteArray bytes =
ForConnectionResponse(service_id_hash_with_salt_2, "1234",
ConnectionResponseFrame::CONNECTION_ACCEPTED);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
auto frame = response.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::CONNECTION_RESPONSE);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(service_id_hash_with_salt_2));
EXPECT_EQ(frame.control_frame()
.connection_response_frame()
.connection_response_code(),
ConnectionResponseFrame::CONNECTION_ACCEPTED);
}
TEST(MultiplexFrameTest, CanGenerateDisconnection) {
ByteArray bytes = ForDisconnection(std::string(kServiceId_1), "1234");
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
auto frame = response.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::DISCONNECTION);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
"1234")));
}
TEST(MultiplexFrameTest, CanGenerateData) {
absl::string_view data = "abcdefghijklmnopqrstuvwxyz";
ByteArray bytes =
ForData(std::string(kServiceId_1), "1234", true, data);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
auto frame = response.result();
EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
"1234")));
EXPECT_EQ(frame.data_frame().data(),
std::string("abcdefghijklmnopqrstuvwxyz"));
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,360 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include "internal/platform/array_blocking_queue.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/future.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
namespace {
using ::location::nearby::mediums::ConnectionResponseFrame;
constexpr absl::string_view kFakeSalt = "RECEIVER_CONDIMENT";
} // namespace
// Implementation for class MultiplexOutputStream
MultiplexOutputStream::MultiplexOutputStream(OutputStream* physical_writer,
AtomicBoolean& is_enabled)
: is_enabled_(is_enabled),
physical_writer_(physical_writer),
multiplex_writer_{physical_writer} {}
Exception MultiplexOutputStream::WaitForResult(const std::string& method_name,
Future<bool>* future) {
if (!future) {
LOG(INFO) << "No future to wait for; return with error.";
return {Exception::kFailed};
}
LOG(INFO) << "Waiting for future to complete: " << method_name;
ExceptionOr<bool> result =
future->Get(FeatureFlags::GetInstance()
.GetFlags()
.mediums_frame_write_timeout_millis);
if (!result.ok()) {
LOG(INFO) << "Future:[" << method_name
<< "] completed with exception:" << result.exception();
return {Exception::kFailed};
}
if (result.result()) {
LOG(INFO) << "Future:[" << method_name << "] completed with success.";
return {Exception::kSuccess};
}
LOG(INFO) << "Future:[" << method_name << "] completed with failure.";
return {Exception::kFailed};
}
bool MultiplexOutputStream::WriteConnectionRequestFrame(
const std::string& service_id, const std::string& service_id_hash_salt) {
if (!is_enabled_.Get()) {
return false;
}
Future<bool> future;
multiplex_writer_.EnqueueToSend(
&future, ForConnectionRequest(service_id, service_id_hash_salt),
"MultiplexFrame::CONNECTION_REQUEST");
if (WaitForResult("MultiplexFrame::CONNECTION_REQUEST", &future).Ok())
return true;
return false;
}
bool MultiplexOutputStream::WriteConnectionResponseFrame(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
ConnectionResponseFrame::ConnectionResponseCode response_code) {
if (!is_enabled_.Get()) {
return false;
}
Future<bool> future;
multiplex_writer_.EnqueueToSend(
&future,
ForConnectionResponse(salted_service_id_hash, service_id_hash_salt,
response_code),
"MultiplexFrame::CONNECTION_RESPONSE");
if (WaitForResult("MultiplexFrame::CONNECTION_RESPONSE", &future).Ok())
return true;
return false;
}
bool MultiplexOutputStream::Close(const std::string& service_id) {
auto item = virtual_output_streams_.find(service_id);
if (item == virtual_output_streams_.end()) {
LOG(INFO) << "Don't need to close VirtualOutputStream(" << service_id
<< ") because it's already gone.";
return false;
}
item->second->Close();
if (is_enabled_.Get()) {
Future<bool> future;
multiplex_writer_.EnqueueToSend(
&future,
ForDisconnection(service_id, item->second->GetServiceIdHashSalt()),
"MultiplexFrame::DISCONNECTION");
WaitForResult("MultiplexFrame::DISCONNECTION", &future);
}
virtual_output_streams_.erase(service_id);
if (virtual_output_streams_.empty()) {
physical_writer_->Close();
multiplex_writer_.Close();
}
return true;
}
void MultiplexOutputStream::CloseAll() {
for (auto& [service_id, virtual_output_stream] : virtual_output_streams_) {
if (is_enabled_.Get()) {
Future<bool> future;
multiplex_writer_.EnqueueToSend(
&future,
ForDisconnection(service_id,
virtual_output_stream->GetServiceIdHashSalt()),
"MultiplexFrame::DISCONNECTION");
WaitForResult("MultiplexFrame::DISCONNECTION", &future);
}
virtual_output_stream->Close();
}
virtual_output_streams_.clear();
physical_writer_->Close();
multiplex_writer_.Close();
}
OutputStream*
MultiplexOutputStream::CreateVirtualOutputStreamForFirstVirtualSocket(
const std::string& service_id, const std::string& service_id_hash_salt) {
return virtual_output_streams_
.emplace(service_id,
std::make_unique<VirtualOutputStream>(
service_id, service_id_hash_salt, physical_writer_,
multiplex_writer_,
VirtualOutputStreamType::kFirstVirtualSocket, *this))
.first->second.get();
}
OutputStream* MultiplexOutputStream::CreateVirtualOutputStream(
const std::string& service_id, const std::string& service_id_hash_salt) {
return virtual_output_streams_
.emplace(service_id,
std::make_unique<VirtualOutputStream>(
service_id, service_id_hash_salt, physical_writer_,
multiplex_writer_,
VirtualOutputStreamType::kNormalVirtualSocket, *this))
.first->second.get();
}
std::string MultiplexOutputStream::GetServiceIdHashSalt(
const std::string& service_id) {
auto item = virtual_output_streams_.find(service_id);
if (item != virtual_output_streams_.end()) {
return item->second->GetServiceIdHashSalt();
}
return {};
}
void MultiplexOutputStream::Shutdown() {
physical_writer_->Close();
multiplex_writer_.Close();
}
// Implementation for class MultiplexOutputStream::MultiplexWriter
MultiplexOutputStream::MultiplexWriter::MultiplexWriter(
OutputStream* physical_writer)
: physical_writer_(physical_writer) {}
MultiplexOutputStream::MultiplexWriter::~MultiplexWriter() {
Close();
physical_writer_ = nullptr;
}
void MultiplexOutputStream::MultiplexWriter::EnqueueToSend(
Future<bool>* future, const ByteArray& data,
const std::string& frame_name) {
MutexLock lock(&writing_mutex_);
data_queue_.Put(EnqueuedFrame(future, data));
if (is_writing_) {
return;
}
is_writing_ = true;
is_writing_cond_.Notify();
if (!is_write_loop_running_) {
is_write_loop_running_ = true;
writer_thread_.Execute("Start writing", [this] { StartWriting(); });
}
}
void MultiplexOutputStream::MultiplexWriter::StartWriting() {
LOG(INFO) << "Writing loop started.";
while (true) {
auto enqueued_frame = data_queue_.TryTake();
if (enqueued_frame != std::nullopt) {
Write(enqueued_frame.value());
continue;
}
{
MutexLock lock(&writing_mutex_);
if (data_queue_.Empty() && is_writing_ && !is_closed_) {
is_writing_ = false;
LOG(INFO) << "Waiting for data_queue_ has data.";
Exception wait_succeeded = is_writing_cond_.Wait();
if (!wait_succeeded.Ok()) {
LOG(WARNING) << "Failure waiting to wait: " << wait_succeeded.value;
return;
}
}
if (is_closed_) {
LOG(INFO) << "Notify to close_writing_thread";
MutexLock lock(&close_writing_thread_mutex_);
close_writing_thread_cond_.Notify();
break;
}
}
}
LOG(INFO) << "Writing loop stopped.";
}
void MultiplexOutputStream::MultiplexWriter::Write(
EnqueuedFrame& enqueued_frame) {
MutexLock lock(&writer_mutex_);
if (!Base64Utils::WriteInt(physical_writer_, enqueued_frame.data_.size())
.Ok()) {
enqueued_frame.future_->SetException({Exception::kIo});
return;
};
if (!physical_writer_->Write(enqueued_frame.data_.AsStringView()).Ok()) {
enqueued_frame.future_->SetException({Exception::kIo});
return;
};
if (!physical_writer_->Flush().Ok()) {
enqueued_frame.future_->SetException({Exception::kIo});
return;
};
enqueued_frame.future_->Set(true);
}
void MultiplexOutputStream::MultiplexWriter::Close() {
if (is_closed_) {
LOG(INFO) << "MultiplexWriter is already closed.";
return;
}
LOG(INFO) << "Stop writing loop and Shutdown writer thread.";
{
MutexLock lock(&writing_mutex_);
is_closed_ = true;
if (!is_write_loop_running_) {
writer_thread_.Shutdown();
return;
}
is_write_loop_running_ = false;
is_writing_cond_.Notify();
}
LOG(INFO) << "Wait to close_writing_thread";
{
MutexLock lock(&close_writing_thread_mutex_);
close_writing_thread_cond_.Wait(absl::Milliseconds(20));
LOG(INFO) << "Shutdown writer thread.";
writer_thread_.Shutdown();
}
}
MultiplexOutputStream::VirtualOutputStream::VirtualOutputStream(
std::string service_id, std::string service_id_hash_salt,
OutputStream* physical_writer, MultiplexWriter& multiplex_writer,
VirtualOutputStreamType virtual_output_stream_type,
MultiplexOutputStream& multiplex_output_stream)
: service_id_(service_id),
service_id_hash_salt_(service_id_hash_salt),
physical_writer_(physical_writer),
multiplex_writer_(multiplex_writer),
virtual_output_stream_type_(virtual_output_stream_type),
multiplex_output_stream_(multiplex_output_stream) {}
Exception MultiplexOutputStream::VirtualOutputStream::Write(
absl::string_view data) {
if (is_closed_.Get()) {
LOG(WARNING) << "Failed to write data because the VirtualOutputStream for "
<< service_id_ << " closed";
return {Exception::kIo};
}
if (multiplex_output_stream_.is_enabled_.Get()) {
bool should_pass_salt = false;
if (IsFirstVirtualOutputStream()) {
if (!first_frame_sent_for_first_virtual_output_stream_) {
first_frame_sent_for_first_virtual_output_stream_ = true;
should_pass_salt = true;
}
// Fixes b/290724590, b/290983930 which can't get the correct socket
// from the virtualSockets map. NS receiver side will pass 2
// DATA_FRAMEs continuously to the remote sender side but originally
// impl will only consider the 1st one. Add below fix to handle 2nd
// frame which the salt is still fake one and change shouldPassSalt to
// true to let the remote handle correctly.
if ((service_id_hash_salt_ == kFakeSalt) && !should_pass_salt) {
should_pass_salt = true;
LOG(INFO) << "service_idHashSalt is still a fake one and "
"not changed yet; continue to pass salt.";
}
}
ByteArray data_frame =
ForData(service_id_, service_id_hash_salt_, should_pass_salt, data);
Future<bool> future;
multiplex_writer_.EnqueueToSend(&future, data_frame,
"MultiplexFrame::DATA_FRAME");
return multiplex_output_stream_.WaitForResult("MultiplexFrame::DATA_FRAME",
&future);
} else {
if (!physical_writer_->Write(data).Ok()) {
return {Exception::kIo};
};
if (!physical_writer_->Flush().Ok()) {
return {Exception::kIo};
};
}
return {Exception::kSuccess};
}
Exception MultiplexOutputStream::VirtualOutputStream::Flush() {
return {Exception::kSuccess};
}
Exception MultiplexOutputStream::VirtualOutputStream::Close() {
LOG(INFO) << "MultiplexOutputStream::VirtualOutputStream::Close";
is_closed_.Set(true);
return {Exception::kSuccess};
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,209 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_
#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_
#include <memory>
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/platform/array_blocking_queue.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/future.h"
#include "internal/platform/mutex.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/single_thread_executor.h"
#include "proto/mediums/multiplex_frames.pb.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
/**
* A helper class to send out the {@code MultiplexControlFrame} and the outgoing
* data from clients. It schedules control and data frames with priority below
*
* <p>{@link MultiplexControlFrameType#CONNECTION_REQUEST} and {@link
* MultiplexControlFrameType#CONNECTION_RESPONSE} have the highest priority
*
* <p>All {@link MultiplexDataFrame} has the medium priority. If there's
* multiple clients send data at the same time, should poll every client's
* outgoing data in sequence. For example, client A and B send data at the same
* time, the outgoing data sequence should like A-Frame-1, B-Frame-1, A-Frame-2,
* B-Frame-2,...
*
* <p>{@link MultiplexControlFrameType#DISCONNECTION} has the same priority with
* {@link MultiplexDataFrame} because the disconnect should not make the already
* enqueued data failed to send out, so put it in the same priority queue with
* the MultiplexDataFrame.
*/
class MultiplexOutputStream {
public:
enum class VirtualOutputStreamType {
// The type of virtual socket established for the physical socket is
// created.
kFirstVirtualSocket = 0,
// The others except FIRST_VIRTUAL_SCOKET type.
kNormalVirtualSocket = 1,
};
MultiplexOutputStream(OutputStream* physical_writer,
AtomicBoolean& is_enabled);
~MultiplexOutputStream() = default;
// Writes the connection request frame to the physical output stream.
bool WriteConnectionRequestFrame(const std::string& service_id,
const std::string& service_id_hash_salt);
// Writes the connection response frame to the physical output stream.
bool WriteConnectionResponseFrame(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
::location::nearby::mediums::ConnectionResponseFrame::
ConnectionResponseCode response_code);
// Closes the virtual output stream.
bool Close(const std::string& service_id);
// Closes all virtual output streams.
void CloseAll();
// Waits for the result of the future.
Exception WaitForResult(const std::string& method_name, Future<bool>* future);
// Creates the virtual output stream for the first virtual socket.
OutputStream* CreateVirtualOutputStreamForFirstVirtualSocket(
const std::string& service_id, const std::string& service_id_hash_salt);
// Creates the virtual output stream.
OutputStream* CreateVirtualOutputStream(
const std::string& service_id, const std::string& service_id_hash_salt);
// Gets the service id hash salt.
std::string GetServiceIdHashSalt(const std::string& service_id);
// Shuts down the multiplex output stream.
void Shutdown();
class EnqueuedFrame {
public:
EnqueuedFrame(Future<bool>* future, ByteArray data)
: future_(future), data_(data) {}
~EnqueuedFrame() = default;
Future<bool>* future_;
ByteArray data_;
};
class MultiplexWriter {
public:
explicit MultiplexWriter(OutputStream* physical_writer);
~MultiplexWriter();
// Enqueues the frame to be sent out.
void EnqueueToSend(Future<bool>* future, const ByteArray& data,
const std::string& frame_name);
// Closes the writer.
void Close();
private:
// Starts the writer thread.
void StartWriting();
// Writes the enqueued frame.
void Write(EnqueuedFrame& enqueued_frame);
Mutex writer_mutex_;
OutputStream* physical_writer_ ABSL_PT_GUARDED_BY(writer_mutex_);
ArrayBlockingQueue<EnqueuedFrame> data_queue_{
FeatureFlags::GetInstance()
.GetFlags()
.multiplex_socket_middle_priority_queue_capacity};
mutable Mutex writing_mutex_;
ConditionVariable is_writing_cond_{&writing_mutex_};
bool is_writing_ ABSL_GUARDED_BY(writing_mutex_) = false;
bool is_closed_ = false;
mutable Mutex close_writing_thread_mutex_;
ConditionVariable close_writing_thread_cond_{&close_writing_thread_mutex_};
// The single thread to write all enqueued frames.
SingleThreadExecutor writer_thread_;
bool is_write_loop_running_ = false;
};
class VirtualOutputStream : public OutputStream {
public:
VirtualOutputStream(std::string service_id,
std::string service_id_hash_salt,
OutputStream* physical_writer,
MultiplexWriter& multiplex_writer,
VirtualOutputStreamType virtual_output_stream_type,
MultiplexOutputStream& multiplex_output_stream);
~VirtualOutputStream() override = default;
// Returns true if the virtual output stream is the first virtual output
// stream.
bool IsFirstVirtualOutputStream() {
return virtual_output_stream_type_ ==
VirtualOutputStreamType::kFirstVirtualSocket;
}
// Returns the service id hash salt.
std::string GetServiceIdHashSalt() { return service_id_hash_salt_; }
// Sets the service id hash salt.
void SetserviceIdHashSalt(std::string service_id_hash_salt) {
service_id_hash_salt_ = service_id_hash_salt;
}
// Writes the data to the physical output stream.
Exception Write(absl::string_view data) override;
// Flushes the physical output stream.
Exception Flush() override;
// Closes the virtual output stream.
Exception Close() override;
private:
AtomicBoolean is_closed_{false};
std::string service_id_;
std::string service_id_hash_salt_;
OutputStream* physical_writer_;
MultiplexWriter& multiplex_writer_;
VirtualOutputStreamType virtual_output_stream_type_;
bool first_frame_sent_for_first_virtual_output_stream_ = false;
MultiplexOutputStream& multiplex_output_stream_;
};
private:
AtomicBoolean& is_enabled_;
OutputStream* physical_writer_;
absl::flat_hash_map<std::string, std::unique_ptr<VirtualOutputStream>>
virtual_output_streams_;
MultiplexWriter multiplex_writer_;
};
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_
@@ -1,253 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/multi_thread_executor.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/pipe.h"
#include "proto/mediums/multiplex_frames.pb.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
constexpr absl::string_view kServiceId_1 = "serviceId_1";
constexpr absl::string_view kServiceId_2 = "serviceId_2";
constexpr absl::string_view kNoSalt = "";
constexpr absl::string_view kSalt_1 = "DNFG";
constexpr absl::string_view kSalt_2 = "YFRT";
using ::location::nearby::mediums::ConnectionResponseFrame;
using ::location::nearby::mediums::MultiplexControlFrame;
using ::location::nearby::mediums::MultiplexFrame;
class MultiplexOutputStreamTest : public ::testing::Test {
protected:
ExceptionOr<MultiplexFrame> ReadFrame() {
ExceptionOr<std::int32_t> read_int = Base64Utils::ReadInt(reader_.get());
if (!read_int.ok()) return read_int.GetException();
if (read_int.result() <= 0) return {Exception::kFailed};
ExceptionOr<ByteArray> received_data =
reader_->ReadExactly(read_int.result());
if (!received_data.ok()) return received_data.GetException();
auto bytes = std::move(received_data.result());
return FromBytes(bytes);
}
AtomicBoolean enabled_{true};
std::pair<std::unique_ptr<InputStream>, std::unique_ptr<OutputStream>> pipe_ =
CreatePipe();
std::unique_ptr<InputStream> reader_ = std::move(pipe_.first);
std::unique_ptr<OutputStream> writer_ = std::move(pipe_.second);
std::unique_ptr<MultiplexOutputStream> multiplex_output_stream_;
};
TEST_F(MultiplexOutputStreamTest, SendConnectionRequestFrame) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_TRUE(multiplex_output_stream_->WriteConnectionRequestFrame(
std::string(kServiceId_1), std::string(kNoSalt)));
auto request = ReadFrame();
ASSERT_TRUE(request.ok());
auto frame = request.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::CONNECTION_REQUEST);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
std::string(kNoSalt))));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, SendConnectionRequestFrameDisabled) {
enabled_.Set(false);
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_FALSE(multiplex_output_stream_->WriteConnectionRequestFrame(
std::string(kServiceId_1), std::string(kNoSalt)));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, SendConnectionResponseFrame) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_TRUE(multiplex_output_stream_->WriteConnectionResponseFrame(
GenerateServiceIdHash(std::string(kServiceId_1)), std::string(kNoSalt),
ConnectionResponseFrame::CONNECTION_ACCEPTED));
auto response = ReadFrame();
ASSERT_TRUE(response.ok());
auto frame = response.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::CONNECTION_RESPONSE);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
std::string(kNoSalt))));
EXPECT_EQ(frame.control_frame()
.connection_response_frame()
.connection_response_code(),
ConnectionResponseFrame::CONNECTION_ACCEPTED);
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, SendConnectionResponseFrameDisabled) {
enabled_.Set(false);
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_FALSE(multiplex_output_stream_->WriteConnectionResponseFrame(
GenerateServiceIdHash(std::string(kServiceId_1)), std::string(kNoSalt),
ConnectionResponseFrame::CONNECTION_ACCEPTED));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, CloseVirtualStreamFailed) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_FALSE(multiplex_output_stream_->Close(std::string(kServiceId_1)));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, CloseVirtualStreamSuccess) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
EXPECT_FALSE(multiplex_output_stream_->Close(std::string(kServiceId_1)));
multiplex_output_stream_->CreateVirtualOutputStream(std::string(kServiceId_1),
std::string(kNoSalt));
EXPECT_TRUE(multiplex_output_stream_->Close(std::string(kServiceId_1)));
auto request = ReadFrame();
ASSERT_TRUE(request.ok());
auto frame = request.result();
EXPECT_EQ(frame.control_frame().control_frame_type(),
MultiplexControlFrame::DISCONNECTION);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
std::string(kNoSalt))));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, CreateVirtualStream_SendData) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
auto virtual_output_stream =
multiplex_output_stream_->CreateVirtualOutputStream(
std::string(kServiceId_1), std::string(kSalt_1));
absl::string_view data = "abcdefghijklmnopqrstuvwxyz";
virtual_output_stream->Write(data);
virtual_output_stream->Flush();
auto frame_data = ReadFrame();
ASSERT_TRUE(frame_data.ok());
auto frame = frame_data.result();
EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME);
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
std::string(kSalt_1))));
EXPECT_EQ(frame.data_frame().data(), std::string(data));
multiplex_output_stream_->Shutdown();
}
TEST_F(MultiplexOutputStreamTest, CreateTwoVirtualStreams_SendData) {
multiplex_output_stream_ =
std::make_unique<MultiplexOutputStream>(writer_.get(), enabled_);
auto virtual_output_stream_1 =
multiplex_output_stream_->CreateVirtualOutputStreamForFirstVirtualSocket(
std::string(kServiceId_1), std::string(kSalt_1));
auto virtual_output_stream_2 =
multiplex_output_stream_->CreateVirtualOutputStreamForFirstVirtualSocket(
std::string(kServiceId_2), std::string(kSalt_2));
absl::string_view data_1("abcdefg");
absl::string_view data_2("hijklmn");
MultiThreadExecutor executor(2);
CountDownLatch latch(2);
executor.Execute([&virtual_output_stream_1, &latch, &data_1]() {
absl::SleepFor(absl::Milliseconds(100));
virtual_output_stream_1->Write(data_1);
virtual_output_stream_1->Flush();
latch.CountDown();
});
executor.Execute([&virtual_output_stream_2, &latch, &data_2]() {
virtual_output_stream_2->Write(data_2);
virtual_output_stream_2->Flush();
latch.CountDown();
});
EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result());
auto frame_data = ReadFrame();
ASSERT_TRUE(frame_data.ok());
auto frame = frame_data.result();
EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME);
bool first_frame_is_data_1 = true;
if (frame.header().salted_service_id_hash() ==
std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1),
std::string(kSalt_1)))) {
EXPECT_EQ(frame.data_frame().data(), std::string(data_1));
LOG(INFO) << "Read first virtual stream frame first.";
} else {
EXPECT_EQ(frame.header().salted_service_id_hash(),
std::string(GenerateServiceIdHashWithSalt(
std::string(kServiceId_2), std::string(kSalt_2))));
EXPECT_EQ(frame.data_frame().data(), std::string(data_2));
first_frame_is_data_1 = false;
LOG(INFO) << "Read second virtual stream frame first.";
}
frame_data = ReadFrame();
ASSERT_TRUE(frame_data.ok());
frame = frame_data.result();
EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME);
if (first_frame_is_data_1) {
EXPECT_EQ(frame.data_frame().data(), std::string(data_2));
} else {
EXPECT_EQ(frame.data_frame().data(), std::string(data_1));
}
multiplex_output_stream_->Shutdown();
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,807 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include <cstdint>
#include <memory>
#include <new>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h"
#include "connections/implementation/mediums/utils.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/future.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/socket.h"
#include "internal/platform/types.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
namespace {
// It is defined for the receiver which send the first packet to the sender
// without getting salt from it yet. The fake salt reminds sender to get the
// correct socket from `virtualSockets` without remapping it.
constexpr absl::string_view kFakeSalt = "RECEIVER_CONDIMENT";
// The max duration to wait for the reader thread to stop.
constexpr absl::Duration kTimeoutForReaderThreadStop = absl::Milliseconds(100);
} // namespace
using ::location::nearby::mediums::ConnectionResponseFrame;
using ::location::nearby::mediums::MultiplexControlFrame;
using ::location::nearby::mediums::MultiplexDataFrame;
using ::location::nearby::mediums::MultiplexFrame;
using ::location::nearby::proto::connections::Medium;
using ::location::nearby::proto::connections::Medium_Name;
using ConnectionResponseCode = ConnectionResponseFrame::ConnectionResponseCode;
// AtomicBoolean is trivial destructible, so it is safe to use it as a static
// variable.
AtomicBoolean MultiplexSocket::is_shutting_down_{false}; // NOLINT
void MultiplexSocket::ListenForIncomingConnection(
const std::string& service_id, Medium type,
MultiplexIncomingConnectionCb incoming_connection_cb) {
GetIncomingConnectionCallbacks().emplace(
std::pair<std::string, Medium>(service_id, type),
std::move(incoming_connection_cb));
}
void MultiplexSocket::StopListeningForIncomingConnection(
const std::string& service_id, Medium type) {
GetIncomingConnectionCallbacks().erase(
std::pair<std::string, Medium>(service_id, type));
}
MultiplexSocket::MultiplexSocket(std::shared_ptr<MediumSocket> physical_socket)
: physical_socket_ptr_(physical_socket),
multiplex_output_stream_{&physical_socket_ptr_->GetOutputStream(),
enabled_},
physical_reader_(&physical_socket_ptr_->GetInputStream()),
medium_(physical_socket_ptr_->GetMedium()) {}
absl::flat_hash_map<std::pair<std::string, Medium>,
MultiplexIncomingConnectionCb>&
MultiplexSocket::GetIncomingConnectionCallbacks() {
using MapType = absl::flat_hash_map<std::pair<std::string, Medium>,
MultiplexIncomingConnectionCb>;
alignas(MapType) static char storage[sizeof(MapType)];
static MapType* incoming_connection_callbacks = new (&storage) MapType();
return *incoming_connection_callbacks;
}
MultiplexSocket* MultiplexSocket::CreateIncomingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id, std::int32_t first_frame_len) {
while (is_shutting_down_.Get()) {
LOG(WARNING)
<< "Shutting down is going on, wait for 2ms to create incoming socket";
absl::SleepFor(absl::Milliseconds(2));
}
MultiplexSocket* multiplex_incoming_socket = nullptr;
static MultiplexSocket* multiplex_incoming_socket_bt = nullptr;
static MultiplexSocket* multiplex_incoming_socket_wlan = nullptr;
switch (physical_socket->GetMedium()) {
case Medium::BLUETOOTH:
if (multiplex_incoming_socket_bt != nullptr) {
LOG(INFO) << "Multiplex incoming socket already exists for BT";
return multiplex_incoming_socket_bt;
}
alignas(MultiplexSocket) static char storage_bt[sizeof(MultiplexSocket)];
multiplex_incoming_socket_bt =
new (&storage_bt) MultiplexSocket(physical_socket);
multiplex_incoming_socket = multiplex_incoming_socket_bt;
break;
case Medium::WIFI_LAN:
case Medium::AWDL:
if (multiplex_incoming_socket_wlan != nullptr) {
LOG(INFO) << "Multiplex incoming socket already exists for WLAN";
return multiplex_incoming_socket_wlan;
}
alignas(
MultiplexSocket) static char storage_wlan[sizeof(MultiplexSocket)];
multiplex_incoming_socket_wlan =
new (&storage_wlan) MultiplexSocket(physical_socket);
multiplex_incoming_socket = multiplex_incoming_socket_wlan;
break;
default:
LOG(ERROR) << __func__
<< "Unsupported medium: " << physical_socket->GetMedium();
multiplex_incoming_socket = nullptr;
return multiplex_incoming_socket;
}
LOG(INFO) << "CreateIncomingSocket with serviceId=" << service_id
<< ", serviceIdHashSalt=" << kFakeSalt
<< " for medium=" << Medium_Name(physical_socket->GetMedium());
multiplex_incoming_socket->CreateFirstVirtualSocket(service_id,
(std::string)kFakeSalt);
multiplex_incoming_socket->StartReaderThread(first_frame_len);
return multiplex_incoming_socket;
}
MultiplexSocket* MultiplexSocket::CreateOutgoingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id, const std::string& service_id_hash_salt) {
while (is_shutting_down_.Get()) {
LOG(WARNING)
<< "Shutting down is going on, wait for 2ms to create outgoing socket";
absl::SleepFor(absl::Milliseconds(2));
}
MultiplexSocket* multiplex_outgoing_socket = nullptr;
static MultiplexSocket* multiplex_outgoing_socket_bt = nullptr;
static MultiplexSocket* multiplex_outgoing_socket_wlan = nullptr;
switch (physical_socket->GetMedium()) {
case Medium::BLUETOOTH:
if (multiplex_outgoing_socket_bt != nullptr) {
LOG(INFO) << "Multiplex outgoing socket already exists for BT";
return multiplex_outgoing_socket_bt;
}
alignas(MultiplexSocket) static char storage_bt[sizeof(MultiplexSocket)];
multiplex_outgoing_socket_bt =
new (&storage_bt) MultiplexSocket(physical_socket);
multiplex_outgoing_socket = multiplex_outgoing_socket_bt;
break;
case Medium::WIFI_LAN:
case Medium::AWDL:
if (multiplex_outgoing_socket_wlan != nullptr) {
LOG(INFO) << "Multiplex outgoing socket already exists for WLAN";
return multiplex_outgoing_socket_wlan;
}
alignas(
MultiplexSocket) static char storage_wlan[sizeof(MultiplexSocket)];
multiplex_outgoing_socket_wlan =
new (&storage_wlan) MultiplexSocket(physical_socket);
multiplex_outgoing_socket = multiplex_outgoing_socket_wlan;
break;
default:
LOG(ERROR) << __func__
<< "Unsupported medium: " << physical_socket->GetMedium();
multiplex_outgoing_socket = nullptr;
return multiplex_outgoing_socket;
}
LOG(INFO) << "CreateOutgoingSocket with serviceId=" << service_id
<< ", serviceIdHashSalt=" << service_id_hash_salt
<< " for medium=" << Medium_Name(physical_socket->GetMedium());
multiplex_outgoing_socket->CreateFirstVirtualSocket(service_id,
service_id_hash_salt);
multiplex_outgoing_socket->StartReaderThread(0);
return multiplex_outgoing_socket;
}
MultiplexSocket* MultiplexSocket::CreateOutgoingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id) {
return CreateOutgoingSocket(physical_socket, service_id,
Utils::GenerateSalt());
}
MediumSocket* MultiplexSocket::CreateFirstVirtualSocket(
const std::string& service_id, const std::string& service_id_hash_salt) {
auto output_stream =
multiplex_output_stream_.CreateVirtualOutputStreamForFirstVirtualSocket(
service_id, service_id_hash_salt);
MutexLock lock(&virtual_socket_mutex_);
std::string salted_service_id_hash_key =
GenerateServiceIdHashKeyWithSalt(service_id, service_id_hash_salt);
LOG(INFO) << __func__ << " for service_id=" << service_id
<< ", salt=" << service_id_hash_salt
<< ", salted_service_id_hash_key=" << salted_service_id_hash_key;
MediumSocket* virtual_socket = physical_socket_ptr_->CreateVirtualSocket(
salted_service_id_hash_key, output_stream, medium_, &virtual_sockets_);
virtual_socket->AddOnSocketClosedListener(
std::make_unique<absl::AnyInvocable<void()>>(
[this, service_id]() { OnVirtualSocketClosed(service_id); }));
if (!IsEnabled()) {
LOG(INFO) << __func__ << ": Register multiplex enabled callback";
virtual_socket->RegisterMultiplexEnabledCallback(enable_cb_);
}
return virtual_socket;
}
MediumSocket* MultiplexSocket::CreateVirtualSocket(
const std::string& service_id, const std::string& service_id_hash_salt) {
auto output_stream = multiplex_output_stream_.CreateVirtualOutputStream(
service_id, service_id_hash_salt);
MutexLock lock(&virtual_socket_mutex_);
std::string salted_service_id_hash_key =
GenerateServiceIdHashKeyWithSalt(service_id, service_id_hash_salt);
LOG(INFO) << __func__ << "service_id=" << service_id
<< ", salt=" << service_id_hash_salt
<< ", salted_service_id_hash_key=" << salted_service_id_hash_key;
MediumSocket* virtual_socket = physical_socket_ptr_->CreateVirtualSocket(
salted_service_id_hash_key, output_stream, medium_, &virtual_sockets_);
virtual_socket->AddOnSocketClosedListener(
std::make_unique<absl::AnyInvocable<void()>>(
[this, service_id]() { OnVirtualSocketClosed(service_id); }));
return virtual_socket;
}
MediumSocket* MultiplexSocket::GetVirtualSocket(const std::string& service_id) {
MutexLock lock(&virtual_socket_mutex_);
LOG(INFO) << __func__ << " service_id=" << service_id << ", Salt="
<< multiplex_output_stream_.GetServiceIdHashSalt(service_id)
<< ", virtual_sockets_.size()=" << virtual_sockets_.size();
auto item = virtual_sockets_.find(GenerateServiceIdHashKeyWithSalt(
service_id, multiplex_output_stream_.GetServiceIdHashSalt(service_id)));
if (item == virtual_sockets_.end()) {
LOG(INFO) << "Not found!";
return nullptr;
}
return item->second.get();
}
int MultiplexSocket::GetVirtualSocketCount() {
MutexLock lock(&virtual_socket_mutex_);
return virtual_sockets_.size();
}
void MultiplexSocket::ListVirtualSocket() {
LOG(INFO) << __func__
<< " virtual_sockets_.size()=" << virtual_sockets_.size();
for (auto& [service_id_hash_key, virtual_socket] : virtual_sockets_) {
LOG(INFO) << __func__ << " service_id_hash_key=" << service_id_hash_key
<< ", virtual_socket=" << virtual_socket;
}
}
std::shared_ptr<Future<ConnectionResponseCode>>
MultiplexSocket::RegisterConnectionResponse(const std::string& service_id) {
auto future = std::make_shared<Future<ConnectionResponseCode>>();
connection_response_futures_.emplace(service_id, future);
return future;
}
void MultiplexSocket::UnRegisterConnectionResponse(
const std::string& service_id) {
connection_response_futures_.erase(service_id);
}
MediumSocket* MultiplexSocket::EstablishVirtualSocket(
const std::string& service_id) {
if (!IsEnabled()) {
LOG(ERROR)
<< "MultiplexSocket is disabled, cannot establish virtual socket.";
return nullptr;
}
std::string service_id_hash_salt = Utils::GenerateSalt();
auto future = RegisterConnectionResponse(service_id);
multiplex_output_stream_.WriteConnectionRequestFrame(service_id,
service_id_hash_salt);
auto result =
future->Get(FeatureFlags::GetInstance()
.GetFlags()
.multiplex_socket_connection_response_timeout_millis);
if (!result.ok()) {
LOG(ERROR) << __func__
<< "EstablishVirtualSocket failed with response code="
<< result.exception();
return nullptr;
}
ConnectionResponseCode response_code = result.GetResult();
switch (response_code) {
case ConnectionResponseFrame::CONNECTION_ACCEPTED:
LOG(INFO) << "EstablishVirtualSocket after remote response to"
" accept the connection with service_id="
<< service_id
<< ", service_id_hash_salt=" << service_id_hash_salt;
return CreateVirtualSocket(service_id, service_id_hash_salt);
case ConnectionResponseFrame::NOT_LISTENING:
LOG(ERROR) << "EstablishVirtualSocket failed for service_id="
<< service_id
<< ", service_id_hash_salt=" << service_id_hash_salt
<< " with response code=NOT_LISTENING";
break;
default:
LOG(ERROR) << "EstablishVirtualSocket failed for service_id="
<< service_id
<< ", service_id_hash_salt=" << service_id_hash_salt
<< " with response code=UNKNOWN_RESPONSE_CODE";
break;
}
return nullptr;
}
void MultiplexSocket::StartReaderThread(std::int32_t first_frame_len) {
if (is_shutdown_) {
LOG(WARNING) << "Stop to start reader thread since socket is "
"shutdown.";
return;
}
reader_thread_shutdown_barrier_ = std::make_unique<CountDownLatch>(1);
physical_reader_thread_.Execute([this, first_frame_len]() {
LOG(INFO) << __func__ << " Reader thread starts.";
auto first_frame_len_copy = first_frame_len;
while (!is_shutdown_) {
bool fail = false;
ExceptionOr<ByteArray> bytes;
ExceptionOr<std::int32_t> read_int;
if (first_frame_len_copy > 0) {
read_int = ExceptionOr<std::int32_t>(first_frame_len);
first_frame_len_copy = 0;
} else {
read_int = Base64Utils::ReadInt(physical_reader_);
}
if (!read_int.ok()) {
LOG(WARNING) << __func__
<< "Failed to read. Exception:" << read_int.exception();
fail = true;
} else {
auto length = read_int.result();
VLOG(1) << __func__ << " length:" << length;
if (length < 0 || length > FeatureFlags::GetInstance()
.GetFlags()
.connection_max_frame_length) {
// Ignore the failure because not only one client use this
// connection.
LOG(WARNING) << __func__
<< "Failed to read because received a invalid length "
<< length << ", but continue to read.";
continue;
}
bytes = physical_reader_->ReadExactly(length);
if (!bytes.ok()) {
LOG(WARNING) << __func__
<< "Read data exception:" << bytes.exception();
fail = true;
}
}
if (fail) {
reader_thread_shutdown_barrier_->CountDown();
return;
}
ExceptionOr<MultiplexFrame> frame_exc =
multiplex::FromBytes(bytes.result());
if (!frame_exc.ok()) {
HandleOfflineFrame(bytes.result());
continue;
}
if (!IsEnabled()) {
// The reader thread will only be enabled when local device
// supports multiplex if we received a multiplex frame from
// the remote, it means that the remote and the local both
// support multiplex as well. So it is safe to just turn on
// the feature at this point.
LOG(INFO) << __func__
<< " Received a multiplex frame while not enabled, enable "
"multiplex.";
Enable();
}
const auto& frame = frame_exc.result();
auto salted_service_id_hash =
ByteArray{std::move(frame.header().salted_service_id_hash())};
auto service_id_hash_salt = frame.header().has_service_id_hash_salt()
? frame.header().service_id_hash_salt()
: "";
switch (frame.frame_type()) {
case MultiplexFrame::CONTROL_FRAME:
HandleControlFrame(salted_service_id_hash, service_id_hash_salt,
frame.control_frame());
break;
case MultiplexFrame::DATA_FRAME:
VLOG(1) << "service_id_hash_salt: " << service_id_hash_salt;
HandleDataFrame(salted_service_id_hash, service_id_hash_salt,
frame.data_frame());
break;
default:
LOG(WARNING) << __func__
<< " Received MultiplexFrame with unknown frame type "
<< frame.frame_type();
}
}
});
}
void MultiplexSocket::HandleOfflineFrame(const ByteArray& bytes) {
MutexLock lock(&virtual_socket_mutex_);
LOG(INFO) << __func__ << " Virtual_socket num:" << virtual_sockets_.size();
if (virtual_sockets_.size() == 1) {
auto item = virtual_sockets_.begin();
if (item->second == nullptr) {
LOG(WARNING) << "Expected one live socket, but found null.";
return;
}
LOG(INFO) << __func__ << "FeedIncomingData:" << std::string(bytes);
item->second->FeedIncomingData(Base64Utils::IntToBytes(bytes.size()));
item->second->FeedIncomingData(bytes);
}
}
void MultiplexSocket::HandleControlFrame(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const MultiplexControlFrame& frame) {
switch (frame.control_frame_type()) {
case MultiplexControlFrame::CONNECTION_REQUEST:
RunOffloadThread("CONNECTION_REQUEST", [this, salted_service_id_hash,
service_id_hash_salt] {
HandleConnectionRequest(salted_service_id_hash, service_id_hash_salt);
});
break;
case MultiplexControlFrame::CONNECTION_RESPONSE:
LOG(INFO) << __func__ << "Received an CONNECTION_RESPONSE frame."
<< " salted_service_id_hash: "
<< std::string(salted_service_id_hash)
<< ", service_id_hash_salt: " << service_id_hash_salt
<< ", ConnectionResponseCode: "
<< frame.connection_response_frame().connection_response_code();
RunOffloadThread("CONNECTION_RESPONSE", [this, salted_service_id_hash,
service_id_hash_salt,
frame = frame] {
HandleConnectionResponse(salted_service_id_hash, service_id_hash_salt,
frame.connection_response_frame());
});
break;
case MultiplexControlFrame::DISCONNECTION:
// The virtual socket will be closed in the offload thread, so don't run
// the thread here.
HandleDisconnection(salted_service_id_hash);
break;
default:
LOG(WARNING) << __func__ << "Received an unknown frame type "
<< frame.control_frame_type();
break;
}
}
void MultiplexSocket::HandleConnectionRequest(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt) {
if (!IsEnabled()) {
LOG(WARNING) << "Received a CONNECTION_REQUEST frame on medium "
<< Medium_Name(medium_)
<< " but status is disabled, ignore it.";
return;
}
std::string salted_service_id_hash_key =
GenerateServiceIdHashKey(salted_service_id_hash);
MultiplexIncomingConnectionCb* incoming_connection_callback = nullptr;
std::string listening_service_id = "";
for (auto& [service_id_medium_pair, callback] :
GetIncomingConnectionCallbacks()) {
if (GenerateServiceIdHashWithSalt(service_id_medium_pair.first,
service_id_hash_salt) ==
salted_service_id_hash) {
incoming_connection_callback = &callback;
listening_service_id = service_id_medium_pair.first;
}
}
if (incoming_connection_callback == nullptr || listening_service_id.empty()) {
LOG(INFO) << "There's no client listening for hash salt : "
<< service_id_hash_salt
<< ", hash key : " << salted_service_id_hash_key << " on medium "
<< Medium_Name(medium_);
LOG(INFO) << "The size of incomingConnectionCallbacks : "
<< GetIncomingConnectionCallbacks().size();
if (!multiplex_output_stream_.WriteConnectionResponseFrame(
salted_service_id_hash, service_id_hash_salt,
ConnectionResponseFrame::NOT_LISTENING)) {
LOG(INFO) << __func__ << "Failed to write NOT_LISTENING frame.";
}
return;
}
LOG(INFO) << "Accept new virtual socket request service ID : "
<< listening_service_id << ", hash salt : " << service_id_hash_salt
<< ", hash key : " << salted_service_id_hash_key << " on medium "
<< Medium_Name(medium_);
if (!multiplex_output_stream_.WriteConnectionResponseFrame(
salted_service_id_hash, service_id_hash_salt,
ConnectionResponseFrame::CONNECTION_ACCEPTED)) {
LOG(INFO) << "Failed to write CONNECTION_ACCEPTED frame.";
return;
}
LOG(INFO)
<< "EstablishVirtualSocket after local device accept the connection "
"with serviceId="
<< listening_service_id;
MediumSocket* virtual_socket =
CreateVirtualSocket(listening_service_id, service_id_hash_salt);
(*incoming_connection_callback)(std::move(listening_service_id),
virtual_socket);
}
void MultiplexSocket::HandleConnectionResponse(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const ConnectionResponseFrame& frame) {
LOG(INFO) << __func__
<< "connection_response_code: " << frame.connection_response_code();
for (auto& [service_id, future] : connection_response_futures_) {
if (GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt) ==
salted_service_id_hash) {
if (future != nullptr) {
future->Set(frame.connection_response_code());
LOG(INFO) << __func__ << "Set the future for serviceId=" << service_id
<< ", serviceIdHashSalt=" << service_id_hash_salt
<< " with response code=" << frame.connection_response_code();
return;
}
}
}
LOG(WARNING)
<< __func__
<< "Received a CONNECTION_RESPONSE frame but no client waiting for "
"service ID Hash Key"
<< GenerateServiceIdHashKey(salted_service_id_hash);
}
void MultiplexSocket::HandleDisconnection(
const ByteArray& salted_service_id_hash) {
std::string salted_service_id_hash_key =
GenerateServiceIdHashKey(salted_service_id_hash);
MediumSocket* virtual_socket_to_close = nullptr;
{
MutexLock lock(&virtual_socket_mutex_);
auto item = virtual_sockets_.find(salted_service_id_hash_key);
if (item != virtual_sockets_.end()) {
LOG(INFO)
<< "Received a DISCONNECTION frame to disconnect virtual socket for "
"salted service ID Hash Key "
<< salted_service_id_hash_key;
virtual_socket_to_close = item->second.get();
} else {
LOG(WARNING)
<< "Received a DISCONNECTION frame but there's no alive socket to "
"disconnect for service ID Hash Key "
<< salted_service_id_hash_key;
}
}
// Close the virtual socket outside of the mutex lock because
// OnVirtualSocketClosed will lock the mutex.
if (virtual_socket_to_close != nullptr) {
virtual_socket_to_close->Close();
}
}
void MultiplexSocket::HandleDataFrame(const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const MultiplexDataFrame& frame) {
std::string salted_service_id_hash_key =
GenerateServiceIdHashKey(salted_service_id_hash);
MediumSocket* virtual_socket = nullptr;
if (service_id_hash_salt.empty()) {
{
MutexLock lock(&virtual_socket_mutex_);
auto item = virtual_sockets_.find(salted_service_id_hash_key);
if (item != virtual_sockets_.end()) {
virtual_socket = item->second.get();
}
}
} else {
virtual_socket =
ReMapAndGetVirtualSocket(salted_service_id_hash, service_id_hash_salt);
}
if (virtual_socket != nullptr) {
VLOG(1)
<< "Received a DATA frame to feed virtual socket for salted service ID "
"Hash Key "
<< salted_service_id_hash_key;
virtual_socket->FeedIncomingData(ByteArray(frame.data()));
} else {
LOG(WARNING)
<< "Received a DATA frame but there's no alive socket to feed for "
"salted service ID Hash Key "
<< salted_service_id_hash_key;
}
}
void MultiplexSocket::OnPhysicalSocketClosed() {
RunOffloadThread("Shutdown", [this]() { Shutdown(); });
}
void MultiplexSocket::OnVirtualSocketClosed(const std::string& service_id) {
LOG(INFO) << __func__ << " for service_id:" << service_id;
CountDownLatch latch(1);
bool shutdown = false;
RunOffloadThread(
"VirtualSocketClosed", [this, service_id, &latch, &shutdown]() {
LOG(INFO) << "Try to close Virtual socket: " << service_id;
MediumSocket* virtual_socket = GetVirtualSocket(service_id);
{
MutexLock lock(&virtual_socket_mutex_);
LOG(INFO) << "virtual_socket:" << virtual_socket;
if (virtual_socket != nullptr) {
auto salted_service_id_hash_key = GenerateServiceIdHashKeyWithSalt(
service_id,
multiplex_output_stream_.GetServiceIdHashSalt(service_id));
multiplex_output_stream_.Close(service_id);
virtual_sockets_.erase(salted_service_id_hash_key);
LOG(INFO) << "Erase Virtual socket with service_id: " << service_id
<< ", hash_key: " << salted_service_id_hash_key;
ListVirtualSocket();
if (virtual_sockets_.empty()) {
LOG(INFO) << "Close the physical socket because all virtual "
"sockets disconnected.";
is_shutting_down_.Set(true);
Shutdown();
shutdown = true;
}
} else {
LOG(INFO) << "Virtual socket(" << service_id << ") not found";
}
}
latch.CountDown();
});
if (!latch.Await(absl::Milliseconds(1000)).result()) {
LOG(ERROR) << "Timeout to close virtual socket";
}
if (shutdown) {
LOG(INFO)
<< "Shutdown single_thread_offloader_ and physical_reader_thread_";
single_thread_offloader_.Shutdown();
physical_reader_thread_.Shutdown();
is_shutting_down_.Set(false);
}
}
MediumSocket* MultiplexSocket::ReMapAndGetVirtualSocket(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt) {
std::string salted_service_id_hash_key =
GenerateServiceIdHashKey(salted_service_id_hash);
VLOG(1) << "ReMapAndGetVirtualSocket with serviceIdHashSalt="
<< service_id_hash_salt
<< ", saltedServiceIdHashKey=" << salted_service_id_hash_key;
{
MutexLock lock(&virtual_socket_mutex_);
for (auto& [hash_key, virtual_socket] : virtual_sockets_) {
auto output_stream =
down_cast<MultiplexOutputStream::VirtualOutputStream*>(
&(virtual_socket->GetOutputStream()));
if (output_stream == nullptr) {
continue;
}
if (!output_stream->IsFirstVirtualOutputStream()) {
continue;
}
if ((service_id_hash_salt == kFakeSalt) ||
(hash_key == salted_service_id_hash_key)) {
return virtual_socket.get();
} else {
LOG(INFO) << "Remap the virtualSockets.";
output_stream->SetserviceIdHashSalt(service_id_hash_salt);
auto virtual_socket_tmp = virtual_socket;
LOG(INFO) << "virtual_socket before:" << virtual_socket;
virtual_sockets_.erase(hash_key);
virtual_sockets_[salted_service_id_hash_key] = virtual_socket_tmp;
ListVirtualSocket();
return virtual_socket_tmp.get();
}
}
}
LOG(INFO) << "Failed to remap the virtualSockets.";
return nullptr;
}
void MultiplexSocket::RunOffloadThread(const std::string& name,
absl::AnyInvocable<void()> runnable) {
single_thread_offloader_.Execute(name, std::move(runnable));
}
void MultiplexSocket::Shutdown() {
LOG(INFO) << __func__ << " start";
if (is_shutdown_) {
LOG(INFO) << __func__ << " Already shutdown";
return;
}
multiplex_output_stream_.Shutdown();
physical_socket_ptr_->Close();
if (reader_thread_shutdown_barrier_) {
reader_thread_shutdown_barrier_->Await(kTimeoutForReaderThreadStop);
}
GetIncomingConnectionCallbacks().clear();
connection_response_futures_.clear();
is_shutdown_ = true;
enabled_.Set(false);
LOG(INFO) << __func__ << " end";
}
void MultiplexSocket::ShutdownAll() {
LOG(INFO) << __func__ << " start";
if (is_shutdown_) {
LOG(WARNING) << __func__ << " Already shutdown";
return;
}
CountDownLatch latch(1);
RunOffloadThread("VirtualSocketClosed", [this, &latch]() {
{
MutexLock lock(&virtual_socket_mutex_);
multiplex_output_stream_.CloseAll();
virtual_sockets_.clear();
Shutdown();
}
latch.CountDown();
});
if (!latch
.Await(FeatureFlags::GetInstance()
.GetFlags()
.mediums_frame_write_timeout_millis +
absl::Milliseconds(100))
.result()) {
LOG(ERROR) << "Timeout to close virtual socket";
}
LOG(INFO) << "Shutdown single_thread_offloader_ and physical_reader_thread_";
single_thread_offloader_.Shutdown();
physical_reader_thread_.Shutdown();
LOG(INFO) << __func__ << " end";
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,222 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_
#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h"
#include "connections/medium_selector.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/future.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/socket.h"
#include "proto/connections_enums.pb.h"
#include "proto/mediums/multiplex_frames.pb.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
using MultiplexEnbaleCb = absl::AnyInvocable<void()>;
using MultiplexIncomingConnectionCb = absl::AnyInvocable<void(
const std::string& service_id, MediumSocket* socket)>;
class MultiplexSocket {
public:
MultiplexSocket(const MultiplexSocket&) = delete;
MultiplexSocket& operator=(const MultiplexSocket&) = delete;
~MultiplexSocket() { ShutdownAll(); };
// Creates a new incoming MultiplexSocket.
static MultiplexSocket* CreateIncomingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id, std::int32_t first_frame_len);
// Creates a new outgoing MultiplexSocket.
static MultiplexSocket* CreateOutgoingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id, const std::string& service_id_hash_salt);
// Creates a new outgoing MultiplexSocket with default service_id_hash_salt.
static MultiplexSocket* CreateOutgoingSocket(
std::shared_ptr<MediumSocket> physical_socket,
const std::string& service_id);
// A Table of service Id as row key, medium type as column key, and
// MultiplexIncomingConnectionCb as value. Non-empty while the client starts
// listening for incoming virtual socket. The MultiplexIncomingConnectionCb
// will be called when the incoming virtual socket is established.
static absl::flat_hash_map<
std::pair<std::string, ::location::nearby::proto::connections::Medium>,
MultiplexIncomingConnectionCb>&
GetIncomingConnectionCallbacks();
// Listens for incoming connection through multiplex for specified {@code
// service_id} on medium
// {@code type}. Should register the callback before new the MultiplexSocket.
static void ListenForIncomingConnection(
const std::string& service_id,
::location::nearby::proto::connections::Medium type,
absl::AnyInvocable<void(const std::string& service_id,
MediumSocket* socket)>
incoming_connection_cb);
// Stops listening for incoming multiplex connection for {@code service_id} on
// medium {@code type}.
static void StopListeningForIncomingConnection(
const std::string& service_id,
::location::nearby::proto::connections::Medium type);
bool IsEnabled() { return enabled_.Get(); }
void Enable() {
LOG(INFO) << "Enable the Multiplex MediumSocket.";
enabled_.Set(true);
}
// Gets the virtual socket by service id.
MediumSocket* GetVirtualSocket(const std::string& service_id);
// Gets the virtual socket count.
int GetVirtualSocketCount();
void ListVirtualSocket()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(virtual_socket_mutex_);
// Establishes the virtual socket by service id.
MediumSocket* EstablishVirtualSocket(const std::string& service_id);
// Shuts down the multiplex socket.
void Shutdown();
bool IsShutdown() { return is_shutdown_; }
void SetShutdown(bool is_shutdown) { is_shutdown_ = is_shutdown; }
void ShutdownAll();
private:
explicit MultiplexSocket(std::shared_ptr<MediumSocket> physical_socket);
// Creates the first virtual socket for the service id. The first virtual
// socket is created by the sender.
MediumSocket* CreateFirstVirtualSocket(
const std::string& service_id, const std::string& service_id_hash_salt);
// Creates the virtual socket for the service id.
MediumSocket* CreateVirtualSocket(const std::string& service_id,
const std::string& service_id_hash_salt);
// Registers the connection response future for the service id.
std::shared_ptr<Future<::location::nearby::mediums::ConnectionResponseFrame::
ConnectionResponseCode>>
RegisterConnectionResponse(const std::string& service_id);
// Unregisters the connection response future for the service id.
void UnRegisterConnectionResponse(const std::string& service_id);
// Starts the reader thread to read the incoming MultiplexFrame from the
// physical socket.
void StartReaderThread(std::int32_t first_frame_len);
// Handles the offline frame from the physical socket.
void HandleOfflineFrame(const ByteArray& bytes);
// Handles the control frame from the physical socket.
void HandleControlFrame(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const ::location::nearby::mediums::MultiplexControlFrame& frame);
// Handles the connection request frame from the physical socket.
void HandleConnectionRequest(const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt);
// Handles the connection response frame from the physical socket.
void HandleConnectionResponse(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const ::location::nearby::mediums::ConnectionResponseFrame& frame);
// Handles the disconnection frame from the physical socket.
void HandleDisconnection(const ByteArray& salted_service_id_hash);
// Handles the data frame from the physical socket.
void HandleDataFrame(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt,
const ::location::nearby::mediums::MultiplexDataFrame& frame);
// Handles the physical socket closed.
void OnPhysicalSocketClosed();
// Remaps and gets the virtual socket by service id hash.
MediumSocket* ReMapAndGetVirtualSocket(
const ByteArray& salted_service_id_hash,
const std::string& service_id_hash_salt);
// Handles the virtual socket closed.
void OnVirtualSocketClosed(const std::string& service_id);
// Runs the offload thread.
void RunOffloadThread(const std::string& name,
absl::AnyInvocable<void()> runnable);
// The physical socket connect to the remote device.
std::shared_ptr<MediumSocket> physical_socket_ptr_;
// The output stream to manage all outgoing frames from all clients.
MultiplexOutputStream multiplex_output_stream_;
// The {@link InputStream} of the physical socket. It is used to read the
// incoming MultiplexFrame from the physical socket.
InputStream* physical_reader_;
// The medium type of the physical socket.
Medium medium_;
// The callback to enable the MultiplexSocket.
std::shared_ptr<absl::AnyInvocable<void()>> enable_cb_ =
std::make_shared<absl::AnyInvocable<void()>>([this]() { Enable(); });
// A map of service Id -> {@link SettableFuture} for waiting the
// ConnectionResponse. Non-empty while requesting the virtual socket.
absl::flat_hash_map<std::string,
std::shared_ptr<Future<
::location::nearby::mediums::ConnectionResponseFrame::
ConnectionResponseCode>>>
connection_response_futures_;
// A map of service Id hash key -> virtual socket. Non-empty while at least
// one virtual socket alive. Class derived from "MediumSocket" should define a
// pointer to the virtual sockets map. When here's any virtual socket
// operation, it will be reflected in both derived MediumSocket class and
// MultiplexSocket object
mutable Mutex virtual_socket_mutex_;
absl::flat_hash_map<std::string, std::shared_ptr<MediumSocket>>
virtual_sockets_ ABSL_GUARDED_BY(virtual_socket_mutex_);
// The thread to receive incoming MultiplexFrame from the physical socket.
SingleThreadExecutor physical_reader_thread_;
// The single thread we throw the potentially blocking work on to.
SingleThreadExecutor single_thread_offloader_;
// The status of the MultiplexSocket enabled or disabled, it depends on both
// Sender and Receiver supports MultiplexSocket or not. Default disabled and
// enable it once two devices negotiated finished.
AtomicBoolean enabled_{false};
// If the socket is already shutdown and no longer in use.
bool is_shutdown_ = false;
static AtomicBoolean is_shutting_down_;
std::unique_ptr<CountDownLatch> reader_thread_shutdown_barrier_;
};
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_
@@ -1,451 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "connections/implementation/mediums/multiplex/multiplex_socket.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/mediums/multiplex/multiplex_frames.h"
#include "connections/implementation/offline_frames.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/future.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/pipe.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/socket.h"
#include "proto/connections_enums.proto.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace multiplex {
constexpr absl::string_view SERVICE_ID_1 = "serviceId_1";
constexpr absl::string_view SERVICE_ID_2 = "serviceId_2";
using location::nearby::mediums::ConnectionResponseFrame;
using location::nearby::mediums::MultiplexControlFrame;
using location::nearby::mediums::MultiplexFrame;
using location::nearby::proto::connections::Medium;
using location::nearby::proto::connections::Medium_Name;
// A fake socket for testing.
class FakeSocket : public MediumSocket {
public:
explicit FakeSocket(Medium medium) : MediumSocket(medium) {
pipe_1_ = CreatePipe();
reader_1_ = std::move(pipe_1_.first);
writer_1_ = std::move(pipe_1_.second);
pipe_2_ = CreatePipe();
reader_2_ = std::move(pipe_2_.first);
writer_2_ = std::move(pipe_2_.second);
LOG(WARNING) << "Physical Socket Medium:" << Medium_Name(GetMedium());
};
~FakeSocket() override = default;
FakeSocket(const FakeSocket&) = default;
FakeSocket& operator=(const FakeSocket&) = default;
/**
* The constructor for a virtual socket which own the virtual {@link
* OutputStream} and {@link InputStream}.
*/
explicit FakeSocket(Medium medium, OutputStream* virtualOutputStream)
: MediumSocket(medium),
is_virtual_socket_(true),
virtual_output_stream_(virtualOutputStream) {
pipe_1_ = CreatePipe();
reader_1_ = std::move(pipe_1_.first);
writer_1_ = std::move(pipe_1_.second);
pipe_2_ = CreatePipe();
reader_2_ = std::move(pipe_2_.first);
writer_2_ = std::move(pipe_2_.second);
}
InputStream& GetInputStream() override { return *reader_1_; }
OutputStream& GetOutputStream() override {
return IsVirtualSocket() ? *virtual_output_stream_
: *writer_2_;
} Exception Close() override {
if (IsVirtualSocket()) {
LOG(INFO) << "Multiplex: Closing virtual socket: " << this;
CloseLocal();
return {Exception::kSuccess};
}
LOG(INFO) << "Multiplex: Closing physical socket: " << this;
reader_1_->Close();
reader_2_->Close();
writer_1_->Close();
writer_2_->Close();
return {Exception::kSuccess};
}
MediumSocket* CreateVirtualSocket(
const std::string& salted_service_id_hash_key, OutputStream* outputstream,
Medium medium,
absl::flat_hash_map<std::string, std::shared_ptr<MediumSocket>>*
virtual_sockets_ptr) override {
if (IsVirtualSocket()) {
LOG(WARNING)
<< "Creating the virtual socket on a virtual socket is not allowed.";
return nullptr;
}
auto virtual_socket = std::make_shared<FakeSocket>(medium, outputstream);
LOG(WARNING) << "Created the virtual socket for Medium: "
<< Medium_Name(virtual_socket->GetMedium());
if (virtual_sockets_ptr_ == nullptr) {
virtual_sockets_ptr_ = virtual_sockets_ptr;
}
(*virtual_sockets_ptr_)[salted_service_id_hash_key] = virtual_socket;
LOG(INFO) << "virtual_sockets_ size: " << virtual_sockets_ptr_->size();
return virtual_socket.get();
}
void FeedIncomingData(ByteArray data) override {
bytes_read_future_.Set(data);
LOG(INFO) << "FeedIncomingData. Size of receive data: " << data.size()
<< ", bytes content:" << std::string(data);
}
bool IsVirtualSocket() override { return is_virtual_socket_; }
Future<ByteArray>& GetByteReadFuture() { return bytes_read_future_; }
std::pair<std::unique_ptr<InputStream>, std::unique_ptr<OutputStream>>
pipe_1_;
std::unique_ptr<InputStream> reader_1_;
std::unique_ptr<OutputStream> writer_1_;
std::pair<std::unique_ptr<InputStream>, std::unique_ptr<OutputStream>>
pipe_2_;
std::unique_ptr<InputStream> reader_2_;
std::unique_ptr<OutputStream> writer_2_;
private:
bool is_virtual_socket_ = false;
Future<ByteArray> bytes_read_future_;
absl::flat_hash_map<std::string, std::shared_ptr<MediumSocket>>*
virtual_sockets_ptr_ = nullptr;
OutputStream* virtual_output_stream_ = nullptr;
};
TEST(MultiplexSocketTest, CreateIncomingSocketSuccess) {
auto fake_socket_ptr = std::make_shared<FakeSocket>(Medium::BLUETOOTH);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1),
Medium::BLUETOOTH);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2),
Medium::BLUETOOTH);
MultiplexSocket::ListenForIncomingConnection(
std::string(SERVICE_ID_1), Medium::BLUETOOTH,
[](const std::string& service_id, MediumSocket* socket) {
LOG(INFO) << "Incoming connection for service_id: " << service_id;
});
MultiplexSocket::ListenForIncomingConnection(
std::string(SERVICE_ID_2), Medium::BLUETOOTH,
[](const std::string& service_id, MediumSocket* socket) {
LOG(INFO) << "Incoming connection for service_id: " << service_id;
});
MultiplexSocket* multiplex_socket_incoming =
MultiplexSocket::CreateIncomingSocket(
fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0);
ASSERT_NE(multiplex_socket_incoming, nullptr);
MultiplexSocket* multiplex_socket_incoming_2 =
MultiplexSocket::CreateIncomingSocket(
fake_socket_ptr, std::string(SERVICE_ID_2), /*first_frame_len*/ 0);
ASSERT_EQ(multiplex_socket_incoming_2, multiplex_socket_incoming);
FakeSocket* virtual_socket =
(FakeSocket*)multiplex_socket_incoming->GetVirtualSocket(
std::string(SERVICE_ID_1));
if (virtual_socket == nullptr) {
LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1;
return;
}
SingleThreadExecutor executor;
FakeSocket* socket = fake_socket_ptr.get();
executor.Execute([socket]() {
ByteArray connection_req_frame = parser::ForConnectionRequestConnections(
{}, {
.local_endpoint_id = "endpoint1",
.local_endpoint_info = ByteArray("endpoint1 info"),
});
auto& writer = socket->writer_1_;
LOG(INFO) << "writer_1_ Write start";
Base64Utils::WriteInt(writer.get(), connection_req_frame.size());
writer->Write(connection_req_frame.AsStringView());
writer->Flush();
LOG(INFO) << "writer_1_ Write end";
});
ExceptionOr<ByteArray> result = virtual_socket->GetByteReadFuture().Get();
if (!result.ok()) {
ADD_FAILURE() << "Read error: " << result.GetException().value;
}
ByteArray data = result.result();
LOG(INFO) << "Received " << data.size() << " bytes of data.";
EXPECT_NE(data.size(), 0);
absl::SleepFor(absl::Milliseconds(100));
EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 1);
virtual_socket->Close();
EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 0);
multiplex_socket_incoming->ShutdownAll();
}
TEST(MultiplexSocketTest, CreateFail_MediumNotSupport) {
auto fake_socket_ptr = std::make_shared<FakeSocket>(Medium::WEB_RTC);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1),
Medium::WEB_RTC);
MultiplexSocket* multiplex_socket_incoming =
MultiplexSocket::CreateIncomingSocket(
fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0);
ASSERT_EQ(multiplex_socket_incoming, nullptr);
}
TEST(MultiplexSocketTest, CreateIncomingVirtualSocketSuccess) {
auto fake_socket_ptr = std::make_shared<FakeSocket>(Medium::WIFI_LAN);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1),
Medium::WIFI_LAN);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2),
Medium::WIFI_LAN);
MultiplexSocket::ListenForIncomingConnection(
std::string(SERVICE_ID_1), Medium::WIFI_LAN,
[](const std::string& service_id, MediumSocket* socket) {
LOG(INFO) << "Incoming connection for service_id: " << service_id;
});
MultiplexSocket::ListenForIncomingConnection(
std::string(SERVICE_ID_2), Medium::WIFI_LAN,
[](const std::string& service_id, MediumSocket* socket) {
LOG(INFO) << "Incoming connection for service_id: " << service_id;
});
MultiplexSocket* multiplex_socket_incoming =
MultiplexSocket::CreateIncomingSocket(
fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0);
ASSERT_NE(multiplex_socket_incoming, nullptr);
FakeSocket* virtual_socket =
(FakeSocket*)multiplex_socket_incoming->GetVirtualSocket(
std::string(SERVICE_ID_1));
if (virtual_socket == nullptr) {
LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1;
return;
}
SingleThreadExecutor executor;
FakeSocket* socket = fake_socket_ptr.get();
executor.Execute([socket]() {
ByteArray connection_req_frame = ForConnectionRequest(
std::string(SERVICE_ID_2), "J7frzSmHK-VBTHjCKpf4ew");
auto& writer = socket->writer_1_;
LOG(INFO) << "writer_1_ Write start";
Base64Utils::WriteInt(writer.get(), connection_req_frame.size());
writer->Write(connection_req_frame.AsStringView());
writer->Flush();
LOG(INFO) << "writer_1_ Write end";
});
absl::SleepFor(absl::Milliseconds(100));
EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 2);
virtual_socket->Close();
EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 1);
multiplex_socket_incoming->ShutdownAll();
}
TEST(MultiplexSocketTest,
EstablishVirtualSocket_Timeout_BecauseNoConnectionResponse) {
auto fake_socket_ptr = std::make_shared<FakeSocket>(Medium::WIFI_LAN);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1),
Medium::WIFI_LAN);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2),
Medium::WIFI_LAN);
MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket(
fake_socket_ptr, std::string(SERVICE_ID_1));
ASSERT_NE(multiplex_socket, nullptr);
MultiplexSocket* multiplex_socket_2 = MultiplexSocket::CreateOutgoingSocket(
fake_socket_ptr, std::string(SERVICE_ID_2));
ASSERT_EQ(multiplex_socket_2, multiplex_socket);
multiplex_socket->Enable();
FakeSocket* virtual_socket = (FakeSocket*)multiplex_socket->GetVirtualSocket(
std::string(SERVICE_ID_1));
if (virtual_socket == nullptr) {
LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1;
return;
}
SingleThreadExecutor establish_socket_executor;
establish_socket_executor.Execute([&multiplex_socket]() {
LOG(INFO) << "EstablishVirtualSocket";
MediumSocket* socket =
multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2));
LOG(INFO) << "EstablishVirtualSocket finished";
EXPECT_EQ(socket, nullptr);
});
SingleThreadExecutor read_executor;
read_executor.Execute([&multiplex_socket, &fake_socket_ptr]() {
auto reader = fake_socket_ptr->reader_2_.get();
LOG(INFO) << "reader_2_ Read start";
ExceptionOr<std::int32_t> read_int = Base64Utils::ReadInt(reader);
if (!read_int.ok()) {
ADD_FAILURE() << "Failed to read. Exception:" << read_int.exception();
}
auto length = read_int.result();
LOG(INFO) << " length:" << length;
EXPECT_GT(length, 0);
EXPECT_EQ(multiplex_socket->GetVirtualSocket(std::string(SERVICE_ID_2)),
nullptr);
});
absl::SleepFor(absl::Milliseconds(300));
EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 1);
virtual_socket->Close();
EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 0);
multiplex_socket->ShutdownAll();
}
TEST(MultiplexSocketTest, EstablishVirtualSocket_RemoteAccepted) {
auto fake_socket_ptr = std::make_shared<FakeSocket>(Medium::BLUETOOTH);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1),
Medium::BLUETOOTH);
MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2),
Medium::BLUETOOTH);
MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket(
fake_socket_ptr, std::string(SERVICE_ID_1));
ASSERT_NE(multiplex_socket, nullptr);
MultiplexSocket* multiplex_socket_2 = MultiplexSocket::CreateOutgoingSocket(
fake_socket_ptr, std::string(SERVICE_ID_2));
ASSERT_EQ(multiplex_socket_2, multiplex_socket);
SingleThreadExecutor executor;
CountDownLatch latch(1);
executor.Execute([&multiplex_socket, &latch]() {
LOG(INFO) << "EstablishVirtualSocket";
MediumSocket* socket =
multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2));
EXPECT_EQ(socket, nullptr);
latch.CountDown();
});
latch.Await();
multiplex_socket->Enable();
executor.Execute([&multiplex_socket]() {
LOG(INFO) << "EstablishVirtualSocket";
MediumSocket* socket =
multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2));
EXPECT_NE(socket, nullptr);
});
auto reader = fake_socket_ptr->reader_2_.get();
LOG(INFO) << "reader_2_ Waiting for CONNECTION_REQUEST frame.";
ExceptionOr<std::int32_t> read_int = Base64Utils::ReadInt(reader);
if (!read_int.ok()) {
ADD_FAILURE() << "Failed to read length.Exception:" << read_int.exception();
}
auto length = read_int.result();
if (length < 0 ||
length >
FeatureFlags::GetInstance().GetFlags().connection_max_frame_length) {
ADD_FAILURE() << "Invalid length:" << length;
}
auto bytes = reader->ReadExactly(length);
if (!bytes.ok()) {
ADD_FAILURE() << "Failed to read frame. Exception:" << bytes.exception();
}
length = read_int.result();
if (length < 0 ||
length >
FeatureFlags::GetInstance().GetFlags().connection_max_frame_length) {
ADD_FAILURE() << "Invalid frame length:" << length;
}
ExceptionOr<MultiplexFrame> frame_exc = multiplex::FromBytes(bytes.result());
if (!frame_exc.ok()) {
ADD_FAILURE() << "Failed to parse MultiplexFrame. Exception:"
<< frame_exc.exception();
}
auto frame = frame_exc.result();
auto salted_service_id_hash =
ByteArray{std::move(frame.header().salted_service_id_hash())};
auto service_id_hash_salt = frame.header().has_service_id_hash_salt()
? frame.header().service_id_hash_salt()
: "";
ASSERT_EQ(frame.frame_type(), MultiplexFrame::CONTROL_FRAME);
auto control_frame = frame.control_frame();
ASSERT_EQ(control_frame.control_frame_type(),
MultiplexControlFrame::CONNECTION_REQUEST);
LOG(INFO) << "Recieved MultiplexControlFrame::CONNECTION_REQUEST "
"frame, now send CONNECTION_RESPONSE frame.";
ByteArray connection_response_frame =
ForConnectionResponse(salted_service_id_hash, service_id_hash_salt,
ConnectionResponseFrame::CONNECTION_ACCEPTED);
auto& writer = fake_socket_ptr->writer_1_;
LOG(INFO) << "writer_1_ Write start";
Base64Utils::WriteInt(writer.get(), connection_response_frame.size());
writer->Write(connection_response_frame.AsStringView());
writer->Flush();
LOG(INFO) << "writer_1_ Write end";
absl::SleepFor(absl::Milliseconds(100));
EXPECT_NE(multiplex_socket->GetVirtualSocket(std::string(SERVICE_ID_2)),
nullptr);
EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 2);
LOG(INFO) << "Send Data frame on virtual socket for SERVICE_ID_2.";
ByteArray data_frame =
ForData(std::string(SERVICE_ID_2), service_id_hash_salt,
/*should_pass_salt=*/true, absl::string_view("data"));
Base64Utils::WriteInt(writer.get(), data_frame.size());
writer->Write(data_frame.AsStringView());
writer->Flush();
absl::SleepFor(absl::Milliseconds(100));
LOG(INFO) << "Send disconnection frame on virtual socket for SERVICE_ID_2.";
ByteArray disconnect_frame =
ForDisconnection(std::string(SERVICE_ID_2), service_id_hash_salt);
Base64Utils::WriteInt(writer.get(), disconnect_frame.size());
writer->Write(disconnect_frame.AsStringView());
writer->Flush();
absl::SleepFor(absl::Milliseconds(100));
EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 1);
multiplex_socket->ShutdownAll();
}
} // namespace multiplex
} // namespace mediums
} // namespace connections
} // namespace nearby
@@ -1,788 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NO_WEBRTC
#include "connections/implementation/mediums/webrtc.h"
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "absl/functional/bind_front.h"
#include "absl/time/time.h"
#include "connections/implementation/mediums/webrtc/connection_flow.h"
#include "connections/implementation/mediums/webrtc/session_description_wrapper.h"
#include "connections/implementation/mediums/webrtc/signaling_frames.h"
#include "connections/implementation/mediums/webrtc_peer_id.h"
#include "connections/implementation/mediums/webrtc_socket.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancelable_alarm.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/future.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
#include "internal/platform/runnable.h"
#include "internal/platform/webrtc.h"
#include "webrtc/api/jsep.h"
namespace nearby {
namespace connections {
namespace mediums {
namespace {
using ::location::nearby::connections::LocationHint;
using ::location::nearby::proto::connections::OperationResultCode;
// The maximum amount of time to wait to connect to a data channel via WebRTC.
constexpr absl::Duration kDataChannelTimeout = absl::Seconds(10);
// Delay between restarting signaling messenger to receive messages.
constexpr absl::Duration kRestartReceiveMessagesDuration = absl::Seconds(60);
} // namespace
WebRtc::WebRtc() : WebRtc(std::make_unique<WebRtcMedium>()) {}
WebRtc::WebRtc(std::unique_ptr<WebRtcMedium> medium)
: medium_(std::move(medium)) {}
WebRtc::~WebRtc() {
// This ensures that all pending callbacks are run before we reset the medium
// and we are not accepting new runnables.
single_thread_executor_.Shutdown();
// Stop accepting all connections
absl::flat_hash_set<std::string> service_ids;
for (auto& item : accepting_connections_info_) {
service_ids.emplace(item.first);
}
for (const auto& service_id : service_ids) {
StopAcceptingConnections(service_id);
}
}
std::string WebRtc::GetDefaultCountryCode() {
return medium_->GetDefaultCountryCode();
}
bool WebRtc::IsAvailable() { return medium_->IsValid(); }
bool WebRtc::IsAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
return IsAcceptingConnectionsLocked(service_id);
}
bool WebRtc::IsAcceptingConnectionsLocked(const std::string& service_id) {
return accepting_connections_info_.contains(service_id);
}
bool WebRtc::StartAcceptingConnections(const std::string& service_id,
const WebrtcPeerId& self_peer_id,
const LocationHint& location_hint,
AcceptedConnectionCallback callback,
bool non_cellular) {
MutexLock lock(&mutex_);
if (!IsAvailable()) {
LOG(WARNING) << "Cannot start accepting WebRTC connections because "
"WebRTC is not available.";
return false;
}
if (IsAcceptingConnectionsLocked(service_id)) {
LOG(WARNING) << "Cannot start accepting WebRTC connections because service "
<< service_id << "is already accepting WebRTC connections.";
return false;
}
// We'll track our state here, so that we're separated from the other services
// who may be also using WebRTC.
AcceptingConnectionsInfo info = AcceptingConnectionsInfo();
info.self_peer_id = self_peer_id;
info.accepted_connection_callback = std::move(callback);
medium_->SetNonCellular(non_cellular);
// Create a new SignalingMessenger so that we can communicate w/ Tachyon.
info.signaling_messenger =
medium_->GetSignalingMessenger(self_peer_id.GetId(), location_hint);
if (!info.signaling_messenger->IsValid()) {
return false;
}
// This registers ourselves w/ Tachyon, creating a room from the PeerId.
// This allows a remote device to message us over Tachyon.
if (!info.signaling_messenger->StartReceivingMessages(
absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id),
absl::bind_front(&WebRtc::OnSignalingComplete, this, service_id))) {
info.signaling_messenger.reset();
return false;
}
// We'll automatically disconnect from Tachyon after 60sec. When this alarm
// fires, we'll recreate our room so we continue to receive messages.
info.restart_tachyon_receive_messages_alarm =
std::make_unique<CancelableAlarm>(
"restart_receiving_messages_webrtc",
std::bind(&WebRtc::ProcessRestartTachyonReceiveMessages, this,
service_id),
kRestartReceiveMessagesDuration, &single_thread_executor_);
// Now that we're set up to receive messages, we'll save our state and return
// a successful result.
accepting_connections_info_.emplace(service_id, std::move(info));
LOG(INFO) << "Started listening for WebRTC connections as "
<< self_peer_id.GetId() << " on service " << service_id;
return true;
}
void WebRtc::StopAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
if (!IsAcceptingConnectionsLocked(service_id)) {
LOG(WARNING) << "Cannot stop accepting WebRTC connections because service "
<< service_id << "is not accepting WebRTC connections.";
return;
}
// Grab our info from the map.
auto& info = accepting_connections_info_.find(service_id)->second;
// Stop receiving messages from Tachyon.
info.signaling_messenger->StopReceivingMessages();
info.signaling_messenger.reset();
// Cancel the scheduled alarm.
if (info.restart_tachyon_receive_messages_alarm &&
info.restart_tachyon_receive_messages_alarm->IsValid()) {
info.restart_tachyon_receive_messages_alarm->Cancel();
info.restart_tachyon_receive_messages_alarm.reset();
}
// If we had any in-progress connections that haven't materialized into full
// DataChannels yet, it's time to shut them down since they can't reach us
// anymore.
absl::flat_hash_set<std::string> peer_ids;
for (auto& item : connection_flows_) {
peer_ids.emplace(item.first);
}
for (const auto& peer_id : peer_ids) {
const auto& entry = connection_flows_.find(peer_id);
// Skip outgoing connections in this step. Start/StopAcceptingConnections
// only deals with incoming connections.
if (requesting_connections_info_.contains(peer_id)) {
continue;
}
// Skip fully connected connections in this step. If the connection was
// formed while we were accepting connections, then it will stay alive until
// it's explicitly closed.
if (!entry->second->CloseIfNotConnected()) {
continue;
}
connection_flows_.erase(peer_id);
}
// Clean up our state. We're now no longer listening for connections.
accepting_connections_info_.erase(service_id);
LOG(INFO) << "Stopped listening for WebRTC connections for service "
<< service_id;
}
ErrorOr<WebRtcSocketWrapper> WebRtc::Connect(
const std::string& service_id, const WebrtcPeerId& remote_peer_id,
const LocationHint& location_hint, CancellationFlag* cancellation_flag,
bool non_cellular) {
service_id_to_connect_attempts_count_map_[service_id] = 1;
medium_->SetNonCellular(non_cellular);
ErrorOr<WebRtcSocketWrapper> wrapper_result = {
Error(OperationResultCode::DETAIL_UNKNOWN)};
while (service_id_to_connect_attempts_count_map_[service_id] <=
kConnectAttemptsLimit) {
if (cancellation_flag->Cancelled()) {
LOG(WARNING) << "Attempt #"
<< service_id_to_connect_attempts_count_map_[service_id]
<< ": Cannot Connect with WebRtc due to cancel.";
return {
Error(OperationResultCode::
CLIENT_CANCELLATION_CANCEL_WEB_RTC_OUTGOING_CONNECTION)};
}
LOG(INFO) << "Attempt #"
<< service_id_to_connect_attempts_count_map_[service_id]
<< ": Beginning connection.";
wrapper_result = AttemptToConnect(service_id, remote_peer_id, location_hint,
cancellation_flag);
if (wrapper_result.has_value()) {
return std::move(wrapper_result.value());
}
service_id_to_connect_attempts_count_map_[service_id]++;
}
LOG(WARNING) << "Giving up after " << kConnectAttemptsLimit << " attempts";
return {Error(wrapper_result.error().operation_result_code().value())};
}
ErrorOr<WebRtcSocketWrapper> WebRtc::AttemptToConnect(
const std::string& service_id, const WebrtcPeerId& remote_peer_id,
const LocationHint& location_hint, CancellationFlag* cancellation_flag) {
ConnectionRequestInfo info = ConnectionRequestInfo();
info.self_peer_id = WebrtcPeerId::FromRandom();
Future<WebRtcSocketWrapper> socket_future = info.socket_future;
// `listener` will go out of scope at the end of `AttemptToConnect`, and this
// is expected. This `listener` is tied to `socket_future` which we block on
// within this stack call, and will not go out of scope until the attempt
// is complete.
CancellationFlagListener listener(
cancellation_flag, [this, &service_id, &socket_future]() {
LOG(WARNING) << "Attempt # "
<< service_id_to_connect_attempts_count_map_[service_id]
<< " to connect with WebRtc stopped due to cancel.";
socket_future.SetException({Exception::kFailed});
});
{
MutexLock lock(&mutex_);
if (!IsAvailable()) {
LOG(WARNING) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId()
<< " because WebRTC is not available.";
return {
Error(OperationResultCode::MEDIUM_UNAVAILABLE_WEB_RTC_NOT_AVAILABLE)};
}
// Create a new ConnectionFlow for this connection attempt.
std::unique_ptr<ConnectionFlow> connection_flow =
CreateConnectionFlow(service_id, remote_peer_id);
if (!connection_flow) {
LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId()
<< " because we failed to create a ConnectionFlow.";
return {Error(OperationResultCode::NEARBY_WEB_RTC_CONNECTION_FLOW_NULL)};
}
// Create a new SignalingMessenger so that we can communicate over Tachyon.
info.signaling_messenger = medium_->GetSignalingMessenger(
info.self_peer_id.GetId(), location_hint);
if (!info.signaling_messenger->IsValid()) {
LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId()
<< " because we failed to create a SignalingMessenger.";
return {
Error(OperationResultCode::
MISCELLEANEOUS_WEB_RTC_TACHYON_SIGNALING_MESSENGER_NULL)};
}
// This registers ourselves w/ Tachyon, creating a room from the PeerId.
// This allows a remote device to message us over Tachyon.
auto signaling_complete_callback = [socket_future](bool success) mutable {
if (!success) {
socket_future.SetException({Exception::kFailed});
}
};
if (!info.signaling_messenger->StartReceivingMessages(
absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id),
signaling_complete_callback)) {
LOG(INFO)
<< "Cannot connect to WebRTC peer " << remote_peer_id.GetId()
<< " because we failed to start receiving messages over Tachyon.";
info.signaling_messenger.reset();
return {Error(OperationResultCode::
MISCELLEANEOUS_WEB_RTC_FAILED_TO_RECEIVE_MESSAGE)};
}
// Poke the remote device. This will cause them to send us an Offer.
if (!info.signaling_messenger->SendMessage(
remote_peer_id.GetId(),
webrtc_frames::EncodeReadyForSignalingPoke(info.self_peer_id))) {
LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId()
<< " because we failed to poke the peer over Tachyon.";
info.signaling_messenger.reset();
return {Error(OperationResultCode::
CONNECTIVITY_WEB_RTC_CONNECT_TO_TACHYON_FAILURE)};
}
// Create a new ConnectionRequest entry. This map will be used later to look
// up state as we negotiate the connection over Tachyon.
requesting_connections_info_.emplace(remote_peer_id.GetId(),
std::move(info));
connection_flows_.emplace(remote_peer_id.GetId(),
std::move(connection_flow));
}
// Wait for the connection to go through. Don't hold the mutex here so that
// we're not blocking necessary operations.
ExceptionOr<WebRtcSocketWrapper> socket_result =
socket_future.Get(kDataChannelTimeout);
{
MutexLock lock(&mutex_);
// Reclaim our info, since we had released ownership while talking to
// Tachyon.
auto& info =
requesting_connections_info_.find(remote_peer_id.GetId())->second;
// Verify that the connection went through.
if (!socket_result.ok()) {
LOG(INFO) << "Failed to connect to WebRTC peer "
<< remote_peer_id.GetId();
RemoveConnectionFlow(remote_peer_id);
info.signaling_messenger.reset();
requesting_connections_info_.erase(remote_peer_id.GetId());
return {Error(OperationResultCode::
CONNECTIVITY_WEB_RTC_CLIENT_SOCKET_CREATION_FAILURE)};
}
// Clean up our ConnectionRequest.
info.signaling_messenger.reset();
requesting_connections_info_.erase(remote_peer_id.GetId());
// Return the result.
return socket_result.GetResult();
}
}
void WebRtc::ProcessLocalIceCandidate(
const std::string& service_id, const WebrtcPeerId& remote_peer_id,
const location::nearby::mediums::IceCandidate ice_candidate) {
MutexLock lock(&mutex_);
// Check first if we have an outgoing request w/ this peer. As this request is
// tied to a specific peer, it takes precedence.
const auto& connection_request_entry =
requesting_connections_info_.find(remote_peer_id.GetId());
if (connection_request_entry != requesting_connections_info_.end()) {
// Pass the ice candidate to the remote side.
if (!connection_request_entry->second.signaling_messenger->SendMessage(
remote_peer_id.GetId(),
webrtc_frames::EncodeIceCandidates(
connection_request_entry->second.self_peer_id,
{ice_candidate}))) {
LOG(INFO) << "Failed to send ice candidate to " << remote_peer_id.GetId();
}
LOG(INFO) << "Sent ice candidate to " << remote_peer_id.GetId();
return;
}
// Check next if we're expecting incoming connection requests.
const auto& accepting_connection_entry =
accepting_connections_info_.find(service_id);
if (accepting_connection_entry != accepting_connections_info_.end()) {
// Pass the ice candidate to the remote side.
// TODO(xlythe) Consider not blocking here, since this can eat into the
// connection time
if (!accepting_connection_entry->second.signaling_messenger->SendMessage(
remote_peer_id.GetId(),
webrtc_frames::EncodeIceCandidates(
accepting_connection_entry->second.self_peer_id,
{ice_candidate}))) {
LOG(INFO) << "Failed to send ice candidate to " << remote_peer_id.GetId();
}
LOG(INFO) << "Sent ice candidate to " << remote_peer_id.GetId();
return;
}
LOG(INFO) << "Skipping restart listening for tachyon inbox messages "
"since we are not accepting connections for service "
<< service_id;
}
void WebRtc::OnSignalingMessage(const std::string& service_id,
const ByteArray& message) {
OffloadFromThread("rtc-on-signaling-message", [this, service_id, message]() {
ProcessTachyonInboxMessage(service_id, message);
});
}
void WebRtc::OnSignalingComplete(const std::string& service_id, bool success) {
LOG(INFO) << "Signaling completed with status: " << success;
if (success) {
return;
}
OffloadFromThread("rtc-on-signaling-complete", [this, service_id]() {
MutexLock lock(&mutex_);
const auto& info_entry = accepting_connections_info_.find(service_id);
if (info_entry == accepting_connections_info_.end()) {
return;
}
if (info_entry->second.restart_accept_connections_count <
kRestartAcceptConnectionsLimit) {
++info_entry->second.restart_accept_connections_count;
} else {
return;
}
RestartTachyonReceiveMessages(service_id);
});
}
void WebRtc::ProcessTachyonInboxMessage(const std::string& service_id,
const ByteArray& message) {
MutexLock lock(&mutex_);
// Attempt to parse the incoming message as a WebRtcSignalingFrame.
location::nearby::mediums::WebRtcSignalingFrame frame;
if (!frame.ParseFromString(std::string(message))) {
LOG(WARNING) << "Failed to parse signaling message.";
return;
}
// Ensure that the frame is valid (no missing fields).
if (!frame.has_sender_id()) {
LOG(WARNING) << "Invalid WebRTC frame: Sender ID is missing.";
return;
}
WebrtcPeerId remote_peer_id = WebrtcPeerId(frame.sender_id().id());
// Depending on the message type, we'll respond as appropriate.
if (requesting_connections_info_.contains(remote_peer_id.GetId())) {
// This is from a peer we have an outgoing connection request with, so we'll
// only process the Answer path.
if (frame.has_offer()) {
ReceiveOffer(remote_peer_id,
SessionDescriptionWrapper(
webrtc_frames::DecodeOffer(frame).release()));
SendAnswer(remote_peer_id);
} else if (frame.has_ice_candidates()) {
ReceiveIceCandidates(remote_peer_id,
webrtc_frames::DecodeIceCandidates(frame));
} else {
LOG(INFO) << "Received unknown WebRTC frame: ignoring.";
}
} else if (IsAcceptingConnectionsLocked(service_id)) {
// We don't have an outgoing connection request with this peer, but we are
// accepting incoming requests so we'll only process the Offer path.
if (frame.has_ready_for_signaling_poke()) {
SendOffer(service_id, remote_peer_id);
} else if (frame.has_answer()) {
ReceiveAnswer(remote_peer_id,
SessionDescriptionWrapper(
webrtc_frames::DecodeAnswer(frame).release()));
} else if (frame.has_ice_candidates()) {
ReceiveIceCandidates(remote_peer_id,
webrtc_frames::DecodeIceCandidates(frame));
} else {
LOG(INFO) << "Received unknown WebRTC frame: ignoring.";
}
} else {
LOG(INFO)
<< "Ignoring Tachyon message since we are not accepting connections.";
}
}
void WebRtc::SendOffer(const std::string& service_id,
const WebrtcPeerId& remote_peer_id) {
std::unique_ptr<ConnectionFlow> connection_flow =
CreateConnectionFlow(service_id, remote_peer_id);
if (!connection_flow) {
LOG(INFO) << "Unable to send offer. Failed to create a ConnectionFlow.";
return;
}
SessionDescriptionWrapper offer = connection_flow->CreateOffer();
if (!offer.IsValid()) {
LOG(INFO) << "Unable to send offer. Failed to create our offer locally.";
RemoveConnectionFlow(remote_peer_id);
return;
}
const webrtc::SessionDescriptionInterface& sdp = offer.GetSdp();
if (!connection_flow->SetLocalSessionDescription(offer)) {
LOG(INFO) << "Unable to send offer. Failed to register our offer locally.";
RemoveConnectionFlow(remote_peer_id);
return;
}
// Grab our info from the map.
auto& info = accepting_connections_info_.find(service_id)->second;
// Pass the offer to the remote side.
if (!info.signaling_messenger->SendMessage(
remote_peer_id.GetId(),
webrtc_frames::EncodeOffer(info.self_peer_id, sdp))) {
LOG(INFO)
<< "Unable to send offer. Failed to write the offer to the remote peer "
<< remote_peer_id.GetId();
RemoveConnectionFlow(remote_peer_id);
return;
}
// Store the ConnectionFlow so that other methods can use it later.
connection_flows_.emplace(remote_peer_id.GetId(), std::move(connection_flow));
LOG(INFO) << "Sent offer to " << remote_peer_id.GetId();
}
void WebRtc::ReceiveOffer(const WebrtcPeerId& remote_peer_id,
SessionDescriptionWrapper offer) {
const auto& entry = connection_flows_.find(remote_peer_id.GetId());
if (entry == connection_flows_.end()) {
LOG(INFO) << "Unable to receive offer. Failed to create a ConnectionFlow.";
return;
}
if (!entry->second->OnOfferReceived(offer)) {
LOG(INFO) << "Unable to receive offer. Failed to process the offer.";
RemoveConnectionFlow(remote_peer_id);
}
}
void WebRtc::SendAnswer(const WebrtcPeerId& remote_peer_id) {
const auto& entry = connection_flows_.find(remote_peer_id.GetId());
if (entry == connection_flows_.end()) {
LOG(INFO) << "Unable to send answer. Failed to create a ConnectionFlow.";
return;
}
SessionDescriptionWrapper answer = entry->second->CreateAnswer();
if (!answer.IsValid()) {
LOG(INFO) << "Unable to send answer. Failed to create our answer locally.";
RemoveConnectionFlow(remote_peer_id);
return;
}
const webrtc::SessionDescriptionInterface& sdp = answer.GetSdp();
if (!entry->second->SetLocalSessionDescription(answer)) {
LOG(INFO)
<< "Unable to send answer. Failed to register our answer locally.";
RemoveConnectionFlow(remote_peer_id);
return;
}
// Grab our info from the map.
const auto& connection_request_entry =
requesting_connections_info_.find(remote_peer_id.GetId());
if (connection_request_entry == requesting_connections_info_.end()) {
LOG(INFO) << "Unable to send answer. Failed to find an outgoing "
"connection request.";
RemoveConnectionFlow(remote_peer_id);
return;
}
// Pass the answer to the remote side.
if (!connection_request_entry->second.signaling_messenger->SendMessage(
remote_peer_id.GetId(),
webrtc_frames::EncodeAnswer(
connection_request_entry->second.self_peer_id, sdp))) {
LOG(INFO)
<< "Unable to send answer. Failed to write the answer to the remote "
"peer "
<< remote_peer_id.GetId();
RemoveConnectionFlow(remote_peer_id);
return;
}
LOG(INFO) << "Sent answer to " << remote_peer_id.GetId();
}
void WebRtc::ReceiveAnswer(const WebrtcPeerId& remote_peer_id,
SessionDescriptionWrapper answer) {
const auto& entry = connection_flows_.find(remote_peer_id.GetId());
if (entry == connection_flows_.end()) {
LOG(INFO) << "Unable to receive answer. Failed to create a ConnectionFlow.";
return;
}
if (!entry->second->OnAnswerReceived(answer)) {
LOG(INFO) << "Unable to receive answer. Failed to process the answer.";
RemoveConnectionFlow(remote_peer_id);
}
}
void WebRtc::ReceiveIceCandidates(
const WebrtcPeerId& remote_peer_id,
std::vector<std::unique_ptr<webrtc::IceCandidate>> ice_candidates) {
const auto& entry = connection_flows_.find(remote_peer_id.GetId());
if (entry == connection_flows_.end()) {
LOG(INFO) << "Unable to receive ice candidates. Failed to create a "
"ConnectionFlow.";
return;
}
entry->second->OnRemoteIceCandidatesReceived(std::move(ice_candidates));
}
void WebRtc::ProcessRestartTachyonReceiveMessages(
const std::string& service_id) {
MutexLock lock(&mutex_);
RestartTachyonReceiveMessages(service_id);
}
void WebRtc::RestartTachyonReceiveMessages(const std::string& service_id) {
if (!IsAcceptingConnectionsLocked(service_id)) {
LOG(INFO)
<< "Skipping restart listening for tachyon inbox messages since we are "
"not accepting connections for service "
<< service_id;
return;
}
// Grab our info from the map.
auto& info = accepting_connections_info_.find(service_id)->second;
// Ensure we've disconnected from Tachyon.
info.signaling_messenger->StopReceivingMessages();
// Attempt to re-register.
if (!info.signaling_messenger->StartReceivingMessages(
absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id),
absl::bind_front(&WebRtc::OnSignalingComplete, this, service_id))) {
LOG(WARNING)
<< "Failed to restart listening for tachyon inbox messages for "
"service "
<< service_id << " since we failed to reach Tachyon.";
return;
}
LOG(INFO) << "Successfully restarted listening for tachyon inbox "
"messages on service "
<< service_id;
}
void WebRtc::ProcessDataChannelOpen(const std::string& service_id,
const WebrtcPeerId& remote_peer_id,
WebRtcSocketWrapper socket_wrapper) {
MutexLock lock(&mutex_);
// Notify the client of the newly formed socket.
const auto& connection_request_entry =
requesting_connections_info_.find(remote_peer_id.GetId());
if (connection_request_entry != requesting_connections_info_.end()) {
connection_request_entry->second.socket_future.Set(socket_wrapper);
return;
}
const auto& accepting_connection_entry =
accepting_connections_info_.find(service_id);
if (accepting_connection_entry != accepting_connections_info_.end() &&
accepting_connection_entry->second.accepted_connection_callback) {
accepting_connection_entry->second.accepted_connection_callback(
service_id, socket_wrapper);
return;
}
// No one to handle the newly created DataChannel, so we'll just close it.
socket_wrapper.Close();
LOG(INFO) << "Ignoring new DataChannel because we are not accepting "
"connections for service "
<< service_id;
}
void WebRtc::ProcessDataChannelClosed(const WebrtcPeerId& remote_peer_id) {
MutexLock lock(&mutex_);
LOG(INFO) << "Data channel has closed, removing connection flow for peer "
<< remote_peer_id.GetId();
RemoveConnectionFlow(remote_peer_id);
}
std::unique_ptr<ConnectionFlow> WebRtc::CreateConnectionFlow(
const std::string& service_id, const WebrtcPeerId& remote_peer_id) {
RemoveConnectionFlow(remote_peer_id);
return ConnectionFlow::Create(
{.local_ice_candidate_found_cb =
{[this, service_id,
remote_peer_id](const webrtc::IceCandidate* ice_candidate) {
// Note: We need to encode the ice candidate here, before we jump
// off the thread. Otherwise, it gets destroyed and we can't read
// it later.
location::nearby::mediums::IceCandidate encoded_ice_candidate =
webrtc_frames::EncodeIceCandidate(*ice_candidate);
OffloadFromThread(
"rtc-ice-candidates",
[this, service_id, remote_peer_id, encoded_ice_candidate]() {
ProcessLocalIceCandidate(service_id, remote_peer_id,
encoded_ice_candidate);
});
}}},
{
.data_channel_open_cb = {[this, service_id, remote_peer_id](
WebRtcSocketWrapper socket_wrapper) {
OffloadFromThread(
"rtc-channel-created",
[this, service_id, remote_peer_id, socket_wrapper]() {
ProcessDataChannelOpen(service_id, remote_peer_id,
socket_wrapper);
});
}},
.data_channel_closed_cb = {[this, remote_peer_id]() {
OffloadFromThread("rtc-channel-closed", [this, remote_peer_id]() {
ProcessDataChannelClosed(remote_peer_id);
});
}},
},
{
.adapter_type_changed_cb = {[this](webrtc::AdapterType adapter_type) {
OffloadFromThread("rtc-adapter-type-changed",
[this, adapter_type]() {
if (FeatureFlags::GetInstance()
.GetFlags()
.support_web_rtc_non_cellular_medium) {
AdapterTypeChangedHandler(adapter_type);
}
});
}},
},
*medium_);
}
void WebRtc::AdapterTypeChangedHandler(webrtc::AdapterType adapter_type) {
MutexLock lock(&mutex_);
is_using_cellular_ = adapter_type == webrtc::ADAPTER_TYPE_CELLULAR ||
adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_2G ||
adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_3G ||
adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_4G ||
adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_5G;
}
void WebRtc::RemoveConnectionFlow(const WebrtcPeerId& remote_peer_id) {
if (!connection_flows_.erase(remote_peer_id.GetId())) {
return;
}
// If we had an outgoing connection request w/ this peer, report the failure
// to the future that's being waited on.
const auto& connection_request_entry =
requesting_connections_info_.find(remote_peer_id.GetId());
if (connection_request_entry != requesting_connections_info_.end()) {
connection_request_entry->second.socket_future.SetException(
{Exception::kFailed});
}
}
void WebRtc::OffloadFromThread(const std::string& name, Runnable runnable) {
single_thread_executor_.Execute(name, std::move(runnable));
}
bool WebRtc::IsUsingCellular() {
MutexLock lock(&mutex_);
return is_using_cellular_;
}
} // namespace mediums
} // namespace connections
} // namespace nearby
#endif
+25 -211
View File
@@ -15,262 +15,76 @@
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_H_
#define CORE_INTERNAL_MEDIUMS_WEBRTC_H_
#ifndef NO_WEBRTC
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "connections/implementation/mediums/webrtc/connection_flow.h"
#include "connections/implementation/mediums/webrtc/session_description_wrapper.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/mediums/webrtc_peer_id.h"
#include "connections/implementation/mediums/webrtc_socket.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancelable_alarm.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/expected.h"
#include "internal/platform/future.h"
#include "internal/platform/mutex.h"
#include "internal/platform/runnable.h"
#include "internal/platform/scheduled_executor.h"
#include "internal/platform/webrtc.h"
#include "proto/mediums/web_rtc_signaling_frames.pb.h"
#include "webrtc/api/jsep.h"
namespace nearby {
namespace connections {
namespace mediums {
// Entry point for connecting a data channel between two devices via WebRtc.
// A non-working base implementation for connecting a data channel between two
// devices via WebRtc.
class WebRtc {
public:
// Callback that is invoked when a new connection is accepted.
using AcceptedConnectionCallback = absl::AnyInvocable<void(
const std::string& service_id, WebRtcSocketWrapper socket)>;
const std::string& service_id, std::shared_ptr<WebRtcSocket> socket)>;
WebRtc();
~WebRtc();
// Gets the default two-letter country code associated with current locale.
// For example, en_US locale resolves to "US".
std::string GetDefaultCountryCode();
virtual ~WebRtc() = default;
// Returns if WebRtc is available as a medium for nearby to transport data.
// Runs on @MainThread.
bool IsAvailable();
virtual bool IsAvailable() { return false; }
// Returns if the device is accepting connection with specific service id.
// Runs on @MainThread.
bool IsAcceptingConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
virtual bool IsAcceptingConnections(const std::string& service_id) {
return false;
}
// Prepares the device to accept incoming WebRtc connections. Returns a
// boolean value indicating if the device has started accepting connections.
// Runs on @MainThread.
bool StartAcceptingConnections(
virtual bool StartAcceptingConnections(
const std::string& service_id, const WebrtcPeerId& self_peer_id,
const location::nearby::connections::LocationHint& location_hint,
AcceptedConnectionCallback callback, bool non_cellular)
ABSL_LOCKS_EXCLUDED(mutex_);
AcceptedConnectionCallback callback, bool non_cellular) {
return false;
}
// Try to stop (accepting) the specific connection with provided service id.
// Runs on @MainThread
void StopAcceptingConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
virtual void StopAcceptingConnections(const std::string& service_id) {}
// Initiates a WebRtc connection with peer device identified by |peer_id|
// with internal retry for maximum attempts of kConnectAttemptsLimit.
// Runs on @MainThread.
ErrorOr<WebRtcSocketWrapper> Connect(
virtual ErrorOr<std::shared_ptr<WebRtcSocket>> Connect(
const std::string& service_id, const WebrtcPeerId& peer_id,
const location::nearby::connections::LocationHint& location_hint,
CancellationFlag* cancellation_flag, bool non_cellular)
ABSL_LOCKS_EXCLUDED(mutex_);
CancellationFlag* cancellation_flag, bool non_cellular) {
return {Error(location::nearby::proto::connections::OperationResultCode::
DETAIL_UNKNOWN)};
}
bool IsUsingCellular() ABSL_LOCKS_EXCLUDED(mutex_);
virtual bool IsUsingCellular() { return false; }
protected:
// Use for unit tests only to inject a WebRtcMedium.
explicit WebRtc(std::unique_ptr<WebRtcMedium> medium);
// Used in unit tests to determine how many calls to `AttemptToConnect`
// occured during a call to `Connect`, per service id.
std::map<std::string, int> service_id_to_connect_attempts_count_map_;
private:
static constexpr int kConnectAttemptsLimit = 3;
static constexpr int kRestartAcceptConnectionsLimit = 3;
enum class Role {
kNone = 0,
kOfferer = 1,
kAnswerer = 2,
};
struct AcceptingConnectionsInfo {
// The self_peer_id is generated from the BT/WiFi advertisements and allows
// the scanner to message us over Tachyon.
WebrtcPeerId self_peer_id;
// The registered callback. When there's an incoming connection, this
// callback is notified.
AcceptedConnectionCallback accepted_connection_callback;
// Allows us to communicate with the Tachyon web server.
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger;
// Restarts the tachyon inbox receives messages streaming rpc if the
// streaming rpc times out. The streaming rpc times out after 60s while
// advertising. Non-null when listening for WebRTC connections as an
// offerer.
std::unique_ptr<CancelableAlarm> restart_tachyon_receive_messages_alarm;
// Tracks the number of times we've restarted receiving messages after a
// failure. We limit the number to prevent endless restarts if we are
// repeatedly unable to communicate with Tachyon.
int restart_accept_connections_count = 0;
};
struct ConnectionRequestInfo {
// The self_peer_id is randomly generated and allows the advertiser to
// message us over Tachyon.
WebrtcPeerId self_peer_id;
// Allows us to communicate with the Tachyon web server.
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger;
// The pending DataChannel future. Our client will be blocked on this while
// they wait for us to set up the channel over Tachyon.
Future<WebRtcSocketWrapper> socket_future;
};
// Attempt to initiates a WebRtc connection with peer device identified by
// |peer_id|.
// Runs on @MainThread.
ErrorOr<WebRtcSocketWrapper> AttemptToConnect(
const std::string& service_id, const WebrtcPeerId& peer_id,
const location::nearby::connections::LocationHint& location_hint,
CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns if the device is accepting connection with specific service id.
// Runs on @MainThread.
bool IsAcceptingConnectionsLocked(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Receives a message from the signaling messenger.
void OnSignalingMessage(const std::string& service_id,
const ByteArray& message);
// Decides whether to restart receiving messages.
void OnSignalingComplete(const std::string& service_id, bool success);
// Runs on |single_thread_executor_|.
void ProcessTachyonInboxMessage(const std::string& service_id,
const ByteArray& message)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|.
void SendOffer(const std::string& service_id,
const WebrtcPeerId& remote_peer_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void ReceiveOffer(const WebrtcPeerId& remote_peer_id,
SessionDescriptionWrapper offer)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void SendAnswer(const WebrtcPeerId& remote_peer_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void ReceiveAnswer(const WebrtcPeerId& remote_peer_id,
SessionDescriptionWrapper answer)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void ReceiveIceCandidates(
const WebrtcPeerId& remote_peer_id,
std::vector<std::unique_ptr<webrtc::IceCandidate>> ice_candidates)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
std::unique_ptr<ConnectionFlow> CreateConnectionFlow(
const std::string& service_id, const WebrtcPeerId& remote_peer_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
std::unique_ptr<ConnectionFlow> GetConnectionFlow(
const WebrtcPeerId& remote_peer_id) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void RemoveConnectionFlow(const WebrtcPeerId& remote_peer_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void ProcessDataChannelOpen(const std::string& service_id,
const WebrtcPeerId& remote_peer_id,
WebRtcSocketWrapper socket_wrapper)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|.
void ProcessDataChannelClosed(const WebrtcPeerId& remote_peer_id)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|.
void ProcessLocalIceCandidate(
const std::string& service_id, const WebrtcPeerId& remote_peer_id,
const location::nearby::mediums::IceCandidate ice_candidate)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|.
void ProcessRestartTachyonReceiveMessages(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|.
void RestartTachyonReceiveMessages(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|.
void AdapterTypeChangedHandler(webrtc::AdapterType adapter_type)
ABSL_LOCKS_EXCLUDED(mutex_);
void OffloadFromThread(const std::string& name, Runnable runnable);
Mutex mutex_;
std::unique_ptr<WebRtcMedium> medium_;
// The single thread we throw the potentially blocking work on to.
ScheduledExecutor single_thread_executor_;
// A map of ServiceID -> State for all services that are listening for
// incoming connections.
absl::flat_hash_map<std::string, AcceptingConnectionsInfo>
accepting_connections_info_ ABSL_GUARDED_BY(mutex_);
// A map of a remote PeerId -> State for pending connection requests. As
// messages from Tachyon come in, this lets us look up the connection request
// info to handle the interaction.
absl::flat_hash_map<std::string, ConnectionRequestInfo>
requesting_connections_info_ ABSL_GUARDED_BY(mutex_);
// A map of a remote PeerId -> ConnectionFlow. For each connection, we create
// a unique ConnectionFlow.
absl::flat_hash_map<std::string, std::unique_ptr<ConnectionFlow>>
connection_flows_ ABSL_GUARDED_BY(mutex_);
bool is_using_cellular_ ABSL_GUARDED_BY(mutex_) = true;
virtual std::unique_ptr<BwuHandler> CreateBwuHandler(
BwuHandler::IncomingConnectionCallback incoming_connection_callback) {
return nullptr;
}
};
} // namespace mediums
} // namespace connections
} // namespace nearby
#endif
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_H_
@@ -1,112 +0,0 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
# 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.
licenses(["notice"])
cc_library(
name = "webrtc",
srcs = [
"connection_flow.cc",
"signaling_frames.cc",
],
hdrs = [
"connection_flow.h",
"data_channel_listener.h",
"local_ice_candidate_listener.h",
"session_description_wrapper.h",
"signaling_frames.h",
],
copts = [
"-DCORE_ADAPTER_DLL",
"-DNO_WEBRTC",
],
visibility = [
"//connections/implementation:__subpackages__",
],
deps = [
":data_types",
"//connections:core_types",
"//connections/implementation/mediums:webrtc_utils",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform:types",
"//proto/mediums:web_rtc_signaling_frames_cc_proto",
# "//third_party/webrtc/files/stable/webrtc/api:create_peerconnection_factory", # buildcleaner: keep
# "//third_party/webrtc/files/stable/webrtc/api:data_channel_interface",
# "//third_party/webrtc/files/stable/webrtc/api:jsep",
# "//third_party/webrtc/files/stable/webrtc/api:peer_connection_interface",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/time",
],
)
cc_library(
name = "data_types",
srcs = [
"webrtc_socket_impl.cc",
],
hdrs = [
"webrtc_socket_impl.h",
],
copts = [
"-DCORE_ADAPTER_DLL",
"-DNO_WEBRTC",
],
visibility = [
"//connections/implementation:__subpackages__",
],
deps = [
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:types",
"@com_google_absl//absl/strings:string_view",
],
)
cc_test(
name = "webrtc_test",
timeout = "short",
srcs = [
"connection_flow_test.cc",
"signaling_frames_test.cc",
"webrtc_socket_impl_test.cc",
],
tags = [
"notsan", # NOTE(b/139734036): known data race in usrsctplib.
"requires-net:external",
],
deps = [
":data_types",
":webrtc",
"//connections/implementation/mediums:webrtc_utils",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # buildcleaner: keep
# "//third_party/webrtc/files/stable/webrtc/api:data_channel_interface",
# "//third_party/webrtc/files/stable/webrtc/api:jsep",
# "//third_party/webrtc/files/stable/webrtc/api:scoped_refptr",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
"@com_google_protobuf//:protobuf",
],
)

Some files were not shown because too many files have changed in this diff Show More