Merge branch 'main' of github.com:kidfromjupiter/nearby

This commit is contained in:
lasan
2026-06-30 10:48:02 +05:30
738 changed files with 21305 additions and 51899 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
+12 -24
View File
@@ -69,14 +69,8 @@ jobs:
- name: Build Connections
run: |
bazel build \
--check_visibility=false \
--spawn_strategy=standalone \
--cxxopt=-std=c++20 \
--host_cxxopt=-std=c++20 \
--@com_google_protobuf//bazel/toolchains:prefer_prebuilt_protoc=true \
--copt='-DGITHUB_BUILD' \
--copt='-fvisibility=hidden' \
--cxxopt='-fvisibility-inlines-hidden' \
//connections:core
# - name: Build Presence
@@ -92,27 +86,21 @@ jobs:
# --cxxopt='-fvisibility-inlines-hidden' \
# //presence
- name: Build Nearby Sharing Linux shared API
- name: Build Nearby Sharing Linux
run: |
bazel build \
--check_visibility=false \
--spawn_strategy=standalone \
--cxxopt=-std=c++20 \
--host_cxxopt=-std=c++20 \
--@com_google_protobuf//bazel/toolchains:prefer_prebuilt_protoc=true \
--copt='-DGITHUB_BUILD' \
--copt='-fvisibility=hidden' \
--cxxopt='-fvisibility-inlines-hidden' \
//sharing/linux:nearby_sharing_api_shared
//sharing/linux:nearby_sharing_cli
build-rust-linux:
name: Build Rust on Linux
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
#build-rust-linux:
# name: Build Rust on Linux
# runs-on: ubuntu-latest
# steps:
# - name: Checkout
# uses: actions/checkout@v6
# with:
# submodules: recursive
- name: Build FPP
run: cargo build --manifest-path presence/fpp/fpp/Cargo.toml
# - name: Build FPP
# run: cargo build --manifest-path presence/fpp/fpp/Cargo.toml
+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"},
)
+6 -1
View File
@@ -11,6 +11,10 @@ bazel_dep(name = "googletest", version = "1.17.0.bcr.2", repo_name = "com_google
bazel_dep(name = "boringssl", version = "0.20251124.0")
bazel_dep(name = "rules_foreign_cc", version = "0.15.1")
# for linux TUI
# Should update to 7.0.0
bazel_dep(name = "ftxui", version = "6.1.9")
git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
@@ -190,10 +194,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"],
+5 -3
View File
@@ -63,6 +63,8 @@
"https://bcr.bazel.build/modules/boringssl/0.20251124.0/source.json": "2f325a76db6c6e14c4db923a26aa9a4bfbbd03e61b9256311f460c18bfba6013",
"https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f",
"https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd",
"https://bcr.bazel.build/modules/ftxui/6.1.9/MODULE.bazel": "cc9326c084f535dab294bc7aaea0be08ceedd7623c421e09e7ab16f921f4fcb7",
"https://bcr.bazel.build/modules/ftxui/6.1.9/source.json": "401772aaf4b1dc988ffe03a8280e94927bd4e318b98724ba309f41000c41283e",
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
@@ -152,8 +154,8 @@
"https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
"https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
"https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
"https://bcr.bazel.build/modules/rules_java/9.1.0/MODULE.bazel": "ee63f27e36a3fada80342869361182f120a9819c74320e8e65b1e04ba0cd7a9d",
"https://bcr.bazel.build/modules/rules_java/9.1.0/source.json": "da589573c1dee2c9ac4a568b301269a2e8191110ff0345c1a959fa7ea6c4dfd6",
"https://bcr.bazel.build/modules/rules_java/9.0.3/MODULE.bazel": "1f98ed015f7e744a745e0df6e898a7c5e83562d6b759dfd475c76456dda5ccea",
"https://bcr.bazel.build/modules/rules_java/9.0.3/source.json": "b038c0c07e12e658135bbc32cc1a2ded6e33785105c9d41958014c592de4593e",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
"https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
"https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
@@ -220,7 +222,7 @@
"moduleExtensions": {
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
"general": {
"bzlTransitiveDigest": "Ga4z8lQy1YQ5rAMy+dOl0dqcCEBnYNCXku8x3YQmDZI=",
"bzlTransitiveDigest": "ABI1D/sbS1ovwaW/kHDoj8nnXjQ0oKU9fzmzEG4iT8o=",
"usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
"recordedInputs": [
"REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools"
+20 -31
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,16 +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/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",
@@ -391,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",
@@ -437,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",
@@ -478,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",
@@ -500,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",
@@ -522,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: [
@@ -564,6 +552,7 @@ let package = Package(
.headerSearchPath("./"),
.headerSearchPath("compiled_proto/"),
.define("NO_WEBRTC"),
.define("NC_OSS_BUILD"),
]
),
.target(
+24 -62
View File
@@ -16,14 +16,13 @@
https://github.com/user-attachments/assets/048afa1e-40a4-4351-a859-c81b642fc6e3
## What
This repo consists of the entirety of google's open source nearby library. Currently, it is seperated into 3 sections.
This repo consists of the entirety of google's open source nearby library. Currently, it is seperated into 3 (now 2) sections.
- Sharing
- Connections
- ~Presence~ ( Build fails for some reason. Haven't had time to investigate. Maybe something minor. Check the validate.yaml for build steps and see why its faiing )
- ~Presence~ ( *Was removed by google from their repo. RIP :(* )
Linux specific implementation and compatibility shims are provided for building **Sharing** and **Connections**.
Nearby presence may or may not build.
## Why
This repo could've been a PR on the official repo. All I've done is implement the platform abstraction layer google has provided for a linux specific environment.
@@ -34,10 +33,8 @@ Moreover, all I've wanted was seamless file sharing between my android devices a
it accomplishes that goal perfectly. This repo wasn't created out of any altruistic goals or out of the goodness of my heart. I had a problem. I solved it. Simple as that.
## How
### How to use
Proper documentation is coming I swear. University's getting pretty hectic so docs is on the backburner. The wiki has some more information but it's nowhere near a proper documentation. It has some good brief
overviews and where generally everything is located if you're thinking about contributing.
## Documentation
Docs is on the backburner for now
If you want any clarification on anything, feel free to open an issue. I'll get back to you ASAP.
@@ -78,80 +75,45 @@ sudo dnf install -y \
Currently there are no prebuilt shared library or headers. You'll have to build them yourself
### How to build
~Check the [wiki](https://github.com/kidfromjupiter/nearby/wiki/Development-Environment-and-Building)~
Wiki isn't built yet. Best place to consult would be the Github actions and workflows.
### How to contribute
~Check the [wiki](https://github.com/kidfromjupiter/nearby/wiki/Development-Environment-and-Building)~
Best place to consult would be the Github actions and workflows.
## TODO
> **Development is paused until my next break (around mid-June.)**
### WIP
- [ ] **Transition from QT to a TUI**
We're moving away from a GUI application to TUI application. On top of this, I've made a nearby sharing daemon with socket based IPC so that even if anyone wants to create a GUI application, it is trivial without them needing to link with nearby sharing libraries.
This change was done to decouple the UI from the library itself since the previous implementation was difficult to work with
---
### 🔴 P0 — Critical / Core Functionality
> Issues that break core functionality. These should be addressed immediately.
- **Merge latest upstream changes**
- **Bluetooth classic bandwidth**
### BUGS
- [ ] **Bluetooth classic bandwidth**
File transfer on bluetooth classic is painfully slow. Bandwidth close to 20KB/s. ~May be a regression issue after bluetooth socket refactor~. May be an issue with sending back acknowledgements. Issue is present on pre-refactor versions. ~Look into Multiplexing maybe~ Multiplexing did not fix it : (?
- **~Linux → Android~ file sharing is unreliable** after the newest Android Quick Share updates.
Investigate why and fix it. ~Possibly related to proprietary certificate changes~. Should probably add unit tests and integration tests for each medium. Everything is so fucking buggy it makes me wanna rip my fucking eyes out. Might be related to recent upstream changes. I could probably properly test linux -> linux bidirectional sharing. Will need to simulate a lot of hardware stuff though. Since there's no stable reference platform to write automatic tests against writing linux to linux tests could be like clown to clown communication
<img width="200" height="143" alt="image" src="https://github.com/user-attachments/assets/caed18f3-1337-4499-ba4d-b49f549c0cf5" />
- **QR code scanning does not work.**
Likely related to the Linux → Android sharing issue above. I did get it working once in a very old build. So it shouldn't impossible. Unless google changed something
---
### 🟠 P1 — Important Annoyances
> Problems that are not fully blocking, but noticeably affect usability.
- **Investigate why Bluetooth connection requests pairing.**
- [ ] **Investigate why Bluetooth connection requests pairing.**
Both the L2CAP socket and Bluetooth profile should be unauthenticated.
- **Handle existing files when receiving.**
- [ ] **Handle existing files when receiving.**
Currently, files are not overwritten if they already exist. Decide whether to overwrite, rename, or skip.
---
### 🟡 P2 — Quality of Life / Cleanup
> Improvements that would make the project cleaner, smoother, or easier to maintain.
- **Bluetooth Classic transfer progress issue.**
- [ ] **Bluetooth Classic transfer progress issue.**
When transferring Android → Linux, Android shows 100% transferred but still says `Sending...`, while Linux lags behind. Could be a bottleneck or Android-side issue.
- **Add tests for basically everything.**
- **Clean up `implementation/linux`.**
Linux-specific implementation files are currently all in one directory. This matches the other platforms, but creates visual bloat.
- **Document basically everything.**
This would be a large project on its own.
- **Resolve random crashes in the Quick Share application.**
---
### 🔵 P3 — New Features
### New Features
> Non-essential features and future improvements.
- **Support fast initiation.**
- Upstream has been slowly adding webrtc support. Should we support it?
## Apologies
I may have done things in *incredibly* stupid and overcomplicated ways. It doesn't certainly help that this was the way I decided to learn C++. Blessed be my naive soul. I also do not have much experience working with such
enormous codebases.
If you see any such stupidities, feel free to berate me in the most shameless of manners in an issue. I look forward to learning how to do it the proper way and to improve my atrocious code quality.
- [ ] Upstream has been slowly adding webrtc support. Should we support it?
## Special thanks
@@ -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&&);
+169 -103
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",
@@ -247,30 +326,29 @@ cc_test(
name = "bwu_test",
srcs = [
"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/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/flags:platform_flags",
"//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",
],
)
@@ -279,6 +357,7 @@ cc_test(
name = "pcp_manager_test",
srcs = ["pcp_manager_test.cc"],
deps = [
":endpoint_channel",
":internal",
":internal_test",
"//connections:core_types",
@@ -304,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",
@@ -325,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",
@@ -362,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",
@@ -382,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",
@@ -411,6 +491,8 @@ cc_test(
"encryption_runner_test.cc",
],
deps = [
":client_proxy",
":endpoint_channel",
":internal",
"//connections/implementation/analytics",
"//internal/platform:base",
@@ -432,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",
@@ -459,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",
@@ -484,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",
],
)
@@ -503,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",
@@ -525,6 +611,7 @@ cc_test(
"service_controller_router_test.cc",
],
deps = [
":client_proxy",
":internal",
":internal_test",
"//connections:core_types",
@@ -575,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",
@@ -586,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_
@@ -0,0 +1,16 @@
// 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/analytics/analytics_recorder_impl.h"
@@ -0,0 +1,150 @@
// 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 CONNECTIONS_IMPLEMENTATION_ANALYTICS_ANALYTICS_RECORDER_IMPL_H_
#define CONNECTIONS_IMPLEMENTATION_ANALYTICS_ANALYTICS_RECORDER_IMPL_H_
#include <cstdint>
#include <string>
#include <vector>
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "location/nearby/analytics/cpp/logging/event_logger.h"
#include "proto/connections_enums.pb.h"
namespace nearby::analytics {
class AnalyticsRecorderImpl : public AnalyticsRecorder {
public:
explicit AnalyticsRecorderImpl(EventLogger* event_logger = nullptr)
: event_logger_(event_logger) {}
~AnalyticsRecorderImpl() override = default;
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; }
void OnStartedIncomingConnectionListening(
connections::Strategy strategy) override {}
void OnStoppedIncomingConnectionListening() override {}
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 {}
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 {}
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 {}
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,
SafeDisconnectionResult result) override {}
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 {}
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 {}
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::CATEGORY_UNKNOWN;
}
void Sync() override {}
private:
EventLogger* event_logger_;
};
} // namespace nearby::analytics
#endif // CONNECTIONS_IMPLEMENTATION_ANALYTICS_ANALYTICS_RECORDER_IMPL_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
@@ -0,0 +1,576 @@
// 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/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/awdl_endpoint_channel.h"
#include "connections/implementation/bwu_handler.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/mediums/awdl.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/strategy.h"
#include "internal/analytics/mock_event_logger.h"
#include "internal/analytics/sharing_log_matchers.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/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"
#include "internal/proto/analytics/connections_log.pb.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::analytics::proto::ConnectionsLog;
using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::V1Frame;
using ::location::nearby::proto::connections::EventType;
using ::location::nearby::proto::connections::OperationResultCode;
using ::nearby::analytics::HasEventType;
using ::testing::_;
using ::testing::ByMove;
using ::protobuf_matchers::EqualsProto;
using ::testing::Matcher;
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_, 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_;
nearby::analytics::MockEventLogger mock_event_logger_;
MockInputStream mock_input_stream_;
MockOutputStream mock_output_stream_;
};
TEST_F(AwdlBwuHandlerTest,
CreateUpgradedEndpointChannel_InvalidCredentials_Fails) {
ClientProxy client(&mock_event_logger_);
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(&mock_event_logger_);
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(&mock_event_logger_);
client.AddCancellationFlag(std::string(kEndpointId));
EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0))
.WillOnce(Return(ByMove(nullptr)));
ByteArray 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(&mock_event_logger_);
client.GetAnalyticsRecorder().OnStartAdvertising(
Strategy::kP2pPointToPoint,
{location::nearby::proto::connections::Medium::BLUETOOTH},
/*advertising_metadata_params=*/nullptr);
client.GetAnalyticsRecorder().OnBandwidthUpgradeStarted(
std::string(kEndpointId),
location::nearby::proto::connections::Medium::BLUETOOTH,
location::nearby::proto::connections::Medium::AWDL,
location::nearby::proto::connections::ConnectionAttemptDirection::
OUTGOING,
/*connection_token=*/"");
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;
});
ByteArray 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(std::string(result)));
awdl_credentials->set_password(result_frame.v1()
.bandwidth_upgrade_negotiation()
.upgrade_path_info()
.awdl_credentials()
.password());
EXPECT_THAT(result_frame, EqualsProto(expected_frame));
constexpr absl::string_view kClientSessionLog = R"pb(
event_type: CLIENT_SESSION
client_session { duration_millis: 0 }
version: "v1.5.0"
)pb";
constexpr absl::string_view kExpectedUpgradeLog = R"pb(
event_type: CLIENT_SESSION
client_session {
duration_millis: 0
strategy_session {
duration_millis: 0
strategy: P2P_POINT_TO_POINT
role: ADVERTISER
advertising_phase {
duration_millis: 0
medium: BLUETOOTH
advertising_metadata {
supports_extended_ble_advertisements: false
connected_ap_frequency: 0
supports_nfc_technology: false
}
stop_reason: FINISH_SESSION_STOP_ADVERTISING
}
upgrade_attempt {
direction: OUTGOING
duration_millis: 0
from_medium: BLUETOOTH
to_medium: AWDL
upgrade_result: UNFINISHED_ERROR
error_stage: UPGRADE_UNFINISHED
connection_token: ""
operation_result {
result_category: CATEGORY_DEVICE_STATE_ERROR
result_code: DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS
}
}
}
}
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(kClientSessionLog))))
.Times(2);
EXPECT_CALL(
mock_event_logger_,
Log(Matcher<const ConnectionsLog&>(EqualsProto(kExpectedUpgradeLog))));
// Flush pending logs.
client.GetAnalyticsRecorder().LogSession();
handler_.RevertInitiatorState();
}
MediumEnvironment::Instance().Stop();
}
TEST_F(AwdlBwuHandlerTest, OnIncomingAwdlConnection_Success) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client(&mock_event_logger_);
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(); });
ByteArray 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(&mock_event_logger_);
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();
});
ByteArray 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(&mock_event_logger_);
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(&mock_event_logger_);
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
@@ -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,21 +90,18 @@ 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;
// currently there's not way to have both kRefactorBleL2cap flag working AND
// have mediums other than ble_l2cap working. upstream may change this in the future
//
// So we have to explicitly add a condition to skip this pathway when medium is l2cap
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kRefactorBleL2cap)) {
kRefactorBleL2cap) && GetMedium() == BLE_L2CAP) {
ExceptionOr<ByteArray> read_control_block_bytes = DispatchPacket();
if (!read_control_block_bytes.ok()) {
LOG(WARNING) << __func__ << ": Failed to dispatch packet: "
@@ -133,8 +128,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 +137,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 +149,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 +167,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 +181,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 +202,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 +218,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 +244,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 +306,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 +470,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
+211 -103
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);
@@ -119,14 +264,11 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger)
supports_safe_to_disconnect_ = NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableSafeToDisconnect);
support_auto_reconnect_ = NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableAutoReconnect);
local_safe_to_disconnect_version_ = NearbyFlags::GetInstance().GetInt64Flag(
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion);
LOG(INFO) << "[safe-to-disconnect]: Local enabled: "
<< supports_safe_to_disconnect_
<< "; Version: " << local_safe_to_disconnect_version_;
<< supports_safe_to_disconnect_ << "; Version: "
<< NearbyFlags::GetInstance().GetInt64Flag(
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion);
// Generate a 7 bits dedup value.
absl::BitGen bitgen;
dct_dedup_ = absl::Uniform(bitgen, 0, 1 << 7);
@@ -189,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;
@@ -219,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;
@@ -226,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;
}
@@ -263,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_);
@@ -284,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());
}
@@ -402,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_);
@@ -412,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());
}
@@ -878,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)) {
@@ -902,6 +1049,7 @@ bool ClientProxy::AutoUpgradeBandwidth() const {
}
bool ClientProxy::ShouldEnforceTopologyConstraints() const {
MutexLock lock(&mutex_);
bool result = false;
if (IsAdvertising() &&
(GetAdvertisingOptions().strategy.IsNone() ||
@@ -922,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
@@ -936,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();
@@ -959,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;
@@ -968,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);
@@ -1008,14 +1162,6 @@ bool ClientProxy::IsSafeToDisconnectEnabled(absl::string_view endpoint_id) {
.min_nc_version_supports_safe_to_disconnect);
}
bool ClientProxy::IsAutoReconnectEnabled(absl::string_view endpoint_id) {
return IsSupportAutoReconnect() &&
GetRemoteSafeToDisconnectVersion(endpoint_id).has_value() &&
(GetRemoteSafeToDisconnectVersion(endpoint_id) >=
FeatureFlags::GetInstance()
.GetFlags()
.min_nc_version_supports_auto_reconnect);
}
bool ClientProxy::IsPayloadReceivedAckEnabled(absl::string_view endpoint_id) {
return IsSupportSafeToDisconnect() &&
@@ -1027,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;
}
@@ -1131,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_;
}
@@ -1215,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 =
@@ -1248,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;
@@ -1325,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;
@@ -1333,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;
}
@@ -1340,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);
@@ -1361,6 +1468,7 @@ void ClientProxy::InitializePreferencesManager() {
<< GetClientId();
}
}
#endif
void ClientProxy::SaveClientInfoToPreferences() {
MutexLock lock(&mutex_);
+10 -42
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.
@@ -303,33 +301,17 @@ class ClientProxy final {
return supports_safe_to_disconnect_;
}
bool IsSupportAutoReconnect() const { return support_auto_reconnect_; }
const std::int32_t& GetLocalSafeToDisconnectVersion() const {
return local_safe_to_disconnect_version_;
}
std::optional<std::int32_t> GetRemoteSafeToDisconnectVersion(
absl::string_view endpoint_id) const;
void SetRemoteSafeToDisconnectVersion(
absl::string_view endpoint_id,
const std::int32_t& safe_to_disconnect_version);
bool IsSafeToDisconnectEnabled(absl::string_view endpoint_id);
bool IsAutoReconnectEnabled(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();
@@ -351,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();
@@ -525,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_;
@@ -549,8 +519,6 @@ class ClientProxy final {
// For Nearby Connections' own device provider.
std::unique_ptr<v3::ConnectionsDeviceProvider> connections_device_provider_;
bool supports_safe_to_disconnect_;
bool support_auto_reconnect_;
std::int32_t local_safe_to_disconnect_version_;
// Allowed to use WebRTC over non-cellular networks.
bool webrtc_non_cellular_ = false;
// Whether DCT is enabled.
+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 -134
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,17 +755,15 @@ 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");
}
}
if (safe_disconnect_result ==
ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION) {
// TODO(b/297259496): Autoreconnect
}
// Unregistering from channel_manager_ will also serve to terminate
// the dedicated handler and KeepAlive threads we started when we registered
@@ -924,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 =
@@ -957,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;
@@ -982,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.
@@ -1011,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,
@@ -136,16 +79,13 @@ class MockFrameProcessor : public EndpointManager::FrameProcessor {
class SetSafeToDisconnect {
public:
SetSafeToDisconnect(bool safe_to_disconnect, bool auto_reconnect,
SetSafeToDisconnect(bool safe_to_disconnect,
bool payload_received_ack,
std::int32_t safe_to_disconnect_version) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableSafeToDisconnect,
safe_to_disconnect);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableAutoReconnect,
auto_reconnect);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnablePayloadReceivedAck,
@@ -187,7 +127,7 @@ class EndpointManagerTest : public ::testing::Test {
EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result());
}
}
SetSafeToDisconnect set_safe_to_disconnect_{true, false, true, 5};
SetSafeToDisconnect set_safe_to_disconnect_{true, true, 5};
std::unique_ptr<ClientProxy> client_ = std::make_unique<ClientProxy>();
ConnectionOptions connection_options_{
.keep_alive_interval_millis = 5000,
@@ -280,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}));
@@ -321,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);
@@ -329,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);
@@ -361,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(_))
@@ -379,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)))
@@ -403,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)))
@@ -419,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));
@@ -432,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()));
}
@@ -464,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_
+12 -23
View File
@@ -31,15 +31,9 @@ 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);
// Enable/Disable auto_reconnect feature.
constexpr auto kEnableAutoReconnect =
flags::Flag<bool>(kConfigPackage, "45427690", false);
// Enable/Disable AWDL in Nearby connections SDK.
constexpr auto kEnableAwdl =
flags::Flag<bool>(kConfigPackage, "45690762", false);
@@ -58,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);
@@ -95,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);
@@ -105,7 +93,8 @@ constexpr auto kMediumMaxAllowedReadBytes =
constexpr auto kRefactorBleL2cap =
flags::Flag<bool>(kConfigPackage, "45737079", false);
// Set the safe-to-disconnect version.
// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3. auto-reconnect
// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3.
// auto-reconnect(deprecated)
// 4. auto-resume 5. non-distance-constraint-recovery 6. payload_ack
constexpr auto kSafeToDisconnectVersion =
flags::Flag<int64_t>(kConfigPackage, "45425841", 0);
+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 -29
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,9 +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",
# TODO: Support WebRTC
"@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",
@@ -86,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__",
@@ -108,7 +133,6 @@ cc_library(
],
deps = [
":utils",
"//connections/implementation/mediums/webrtc:data_types",
"//internal/platform:base",
"@com_google_absl//absl/strings",
],
@@ -130,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 = [
@@ -144,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",
@@ -179,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 = [
@@ -199,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

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