Merge remote-tracking branch 'nearby/main'

# Conflicts:
#	connections/implementation/bwu_manager_test.cc
#	sharing/BUILD
#	sharing/certificates/fake_nearby_share_certificate_manager.cc
#	sharing/certificates/fake_nearby_share_certificate_manager.h
#	sharing/internal/base/utf_string_conversions.h
This commit is contained in:
Lasan Mahaliyana
2026-07-26 22:46:37 +05:30
155 changed files with 5257 additions and 2018 deletions
+4
View File
@@ -99,6 +99,8 @@ cc_library(
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:mac_address",
"//sharing/internal/base:utf_utils",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/time",
],
@@ -262,6 +264,7 @@ cc_library(
"//internal/platform/implementation:wifi_utils",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
@@ -349,6 +352,7 @@ cc_test(
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
@@ -422,6 +422,15 @@ int BaseEndpointChannel::GetFrequency() const { return frequency_; }
// Returns the try count of this EndpointChannel.
int BaseEndpointChannel::GetTryCount() const { return try_count_; }
void BaseEndpointChannel::SetLocalEndpointId(
const std::string& local_endpoint_id) {
local_endpoint_id_ = local_endpoint_id;
}
std::string BaseEndpointChannel::GetLocalEndpointId() const {
return local_endpoint_id_;
}
int BaseEndpointChannel::GetMaxAllowedReadBytes() const {
int64_t max_allowed_read_bytes = NearbyFlags::GetInstance().GetInt64Flag(
config_package_nearby::nearby_connections_feature::
@@ -81,6 +81,8 @@ class BaseEndpointChannel : public EndpointChannel {
uint32_t GetNextKeepAliveSeqNo() const override;
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
const std::string& endpoint_id) override;
void SetLocalEndpointId(const std::string& local_endpoint_id) override;
std::string GetLocalEndpointId() const override;
// Reads a complete packet from the underlying medium.
virtual ExceptionOr<ByteArray> DispatchPacket() {
@@ -166,6 +168,7 @@ class BaseEndpointChannel : public EndpointChannel {
analytics::AnalyticsRecorder* analytics_recorder_ = nullptr;
std::string endpoint_id_ = "";
std::string local_endpoint_id_ = "";
};
} // namespace nearby::connections
+30 -15
View File
@@ -25,6 +25,7 @@
#include "securegcm/ukey2_handshake.h"
#include "absl/base/thread_annotations.h"
#include "absl/cleanup/cleanup.h"
#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
@@ -94,7 +95,6 @@ using ::location::nearby::connections::ConnectionResponseFrame;
using ::location::nearby::connections::ConnectionsDevice;
using ::location::nearby::connections::MediumMetadata;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::connections::PresenceDevice;
using ::location::nearby::connections::V1Frame;
using ::location::nearby::proto::connections::OperationResultCode;
@@ -576,15 +576,16 @@ Status BasePcpHandler::WaitForResult(const std::string& method_name,
return result.result();
}
void BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
bool BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
Runnable runnable) {
if (closed_.Get()) {
LOG(WARNING) << "Skip to run PCP Handler task " << name
<< " due to PCP Handler is closed";
return;
return false;
}
serial_executor_.Execute(name, std::move(runnable));
return true;
}
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener(
@@ -894,13 +895,19 @@ ConnectionInfo BasePcpHandler::FillConnectionInfo(
connection_info.ap_frequency = wifi_info.ap_frequency;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch) &&
client->GetLocalOsInfo().type() == OsInfo::APPLE) {
::location::nearby::connections::MediumRole medium_role_info;
medium_role_info.set_support_awdl_publisher(true);
medium_role_info.set_support_awdl_subscriber(true);
medium_role_info.set_support_wifi_hotspot_client(true);
connection_info.medium_role.emplace(medium_role_info);
kEnableDynamicRoleSwitch)) {
LOG(INFO) << "kEnableDynamicRoleSwitch is enabled";
ClientProxy::MediumsAvailability mediums_availability;
mediums_availability.is_wifi_direct_go_available =
mediums_->GetWifiDirect().IsGOAvailable();
mediums_availability.is_wifi_direct_gc_available =
mediums_->GetWifiDirect().IsGCAvailable();
mediums_availability.is_wifi_hotspot_ap_available =
mediums_->GetWifiHotspot().IsAPAvailable();
mediums_availability.is_wifi_hotspot_client_available =
mediums_->GetWifiHotspot().IsClientAvailable();
connection_info.medium_role.emplace(
client->GetLocalMediumRole(mediums_availability));
}
LOG(INFO) << "Query for WIFI information: is_supports_5_ghz="
<< connection_info.supports_5_ghz
@@ -1585,7 +1592,8 @@ Status BasePcpHandler::AcceptConnection(ClientProxy* client,
Exception write_exception =
channel->Write(parser::ForConnectionResponse(
Status::kSuccess, client->GetLocalOsInfo()));
Status::kSuccess, client->GetLocalOsInfo(),
client->GetLocalDeviceName()));
if (!write_exception.Ok()) {
LOG(INFO) << "AcceptConnection: failed to send response: endpoint_id="
<< endpoint_id;
@@ -1646,7 +1654,8 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client,
Exception write_exception =
channel->Write(parser::ForConnectionResponse(
Status::kConnectionRejected, client->GetLocalOsInfo()));
Status::kConnectionRejected, client->GetLocalOsInfo(),
client->GetLocalDeviceName()));
if (!write_exception.Ok()) {
LOG(INFO) << "RejectConnection: failed to send response: endpoint_id="
<< endpoint_id;
@@ -1673,9 +1682,10 @@ void BasePcpHandler::OnIncomingFrame(
OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client,
location::nearby::proto::connections::Medium medium) {
CountDownLatch latch(1);
RunOnPcpHandlerThread(
bool scheduled = RunOnPcpHandlerThread(
"incoming-frame",
[this, client, endpoint_id, frame, &latch]() RUN_ON_PCP_HANDLER_THREAD() {
absl::Cleanup release_caller = [&latch] { latch.CountDown(); };
LOG(INFO) << "OnConnectionResponse: endpoint_id=" << endpoint_id;
if (client->HasRemoteEndpointResponded(endpoint_id)) {
@@ -1729,9 +1739,14 @@ void BasePcpHandler::OnIncomingFrame(
EvaluateConnectionResult(client, endpoint_id,
/* can_close_immediately= */ true);
latch.CountDown();
if (connection_response.has_wifi_direct_device_name()) {
client->SetRemoteDeviceName(
endpoint_id, connection_response.wifi_direct_device_name());
}
});
WaitForLatch("OnIncomingFrame()", &latch);
if (scheduled) {
WaitForLatch("OnIncomingFrame()", &latch);
}
}
void BasePcpHandler::OnEndpointDisconnect(ClientProxy* client,
@@ -278,7 +278,7 @@ class BasePcpHandler : public PcpHandler,
};
void Shutdown();
void RunOnPcpHandlerThread(const std::string& name, Runnable runnable);
bool RunOnPcpHandlerThread(const std::string& name, Runnable runnable);
BluetoothDevice GetRemoteBluetoothDevice(
MacAddress remote_bluetooth_mac_address);
@@ -455,8 +455,7 @@ class BasePcpHandlerTest
void TearDown() override { env_.Stop(); }
std::unique_ptr<analytics::AnalyticsRecorder> CreateAnalyticsRecorder() {
auto recorder =
std::make_unique<analytics::MockAnalyticsRecorder>();
auto recorder = std::make_unique<analytics::MockAnalyticsRecorder>();
mock_analytics_recorder_ptr_ = recorder.get();
return recorder;
}
@@ -576,10 +575,9 @@ class BasePcpHandlerTest
[channel = channel_a.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_a, Write(_))
.WillOnce(Return(Exception{Exception::kSuccess}))
.WillRepeatedly(
[channel = channel_a.get()](absl::string_view data) {
return channel->DoWrite(data);
});
.WillRepeatedly([channel = channel_a.get()](absl::string_view data) {
return channel->DoWrite(data);
});
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_a, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
@@ -588,10 +586,9 @@ class BasePcpHandlerTest
.WillRepeatedly(
[channel = channel_b.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_b, Write(_))
.WillRepeatedly(
[channel = channel_b.get()](absl::string_view data) {
return channel->DoWrite(data);
});
.WillRepeatedly([channel = channel_b.get()](absl::string_view data) {
return channel->DoWrite(data);
});
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
@@ -628,10 +625,9 @@ class BasePcpHandlerTest
.WillRepeatedly(
[channel = channel_b.get()]() { return channel->DoRead(); });
EXPECT_CALL(*channel_b, Write(_))
.WillRepeatedly(
[channel = channel_b.get()](absl::string_view data) {
return channel->DoWrite(data);
});
.WillRepeatedly([channel = channel_b.get()](absl::string_view data) {
return channel->DoWrite(data);
});
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
@@ -751,16 +747,15 @@ class BasePcpHandlerTest
auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client);
EXPECT_CALL(*pcp_handler, ConnectImpl)
.WillRepeatedly(
[&channel_a, connect_medium](
ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
.medium = connect_medium,
.status = {Status::kSuccess},
.endpoint_channel = std::move(channel_a),
};
});
.WillRepeatedly([&channel_a, connect_medium](
ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
.medium = connect_medium,
.status = {Status::kSuccess},
.endpoint_channel = std::move(channel_a),
};
});
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler->OnEndpointFound(
@@ -1610,7 +1605,7 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
LOG(INFO) << "Simulating remote accept: id=" << endpoint_id;
OsInfo os_info;
auto frame = parser::FromBytes(
parser::ForConnectionResponse(Status::kSuccess, os_info));
parser::ForConnectionResponse(Status::kSuccess, os_info, "device_name"));
EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1);
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
connect_medium);
@@ -1621,6 +1616,48 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
env_.Stop();
}
TEST_P(BasePcpHandlerTest, OnIncomingFrameDuplicateFrameDoesNotDeadlock) {
env_.Start();
std::string endpoint_id{"1234"};
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
StartDiscovery(client_.get(), &pcp_handler);
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
std::shared_ptr<MockEndpointChannel> channel_b =
std::move(channel_pair.second);
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
&pcp_handler, connect_medium);
LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id;
EXPECT_CALL(mock_connection_listener_.accepted_cb, Call).Times(1);
EXPECT_CALL(mock_connection_listener_.disconnected_cb, Call)
.Times(AtLeast(0));
EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}),
Status{Status::kSuccess});
LOG(INFO) << "Simulating remote accept: id=" << endpoint_id;
OsInfo os_info;
auto frame = parser::FromBytes(
parser::ForConnectionResponse(Status::kSuccess, os_info, "device_name"));
EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1);
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
connect_medium);
LOG(INFO) << "Simulating duplicate remote accept: id=" << endpoint_id;
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(),
connect_medium);
LOG(INFO) << "Closing connection: id=" << endpoint_id;
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
env_.Start();
std::atomic_int destroyed_flag = 0;
@@ -1798,8 +1835,8 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) {
EXPECT_CALL(pcp_handler, InjectEndpointImpl(client_.get(), service_id, _))
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
@@ -1862,8 +1899,8 @@ TEST_F(BasePcpHandlerTest,
::testing::InSequence seq;
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
const ByteArray& endpoint_info,
const std::string& service_id) {
const ByteArray& endpoint_info,
const std::string& service_id) {
EXPECT_EQ(endpoint_id, id);
EXPECT_EQ(endpoint_info, ByteArray{"ABCD"});
});
@@ -1875,8 +1912,8 @@ TEST_F(BasePcpHandlerTest,
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call)
.WillOnce([id = endpoint_id](const std::string& endpoint_id,
const ByteArray& endpoint_info,
const std::string& service_id) {
const ByteArray& endpoint_info,
const std::string& service_id) {
EXPECT_EQ(endpoint_id, id);
EXPECT_EQ(endpoint_info, ByteArray{"ABCDEF"});
});
@@ -1975,8 +2012,8 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) {
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
@@ -2038,8 +2075,8 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) {
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
@@ -2103,31 +2140,30 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) {
bool first_call = true;
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.Times(2)
.WillRepeatedly(
[&pcp_handler, &endpoint_id, &first_call](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ByteArray endpoint_info;
if (first_call) {
endpoint_info = ByteArray("ABCD");
} else {
endpoint_info = ByteArray("ABCDE");
}
first_call = false;
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
endpoint_id,
endpoint_info,
service_id,
Medium::BLUETOOTH,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
return Status{Status::kSuccess};
});
.WillRepeatedly([&pcp_handler, &endpoint_id, &first_call](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ByteArray endpoint_info;
if (first_call) {
endpoint_info = ByteArray("ABCD");
} else {
endpoint_info = ByteArray("ABCDE");
}
first_call = false;
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
endpoint_id,
endpoint_info,
service_id,
Medium::BLUETOOTH,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
return Status{Status::kSuccess};
});
pcp_handler.InjectEndpoint(
client_.get(), service_id,
OutOfBandConnectionMetadata{
@@ -2949,5 +2985,37 @@ TEST_F(BasePcpHandlerTest, TestForceUpdateEndpointIdAdvertisingOption) {
env_.Stop();
}
TEST_P(BasePcpHandlerTest,
FillConnectionInfo_kEnableDynamicRoleSwitch_Enabled) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
ConnectionRequestInfo request_info = {
.endpoint_info = ByteArray("EndpointInfo"),
};
ConnectionOptions connection_options = {};
// Call FillConnectionInfo with dynamic role switch enabled
ConnectionInfo connection_info = pcp_handler.FillConnectionInfo(
client_.get(), request_info, connection_options);
// Verify that medium_role is set (populated) in connection_info!
EXPECT_TRUE(connection_info.medium_role.has_value());
bwu.Shutdown();
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
}
} // namespace
} // namespace nearby::connections
+160 -8
View File
@@ -36,6 +36,7 @@
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/service_id_constants.h"
#include "connections/strategy.h"
#include "internal/flags/nearby_flags.h"
#include "connections/medium_selector.h"
#include "internal/platform/cancelable_alarm.h"
@@ -311,11 +312,16 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client,
if (is_dynamic_role_switch_enabled_ &&
client->GetMediumRole(endpoint_id).has_value()) {
MediumRole medium_role = client->GetMediumRole(endpoint_id).value();
if (NeedToSwitchRole(client, endpoint_id, proposed_medium, medium_role)) {
auto remote_os_info = client->GetRemoteOsInfo(endpoint_id);
if (NeedToSwitchRole(client, endpoint_id, proposed_medium, medium_role,
remote_os_info.value_or(OsInfo()))) {
if (!channel
->Write(parser::ForBwuPathRequest(
proposed_medium,
client->GetUpgradeMediums(endpoint_id).GetMediums(true),
medium_role))
medium_role,
mediums_->GetWifi().GetCapability().supports_5_ghz))
.Ok()) {
LOG(ERROR) << "BwuManager couldn't complete the upgrade for endpoint "
<< endpoint_id << " to medium "
@@ -585,6 +591,12 @@ void BwuManager::OnBwuNegotiationFrame(
/* record_analytic= */ true,
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
break;
case BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_REQUEST:
if (frame.upgrade_path_info().has_upgrade_path_request()) {
ProcessUpgradePathRequest(client, endpoint_id,
frame.upgrade_path_info());
}
break;
case BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL:
if (!in_progress_upgrades_.contains(endpoint_id)) {
LOG(ERROR) << "Received LAST_WRITE_TO_PRIOR_CHANNEL for endpoint "
@@ -670,7 +682,19 @@ void BwuManager::OnIncomingConnection(
"OfflineFrame on EndpointChannel "
<< channel->GetName();
const std::string& endpoint_id = introduction.endpoint_id();
std::string endpoint_id = introduction.endpoint_id();
if (is_dynamic_role_switch_enabled_ &&
!in_progress_upgrades_.contains(endpoint_id) &&
introduction.has_last_endpoint_id() &&
!introduction.last_endpoint_id().empty()) {
std::string last_endpoint_id = introduction.last_endpoint_id();
if (in_progress_upgrades_.contains(last_endpoint_id)) {
LOG(INFO) << "BwuManager: aliasing endpoint ID " << endpoint_id
<< " to " << last_endpoint_id;
endpoint_id = last_endpoint_id;
}
}
ClientProxy* mapped_client;
const auto item = in_progress_upgrades_.find(endpoint_id);
if (item == in_progress_upgrades_.end()) return;
@@ -724,6 +748,7 @@ void BwuManager::RunOnBwuManagerThread(const std::string& name,
void BwuManager::RunUpgradeProtocol(
ClientProxy* client, const std::string& endpoint_id,
std::unique_ptr<EndpointChannel> new_channel, bool enable_encryption) {
new_channel->SetLocalEndpointId(client->GetLocalEndpointId());
LOG(INFO) << "RunUpgradeProtocol new channel @" << new_channel.get()
<< " name: " << new_channel->GetName() << ", medium: "
<< location::nearby::proto::connections::Medium_Name(
@@ -823,9 +848,11 @@ void BwuManager::ProcessBwuPathAvailableEvent(
abort_bwu = true;
} else {
auto medium_role = client->GetMediumRole(endpoint_id);
auto remote_os_info = client->GetRemoteOsInfo(endpoint_id);
if (medium_role.has_value() &&
!NeedToSwitchRole(client, endpoint_id, upgrade_medium,
medium_role.value())) {
medium_role.value(),
remote_os_info.value_or(OsInfo()))) {
abort_bwu = true;
}
}
@@ -937,8 +964,13 @@ void BwuManager::ProcessBwuPathAvailableEvent(
}
in_progress_upgrades_.emplace(endpoint_id, client);
bool local_supports_disabling =
(client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint ||
client->GetDiscoveryOptions().strategy == Strategy::kP2pPointToPoint);
bool enable_encryption = !upgrade_path_info.supports_disabling_encryption() ||
!local_supports_disabling;
RunUpgradeProtocol(client, endpoint_id, std::move(channel),
!upgrade_path_info.supports_disabling_encryption());
enable_encryption);
}
ErrorOr<std::unique_ptr<EndpointChannel>>
@@ -1032,10 +1064,25 @@ BwuManager::ProcessBwuPathAvailableEventInternal(
// Write the requisite BANDWIDTH_UPGRADE_NEGOTIATION.CLIENT_INTRODUCTION as
// the first OfflineFrame on this new EndpointChannel.
std::string last_local_endpoint_id = client->GetLastLocalEndpointId();
std::shared_ptr<EndpointChannel> previous_channel =
channel_manager_->GetChannelForEndpoint(endpoint_id);
if (previous_channel != nullptr) {
last_local_endpoint_id = previous_channel->GetLocalEndpointId();
}
LOG(INFO) << "BwuManager get last_local_endpoint_id "
<< last_local_endpoint_id << " from "
<< (previous_channel != nullptr ? "endpoint channel"
: "client proxy");
bool local_supports_disabling =
(client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint ||
client->GetDiscoveryOptions().strategy == Strategy::kP2pPointToPoint);
if (!new_channel
->Write(parser::ForBwuIntroduction(
client->GetLocalEndpointId(),
upgrade_path_info.supports_disabling_encryption()))
client->GetLocalEndpointId(), last_local_endpoint_id,
local_supports_disabling &&
upgrade_path_info.supports_disabling_encryption()))
.Ok()) {
// This was never a fully EstablishedConnection, no need to provide a
// closure reason.
@@ -1634,7 +1681,13 @@ void BwuManager::AttemptToRecordBandwidthUpgradeErrorForUnknownEndpoint(
bool BwuManager::NeedToSwitchRole(
ClientProxy* client, const std::string& endpoint_id, Medium medium,
const location::nearby::connections::MediumRole& medium_role) {
const location::nearby::connections::MediumRole& medium_role,
const location::nearby::connections::OsInfo& remote_os_info) {
if (!is_dynamic_role_switch_enabled_) {
return false;
}
// On called by receiver device, check if the sender device can host the
// upgrade medium or not
if (GetLocalOsInfo(client).type() == OsInfo::APPLE) {
switch (medium) {
case Medium::WIFI_HOTSPOT:
@@ -1643,6 +1696,105 @@ bool BwuManager::NeedToSwitchRole(
break;
}
}
// For testing on Windows as a receiver device to request dynamic role switch.
// No need for final check in.
if (GetLocalOsInfo(client).type() == OsInfo::WINDOWS &&
remote_os_info.type() == OsInfo::ANDROID) {
LOG(INFO) << "Local: Windows OS, Remote: Android device detected. "
"WifiDirect NeedToSwitchRole and let Android be GO. "
"medium_role.support_wifi_direct_group_owner(): "
<< medium_role.support_wifi_direct_group_owner();
switch (medium) {
case Medium::WIFI_DIRECT:
return medium_role.support_wifi_direct_group_owner();
default:
break;
}
}
return false;
}
// This feature currently is only used by Android as receiver device to request
// a dynamic role switch to Windows as Wi-Fi Direct GO. So WIFI_DIRECT is the
// preferred medium to upgrade to.
void BwuManager::ProcessUpgradePathRequest(
ClientProxy* client, const std::string& endpoint_id,
const location::nearby::connections::BandwidthUpgradeNegotiationFrame::
UpgradePathInfo& upgrade_path_info) {
if (!is_dynamic_role_switch_enabled_) {
return;
}
LOG(INFO) << "BwuManager: processing incoming UPGRADE_PATH_REQUEST frame for "
"endpoint "
<< endpoint_id;
const auto& request = upgrade_path_info.upgrade_path_request();
std::vector<Medium> upgrade_mediums;
upgrade_mediums.reserve(request.mediums_size());
bool has_wifi_direct = false;
for (auto m : request.mediums()) {
Medium medium = parser::UpgradePathInfoMediumToMedium(
static_cast<BandwidthUpgradeNegotiationFrame::UpgradePathInfo::Medium>(
m));
LOG(INFO) << "BwuManager: UpgradePathRequest medium: "
<< location::nearby::proto::connections::Medium_Name(medium);
upgrade_mediums.push_back(medium);
if (medium == Medium::WIFI_DIRECT) {
has_wifi_direct = true;
}
}
const location::nearby::connections::MediumRole& medium_role =
request.medium_meta_data().medium_role();
LOG(INFO) << "BwuManager: medium_role: " << medium_role.DebugString();
if (CanHost(client, medium_role)) {
Medium medium = ChooseBestUpgradeMedium(endpoint_id, upgrade_mediums);
if (has_wifi_direct) {
medium = Medium::WIFI_DIRECT;
}
LOG(INFO) << "BwuManager: Initiating BWU for endpoint " << endpoint_id
<< " with medium "
<< location::nearby::proto::connections::Medium_Name(medium);
InitiateBwuForEndpoint(client, endpoint_id, medium);
} else {
ProcessUpgradeFailureEvent(
client, endpoint_id, upgrade_path_info,
BandwidthUpgradeResult::REMOTE_CONNECTION_ERROR,
/* record_analytic= */ true,
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
}
}
bool BwuManager::CanHost(
ClientProxy* client,
const location::nearby::connections::MediumRole& medium_role) {
if (!is_dynamic_role_switch_enabled_) {
return false;
}
ClientProxy::MediumsAvailability mediums_availability;
mediums_availability.is_wifi_direct_go_available =
mediums_->GetWifiDirect().IsGOAvailable();
mediums_availability.is_wifi_direct_gc_available =
mediums_->GetWifiDirect().IsGCAvailable();
mediums_availability.is_wifi_hotspot_ap_available =
mediums_->GetWifiHotspot().IsAPAvailable();
mediums_availability.is_wifi_hotspot_client_available =
mediums_->GetWifiHotspot().IsClientAvailable();
const location::nearby::connections::MediumRole& local_medium_role =
client->GetLocalMediumRole(mediums_availability);
if ((local_medium_role.support_wifi_direct_group_owner() &&
medium_role.support_wifi_direct_group_client() &&
mediums_->GetWifiDirect().IsGOAvailable()) ||
(local_medium_role.support_wifi_hotspot_host() &&
medium_role.support_wifi_hotspot_client() &&
mediums_->GetWifiHotspot().IsAPAvailable()) ||
(local_medium_role.support_wifi_aware_publisher() &&
medium_role.support_wifi_aware_subscriber())) {
LOG(INFO) << "BwuManager: Can host the upgrade medium.";
return true;
}
LOG(INFO) << "BwuManager: Can't host the upgrade medium.";
return false;
}
+10 -1
View File
@@ -221,7 +221,16 @@ class BwuManager : public EndpointManager::FrameProcessor {
bool NeedToSwitchRole(
ClientProxy* client, const std::string& endpoint_id, Medium medium,
const location::nearby::connections::MediumRole& medium_role);
const location::nearby::connections::MediumRole& medium_role,
const location::nearby::connections::OsInfo& remote_os_info);
void ProcessUpgradePathRequest(
ClientProxy* client, const std::string& endpoint_id,
const location::nearby::connections::BandwidthUpgradeNegotiationFrame::
UpgradePathInfo& upgrade_path_info);
bool CanHost(ClientProxy* client,
const location::nearby::connections::MediumRole& medium_role);
virtual const location::nearby::connections::OsInfo& GetLocalOsInfo(
ClientProxy* client) const;
+569 -195
View File
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/connection_options.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/bwu_handler.h"
@@ -81,12 +82,193 @@ CreateWifiHotspotCredentials() {
return credentials;
}
class BwuManagerTest : public ::testing::Test {
class BwuManagerBaseTest : public ::testing::Test {
protected:
BwuManagerTest() {
void SetUp() override {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
true);
}
void TearDown() override {
NearbyFlags::GetInstance().ResetOverridedValues();
}
};
TEST_F(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) {
ClientProxy client;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
Mediums mediums;
BwuManager::Config config;
config.allow_upgrade_to.SetAll(false);
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
std::move(handlers), config);
client.SetLocalOsType(OsInfo::APPLE);
auto channel1 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
MediumRole medium_role;
medium_role.set_support_wifi_hotspot_host(true);
client.OnConnectionInitiated(
std::string(kEndpointId1),
{.remote_endpoint_info = ByteArray("remote endpoint")},
{.auto_upgrade_bandwidth = false,
.connection_info =
{
.medium_role = {medium_role},
}},
{}, "");
client.OnConnectionAccepted(std::string(kEndpointId1));
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
std::move(channel1));
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
Medium::WIFI_HOTSPOT);
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
}
TEST_F(BwuManagerBaseTest,
InitiateBwu_NeedToSwitchRole_WindowsAndroid_Success) {
ClientProxy client;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
Mediums mediums;
BwuManager::Config config;
config.allow_upgrade_to.SetAll(false);
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
std::move(handlers), config);
// Set up local as WINDOWS, remote as ANDROID
client.SetLocalOsType(OsInfo::WINDOWS);
OsInfo remote_os_info;
remote_os_info.set_type(OsInfo::ANDROID);
auto channel1 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
auto* channel1_ptr = channel1.get();
MediumRole remote_medium_role;
remote_medium_role.set_support_wifi_direct_group_owner(true);
client.OnConnectionInitiated(
std::string(kEndpointId1),
{.remote_endpoint_info = ByteArray("remote endpoint")},
{.auto_upgrade_bandwidth = false,
.connection_info =
{
.medium_role = {remote_medium_role},
}},
{}, "");
client.OnConnectionAccepted(std::string(kEndpointId1));
client.SetRemoteOsInfo(kEndpointId1, remote_os_info);
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
std::move(channel1));
// Verify that before upgrade, write_timestamp is infinite past
EXPECT_EQ(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast());
// Initiate BWU for WiFi Direct on Windows, which forces
// role switch to Android
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
Medium::WIFI_DIRECT);
// Since role is switched, upgrade is NOT initiated locally, but delegated
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
// Verify that an UPGRADE_PATH_REQUEST frame was actually written to
// the channel
EXPECT_NE(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast());
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
}
TEST_F(BwuManagerBaseTest,
InitiateBwu_NeedToSwitchRole_WindowsAndroid_NoSwitch_Success) {
ClientProxy client;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
Mediums mediums;
BwuManager::Config config;
config.allow_upgrade_to.SetAll(false);
config.allow_upgrade_to.wifi_direct = true;
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_wifi_direct = std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
auto* fake_wifi_direct_ptr = fake_wifi_direct.get();
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
std::move(handlers), config);
// Set up local as WINDOWS, remote as ANDROID
client.SetLocalOsType(OsInfo::WINDOWS);
OsInfo remote_os_info;
remote_os_info.set_type(OsInfo::ANDROID);
auto channel1 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
MediumRole remote_medium_role;
remote_medium_role.set_support_wifi_direct_group_owner(false);
client.OnConnectionInitiated(
std::string(kEndpointId1),
{.remote_endpoint_info = ByteArray("remote endpoint")},
{.auto_upgrade_bandwidth = false,
.connection_info =
{
.medium_role = {remote_medium_role},
}},
{}, "");
client.OnConnectionAccepted(std::string(kEndpointId1));
client.SetRemoteOsInfo(kEndpointId1, remote_os_info);
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
std::move(channel1));
// Verify that before upgrade, upgrade is not ongoing
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
// Initiate BWU for WiFi Direct on Windows. Since remote doesn't support GO,
// we do not switch roles, so we host/upgrade locally.
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
Medium::WIFI_DIRECT);
// Upgrade is ongoing locally
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
EXPECT_EQ(fake_wifi_direct_ptr->handle_initialize_calls().size(), 1u);
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
}
class BwuManagerTest : public ::testing::Test {
protected:
static void SetUpTestSuite() {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
true);
}
static void TearDownTestSuite() {
NearbyFlags::GetInstance().ResetOverridedValues();
}
BwuManagerTest() {
// Set up fake BWU handlers for WebRTC and WifiLAN.
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_web_rtc = std::make_unique<FakeBwuHandler>(Medium::WEB_RTC);
@@ -210,65 +392,50 @@ class BwuManagerTest : public ::testing::Test {
std::unique_ptr<BwuManager> bwu_manager_;
};
TEST(BwuManagerBaseTest, AllowToUpgradeMedium) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::kEnableWifiDirect,
true);
ClientProxy client;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
Mediums mediums;
BwuManager::Config config;
config.allow_upgrade_to.SetAll(false);
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto bwu_manager = std::make_unique<BwuManager>(mediums, em, ecm,
std::move(handlers), config);
TEST_F(BwuManagerTest, AllowToUpgradeMedium) {
auto channel1 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1),
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId1),
std::move(channel1));
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1),
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_LAN);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1)));
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1),
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1)));
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel2 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId2),
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId2),
std::move(channel2));
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2),
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId2),
Medium::WIFI_HOTSPOT);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2)));
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId2),
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)));
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel3 = std::make_unique<FakeEndpointChannel>(
Medium::BLUETOOTH, std::string(kServiceIdA));
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId3),
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId3),
std::move(channel3));
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3),
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId3),
Medium::WIFI_DIRECT);
EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3)));
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId3),
EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId3)));
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId3),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
auto channel4 = std::make_unique<FakeEndpointChannel>(
Medium::WEB_RTC, std::string(kServiceIdA));
ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId4),
ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId4),
std::move(channel4));
bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4),
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId4),
Medium::BLUETOOTH);
EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4)));
ecm.UnregisterChannelForEndpoint(std::string(kEndpointId4),
EXPECT_FALSE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId4)));
ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId4),
DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
bwu_manager->Shutdown();
}
TEST(BwuManagerBaseTest, GcOnlyDoesNotInitializeWifiDirectAsGO) {
@@ -428,167 +595,6 @@ TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) {
false);
}
class BwuManagerTestParam : public BwuManagerTest,
public ::testing::WithParamInterface<bool> {
protected:
BwuManagerTestParam() {
SetSupportMultipleBwuMediums(GetParam());
}
};
TEST_P(BwuManagerTestParam, InitiateBwu_Success) {
// Create the initial device-to-device Bluetooth connection.
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE
// to the Responder over the initial Bluetooth channel.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
// The appropriate upgrade medium handler is informed of the BWU initiation.
ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA),
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id);
EXPECT_EQ(
kEndpointId1,
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id);
// Establish the incoming connection on the new medium. Verify that the
// upgrade channel replaces the initial channel.
std::shared_ptr<EndpointChannel> shared_initial_channel =
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
EXPECT_EQ(initial_channel, shared_initial_channel.get());
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
EXPECT_EQ(upgraded_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
// Confirm that upgrade channel is paused until initial channel is shut down.
EXPECT_TRUE(upgraded_channel->IsPaused());
EXPECT_FALSE(initial_channel->is_closed());
// Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then
// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the
// Responder device to trigger the shutdown of the initial Bluetooth channel.
ExceptionOr<OfflineFrame> last_write_frame =
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
ExceptionOr<OfflineFrame> safe_to_close_frame =
parser::FromBytes(parser::ForBwuSafeToClose());
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
// Confirm that upgrade channel is resumed after initial channel is shut down.
// Note: If we didn't grab the shared initial channel pointer above, this
// channel would have already been destroyed.
auto old_channel =
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
EXPECT_FALSE(upgraded_channel->IsPaused());
EXPECT_TRUE(old_channel->is_closed());
EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED,
old_channel->disconnection_reason());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH,
/*upgrade_medium=*/Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// Ignore request to upgrade to WebRTC if we're already connected.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN);
// Ignore request to upgrade to WebRTC if we're already connected.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_HOTSPOT);
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) {
// Try to upgrade to a Medium without an initial Medium.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_HOTSPOT);
// Make sure none of the other medium handlers are called.
EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
}
TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// Try to upgrade an endpoint that already has an ungrade in progress. Should
// just early return with no action.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_LAN);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) {
// Create the initial device-to-device Bluetooth connection.
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Make the initial endpoint channel fail when writing the
// UPGRADE_PATH_AVAILABLE frame.
initial_channel->set_write_output(Exception{Exception::kIo});
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
// After we notify the WebRTC handler, we try to write the
// UPGRADE_PATH_AVAILABLE frame, but fail by just early returning.
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// However, we do not record an in-progress attempt. So, if we see an incoming
// connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH
// channel is still used.
EXPECT_EQ(initial_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
EXPECT_NE(upgraded_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
EXPECT_EQ(initial_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_F(BwuManagerTest,
InitiateBwu_Revert_OnDisconnect_MultipleEndpoints_FlagEnabled) {
SetSupportMultipleBwuMediums(true);
@@ -1286,6 +1292,374 @@ TEST_F(BwuManagerTest, ReceiveUnexpectedLastWriteBeforeUpgrade_NoWedge) {
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_CanHost_True) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
// Shutdown original BwuManager to clean up registrations cleanly.
bwu_manager_->Shutdown();
// Set up fake BWU handlers for WifiDirect.
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_wifi_direct =
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
BwuManager::Config config;
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
bwu_manager_ = std::make_unique<BwuManager>(
mediums_, em_, ecm_, std::move(handlers), config);
bwu_manager_->MakeSingleThreadedForTesting();
// Create initial connection
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Build the UpgradePathRequest frame using the parser helper
location::nearby::connections::MediumRole remote_medium_role;
remote_medium_role.set_support_wifi_direct_group_client(true);
std::string bytes = parser::ForBwuPathRequest(
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
/*supports_5_ghz=*/true);
OfflineFrame frame;
frame.ParseFromString(bytes);
// Process the request
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
// Verify that WiFi Direct BWU was initiated
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 1u);
UnRegisterChannelForEndpoint(kEndpointId1);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
}
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_CanHost_False) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
// Shutdown original BwuManager to clean up registrations cleanly.
bwu_manager_->Shutdown();
// Set up fake BWU handlers for WifiDirect.
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_wifi_direct =
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
BwuManager::Config config;
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
bwu_manager_ = std::make_unique<BwuManager>(
mediums_, em_, ecm_, std::move(handlers), config);
bwu_manager_->MakeSingleThreadedForTesting();
// Create initial connection
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Build the UpgradePathRequest frame where remote doesn't support GC
location::nearby::connections::MediumRole remote_medium_role;
std::string bytes = parser::ForBwuPathRequest(
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
/*supports_5_ghz=*/true);
OfflineFrame frame;
frame.ParseFromString(bytes);
// Process the request
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
// Verify that WiFi Direct BWU was NOT initiated
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 0u);
UnRegisterChannelForEndpoint(kEndpointId1);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
}
TEST_F(BwuManagerTest, ProcessUpgradePathRequest_DynamicRoleSwitchDisabled) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
// Shutdown original BwuManager to clean up registrations cleanly.
bwu_manager_->Shutdown();
// Set up fake BWU handlers for WifiDirect.
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_wifi_direct =
std::make_unique<FakeBwuHandler>(Medium::WIFI_DIRECT);
FakeBwuHandler* fake_wifi_direct_handler_ptr = fake_wifi_direct.get();
handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct));
BwuManager::Config config;
config.allow_upgrade_to = BooleanMediumSelector{.wifi_direct = true};
bwu_manager_ = std::make_unique<BwuManager>(
mediums_, em_, ecm_, std::move(handlers), config);
bwu_manager_->MakeSingleThreadedForTesting();
// Create initial connection
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Build the UpgradePathRequest frame where remote supports GC
location::nearby::connections::MediumRole remote_medium_role;
remote_medium_role.set_support_wifi_direct_group_client(true);
std::string bytes = parser::ForBwuPathRequest(
Medium::WIFI_DIRECT, {Medium::WIFI_DIRECT}, remote_medium_role,
/*supports_5_ghz=*/true);
OfflineFrame frame;
frame.ParseFromString(bytes);
// Process the request
bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
// Verify that WiFi Direct BWU was NOT initiated
EXPECT_EQ(fake_wifi_direct_handler_ptr->handle_initialize_calls().size(), 0u);
UnRegisterChannelForEndpoint(kEndpointId1);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
}
TEST_F(BwuManagerTest, OnIncomingConnection_EndpointAliasesToLastEndpointId) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
// Shutdown original BwuManager to clean up registrations cleanly.
bwu_manager_->Shutdown();
// Create a new BwuManager with the overridden flag. We use WEB_RTC since
// it has a simple, standard BWU flow.
absl::flat_hash_map<Medium, std::unique_ptr<BwuHandler>> handlers;
auto fake_web_rtc = std::make_unique<FakeBwuHandler>(Medium::WEB_RTC);
handlers.emplace(Medium::WEB_RTC, std::move(fake_web_rtc));
BwuManager::Config config;
config.allow_upgrade_to = BooleanMediumSelector{.web_rtc = true};
bwu_manager_ = std::make_unique<BwuManager>(
mediums_, em_, ecm_, std::move(handlers), config);
bwu_manager_->MakeSingleThreadedForTesting();
// Create initial connection with the old endpoint ID "OldEndpoint"
CreateInitialEndpoint(&client_, kServiceIdA, "OldEndpoint",
Medium::BLUETOOTH);
// Initiate upgrade for "OldEndpoint" (inserts into in_progress_upgrades_)
bwu_manager_->InitiateBwuForEndpoint(&client_, "OldEndpoint",
Medium::WEB_RTC);
// Now simulate incoming upgraded connection. Set introduction read output:
// - endpoint_id = "NewEndpoint"
// - last_endpoint_id = "OldEndpoint"
auto upgraded_channel = std::make_unique<FakeEndpointChannel>(
Medium::WEB_RTC, std::string(kServiceIdA));
FakeEndpointChannel* upgraded_channel_raw = upgraded_channel.get();
std::string intro_frame = parser::ForBwuIntroduction(
"NewEndpoint", "OldEndpoint", /*supports_disabling_encryption=*/false);
upgraded_channel->set_read_output(
ExceptionOr<ByteArray>(ByteArray(intro_frame)));
auto connection = std::make_unique<BwuHandler::IncomingSocketConnection>();
connection->channel = std::move(upgraded_channel);
// Invoke OnIncomingConnection
bwu_manager_->InvokeOnIncomingConnectionForTesting(&client_,
std::move(connection));
// Verify that an Ack frame was written to upgraded_channel_raw
EXPECT_NE(upgraded_channel_raw->GetLastWriteTimestamp(),
absl::InfinitePast());
// Clean up
UnRegisterChannelForEndpoint("OldEndpoint");
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
}
class BwuManagerTestParam : public BwuManagerTest,
public ::testing::WithParamInterface<bool> {
protected:
BwuManagerTestParam() {
SetSupportMultipleBwuMediums(GetParam());
}
};
TEST_P(BwuManagerTestParam, InitiateBwu_Success) {
// Create the initial device-to-device Bluetooth connection.
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE
// to the Responder over the initial Bluetooth channel.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
// The appropriate upgrade medium handler is informed of the BWU initiation.
ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA),
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id);
EXPECT_EQ(
kEndpointId1,
fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id);
// Establish the incoming connection on the new medium. Verify that the
// upgrade channel replaces the initial channel.
std::shared_ptr<EndpointChannel> shared_initial_channel =
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
EXPECT_EQ(initial_channel, shared_initial_channel.get());
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
EXPECT_EQ(upgraded_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
// Confirm that upgrade channel is paused until initial channel is shut down.
EXPECT_TRUE(upgraded_channel->IsPaused());
EXPECT_FALSE(initial_channel->is_closed());
// Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then
// BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the
// Responder device to trigger the shutdown of the initial Bluetooth channel.
ExceptionOr<OfflineFrame> last_write_frame =
parser::FromBytes(parser::ForBwuLastWrite());
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
ExceptionOr<OfflineFrame> safe_to_close_frame =
parser::FromBytes(parser::ForBwuSafeToClose());
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
std::string(kEndpointId1), &client_,
Medium::BLUETOOTH);
// Confirm that upgrade channel is resumed after initial channel is shut down.
// Note: If we didn't grab the shared initial channel pointer above, this
// channel would have already been destroyed.
auto old_channel =
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
EXPECT_FALSE(upgraded_channel->IsPaused());
EXPECT_TRUE(old_channel->is_closed());
EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED,
old_channel->disconnection_reason());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH,
/*upgrade_medium=*/Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// Ignore request to upgrade to WebRTC if we're already connected.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN);
// Ignore request to upgrade to WebRTC if we're already connected.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_HOTSPOT);
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) {
// Try to upgrade to a Medium without an initial Medium.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_HOTSPOT);
// Make sure none of the other medium handlers are called.
EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
}
TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) {
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// Try to upgrade an endpoint that already has an ungrade in progress. Should
// just early return with no action.
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WIFI_LAN);
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(
fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty());
EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty());
UnRegisterChannelForEndpoint(kEndpointId1);
}
TEST_P(BwuManagerTestParam,
InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) {
// Create the initial device-to-device Bluetooth connection.
FakeEndpointChannel* initial_channel = CreateInitialEndpoint(
&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
// Make the initial endpoint channel fail when writing the
// UPGRADE_PATH_AVAILABLE frame.
initial_channel->set_write_output(Exception{Exception::kIo});
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
Medium::WEB_RTC);
// After we notify the WebRTC handler, we try to write the
// UPGRADE_PATH_AVAILABLE frame, but fail by just early returning.
EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size());
// However, we do not record an in-progress attempt. So, if we see an incoming
// connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH
// channel is still used.
EXPECT_EQ(initial_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
FakeEndpointChannel* upgraded_channel =
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
/*initialize_call_index=*/0u, bwu_manager_.get());
EXPECT_NE(upgraded_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
EXPECT_EQ(initial_channel,
ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get());
UnRegisterChannelForEndpoint(kEndpointId1);
}
INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam,
testing::Bool());
+126 -3
View File
@@ -276,6 +276,12 @@ ClientProxy::ClientProxy(std::unique_ptr<AnalyticsRecorder> analytics_recorder)
// Load advertising info from preferences.
LoadClientInfoFromPreferences();
#ifndef NEARBY_CHROMIUM
local_device_name_ = api::ImplementationPlatform::CreateDeviceInfo()
->GetOsDeviceName()
.value_or("");
#endif
if (preferences_manager_ != nullptr) {
app_lifecycle_monitor_ =
api::ImplementationPlatform::CreateAppLifecycleMonitor(
@@ -376,9 +382,10 @@ void ClientProxy::SetBluetoothMacAddress(const std::string& endpoint_id,
std::string ClientProxy::GenerateLocalEndpointId() {
if (!cached_endpoint_id_.empty()) {
if (stable_endpoint_id_mode_) {
if (stable_endpoint_id_mode_ || HasOngoingConnection()) {
LOG(INFO) << "ClientProxy [Local Endpoint Re-using cached "
"endpoint id due to in stable endpoint id mode]: "
"endpoint id due to in stable endpoint id mode or having "
"ongoing connection]: "
"client="
<< GetClientId()
<< "; cached_endpoint_id_=" << cached_endpoint_id_;
@@ -875,6 +882,48 @@ bool ClientProxy::HasOngoingConnection() const {
!GetConnectedEndpoints().empty();
}
bool ClientProxy::HasWifiDirectConnection() const {
MutexLock lock(&mutex_);
for (const auto& entry : connections_) {
if (entry.second.first.connected_medium == Medium::WIFI_DIRECT) {
LOG(INFO) << "ClientProxy [HasWifiDirectConnection]: true";
return true;
}
}
LOG(INFO) << "ClientProxy [HasWifiDirectConnection]: false";
return false;
}
bool ClientProxy::HasWifiHotspotConnection() const {
MutexLock lock(&mutex_);
for (const auto& entry : connections_) {
if (entry.second.first.connected_medium == Medium::WIFI_HOTSPOT) {
return true;
}
}
return false;
}
bool ClientProxy::HasWifiAwareConnection() const {
MutexLock lock(&mutex_);
for (const auto& entry : connections_) {
if (entry.second.first.connected_medium == Medium::WIFI_AWARE) {
return true;
}
}
return false;
}
std::string ClientProxy::GetLastLocalEndpointId() const {
MutexLock lock(&mutex_);
return last_local_endpoint_id_;
}
void ClientProxy::SetLastLocalEndpointId(absl::string_view endpoint_id) {
MutexLock lock(&mutex_);
last_local_endpoint_id_ = std::string(endpoint_id);
}
std::int32_t ClientProxy::GetNumOutgoingConnections() const {
return GetMatchingEndpoints([](const Connection& connection) {
return connection.status == Connection::kConnected &&
@@ -1133,6 +1182,26 @@ void ClientProxy::SetRemoteOsInfo(absl::string_view endpoint_id,
}
}
void ClientProxy::SetRemoteDeviceName(absl::string_view endpoint_id,
absl::string_view device_name) {
MutexLock lock(&mutex_);
ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
item->first.device_name = std::string(device_name);
LOG(INFO) << "ClientProxy [SetRemoteDeviceName]: " << device_name;
}
}
std::string ClientProxy::GetRemoteDeviceName(
absl::string_view endpoint_id) const {
MutexLock lock(&mutex_);
const ConnectionPair* item = LookupConnection(endpoint_id);
if (item != nullptr) {
return item->first.device_name;
}
return "";
}
std::optional<std::int32_t> ClientProxy::GetRemoteSafeToDisconnectVersion(
absl::string_view endpoint_id) const {
MutexLock lock(&mutex_);
@@ -1249,9 +1318,23 @@ void ClientProxy::RemoveAllEndpoints() {
OnSessionComplete();
}
void ClientProxy::ResetLocalEndpointId() {
MutexLock lock(&mutex_);
if (HasOngoingConnection()) {
return;
}
if (!local_endpoint_id_.empty()) {
last_local_endpoint_id_ = local_endpoint_id_;
local_endpoint_id_.clear();
}
}
void ClientProxy::OnSessionComplete() {
MutexLock lock(&mutex_);
if (connections_.empty() && !IsAdvertising()) {
if (!local_endpoint_id_.empty()) {
last_local_endpoint_id_ = local_endpoint_id_;
}
local_endpoint_id_.clear();
analytics_recorder_->LogSession();
@@ -1298,6 +1381,9 @@ void ClientProxy::EnterStableEndpointIdMode() {
<< GetClientId();
stable_endpoint_id_mode_ = true;
if (!IsAdvertising() && !IsDiscovering() && !HasOngoingConnection()) {
ResetLocalEndpointId();
}
}
void ClientProxy::ExitStableEndpointIdMode() {
@@ -1305,6 +1391,7 @@ void ClientProxy::ExitStableEndpointIdMode() {
VLOG(1) << "ClientProxy [ExitStableEndpointIdMode]: client=" << GetClientId();
stable_endpoint_id_mode_ = false;
ResetLocalEndpointId();
ScheduleClearCachedEndpointIdAlarm();
}
@@ -1318,7 +1405,7 @@ void ClientProxy::ScheduleClearCachedEndpointIdAlarm() {
return;
}
if (HasOngoingConnection()) {
if (IsAdvertising() || IsDiscovering() || HasOngoingConnection()) {
VLOG(1) << "ClientProxy [Handle clearing cached endpoint ID "
"during disconnection]: client="
<< GetClientId();
@@ -1431,6 +1518,41 @@ std::optional<MediumRole> ClientProxy::GetMediumRole(
return std::nullopt;
}
location::nearby::connections::MediumRole ClientProxy::GetLocalMediumRole(
const ClientProxy::MediumsAvailability& mediums_availability) const {
location::nearby::connections::MediumRole medium_role;
if (!NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch)) {
return medium_role;
}
if (GetLocalOsInfo().type() == OsInfo::APPLE) {
medium_role.set_support_awdl_publisher(true);
medium_role.set_support_awdl_subscriber(true);
// Apple always supports wifi hotspot client role since they can always
// join a hotspot.
medium_role.set_support_wifi_hotspot_client(true);
return medium_role;
}
medium_role.set_support_wifi_direct_group_owner(
mediums_availability.is_wifi_direct_go_available && !IsUsingP2pMedium());
medium_role.set_support_wifi_direct_group_client(
mediums_availability.is_wifi_direct_gc_available);
medium_role.set_support_wifi_hotspot_host(
mediums_availability.is_wifi_hotspot_ap_available && !IsUsingP2pMedium());
medium_role.set_support_wifi_hotspot_client(
mediums_availability.is_wifi_hotspot_client_available);
LOG(INFO) << "medium_role: " << medium_role.DebugString();
return medium_role;
}
bool ClientProxy::IsUsingP2pMedium() const {
return HasWifiDirectConnection() || HasWifiHotspotConnection() ||
HasWifiAwareConnection();
}
std::optional<std::string> ClientProxy::GetEndpointIdForDct() const {
MutexLock lock(&mutex_);
if (dct_endpoint_id_.empty()) {
@@ -1559,6 +1681,7 @@ std::string ClientProxy::Dump() {
? location::nearby::connections::OsInfo::OsType_Name(
it->second.first.os_info->type())
: "unknown")
<< ", (remote device name) " << it->second.first.device_name
<< std::endl;
}
+32 -1
View File
@@ -75,6 +75,9 @@ class ClientProxy final {
std::string GetLocalEndpointId();
std::string GetLocalEndpointInfo() { return local_endpoint_info_; }
std::string GetLocalDeviceName() {
return local_device_name_;
}
// Override the base for received file attachments from a specific endpoint.
// Returns true if the endpoint is found and the path is overridden.
@@ -103,6 +106,9 @@ class ClientProxy final {
// Clears all the runtime state of this client.
void Reset();
// Resets the local endpoint ID and sets the last local endpoint ID.
void ResetLocalEndpointId();
// Marks this client as advertising with the given callbacks.
void StartedAdvertising(
const std::string& service_id, Strategy strategy,
@@ -145,7 +151,6 @@ class ClientProxy final {
MutexLock lock(&mutex_);
local_endpoint_info_ = std::string(endpoint_info);
}
void UpdateAdvertisingOptions(const AdvertisingOptions& advertising_options) {
MutexLock lock(&mutex_);
advertising_options_ = advertising_options;
@@ -210,6 +215,14 @@ class ClientProxy final {
// Returns true if there is at least one connected connection or one pending
// connection.
bool HasOngoingConnection() const;
// Returns true if there is at least one active WiFi Direct connection.
bool HasWifiDirectConnection() const;
// Returns true if there is at least one active WiFi Hotspot connection.
bool HasWifiHotspotConnection() const;
// Returns true if there is at least one active WiFi Aware connection.
bool HasWifiAwareConnection() const;
std::string GetLastLocalEndpointId() const;
void SetLastLocalEndpointId(absl::string_view endpoint_id);
// Returns the number of endpoints that are connected and outgoing.
std::int32_t GetNumOutgoingConnections() const;
// Returns the number of endpoints that are connected and incoming.
@@ -287,6 +300,9 @@ class ClientProxy final {
void SetRemoteOsInfo(
absl::string_view endpoint_id,
const location::nearby::connections::OsInfo& remote_os_info);
void SetRemoteDeviceName(absl::string_view endpoint_id,
absl::string_view device_name);
std::string GetRemoteDeviceName(absl::string_view endpoint_id) const;
void RegisterDeviceProvider(NearbyDeviceProvider* provider) {
external_device_provider_ = provider;
@@ -333,6 +349,18 @@ class ClientProxy final {
std::optional<location::nearby::connections::MediumRole> GetMediumRole(
absl::string_view endpoint_id) const;
struct MediumsAvailability {
bool is_wifi_direct_go_available = false;
bool is_wifi_direct_gc_available = false;
bool is_wifi_hotspot_ap_available = false;
bool is_wifi_hotspot_client_available = false;
};
location::nearby::connections::MediumRole GetLocalMediumRole(
const MediumsAvailability& mediums_availability) const;
bool IsUsingP2pMedium() const;
// Forces client to regenerate a new local endpoint id.
void ClearCachedLocalEndpointId();
@@ -372,6 +400,7 @@ class ClientProxy final {
std::int32_t safe_to_disconnect_version;
std::int32_t remote_multiplex_socket_bitmask;
std::string save_path;
std::string device_name;
};
using ConnectionPair = std::pair<Connection, PayloadListener>;
@@ -441,6 +470,8 @@ class ClientProxy final {
std::int64_t client_id_;
std::string local_endpoint_id_;
std::string local_endpoint_info_;
std::string last_local_endpoint_id_;
std::string local_device_name_;
// If advertising is in stable endpoint ID mode, the endpoint ID is stable
// for 30s after advertising or disconnection. When stable_endpoint_id_mode_
@@ -1345,6 +1345,7 @@ TEST_F(ClientProxyTest, GetRemoteInfoNullWithoutConnections) {
EXPECT_FALSE(client1()
->GetRemoteSafeToDisconnectVersion(advertising_endpoint.id)
.has_value());
EXPECT_EQ(client1()->GetRemoteDeviceName(advertising_endpoint.id), "");
}
TEST_F(ClientProxyTest, SetRemoteInfoCorrect) {
@@ -1365,6 +1366,10 @@ TEST_F(ClientProxyTest, SetRemoteInfoCorrect) {
EXPECT_EQ(
client1()->GetRemoteSafeToDisconnectVersion(advertising_endpoint.id),
nearby_connections_version);
std::string device_name = "device_name";
client1()->SetRemoteDeviceName(advertising_endpoint.id, device_name);
EXPECT_EQ(client1()->GetRemoteDeviceName(advertising_endpoint.id),
device_name);
}
// Test ClientProxy::AddCancellationFlag, where if a flag is already in the map,
@@ -1563,6 +1568,257 @@ TEST_F(ClientProxyTest, GetSavePathDefaultsToEmpty) {
EXPECT_THAT(client1()->GetSavePath(advertising_endpoint.id), IsEmpty());
}
TEST_F(ClientProxyTest, GetLocalMediumRoleFlagDisabled) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
false);
ClientProxy::MediumsAvailability availability;
availability.is_wifi_direct_go_available = true;
availability.is_wifi_direct_gc_available = true;
availability.is_wifi_hotspot_ap_available = true;
availability.is_wifi_hotspot_client_available = true;
location::nearby::connections::MediumRole role =
client1()->GetLocalMediumRole(availability);
EXPECT_FALSE(role.support_awdl_publisher());
EXPECT_FALSE(role.support_awdl_subscriber());
EXPECT_FALSE(role.support_wifi_direct_group_owner());
EXPECT_FALSE(role.support_wifi_direct_group_client());
EXPECT_FALSE(role.support_wifi_hotspot_host());
EXPECT_FALSE(role.support_wifi_hotspot_client());
}
TEST_F(ClientProxyTest, GetLocalMediumRoleAppleOs) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
client1()->SetLocalOsType(location::nearby::connections::OsInfo::APPLE);
ClientProxy::MediumsAvailability availability;
location::nearby::connections::MediumRole role =
client1()->GetLocalMediumRole(availability);
EXPECT_TRUE(role.support_awdl_publisher());
EXPECT_TRUE(role.support_awdl_subscriber());
EXPECT_TRUE(role.support_wifi_hotspot_client());
EXPECT_FALSE(role.support_wifi_direct_group_owner());
EXPECT_FALSE(role.support_wifi_direct_group_client());
EXPECT_FALSE(role.support_wifi_hotspot_host());
}
TEST_F(ClientProxyTest, GetLocalMediumRoleNonAppleOsNoP2pConnection) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
client1()->SetLocalOsType(location::nearby::connections::OsInfo::ANDROID);
ClientProxy::MediumsAvailability availability;
availability.is_wifi_direct_go_available = true;
availability.is_wifi_direct_gc_available = true;
availability.is_wifi_hotspot_ap_available = true;
availability.is_wifi_hotspot_client_available = true;
location::nearby::connections::MediumRole role =
client1()->GetLocalMediumRole(availability);
EXPECT_TRUE(role.support_wifi_direct_group_owner());
EXPECT_TRUE(role.support_wifi_direct_group_client());
EXPECT_TRUE(role.support_wifi_hotspot_host());
EXPECT_TRUE(role.support_wifi_hotspot_client());
}
TEST_F(ClientProxyTest, GetLocalMediumRoleNonAppleOsWithP2pConnection) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
client1()->SetLocalOsType(location::nearby::connections::OsInfo::ANDROID);
// Setup an active P2P connection to make IsUsingP2pMedium() true
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), advertising_endpoint);
client1()->OnBandwidthChanged(advertising_endpoint.id, Medium::WIFI_DIRECT);
EXPECT_TRUE(client1()->IsUsingP2pMedium());
ClientProxy::MediumsAvailability availability;
availability.is_wifi_direct_go_available = true;
availability.is_wifi_direct_gc_available = true;
availability.is_wifi_hotspot_ap_available = true;
availability.is_wifi_hotspot_client_available = true;
location::nearby::connections::MediumRole role =
client1()->GetLocalMediumRole(availability);
EXPECT_FALSE(role.support_wifi_direct_group_owner());
EXPECT_TRUE(role.support_wifi_direct_group_client());
EXPECT_FALSE(role.support_wifi_hotspot_host());
EXPECT_TRUE(role.support_wifi_hotspot_client());
}
TEST_F(ClientProxyTest, GetNumIncomingAndOutgoingConnections) {
// Initially no connections
EXPECT_EQ(client1()->GetNumIncomingConnections(), 0);
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 0);
// Set expectation for acceptance callback on step 1
// (which is outgoing based on discovery_connection_info_)
EXPECT_CALL(mock_advertising_connection_.accepted_cb, Call).Times(1);
// Define a complete listener for advertising
ConnectionListener advertising_listener = {
.initiated_cb = mock_advertising_connection_.initiated_cb.AsStdFunction(),
.accepted_cb = mock_advertising_connection_.accepted_cb.AsStdFunction(),
};
// 1. Establish connection 1
Endpoint advertising_endpoint =
StartAdvertising(client1(), advertising_listener);
EXPECT_CALL(mock_advertising_connection_.initiated_cb, Call).Times(1);
client1()->OnConnectionInitiated(
advertising_endpoint.id, discovery_connection_info_, connection_options_,
advertising_listener, "connection_token1");
// Accept local, accept remote, and then OnConnectionAccepted
client1()->LocalEndpointAcceptedConnection(
advertising_endpoint.id,
{
.payload_cb = mock_discovery_payload_.payload_cb.AsStdFunction(),
.payload_progress_cb =
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
});
client1()->RemoteEndpointAcceptedConnection(advertising_endpoint.id);
client1()->OnConnectionAccepted(advertising_endpoint.id);
// Verify client1 has 0 incoming connections and 1 outgoing connection
EXPECT_EQ(client1()->GetNumIncomingConnections(), 0);
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 1);
// Set expectation for acceptance callback on step 2
// (which is incoming based on advertising_connection_info_)
EXPECT_CALL(mock_discovery_connection_.accepted_cb, Call).Times(1);
// 2. Establish connection 2
StartDiscovery(client1(), GetDiscoveryListener());
Endpoint remote_endpoint = {
.info = ByteArray{"remote endpoint name"},
.id = "rem_ep_id",
};
OnDiscoveryEndpointFound(client1(), remote_endpoint);
EXPECT_CALL(mock_discovery_connection_.initiated_cb, Call).Times(1);
client1()->OnConnectionInitiated(
remote_endpoint.id, advertising_connection_info_, connection_options_,
discovery_connection_listener_, "connection_token2");
// Accept local, accept remote, and then OnConnectionAccepted
client1()->LocalEndpointAcceptedConnection(
remote_endpoint.id,
{
.payload_cb = mock_discovery_payload_.payload_cb.AsStdFunction(),
.payload_progress_cb =
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
});
client1()->RemoteEndpointAcceptedConnection(remote_endpoint.id);
client1()->OnConnectionAccepted(remote_endpoint.id);
// Verify client1 has 1 incoming connection and 1 outgoing connection
EXPECT_EQ(client1()->GetNumIncomingConnections(), 1);
EXPECT_EQ(client1()->GetNumOutgoingConnections(), 1);
}
TEST_F(ClientProxyTest, IsUsingP2pMediumTests) {
// With no connections, IsUsingP2pMedium should be false
EXPECT_FALSE(client1()->IsUsingP2pMedium());
// 1. Connection with Non-P2P medium (e.g. WIFI_LAN)
Endpoint endpoint_lan =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), endpoint_lan);
client1()->OnBandwidthChanged(endpoint_lan.id, Medium::WIFI_LAN);
EXPECT_FALSE(client1()->IsUsingP2pMedium());
// Clean-up connection
client1()->OnDisconnected(endpoint_lan.id, /*notify=*/false);
EXPECT_FALSE(client1()->IsUsingP2pMedium());
// 2. Connection with WIFI_DIRECT
Endpoint endpoint_direct =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), endpoint_direct);
client1()->OnBandwidthChanged(endpoint_direct.id, Medium::WIFI_DIRECT);
EXPECT_TRUE(client1()->IsUsingP2pMedium());
client1()->OnDisconnected(endpoint_direct.id, /*notify=*/false);
// 3. Connection with WIFI_HOTSPOT
Endpoint endpoint_hotspot =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), endpoint_hotspot);
client1()->OnBandwidthChanged(endpoint_hotspot.id, Medium::WIFI_HOTSPOT);
EXPECT_TRUE(client1()->IsUsingP2pMedium());
client1()->OnDisconnected(endpoint_hotspot.id, /*notify=*/false);
// 4. Connection with WIFI_AWARE
Endpoint endpoint_aware =
StartAdvertising(client1(), advertising_connection_listener_);
OnAdvertisingConnectionInitiated(client1(), endpoint_aware);
client1()->OnBandwidthChanged(endpoint_aware.id, Medium::WIFI_AWARE);
EXPECT_TRUE(client1()->IsUsingP2pMedium());
client1()->OnDisconnected(endpoint_aware.id, /*notify=*/false);
EXPECT_FALSE(client1()->IsUsingP2pMedium());
}
TEST_F(ClientProxyTest, GetAndSetLastLocalEndpointId) {
EXPECT_TRUE(client1()->GetLastLocalEndpointId().empty());
client1()->SetLastLocalEndpointId("TestEndpointID");
EXPECT_EQ(client1()->GetLastLocalEndpointId(), "TestEndpointID");
}
TEST_F(ClientProxyTest, ResetLocalEndpointId_OngoingConnectionReturnsEarly) {
std::string old_id = client1()->GetLocalEndpointId();
ASSERT_FALSE(old_id.empty());
// Set up an ongoing connection
OnAdvertisingConnectionInitiated(client1(),
{ByteArray("EndpointInfo"), "EndA"});
EXPECT_TRUE(client1()->HasOngoingConnection());
// ResetLocalEndpointId should NOT clear local_endpoint_id
client1()->ResetLocalEndpointId();
EXPECT_EQ(client1()->GetLocalEndpointId(), old_id);
// Terminate connection
client1()->OnDisconnected("EndA", /*notify=*/false);
EXPECT_FALSE(client1()->HasOngoingConnection());
// ResetLocalEndpointId should now successfully clear local_endpoint_id
client1()->ResetLocalEndpointId();
EXPECT_NE(client1()->GetLocalEndpointId(), old_id);
}
TEST_F(ClientProxyTest, ResetLocalEndpointId_SavesToLastLocalEndpointId) {
std::string old_id = client1()->GetLocalEndpointId();
ASSERT_FALSE(old_id.empty());
client1()->ResetLocalEndpointId();
EXPECT_EQ(client1()->GetLastLocalEndpointId(), old_id);
}
TEST_F(ClientProxyTest, OnSessionComplete_SavesToLastLocalEndpointId) {
std::string old_id = client1()->GetLocalEndpointId();
ASSERT_FALSE(old_id.empty());
// Put client into advertising mode first
client1()->StartedAdvertising(service_id_, strategy_, {}, {}, {});
EXPECT_TRUE(client1()->IsAdvertising());
// Stopping advertising triggers OnSessionComplete.
// Since connections_ is empty, it completes the session and should save last
// endpoint ID.
client1()->StoppedAdvertising();
EXPECT_FALSE(client1()->IsAdvertising());
EXPECT_EQ(client1()->GetLastLocalEndpointId(), old_id);
}
} // namespace
} // namespace connections
} // namespace nearby
@@ -103,6 +103,10 @@ class FakeEndpointChannel : public EndpointChannel {
}
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
const std::string& endpoint_id) override {}
void SetLocalEndpointId(const std::string& local_endpoint_id) override {
local_endpoint_id_ = local_endpoint_id;
}
std::string GetLocalEndpointId() const override { return local_endpoint_id_; }
private:
InputStream* in_ = nullptr;
@@ -110,6 +114,7 @@ class FakeEndpointChannel : public EndpointChannel {
absl::Time read_timestamp_ = absl::InfinitePast();
absl::Time write_timestamp_ = absl::InfinitePast();
mutable uint32_t next_keep_alive_seq_no_ = 0;
std::string local_endpoint_id_;
};
struct User {
@@ -128,6 +128,9 @@ class EndpointChannel {
// Enables the multiplex socket on the EndpointChannel.
virtual bool EnableMultiplexSocket() { return false; }
virtual void SetLocalEndpointId(const std::string& local_endpoint_id) = 0;
virtual std::string GetLocalEndpointId() const = 0;
};
inline bool operator==(const EndpointChannel& lhs, const EndpointChannel& rhs) {
@@ -17,7 +17,9 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
@@ -48,7 +50,9 @@ void EndpointChannelManager::RegisterChannelForEndpoint(
LOG(INFO) << "EndpointChannelManager registered channel of type "
<< channel->GetType() << " to endpoint " << endpoint_id;
SetActiveEndpointChannel(client, endpoint_id, std::move(channel),
std::shared_ptr<ChannelState::EndpointData> endpoint =
channel_state_.RegisterEndpoint(endpoint_id);
SetActiveEndpointChannel(client, endpoint_id, endpoint, std::move(channel),
true /* enable_encryption */);
LOG(INFO) << "Registered channel: id=" << endpoint_id;
@@ -58,8 +62,17 @@ void EndpointChannelManager::ReplaceChannelForEndpoint(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
MutexLock lock(&mutex_);
std::shared_ptr<ChannelState::EndpointData> endpoint =
channel_state_.GetEndpointData(endpoint_id);
if (endpoint == nullptr) {
LOG(WARNING) << "EndpointChannelManager failed to replace channel because "
"endpoint "
<< endpoint_id << " is not registered.";
return;
}
if (client->IsSafeToDisconnectEnabled(endpoint_id) &&
channel_state_.IsWaitingForSafeToDisconnectTimeout(endpoint_id)) {
endpoint->IsWaitingForSafeToDisconnectTimeout()) {
LOG(WARNING)
<< "EndpointChannelManager failed to replace endpoint " << endpoint_id
<< "'s channel with type " << channel->GetType()
@@ -67,13 +80,7 @@ void EndpointChannelManager::ReplaceChannelForEndpoint(
return;
}
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
if (endpoint != nullptr && endpoint->channel == nullptr) {
LOG(INFO) << "EndpointChannelManager is missing channel while "
"trying to update: endpoint "
<< endpoint_id;
}
SetActiveEndpointChannel(client, endpoint_id, std::move(channel),
SetActiveEndpointChannel(client, endpoint_id, endpoint, std::move(channel),
enable_encryption);
}
@@ -82,37 +89,47 @@ bool EndpointChannelManager::EncryptChannelForEndpoint(
std::unique_ptr<EncryptionContext> context) {
MutexLock lock(&mutex_);
channel_state_.UpdateEncryptionContextForEndpoint(endpoint_id,
std::move(context));
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
return channel_state_.EncryptChannel(endpoint);
std::shared_ptr<ChannelState::EndpointData> endpoint =
channel_state_.GetEndpointData(endpoint_id);
if (endpoint == nullptr) {
LOG(WARNING) << "EncryptChannelForEndpoint failed "
<< "because endpoint is not registered: " << endpoint_id;
return false;
}
endpoint->set_context(std::move(context));
return endpoint->EncryptChannel();
}
std::shared_ptr<EndpointChannel> EndpointChannelManager::GetChannelForEndpoint(
const std::string& endpoint_id) {
absl::string_view endpoint_id) {
MutexLock lock(&mutex_);
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
std::shared_ptr<ChannelState::EndpointData> endpoint =
channel_state_.GetEndpointData(endpoint_id);
if (endpoint == nullptr) {
LOG(INFO) << "No channel info for endpoint " << endpoint_id;
return {};
}
return endpoint->channel;
return endpoint->channel();
}
void EndpointChannelManager::SetActiveEndpointChannel(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<ChannelState::EndpointData> endpoint,
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
// Update the channel first, then encrypt this new channel, if
// crypto context is present.
channel->SetAnalyticsRecorder(&client->GetAnalyticsRecorder(), endpoint_id);
channel_state_.UpdateChannelForEndpoint(endpoint_id, std::move(channel));
channel_state_.UpdateSafeToDisconnectForEndpoint(
endpoint_id, client->IsSafeToDisconnectEnabled(endpoint_id));
auto* endpoint = channel_state_.LookupEndpointData(endpoint_id);
if (endpoint->IsEncrypted() && enable_encryption)
channel_state_.EncryptChannel(endpoint);
channel->SetLocalEndpointId(client->GetLocalEndpointId());
endpoint->set_channel(std::move(channel));
endpoint->set_safe_to_disconnect_enabled(
client->IsSafeToDisconnectEnabled(endpoint_id));
if (endpoint->IsEncrypted() && enable_encryption) {
endpoint->EncryptChannel();
}
}
int EndpointChannelManager::GetConnectedEndpointsCount() const {
@@ -133,7 +150,7 @@ void EndpointChannelManager::UpdateSafeToDisconnectForEndpoint(
}
void EndpointChannelManager::MarkEndpointStopWaitToDisconnect(
const std::string& endpoint_id, bool is_safe_to_disconnect,
absl::string_view endpoint_id, bool is_safe_to_disconnect,
bool notify_stop_waiting) {
MutexLock lock(&mutex_);
channel_state_.MarkEndpointStopWaitToDisconnect(
@@ -141,61 +158,128 @@ void EndpointChannelManager::MarkEndpointStopWaitToDisconnect(
}
bool EndpointChannelManager::CreateNewTimeoutDisconnectedState(
const std::string& endpoint_id, absl::Duration timeout_millis) {
return channel_state_.CreateNewTimeoutDisconnectedState(endpoint_id,
timeout_millis);
absl::string_view endpoint_id, absl::Duration timeout_millis) {
std::shared_ptr<ChannelState::EndpointData> endpoint_data;
{
MutexLock lock(&mutex_);
endpoint_data = channel_state_.GetEndpointData(endpoint_id);
}
if (!endpoint_data) return false;
LOG(INFO) << "[safe-to-disconnect] "
"Create TimeoutDisconnectedState for endpoint: "
<< endpoint_id;
endpoint_data->CreateNewTimeoutDisconnectedState(timeout_millis);
return true;
}
bool EndpointChannelManager::IsSafeToDisconnect(
const std::string& endpoint_id) {
bool EndpointChannelManager::IsSafeToDisconnect(absl::string_view endpoint_id) {
MutexLock lock(&mutex_);
return channel_state_.IsSafeToDisconnect(endpoint_id);
}
bool EndpointChannelManager::IsWaitingForSafeToDisconnectTimeoutForTesting(
absl::string_view endpoint_id) {
MutexLock lock(&mutex_);
return channel_state_.IsWaitingForSafeToDisconnectTimeoutForTesting(
endpoint_id);
}
void EndpointChannelManager::RemoveTimeoutDisconnectedState(
const std::string& endpoint_id) {
absl::string_view endpoint_id) {
MutexLock lock(&mutex_);
channel_state_.RemoveTimeoutDisconnectedState(endpoint_id);
}
///////////////////////////////// ChannelState /////////////////////////////////
// endpoint - channel endpoint to encrypt
bool EndpointChannelManager::ChannelState::EncryptChannel(
EndpointChannelManager::ChannelState::EndpointData* endpoint) {
if (endpoint != nullptr && endpoint->channel != nullptr &&
endpoint->context != nullptr) {
endpoint->channel->EnableEncryption(endpoint->context);
void EndpointChannelManager::ChannelState::EndpointData::
CreateNewTimeoutDisconnectedState(absl::Duration timeout_millis) {
MutexLock lock(&timeout_to_disconnected_mutex_);
timeout_to_disconnected_enabled_ = true;
timeout_to_disconnected_notified_ = false;
timeout_to_disconnected_.Wait(timeout_millis);
LOG(INFO) << "[safe-to-disconnect] Wait is done with "
<< (timeout_to_disconnected_notified_ ? "notification" : "timeout");
if (!timeout_to_disconnected_notified_) {
is_safe_to_disconnect_ = true;
}
timeout_to_disconnected_notified_ = false;
timeout_to_disconnected_enabled_ = false;
}
void EndpointChannelManager::ChannelState::EndpointData::
MarkEndpointStopWaitToDisconnect(bool is_safe_to_disconnect,
bool notify_stop_waiting) {
MutexLock lock(&timeout_to_disconnected_mutex_);
this->is_safe_to_disconnect_ = is_safe_to_disconnect;
if (!timeout_to_disconnected_enabled_) return;
if (notify_stop_waiting) {
LOG(INFO) << "[safe-to-disconnect] Notify stop waiting before timeout.";
timeout_to_disconnected_.Notify();
timeout_to_disconnected_notified_ = true;
}
}
bool EndpointChannelManager::ChannelState::EndpointData::
IsWaitingForSafeToDisconnectTimeout() const {
MutexLock lock(&timeout_to_disconnected_mutex_);
return timeout_to_disconnected_enabled_;
}
bool EndpointChannelManager::ChannelState::EndpointData::IsSafeToDisconnect()
const {
MutexLock lock(&timeout_to_disconnected_mutex_);
return is_safe_to_disconnect_;
}
void EndpointChannelManager::ChannelState::EndpointData::
RemoveTimeoutDisconnectedState() {
MutexLock lock(&timeout_to_disconnected_mutex_);
timeout_to_disconnected_notified_ = false;
timeout_to_disconnected_enabled_ = false;
}
bool EndpointChannelManager::ChannelState::EndpointData::EncryptChannel() {
if (context_ != nullptr) {
channel_->EnableEncryption(context_);
return true;
}
return false;
}
EndpointChannelManager::ChannelState::EndpointData*
EndpointChannelManager::ChannelState::LookupEndpointData(
const std::string& endpoint_id) {
auto item = endpoints_.find(endpoint_id);
return item != endpoints_.end() ? &item->second : nullptr;
std::shared_ptr<EndpointChannelManager::ChannelState::EndpointData>
EndpointChannelManager::ChannelState::GetEndpointData(
absl::string_view endpoint_id) {
auto it = endpoints_.find(endpoint_id);
return it != endpoints_.end() ? it->second : nullptr;
}
std::shared_ptr<EndpointChannelManager::ChannelState::EndpointData>
EndpointChannelManager::ChannelState::RegisterEndpoint(
absl::string_view endpoint_id) {
std::shared_ptr<EndpointData>& endpoint = endpoints_[endpoint_id];
if (endpoint == nullptr) {
endpoint = std::make_shared<EndpointData>();
} else {
LOG(DFATAL) << "Endpoint " << endpoint_id
<< " is already registered. It might not have been cleaned up "
"properly.";
}
return endpoint;
}
void EndpointChannelManager::ChannelState::DestroyAll() {
for (auto& item : endpoints_) {
RemoveEndpoint(item.first, DisconnectionReason::SHUTDOWN,
/* safe_to_disconnect_enabled */ false,
SafeDisconnectionResult::kSafeDisconnection);
// Collect all endpoint IDs to avoid iterator invalidation.
std::vector<std::string> endpoint_ids;
endpoint_ids.reserve(endpoints_.size());
for (const auto& [endpoint_id, endpoint_data] : endpoints_) {
endpoint_ids.push_back(endpoint_id);
}
endpoints_.clear();
}
void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint(
const std::string& endpoint_id, std::shared_ptr<EndpointChannel> channel) {
// Create EndpointData instance, if necessary, and populate channel.
endpoints_[endpoint_id].channel = std::move(channel);
}
void EndpointChannelManager::ChannelState::UpdateEncryptionContextForEndpoint(
const std::string& endpoint_id,
std::unique_ptr<EncryptionContext> context) {
// Create EndpointData instance, if necessary, and populate crypto context.
endpoints_[endpoint_id].context = std::move(context);
for (const auto& endpoint_id : endpoint_ids) {
RemoveEndpoint(endpoint_id, DisconnectionReason::SHUTDOWN);
}
}
void EndpointChannelManager::ChannelState::UpdateSafeToDisconnectForEndpoint(
@@ -204,32 +288,28 @@ void EndpointChannelManager::ChannelState::UpdateSafeToDisconnectForEndpoint(
"UpdateSafeToDisconnectForEndpoint for: "
<< endpoint_id << " " << safe_to_disconnect_enabled;
endpoints_[endpoint_id].safe_to_disconnect_enabled =
safe_to_disconnect_enabled;
}
bool EndpointChannelManager::ChannelState::GetSafeToDisconnectForEndpoint(
const std::string& endpoint_id) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return false;
LOG(INFO) << "[safe-to-disconnect] GetSafeToDisconnectForEndpoint: "
<< item->second.safe_to_disconnect_enabled;
return item->second.safe_to_disconnect_enabled;
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
if (endpoint == nullptr) {
LOG(WARNING) << "UpdateSafeToDisconnectForEndpoint failed because endpoint "
<< endpoint_id << " is not registered.";
return;
}
endpoint->set_safe_to_disconnect_enabled(safe_to_disconnect_enabled);
}
bool EndpointChannelManager::ChannelState::RemoveEndpoint(
const std::string& endpoint_id, DisconnectionReason reason,
bool safe_to_disconnect_enabled, SafeDisconnectionResult result) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return false;
absl::string_view endpoint_id, DisconnectionReason reason) {
auto it = endpoints_.find(endpoint_id);
if (it == endpoints_.end()) return false;
MarkEndpointStopWaitToDisconnect(endpoint_id,
/* is_safe_to_disconnect */ true,
/* notify_stop_waiting */ true);
item->second.disconnect_reason = reason;
auto channel = item->second.channel;
it->second->set_disconnect_reason(reason);
std::shared_ptr<EndpointChannel> channel = it->second->channel();
bool safe_to_disconnect_enabled = it->second->safe_to_disconnect_enabled();
if (channel && !channel->IsClosed() && !safe_to_disconnect_enabled) {
if (!channel->IsClosed() && !safe_to_disconnect_enabled) {
// If the channel was paused (i.e. during a bandwidth upgrade negotiation)
// we resume to ensure the thread won't hang when trying to write to it.
channel->Resume();
@@ -246,18 +326,16 @@ bool EndpointChannelManager::ChannelState::RemoveEndpoint(
}
LOG(INFO) << "Remove Endpoint: " << endpoint_id;
endpoints_.erase(item);
endpoints_.erase(it);
return true;
}
bool EndpointChannelManager::ChannelState::isWifiLanConnected() const {
for (auto& endpoint : endpoints_) {
auto channel = endpoint.second.channel;
if (channel) {
if (channel->GetMedium() == Medium::WIFI_LAN) {
LOG(INFO) << "Found WIFI_LAN Medium for endpoint:" << endpoint.first;
return true;
}
for (const auto& [endpoint_id, endpoint_data] : endpoints_) {
std::shared_ptr<EndpointChannel> channel = endpoint_data->channel();
if (channel->GetMedium() == Medium::WIFI_LAN) {
LOG(INFO) << "Found WIFI_LAN Medium for endpoint:" << endpoint_id;
return true;
}
}
@@ -265,96 +343,53 @@ bool EndpointChannelManager::ChannelState::isWifiLanConnected() const {
}
void EndpointChannelManager::ChannelState::MarkEndpointStopWaitToDisconnect(
const std::string& endpoint_id, bool is_safe_to_disconnect,
absl::string_view endpoint_id, bool is_safe_to_disconnect,
bool notify_stop_waiting) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return;
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
if (endpoint == nullptr) return;
LOG(INFO) << "[safe-to-disconnect] is_safe_to_disconnect= "
<< is_safe_to_disconnect
<< ", notify_stop_waiting= " << notify_stop_waiting
<< " for endpoint: " << endpoint_id;
{
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
item->second.is_safe_to_disconnect = is_safe_to_disconnect;
if (!item->second.timeout_to_disconnected_enabled) return;
if (notify_stop_waiting) {
LOG(INFO) << "[safe-to-disconnect] Notify stop "
"waiting before timeout.";
item->second.timeout_to_disconnected.Notify();
item->second.timeout_to_disconnected_notified = true;
}
}
endpoint->MarkEndpointStopWaitToDisconnect(is_safe_to_disconnect,
notify_stop_waiting);
}
bool EndpointChannelManager::ChannelState::CreateNewTimeoutDisconnectedState(
const std::string& endpoint_id, absl::Duration timeout_millis) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return false;
bool EndpointChannelManager::ChannelState::
IsWaitingForSafeToDisconnectTimeoutForTesting(
absl::string_view endpoint_id) {
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
if (endpoint == nullptr) return false;
bool enabled = endpoint->IsWaitingForSafeToDisconnectTimeout();
LOG(INFO) << "[safe-to-disconnect] "
"Create TimeoutDisconnectedState for endpoint: "
<< endpoint_id;
{
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
item->second.timeout_to_disconnected_enabled = true;
item->second.timeout_to_disconnected_notified = false;
item->second.timeout_to_disconnected.Wait(timeout_millis);
LOG(INFO) << "[safe-to-disconnect] Wait is done with "
<< (item->second.timeout_to_disconnected_notified ? "notification"
: "timeout");
if (!item->second.timeout_to_disconnected_notified)
item->second.is_safe_to_disconnect = true;
item->second.timeout_to_disconnected_notified = false;
item->second.timeout_to_disconnected_enabled = false;
}
return true;
}
bool EndpointChannelManager::ChannelState::IsWaitingForSafeToDisconnectTimeout(
const std::string& endpoint_id) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return false;
{
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
LOG(INFO) << "[safe-to-disconnect] "
"IsWaitingForSafeToDisconnectTimeout for endpoint: "
<< endpoint_id << ": "
<< item->second.timeout_to_disconnected_enabled;
return (item->second.timeout_to_disconnected_enabled);
}
"IsWaitingForSafeToDisconnectTimeout for endpoint: "
<< endpoint_id << ": " << enabled;
return enabled;
}
bool EndpointChannelManager::ChannelState::IsSafeToDisconnect(
const std::string& endpoint_id) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return true;
{
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
LOG(INFO)
<< "[safe-to-disconnect] Get SafeToDisconnect status for endpoint: "
<< endpoint_id << ": " << item->second.is_safe_to_disconnect;
return (item->second.is_safe_to_disconnect);
}
absl::string_view endpoint_id) {
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
if (endpoint == nullptr) return true;
bool is_safe = endpoint->IsSafeToDisconnect();
LOG(INFO) << "[safe-to-disconnect] Get SafeToDisconnect status for endpoint: "
<< endpoint_id << ": " << is_safe;
return is_safe;
}
void EndpointChannelManager::ChannelState::RemoveTimeoutDisconnectedState(
const std::string& endpoint_id) {
auto item = endpoints_.find(endpoint_id);
if (item == endpoints_.end()) return;
{
MutexLock lock(&item->second.timeout_to_disconnected_mutex);
item->second.timeout_to_disconnected_notified = false;
item->second.timeout_to_disconnected_enabled = false;
}
absl::string_view endpoint_id) {
std::shared_ptr<EndpointData> endpoint = GetEndpointData(endpoint_id);
if (endpoint == nullptr) return;
endpoint->RemoveTimeoutDisconnectedState();
}
bool EndpointChannelManager::UnregisterChannelForEndpoint(
const std::string& endpoint_id, DisconnectionReason reason,
absl::string_view endpoint_id, DisconnectionReason reason,
SafeDisconnectionResult result) {
MutexLock lock(&mutex_);
auto safe_to_disconnect_enabled =
channel_state_.GetSafeToDisconnectForEndpoint(endpoint_id);
if (!channel_state_.RemoveEndpoint(endpoint_id, reason,
safe_to_disconnect_enabled, result)) {
if (!channel_state_.RemoveEndpoint(endpoint_id, reason)) {
return false;
}
LOG(INFO) << "EndpointChannelManager unregistered channel for endpoint "
@@ -17,9 +17,11 @@
#include <memory>
#include <string>
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/client_proxy.h"
@@ -91,11 +93,11 @@ class EndpointChannelManager final {
// EndpointManager methods that use a channel are running, it is better to
// have a shared ownership.
std::shared_ptr<EndpointChannel> GetChannelForEndpoint(
const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
absl::string_view endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if 'endpoint_id' actually had a registered EndpointChannel.
// IOW, a return of false signifies a no-op.
bool UnregisterChannelForEndpoint(const std::string& endpoint_id,
bool UnregisterChannelForEndpoint(absl::string_view endpoint_id,
DisconnectionReason reason,
SafeDisconnectionResult result)
ABSL_LOCKS_EXCLUDED(mutex_);
@@ -107,16 +109,19 @@ class EndpointChannelManager final {
void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id,
bool safe_to_disconnect_enabled)
ABSL_LOCKS_EXCLUDED(mutex_);
void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id,
bool CreateNewTimeoutDisconnectedState(absl::string_view endpoint_id,
absl::Duration timeout_millis)
ABSL_LOCKS_EXCLUDED(mutex_);
void MarkEndpointStopWaitToDisconnect(absl::string_view endpoint_id,
bool is_safe_to_disconnect,
bool notify_stop_waiting)
ABSL_LOCKS_EXCLUDED(mutex_);
bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id,
absl::Duration timeout_millis)
bool IsSafeToDisconnect(absl::string_view endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
bool IsSafeToDisconnect(const std::string& endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
void RemoveTimeoutDisconnectedState(const std::string& endpoint_id)
bool IsWaitingForSafeToDisconnectTimeoutForTesting(
absl::string_view endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
void RemoveTimeoutDisconnectedState(absl::string_view endpoint_id)
ABSL_LOCKS_EXCLUDED(mutex_);
private:
@@ -125,32 +130,69 @@ class EndpointChannelManager final {
// been encrypted yet.
class ChannelState {
public:
struct EndpointData {
class EndpointData {
public:
EndpointData() = default;
EndpointData(EndpointData&&) = default;
EndpointData& operator=(EndpointData&&) = default;
~EndpointData() {
if (channel != nullptr) {
channel->Close(disconnect_reason);
if (channel_ != nullptr) {
channel_->Close(disconnect_reason_);
}
}
// True if we have a 'context' for the endpoint.
bool IsEncrypted() const { return context != nullptr; }
bool IsEncrypted() const { return context_ != nullptr; }
std::shared_ptr<EndpointChannel> channel;
std::shared_ptr<EncryptionContext> context;
DisconnectionReason disconnect_reason =
void CreateNewTimeoutDisconnectedState(absl::Duration timeout_millis)
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
void MarkEndpointStopWaitToDisconnect(bool is_safe_to_disconnect,
bool notify_stop_waiting)
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
bool IsWaitingForSafeToDisconnectTimeout() const
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
bool IsSafeToDisconnect() const
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
void RemoveTimeoutDisconnectedState()
ABSL_LOCKS_EXCLUDED(timeout_to_disconnected_mutex_);
bool EncryptChannel();
std::shared_ptr<EndpointChannel> channel() const { return channel_; }
void set_channel(std::shared_ptr<EndpointChannel> channel) {
channel_ = std::move(channel);
}
std::shared_ptr<EncryptionContext> context() const { return context_; }
void set_context(std::shared_ptr<EncryptionContext> context) {
context_ = std::move(context);
}
void set_disconnect_reason(DisconnectionReason disconnect_reason) {
disconnect_reason_ = disconnect_reason;
}
bool safe_to_disconnect_enabled() const {
return safe_to_disconnect_enabled_;
}
void set_safe_to_disconnect_enabled(bool safe_to_disconnect_enabled) {
safe_to_disconnect_enabled_ = safe_to_disconnect_enabled;
}
private:
std::shared_ptr<EndpointChannel> channel_;
std::shared_ptr<EncryptionContext> context_;
DisconnectionReason disconnect_reason_ =
DisconnectionReason::UNKNOWN_DISCONNECTION_REASON;
bool safe_to_disconnect_enabled = false;
mutable Mutex timeout_to_disconnected_mutex;
ConditionVariable timeout_to_disconnected{&timeout_to_disconnected_mutex};
bool timeout_to_disconnected_enabled
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
bool timeout_to_disconnected_notified
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
bool is_safe_to_disconnect
ABSL_GUARDED_BY(timeout_to_disconnected_mutex) = false;
bool safe_to_disconnect_enabled_ = false;
mutable Mutex timeout_to_disconnected_mutex_;
ConditionVariable timeout_to_disconnected_{
&timeout_to_disconnected_mutex_};
bool timeout_to_disconnected_enabled_
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
bool timeout_to_disconnected_notified_
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
bool is_safe_to_disconnect_
ABSL_GUARDED_BY(timeout_to_disconnected_mutex_) = false;
};
ChannelState() = default;
@@ -160,57 +202,48 @@ class EndpointChannelManager final {
// Provides a way to destroy contents of a container, while holding a lock.
void DestroyAll();
// Return pointer to endpoint data, or nullptr, it not found.
EndpointData* LookupEndpointData(const std::string& endpoint_id);
std::shared_ptr<EndpointData> GetEndpointData(
absl::string_view endpoint_id);
// Stores a new EndpointChannel for the endpoint.
// Prevoius one is destroyed, if it existed.
void UpdateChannelForEndpoint(const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> channel);
// Stores a new EncryptionContext for the endpoint.
// Prevoius one is destroyed, if it existed.
void UpdateEncryptionContextForEndpoint(
const std::string& endpoint_id,
std::unique_ptr<EncryptionContext> context);
// Registers a new endpoint id. This is the only spot EndpointData is
// created.
std::shared_ptr<EndpointData> RegisterEndpoint(
absl::string_view endpoint_id);
void UpdateSafeToDisconnectForEndpoint(const std::string& endpoint_id,
bool safe_to_disconnect_enabled);
bool GetSafeToDisconnectForEndpoint(const std::string& endpoint_id);
// Removes all knowledge of this endpoint, cleaning up as necessary.
// Returns false if the endpoint was not found.
bool RemoveEndpoint(const std::string& endpoint_id,
DisconnectionReason reason,
bool safe_to_disconnect_enabled,
SafeDisconnectionResult result);
bool RemoveEndpoint(absl::string_view endpoint_id,
DisconnectionReason reason);
bool EncryptChannel(EndpointData* endpoint);
int GetConnectedEndpointsCount() const { return endpoints_.size(); }
bool isWifiLanConnected() const;
void MarkEndpointStopWaitToDisconnect(const std::string& endpoint_id,
void MarkEndpointStopWaitToDisconnect(absl::string_view endpoint_id,
bool is_safe_to_disconnect,
bool notify_stop_waiting);
bool CreateNewTimeoutDisconnectedState(const std::string& endpoint_id,
absl::Duration timeout_millis);
bool IsWaitingForSafeToDisconnectTimeout(const std::string& endpoint_id);
bool IsSafeToDisconnect(const std::string& endpoint_id);
void RemoveTimeoutDisconnectedState(const std::string& endpoint_id);
bool IsWaitingForSafeToDisconnectTimeoutForTesting(
absl::string_view endpoint_id);
bool IsSafeToDisconnect(absl::string_view endpoint_id);
void RemoveTimeoutDisconnectedState(absl::string_view endpoint_id);
private:
// Endpoint ID -> EndpointData. Contains everything we know about the
// endpoint.
absl::flat_hash_map<std::string, EndpointData> endpoints_;
absl::flat_hash_map<std::string, std::shared_ptr<EndpointData>> endpoints_;
};
void SetActiveEndpointChannel(ClientProxy* client,
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> channel,
bool enable_encryption)
void SetActiveEndpointChannel(
ClientProxy* client, const std::string& endpoint_id,
std::shared_ptr<ChannelState::EndpointData> endpoint,
std::shared_ptr<EndpointChannel> channel, bool enable_encryption)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable Mutex mutex_;
ChannelState channel_state_;
ChannelState channel_state_ ABSL_GUARDED_BY(mutex_);
};
} // namespace nearby::connections
@@ -26,6 +26,7 @@
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "connections/implementation/analytics/analytics_recorder.h"
#include "connections/implementation/base_endpoint_channel.h"
@@ -210,16 +211,16 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
ASSERT_NE(context.second, nullptr);
EndpointChannelManager ecm_a;
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.first));
ecm_a.RegisterChannelForEndpoint(&proxy_a, std::string(kEndpointId),
std::move(channel_a));
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.first));
EndpointChannelManager ecm_b;
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.second));
ecm_b.RegisterChannelForEndpoint(&proxy_b, std::string(kEndpointId),
std::move(channel_b));
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.second));
EXPECT_EQ(channel_a_raw->GetType(), "ENCRYPTED_BLUETOOTH");
EXPECT_EQ(channel_b_raw->GetType(), "ENCRYPTED_BLUETOOTH");
@@ -241,10 +242,10 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
ecm_a.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
ecm_b.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
kEndpointId, DisconnectionReason::REMOTE_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
}
@@ -290,13 +291,26 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
ASSERT_NE(context.first, nullptr);
ASSERT_NE(context.second, nullptr);
auto client_a_dummy = CreatePipe();
auto server_a_dummy = CreatePipe();
auto channel_a_init = std::make_shared<MockEndpointChannel>(
server_a_dummy.first.get(), client_a_dummy.second.get());
auto client_b_dummy = CreatePipe();
auto server_b_dummy = CreatePipe();
auto channel_b_init = std::make_shared<MockEndpointChannel>(
server_b_dummy.first.get(), client_b_dummy.second.get());
EndpointChannelManager ecm_a;
ecm_a.RegisterChannelForEndpoint(&proxy_a, std::string(kEndpointId),
std::move(channel_a_init));
ecm_a.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.first));
ecm_a.ReplaceChannelForEndpoint(&proxy_a, std::string(kEndpointId),
std::move(channel_a), false);
EndpointChannelManager ecm_b;
ecm_b.RegisterChannelForEndpoint(&proxy_b, std::string(kEndpointId),
std::move(channel_b_init));
ecm_b.EncryptChannelForEndpoint(std::string(kEndpointId),
std::move(context.second));
ecm_b.ReplaceChannelForEndpoint(&proxy_b, std::string(kEndpointId),
@@ -309,12 +323,75 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
channel_a_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION);
ecm_a.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION,
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
ecm_b.UnregisterChannelForEndpoint(
std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION,
kEndpointId, DisconnectionReason::REMOTE_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
}
TEST(BaseEndpointChannelManagerTest,
CreateNewTimeoutDisconnectedStateUnregisterDuringWait) {
ClientProxy proxy;
EndpointChannelManager ecm;
auto client = CreatePipe();
auto server = CreatePipe();
auto channel = std::make_shared<MockEndpointChannel>(server.first.get(),
client.second.get());
auto channel_raw = channel.get();
ON_CALL(*channel_raw, GetMedium).WillByDefault([]() {
return Medium::BLUETOOTH;
});
ecm.RegisterChannelForEndpoint(&proxy, std::string(kEndpointId),
std::move(channel));
EXPECT_EQ(ecm.GetConnectedEndpointsCount(), 1);
MultiThreadExecutor executor(1);
CountDownLatch start_latch(1);
CountDownLatch finish_latch(1);
bool wait_result = false;
executor.Execute([&]() {
start_latch.CountDown();
wait_result =
ecm.CreateNewTimeoutDisconnectedState(kEndpointId, absl::Seconds(5));
finish_latch.CountDown();
});
ASSERT_TRUE(start_latch.Await(absl::Seconds(1)).result());
// Wait for the endpoint to enter the waiting state.
absl::Time deadline = absl::Now() + absl::Seconds(1);
while (!ecm.IsWaitingForSafeToDisconnectTimeoutForTesting(kEndpointId)) {
ASSERT_TRUE(absl::Now() < deadline)
<< "Timed out waiting for endpoint to enter wait state.";
absl::SleepFor(absl::Milliseconds(10));
}
// Close the channel first to prevent UnregisterChannelForEndpoint from
// attempting to write disconnection frames to it, bypassing the 500ms data
// transfer delay and potential segfaults.
channel_raw->Close(DisconnectionReason::LOCAL_DISCONNECTION);
bool unregister_result = ecm.UnregisterChannelForEndpoint(
kEndpointId, DisconnectionReason::LOCAL_DISCONNECTION,
SafeDisconnectionResult::kSafeDisconnection);
EXPECT_TRUE(unregister_result);
EXPECT_TRUE(finish_latch.Await(absl::Seconds(2)).result());
EXPECT_TRUE(wait_result);
EXPECT_EQ(ecm.GetConnectedEndpointsCount(), 0);
}
TEST(BaseEndpointChannelManagerTest,
CreateNewTimeoutDisconnectedStateReturnsFalseForNonexistentEndpoint) {
EndpointChannelManager ecm;
EXPECT_FALSE(ecm.CreateNewTimeoutDisconnectedState("NonexistentEndpoint",
absl::Seconds(1)));
}
} // namespace
} // namespace nearby::connections
+48 -19
View File
@@ -28,11 +28,13 @@
#include "connections/implementation/client_proxy.h"
#include "connections/implementation/endpoint_channel.h"
#include "connections/implementation/endpoint_channel_manager.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "connections/implementation/service_id_constants.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
@@ -64,6 +66,15 @@ constexpr absl::Time kInvalidTimestamp = absl::InfinitePast();
// The maximum time we will wait for the encryption setup during negotiating a
// connection.
constexpr absl::Duration kDecryptRetryTimeout = absl::Seconds(3);
// Returns true if the given `frame_type` is allowed before the connection to
// the endpoint is confirmed (i.e., KEEP_ALIVE, CONNECTION_RESPONSE, and
// DISCONNECTION frames).
bool IsAllowedPreConfirmationFrameType(V1Frame::FrameType frame_type) {
return frame_type == V1Frame::KEEP_ALIVE ||
frame_type == V1Frame::CONNECTION_RESPONSE ||
frame_type == V1Frame::DISCONNECTION;
}
} // namespace
class EndpointManager::LockedFrameProcessor {
@@ -112,7 +123,8 @@ class EndpointManager::LockedFrameProcessor {
void EndpointManager::EndpointChannelLoopRunnable(
const std::string& runnable_name, ClientProxy* client,
const std::string& endpoint_id,
absl::AnyInvocable<ExceptionOr<bool>(EndpointChannel*)> handler) {
absl::AnyInvocable<ExceptionOr<bool>(std::shared_ptr<EndpointChannel>)>
handler) {
// EndpointChannelManager will not let multiple channels exist simultaneously
// for the same endpoint_id; it will be closing "old" channels as new ones
// come.
@@ -143,7 +155,7 @@ void EndpointManager::EndpointChannelLoopRunnable(
break;
}
ExceptionOr<bool> keep_using_channel = handler(channel.get());
ExceptionOr<bool> keep_using_channel = handler(channel);
if (!keep_using_channel.ok()) {
Exception exception = keep_using_channel.GetException();
@@ -195,7 +207,7 @@ void EndpointManager::EndpointChannelLoopRunnable(
}
ExceptionOr<OfflineFrame> EndpointManager::TryDecryptFrame(
const ByteArray& data, EndpointChannel* endpoint_channel) {
const ByteArray& data, std::shared_ptr<EndpointChannel> endpoint_channel) {
auto start_time = SystemClock::ElapsedRealtime();
while (true) {
ExceptionOr<ByteArray> decrypted = endpoint_channel->TryDecrypt(data);
@@ -222,7 +234,7 @@ ExceptionOr<OfflineFrame> EndpointManager::TryDecryptFrame(
ExceptionOr<bool> EndpointManager::HandleData(
const std::string& endpoint_id, ClientProxy* client,
EndpointChannel* endpoint_channel) {
std::shared_ptr<EndpointChannel> endpoint_channel) {
bool try_decrypting = !endpoint_channel->IsEncrypted();
// Read as much as we can from the healthy EndpointChannel - when it is no
// longer in good shape (i.e. our read from it throws an Exception), our
@@ -274,8 +286,23 @@ ExceptionOr<bool> EndpointManager::HandleData(
// Route the incoming offlineFrame to its registered processor.
V1Frame::FrameType frame_type = parser::GetFrameType(frame);
LockedFrameProcessor frame_processor = GetFrameProcessor(frame_type);
if (!frame_processor) {
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::
kFilterUnconfirmedEndpointFrames) &&
client->HasPendingConnectionToEndpoint(endpoint_id) &&
!IsAllowedPreConfirmationFrameType(frame_type)) {
LOG(WARNING) << "EndpointManager discarded unauthorized frame ("
<< V1Frame::FrameType_Name(frame_type)
<< ") from unconfirmed endpoint " << endpoint_id << ".";
continue;
}
FrameProcessor* processor = nullptr;
{
LockedFrameProcessor frame_processor = GetFrameProcessor(frame_type);
processor = frame_processor.get();
}
if (!processor) {
// report messages without handlers, except KEEP_ALIVE, which has
// no explicit handler.
if (frame_type == V1Frame::KEEP_ALIVE) {
@@ -310,14 +337,14 @@ ExceptionOr<bool> EndpointManager::HandleData(
continue;
}
frame_processor->OnIncomingFrame(frame, endpoint_id, client,
endpoint_channel->GetMedium());
processor->OnIncomingFrame(frame, endpoint_id, client,
endpoint_channel->GetMedium());
}
}
void EndpointManager::ProcessDisconnectionFrame(
ClientProxy* client, const std::string& endpoint_id,
EndpointChannel* endpoint_channel, OfflineFrame& frame) {
std::shared_ptr<EndpointChannel> endpoint_channel, OfflineFrame& frame) {
if (!client->IsSafeToDisconnectEnabled(endpoint_id)) {
LOG(INFO) << "EndpointManager received a DISCONNECTION frame from endpoint "
<< endpoint_id << " on channel " << endpoint_channel->GetType()
@@ -371,9 +398,9 @@ void EndpointManager::ProcessDisconnectionFrame(
}
ExceptionOr<bool> EndpointManager::HandleKeepAlive(
EndpointChannel* endpoint_channel, absl::Duration keep_alive_interval,
absl::Duration keep_alive_timeout, Mutex* keep_alive_waiter_mutex,
ConditionVariable* keep_alive_waiter) {
std::shared_ptr<EndpointChannel> endpoint_channel,
absl::Duration keep_alive_interval, absl::Duration keep_alive_timeout,
Mutex* keep_alive_waiter_mutex, ConditionVariable* keep_alive_waiter) {
// Check if it has been too long since we received a frame from our endpoint.
absl::Time last_read_time = endpoint_channel->GetLastReadTimestamp();
absl::Duration duration_until_timeout =
@@ -578,7 +605,8 @@ void EndpointManager::RegisterEndpoint(
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
EndpointChannelLoopRunnable(
"Read", client, endpoint_id,
[this, client, endpoint_id](EndpointChannel* channel) {
[this, client,
endpoint_id](std::shared_ptr<EndpointChannel> channel) {
return HandleData(endpoint_id, client, channel);
});
});
@@ -605,7 +633,7 @@ void EndpointManager::RegisterEndpoint(
"KeepAliveManager", client, endpoint_id,
[this, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex,
keep_alive_waiter](EndpointChannel* channel) {
keep_alive_waiter](std::shared_ptr<EndpointChannel> channel) {
return HandleKeepAlive(
channel, keep_alive_interval, keep_alive_timeout,
keep_alive_waiter_mutex, keep_alive_waiter);
@@ -745,8 +773,8 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
SafeDisconnectionResult::kSafeDisconnection;
// Grab the service ID before we destroy the channel.
EndpointChannel* channel =
channel_manager_->GetChannelForEndpoint(endpoint_id).get();
std::shared_ptr<EndpointChannel> channel =
channel_manager_->GetChannelForEndpoint(endpoint_id);
std::string service_id =
channel ? channel->GetServiceId() : std::string(kUnknownServiceId);
@@ -784,9 +812,10 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client,
RemoveEndpointState(endpoint_id);
}
bool EndpointManager::ApplySafeToDisconnect(const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
DisconnectionReason reason) {
bool EndpointManager::ApplySafeToDisconnect(
const std::string& endpoint_id,
std::shared_ptr<EndpointChannel> endpoint_channel,
DisconnectionReason reason) {
LOG(INFO) << "[safe-to-disconnect] ApplySafeToDisconnect reason: " << reason;
// TODO(b/303544913): clean up the safe-to-disconnect logic
bool is_safe_disconnection = false;
+13 -13
View File
@@ -229,15 +229,14 @@ class EndpointManager {
LockedFrameProcessor GetFrameProcessor(
location::nearby::connections::V1Frame::FrameType frame_type);
ExceptionOr<bool> HandleData(const std::string& endpoint_id,
ClientProxy* client_proxy,
EndpointChannel* endpoint_channel);
ExceptionOr<bool> HandleData(
const std::string& endpoint_id, ClientProxy* client_proxy,
std::shared_ptr<EndpointChannel> endpoint_channel);
ExceptionOr<bool> HandleKeepAlive(EndpointChannel* endpoint_channel,
absl::Duration keep_alive_interval,
absl::Duration keep_alive_timeout,
Mutex* keep_alive_waiter_mutex,
ConditionVariable* keep_alive_waiter);
ExceptionOr<bool> HandleKeepAlive(
std::shared_ptr<EndpointChannel> endpoint_channel,
absl::Duration keep_alive_interval, absl::Duration keep_alive_timeout,
Mutex* keep_alive_waiter_mutex, ConditionVariable* keep_alive_waiter);
// Waits for a given endpoint EndpointChannelLoopRunnable() workers to
// terminate.
@@ -249,7 +248,8 @@ class EndpointManager {
void EndpointChannelLoopRunnable(
const std::string& runnable_name, ClientProxy* client_proxy,
const std::string& endpoint_id,
absl::AnyInvocable<ExceptionOr<bool>(EndpointChannel*)> handler);
absl::AnyInvocable<ExceptionOr<bool>(std::shared_ptr<EndpointChannel>)>
handler);
static void WaitForLatch(const std::string& method_name,
CountDownLatch* latch);
@@ -265,7 +265,7 @@ class EndpointManager {
void RemoveEndpoint(ClientProxy* client, const std::string& endpoint_id,
bool notify, DisconnectionReason reason);
bool ApplySafeToDisconnect(const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
DisconnectionReason reason);
void WaitForEndpointDisconnectionProcessing(ClientProxy* client,
const std::string& service_id,
@@ -273,7 +273,7 @@ class EndpointManager {
DisconnectionReason reason);
void ProcessDisconnectionFrame(
ClientProxy* client, const std::string& endpoint_id,
EndpointChannel* endpoint_channel,
std::shared_ptr<EndpointChannel> endpoint_channel,
location::nearby::connections::OfflineFrame& frame);
CountDownLatch NotifyFrameProcessorsOnEndpointDisconnect(
ClientProxy* client, const std::string& service_id,
@@ -287,8 +287,8 @@ class EndpointManager {
// Executes all jobs sequentially, on a serial_executor_.
void RunOnEndpointManagerThread(const std::string& name, Runnable runnable);
ExceptionOr<OfflineFrame> TryDecryptFrame(const ByteArray& data,
EndpointChannel* endpoint_channel);
ExceptionOr<OfflineFrame> TryDecryptFrame(
const ByteArray& data, std::shared_ptr<EndpointChannel> endpoint_channel);
EndpointChannelManager* channel_manager_;
RecursiveMutex frame_processors_lock_;
@@ -94,6 +94,10 @@ class SetSafeToDisconnect {
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion,
safe_to_disconnect_version);
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kFilterUnconfirmedEndpointFrames,
false);
}
};
@@ -108,11 +112,11 @@ class EndpointManagerTest : public ::testing::Test {
protected:
void RegisterEndpoint(std::unique_ptr<MockEndpointChannel> channel,
bool should_close = true) {
CountDownLatch done(1);
auto done = std::make_shared<CountDownLatch>(1);
if (should_close) {
ON_CALL(*channel, Close(_))
.WillByDefault(
[&done](DisconnectionReason reason) { done.CountDown(); });
[done](DisconnectionReason reason) { done->CountDown(); });
}
EXPECT_CALL(*channel, GetMedium()).WillRepeatedly(Return(Medium::BLE));
EXPECT_CALL(*channel, GetLastReadTimestamp())
@@ -124,7 +128,7 @@ class EndpointManagerTest : public ::testing::Test {
connection_options_, std::move(channel), listener_,
connection_token_);
if (should_close) {
EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result());
EXPECT_TRUE(done->Await(absl::Milliseconds(1000)).result());
}
}
SetSafeToDisconnect set_safe_to_disconnect_{true, true, 5};
@@ -429,6 +433,70 @@ TEST_F(EndpointManagerTest, TryDecrypt) {
RegisterEndpoint(std::move(endpoint_channel));
}
TEST_F(EndpointManagerTest,
FilterUnconfirmedFrames_DiscardsPayloadBeforeConfirmation) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kFilterUnconfirmedEndpointFrames,
true);
PayloadTransferFrame::PayloadHeader header;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
header.set_total_size(1024);
PayloadTransferFrame::PayloadChunk chunk;
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
std::string payload_bytes = parser::ForDataPayloadTransfer(header, chunk);
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
auto payload_processor = std::make_unique<MockFrameProcessor>();
EXPECT_CALL(*payload_processor, OnIncomingFrame).Times(0);
EXPECT_CALL(*payload_processor, OnEndpointDisconnect);
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce(Return(ExceptionOr<ByteArray>(ByteArray(payload_bytes))))
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, Write(_))
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
em_.RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER,
payload_processor.get());
processors_.emplace_back(std::move(payload_processor));
RegisterEndpoint(std::move(endpoint_channel));
}
TEST_F(EndpointManagerTest,
FilterUnconfirmedFrames_AllowsPayloadAfterConfirmation) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kFilterUnconfirmedEndpointFrames,
true);
PayloadTransferFrame::PayloadHeader header;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
header.set_total_size(1024);
PayloadTransferFrame::PayloadChunk chunk;
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
std::string payload_bytes = parser::ForDataPayloadTransfer(header, chunk);
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
auto payload_processor = std::make_unique<MockFrameProcessor>();
EXPECT_CALL(mock_listener_.accepted_cb, Call).Times(1);
EXPECT_CALL(*payload_processor, OnIncomingFrame).Times(1);
EXPECT_CALL(*payload_processor, OnEndpointDisconnect);
EXPECT_CALL(*endpoint_channel, Read())
.WillOnce([this, payload_bytes]() {
client_->OnConnectionAccepted(endpoint_id_);
return ExceptionOr<ByteArray>(ByteArray(payload_bytes));
})
.WillRepeatedly(Return(ExceptionOr<ByteArray>(Exception::kIo)));
EXPECT_CALL(*endpoint_channel, Write(_))
.WillRepeatedly(Return(Exception{Exception::kSuccess}));
em_.RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER,
payload_processor.get());
processors_.emplace_back(std::move(payload_processor));
RegisterEndpoint(std::move(endpoint_channel));
}
// Regression test for b/278729669.
//
// During the destruction of NearbyConnections, Core (which owns ClientProxy)
@@ -89,6 +89,7 @@ class FakeBwuHandler : public BaseBwuHandler {
upgraded_channel->set_read_output(
ExceptionOr<ByteArray>(ByteArray(parser::ForBwuIntroduction(
*handle_initialize_calls_[initialize_call_index].endpoint_id,
/*last_endpoint_id=*/"",
false /* supports_disabling_encryption */))));
auto connection = std::make_unique<IncomingSocketConnection>();
connection->channel = std::move(upgraded_channel);
@@ -93,6 +93,10 @@ class FakeEndpointChannel : public EndpointChannel {
}
void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder,
const std::string& endpoint_id) override {}
void SetLocalEndpointId(const std::string& local_endpoint_id) override {
local_endpoint_id_ = local_endpoint_id;
}
std::string GetLocalEndpointId() const override { return local_endpoint_id_; }
void set_read_output(ExceptionOr<ByteArray> output) { read_output_ = output; }
void set_write_output(Exception output) { write_output_ = output; }
@@ -113,6 +117,7 @@ class FakeEndpointChannel : public EndpointChannel {
bool is_paused_ = false;
location::nearby::proto::connections::DisconnectionReason
disconnection_reason_;
std::string local_endpoint_id_;
mutable uint32_t next_keep_alive_seq_no_ = 0;
};
@@ -83,6 +83,11 @@ constexpr auto kEnableWifiDirectGcOnly =
// by default, enable Wi-Fi Hotspot client.
constexpr auto kEnableWifiHotspotClient =
flags::Flag<bool>(kConfigPackage, "45648734", true);
// Enforces frame filtering on unconfirmed endpoints in EndpointManager and
// BaseEndpointChannel so application payloads and upgrade requests are blocked
// before connection acceptance.
constexpr auto kFilterUnconfirmedEndpointFrames =
flags::Flag<bool>(kConfigPackage, "45813128", true);
// When true, fix the BleServerSocket deadlock/use-after-free (b/494335036).
constexpr auto kFixBleServerSocketDeadlock =
flags::Flag<bool>(kConfigPackage, "45782647", true);
+1
View File
@@ -248,6 +248,7 @@ cc_test(
"//connections/implementation:client_proxy",
"//connections/implementation:endpoint_channel",
"//connections/implementation:offline_frames",
"//connections/implementation:service_id_constants",
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
@@ -29,7 +29,6 @@ cc_library(
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:util",
"@com_google_absl//absl/strings",
],
)
@@ -45,7 +44,6 @@ cc_library(
"//internal/platform:logging",
"//internal/platform:types",
"//internal/platform:util",
"@com_google_absl//absl/strings",
],
)
@@ -54,9 +52,7 @@ cc_library(
srcs = ["advertisement_util.cc"],
hdrs = ["advertisement_util.h"],
deps = [
":dct_advertisement",
"//internal/platform:base",
"//internal/platform:logging",
"//internal/platform:util",
"@com_google_absl//absl/strings:string_view",
],
@@ -79,8 +75,6 @@ cc_test(
srcs = ["dct_advertisement_test.cc"],
deps = [
":dct_advertisement",
"//internal/platform:base",
"//internal/platform:util",
"//internal/platform/implementation/g3",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
@@ -93,7 +87,6 @@ cc_test(
deps = [
":util",
"//internal/platform:base",
"//internal/platform:util",
"//internal/platform/implementation/g3",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
@@ -129,7 +129,8 @@ std::optional<DctAdvertisement> DctAdvertisement::Parse(
LOG(WARNING) << "Failed to read device information.";
return std::nullopt;
}
if (device_information->type() != kDataTypeDeviceInformation) {
if (device_information->type() != kDataTypeDeviceInformation ||
device_information->value().empty()) {
LOG(WARNING) << "Invalid device information.";
return std::nullopt;
}
@@ -113,5 +113,10 @@ TEST(DctAdvertisementTest, ParseData) {
EXPECT_EQ(dct_advertisement->GetPsm(), 192);
}
TEST(DctAdvertisementTest, ParseWithEmptyDeviceInformationDataElement) {
std::string data = std::string("\x20\x25\0\0\x24\0\0\x07", 8);
EXPECT_FALSE(DctAdvertisement::Parse(data).has_value());
}
} // namespace
} // namespace nearby::connections::advertisements::ble
@@ -182,6 +182,7 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
OperationResultCode::NEARBY_AWDL_ENDPOINT_CHANNEL_CREATION_FAILURE)};
}
awdl_medium_.StopDiscovery(upgrade_service_id);
return {std::move(channel)};
}
@@ -43,7 +43,8 @@
#include "internal/platform/mock_input_stream.h"
#include "internal/platform/mock_output_stream.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/output_stream.h"
#include "connections/implementation/service_id_constants.h"
namespace nearby {
@@ -175,7 +176,9 @@ TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) {
}
return true;
});
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_))
.Times(1)
.WillRepeatedly(Return(true));
EXPECT_CALL(*awdl_medium_mock, ConnectToService(_, _, _))
.WillOnce(Return(ByMove(std::move(awdl_socket))));
@@ -191,6 +194,8 @@ TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) {
path_info);
EXPECT_TRUE(result.has_value());
EXPECT_FALSE(mediums_.GetAwdl().IsDiscovering(
WrapInitiatorUpgradeServiceId(kServiceId)));
}
TEST_F(AwdlBwuHandlerTest,
@@ -66,8 +66,7 @@ constexpr absl::Duration kAdvertisementHeaderExpiry = absl::Seconds(15);
// Private c'tor for testing.
DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
bool is_extended_advertisement_available, bool start_fetch_executor)
: is_extended_advertisement_available_(
is_extended_advertisement_available),
: is_extended_advertisement_available_(is_extended_advertisement_available),
start_fetch_executor_(start_fetch_executor) {}
DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
@@ -75,9 +74,7 @@ DiscoveredPeripheralTracker::DiscoveredPeripheralTracker(
: DiscoveredPeripheralTracker(is_extended_advertisement_available,
/*start_fetch_executor=*/true) {}
DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() {
Shutdown();
}
DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() { Shutdown(); }
void DiscoveredPeripheralTracker::StartFetchExecutorIfNeeded() {
if (executor_ != nullptr) {
@@ -199,7 +196,8 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement(
return;
}
if (advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) {
if (!dct_service_id_hash_to_service_id_map_.empty() &&
advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) {
std::optional<BleAdvertisementData> dct_advertisement_data =
HandleDctAdvertisement(advertisement_data);
@@ -749,15 +747,14 @@ void DiscoveredPeripheralTracker::HandleAdvertisementHeader(
// support extended advertisement.
if (!advertisement_header.IsSupportExtendedAdvertisement()) {
for (auto& item : service_id_infos_) {
item.second.discovered_peripheral_callback
.legacy_device_discovered_cb();
item.second.discovered_peripheral_callback.legacy_device_discovered_cb();
}
}
// Determine whether or not we need to read a fresh GATT advertisement.
VLOG(1) << "Handle GATT advertisement header with hash "
<< absl::BytesToHexString(
advertisement_header.GetAdvertisementHash().AsStringView())
advertisement_header.GetAdvertisementHash().AsStringView())
<< " in thread";
if (!ShouldReadRawAdvertisementFromServer(advertisement_header)) {
@@ -1015,7 +1012,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() {
}
if (!found_task) {
LOG(WARNING) << "No task found, skip to fetch raw advertisement.";
continue;;
continue;
}
// Check if the task is expired.
@@ -1027,8 +1024,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() {
.AsStringView())
<< " is expired, skip to fetch raw advertisement.";
} else {
FetchRawAdvertisementsInThread(task.peripheral,
task.advertisement_header,
FetchRawAdvertisementsInThread(task.peripheral, task.advertisement_header,
std::move(task.advertisement_fetcher));
}
// Clear in progress header after the task is done.
@@ -60,7 +60,8 @@ class WifiDirect {
bool IsGOStarted() ABSL_LOCKS_EXCLUDED(mutex_);
// Start WifiDirect Group Owner. Returns true if WifiDirect GO is successfully
// started.
bool StartWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_);
bool StartWifiDirect()
ABSL_LOCKS_EXCLUDED(mutex_);
// Stop WifiDirect Group Owner
bool StopWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_);
@@ -54,6 +54,11 @@ WifiDirectBwuHandler::WifiDirectBwuHandler(
std::string WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) {
auto remote_device_name = client->GetRemoteDeviceName(endpoint_id);
WifiDirectCredentials* wifi_direct_crendential =
wifi_direct_medium_.GetCredentials(upgrade_service_id);
wifi_direct_crendential->SetRemoteDeviceName(remote_device_name);
// Create WifiDirect GO
if (!wifi_direct_medium_.StartWifiDirect()) {
LOG(INFO) << "Failed to start Wifi Direct!";
@@ -82,7 +87,7 @@ std::string WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
// Note: Credentials are not generated until Medium StartWifiDirect() is
// called and the server socket is created. Be careful moving this codeblock
// around.
WifiDirectCredentials* wifi_direct_crendential =
wifi_direct_crendential =
wifi_direct_medium_.GetCredentials(upgrade_service_id);
std::string ssid = wifi_direct_crendential->GetSSID();
std::string password = wifi_direct_crendential->GetPassword();
@@ -194,7 +194,9 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel(
}
// Add gateway and port to address candidates if address candidates is empty.
if (service_addresses.empty() &&
upgrade_path_info_credentials.has_gateway()) {
upgrade_path_info_credentials.has_gateway() &&
upgrade_path_info_credentials.port() > 0 &&
upgrade_path_info_credentials.port() <= 65535) {
std::vector<char> address_bytes =
GatewayToAddressBytes(upgrade_path_info_credentials.gateway());
if (!address_bytes.empty()) {
@@ -230,7 +232,8 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel(
LOG(ERROR) << "WifiHotspotBwuHandler failed to connect to the WifiHotspot "
"service for endpoint "
<< endpoint_id;
return {Error(socket_result.error().operation_result_code().value())};
return {Error(socket_result.error().operation_result_code().value_or(
OperationResultCode::DETAIL_UNKNOWN))};
}
VLOG(1)
<< "WifiHotspotBwuHandler successfully connected to WifiHotspot service "
@@ -55,8 +55,9 @@ class WifiHotspotTest : public testing::Test {
~WifiHotspotTest() override { env_.Stop(); }
void SetUp() override {
nearby::NearbyFlags::GetInstance().OverrideInt64FlagValue(
platform::config_package_nearby::nearby_platform_feature::
kWifiHotspotConnectionIntervalMillis, 1);
platform::config_package_nearby::nearby_platform_feature::
kWifiHotspotConnectionIntervalMillis,
1);
}
void TearDown() override {
nearby::NearbyFlags::GetInstance().ResetOverridedValues();
@@ -89,9 +90,10 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) {
ExceptionOr<OfflineFrame> upgrade_frame;
auto handler_1 = std::make_unique<WifiHotspotBwuHandler>(
&mediums_HS_ap.GetWifiHotspot(), [&](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
mutable_connection) {
&mediums_HS_ap.GetWifiHotspot(),
[&](ClientProxy* client,
std::unique_ptr<BwuHandler::IncomingSocketConnection>
mutable_connection) {
LOG(INFO) << "Server socket connection accept call back, Socket name: "
<< mutable_connection->socket->ToString();
accept_latch.CountDown();
@@ -169,5 +171,42 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) {
EXPECT_FALSE(mediums_HS_sta.GetWifiHotspot().IsConnectedToHotspot());
}
TEST_F(WifiHotspotTest, CreateUpgradedEndpointChannel_RejectGatewayPort0) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointID));
Mediums mediums;
WifiHotspotBwuHandler handler(&mediums.GetWifiHotspot(), nullptr);
UpgradePathInfo path_info;
auto* credentials = path_info.mutable_wifi_hotspot_credentials();
credentials->set_ssid("SSID");
credentials->set_password("password");
credentials->set_gateway("192.168.43.1");
// Port 0
credentials->set_port(0);
auto result = handler.CreateUpgradedEndpointChannel(
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
EXPECT_TRUE(result.has_error());
EXPECT_EQ(result.error().operation_result_code().value(),
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
// Port > 65535
credentials->set_port(65536);
result = handler.CreateUpgradedEndpointChannel(
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
EXPECT_TRUE(result.has_error());
EXPECT_EQ(result.error().operation_result_code().value(),
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
// Port < 0
credentials->set_port(-1);
result = handler.CreateUpgradedEndpointChannel(
&client, std::string(kServiceID), std::string(kEndpointID), path_info);
EXPECT_TRUE(result.has_error());
EXPECT_EQ(result.error().operation_result_code().value(),
OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL);
}
} // namespace connections
} // namespace nearby
@@ -79,21 +79,42 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel(
<< address_candidate.ip_address().size();
continue;
}
if (service_address.IsLoopbackAddress() ||
service_address.IsLinkLocalAddress()) {
LOG(WARNING) << "Loopback/link-local address candidate is rejected.";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
}
address_candidates.push_back(std::move(service_address));
}
// Only use ip_address and wifi_port if address_candidates is empty.
if (address_candidates.empty()) {
address_candidates.push_back(ServiceAddress{
.address =
std::vector<char>(upgrade_path_info_socket.ip_address().begin(),
upgrade_path_info_socket.ip_address().end()),
.port = static_cast<uint16_t>(upgrade_path_info_socket.wifi_port())});
if (upgrade_path_info_socket.ip_address().size() != 4 ||
upgrade_path_info_socket.wifi_port() <= 0 ||
upgrade_path_info_socket.wifi_port() > 65535) {
LOG(ERROR) << "WifiLanBwuHandler: fallback ip_address size is not 4 "
<< "or port is invalid (IPv4 only).";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_IP_ADDRESS_ERROR)};
}
ServiceAddress service_address;
service_address.address = {upgrade_path_info_socket.ip_address().begin(),
upgrade_path_info_socket.ip_address().end()};
service_address.port =
static_cast<uint16_t>(upgrade_path_info_socket.wifi_port());
if (service_address.IsLoopbackAddress() ||
service_address.IsLinkLocalAddress()) {
LOG(WARNING) << "Loopback/link-local fallback address is rejected.";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
}
address_candidates.push_back(std::move(service_address));
}
Error error;
for (const auto& address_candidate : address_candidates) {
VLOG(1) << "WifiLanBwuHandler is attempting to connect to available "
"WifiLan service (" << address_candidate << ") for endpoint "
<< endpoint_id;
"WifiLan service ("
<< address_candidate << ") for endpoint " << endpoint_id;
std::shared_ptr<CancellationFlag> cancellation_flag =
client->GetCancellationFlag(endpoint_id);
ErrorOr<WifiLanSocket> socket_result = wifi_lan_medium_.Connect(
@@ -102,7 +123,8 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel(
LOG(ERROR)
<< "WifiLanBwuHandler failed to connect to the WifiLan service ("
<< address_candidate << ") for endpoint " << endpoint_id;
error = Error(socket_result.error().operation_result_code().value());
error = Error(socket_result.error().operation_result_code().value_or(
OperationResultCode::DETAIL_UNKNOWN));
continue;
}
VLOG(1) << "WifiLanBwuHandler successfully connected to WifiLan service ("
@@ -209,6 +209,98 @@ TEST_F(WifiLanBwuHandlerTest,
EXPECT_TRUE(result.has_value());
};
TEST_F(WifiLanBwuHandlerTest,
CreateUpgradedEndpointChannel_RejectLoopbackAndLinkLocalCandidates) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
// 1st candidate: Loopback
auto* address_candidate =
path_info.mutable_wifi_lan_socket()->add_address_candidates();
address_candidate->set_ip_address(std::string("\x7f\x00\x00\x01", 4));
address_candidate->set_port(8080);
// 2nd candidate: Link-Local (169.254.1.1)
address_candidate =
path_info.mutable_wifi_lan_socket()->add_address_candidates();
address_candidate->set_ip_address("\xa9\xfe\x01\x01");
address_candidate->set_port(8080);
// 3rd candidate: Valid IP
address_candidate =
path_info.mutable_wifi_lan_socket()->add_address_candidates();
address_candidate->set_ip_address(kIpv4Address);
address_candidate->set_port(8080);
auto result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId),
std::move(path_info));
EXPECT_FALSE(result.has_value());
}
TEST_F(WifiLanBwuHandlerTest,
CreateUpgradedEndpointChannel_RejectLoopbackFallbackIp) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
path_info.mutable_wifi_lan_socket()->set_ip_address(
std::string("\x7f\x00\x00\x01", 4));
path_info.mutable_wifi_lan_socket()->set_wifi_port(8080);
auto result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId),
std::move(path_info));
EXPECT_FALSE(result.has_value());
}
TEST_F(WifiLanBwuHandlerTest,
CreateUpgradedEndpointChannel_RejectInvalidFallbackIpLength) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
path_info.mutable_wifi_lan_socket()->set_ip_address("123");
path_info.mutable_wifi_lan_socket()->set_wifi_port(8080);
auto result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId),
std::move(path_info));
EXPECT_FALSE(result.has_value());
}
TEST_F(WifiLanBwuHandlerTest,
CreateUpgradedEndpointChannel_RejectFallbackPort0) {
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info;
path_info.mutable_wifi_lan_socket()->set_ip_address(kIpv4Address);
// Port 0
path_info.mutable_wifi_lan_socket()->set_wifi_port(0);
auto result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
EXPECT_FALSE(result.has_value());
// Port > 65535
path_info.mutable_wifi_lan_socket()->set_wifi_port(65536);
result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
EXPECT_FALSE(result.has_value());
// Port < 0
path_info.mutable_wifi_lan_socket()->set_wifi_port(-1);
result = handler_.CreateUpgradedEndpointChannel(
&client, std::string(kServiceId), std::string(kEndpointId), path_info);
EXPECT_FALSE(result.has_value());
}
TEST_F(WifiLanBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
@@ -289,9 +381,8 @@ TEST_F(WifiLanBwuHandlerTest,
mediums_.GetWifiLan().IsAcceptingConnections("service_id_UPGRADE"));
}
TEST_F(
WifiLanBwuHandlerTest,
InitializeUpgradedMediumForEndpoint_AlreadyAccepting_KeepAccepting) {
TEST_F(WifiLanBwuHandlerTest,
InitializeUpgradedMediumForEndpoint_AlreadyAccepting_KeepAccepting) {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
ClientProxy client;
client.AddCancellationFlag(std::string(kEndpointId));
@@ -69,6 +69,9 @@ class MockEndpointChannel : public EndpointChannel {
MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override));
MOCK_METHOD(void, SetAnalyticsRecorder,
(analytics::AnalyticsRecorder*, const std::string&), (override));
MOCK_METHOD(void, SetLocalEndpointId, (const std::string& local_endpoint_id),
(override));
MOCK_METHOD(std::string, GetLocalEndpointId, (), (const, override));
};
} // namespace nearby::connections
+16 -7
View File
@@ -180,7 +180,8 @@ std::string ForConnectionRequestPresence(
return frame.SerializeAsString();
}
std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info) {
std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info,
const std::string& device_name) {
OfflineFrame frame;
frame.set_version(OfflineFrame::V1);
@@ -201,6 +202,7 @@ std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info) {
NearbyFlags::GetInstance().GetInt64Flag(
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion));
sub_frame->set_wifi_direct_device_name(device_name);
return frame.SerializeAsString();
}
@@ -460,6 +462,7 @@ std::string ForBwuSafeToClose() {
}
std::string ForBwuIntroduction(const std::string& endpoint_id,
const std::string& last_endpoint_id,
bool supports_disabling_encryption) {
OfflineFrame frame;
@@ -473,6 +476,9 @@ std::string ForBwuIntroduction(const std::string& endpoint_id,
client_introduction->set_endpoint_id(endpoint_id);
client_introduction->set_supports_disabling_encryption(
supports_disabling_encryption);
if (!last_endpoint_id.empty()) {
client_introduction->set_last_endpoint_id(last_endpoint_id);
}
return frame.SerializeAsString();
}
@@ -498,16 +504,14 @@ std::string ForBwuFailure(const UpgradePathInfo& info) {
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
sub_frame->set_event_type(BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE);
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
*upgrade_path_info = info;
*sub_frame->mutable_upgrade_path_info() = info;
return frame.SerializeAsString();
}
std::string ForBwuPathRequest(const std::vector<Medium>& mediums,
const MediumRole& medium_role) {
std::string ForBwuPathRequest(Medium medium, const std::vector<Medium>& mediums,
const MediumRole& medium_role,
bool supports_5_ghz) {
OfflineFrame frame;
frame.set_version(OfflineFrame::V1);
@@ -516,11 +520,16 @@ std::string ForBwuPathRequest(const std::vector<Medium>& mediums,
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
sub_frame->set_event_type(
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_REQUEST);
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
upgrade_path_info->set_medium(MediumToUpgradePathInfoMedium(medium));
auto* upgrade_path_request =
sub_frame->mutable_upgrade_path_info()->mutable_upgrade_path_request();
upgrade_path_info->mutable_upgrade_path_request();
for (const auto& medium : mediums) {
upgrade_path_request->add_mediums(MediumToUpgradePathInfoMedium(medium));
}
LOG(INFO) << "ForBwuPathRequest: supports_5_ghz: " << supports_5_ghz;
upgrade_path_request->mutable_medium_meta_data()->set_supports_5_ghz(
supports_5_ghz);
auto* role =
upgrade_path_request->mutable_medium_meta_data()->mutable_medium_role();
role->MergeFrom(medium_role);
+6 -3
View File
@@ -59,7 +59,8 @@ std::string ForConnectionRequestPresence(
const location::nearby::connections::PresenceDevice& proto_presence_device,
const ConnectionInfo& connection_info);
std::string ForConnectionResponse(
std::int32_t status, const location::nearby::connections::OsInfo& os_info);
std::int32_t status, const location::nearby::connections::OsInfo& os_info,
const std::string& device_name);
// Builds Payload transfer messages.
std::string ForDataPayloadTransfer(
@@ -76,6 +77,7 @@ std::string ForPayloadAckPayloadTransfer(std::int64_t payload_id);
// Builds Bandwidth Upgrade [BWU] messages.
std::string ForBwuIntroduction(const std::string& endpoint_id,
const std::string& last_endpoint_id,
bool supports_disabling_encryption);
std::string ForBwuIntroductionAck();
std::string ForBwuWifiHotspotPathAvailable(
@@ -107,8 +109,9 @@ std::string ForBwuWebrtcPathAvailable(
const location::nearby::connections::LocationHint& location_hint_a);
std::string ForBwuFailure(const UpgradePathInfo& info);
std::string ForBwuPathRequest(
const std::vector<Medium>& mediums,
const location::nearby::connections::MediumRole& medium_role);
Medium medium, const std::vector<Medium>& mediums,
const location::nearby::connections::MediumRole& medium_role,
bool supports_5_ghz);
std::string ForBwuLastWrite();
std::string ForBwuSafeToClose();
@@ -352,6 +352,7 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) {
os_info { type: LINUX }
multiplex_socket_bitmask: 0
safe_to_disconnect_version: 5
wifi_direct_device_name: "device_name"
>
>)pb";
@@ -361,7 +362,8 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) {
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion,
5);
auto response = FromBytes(ForConnectionResponse(1, os_info));
auto response = FromBytes(
ForConnectionResponse(1, os_info, "device_name"));
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
@@ -502,10 +504,7 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) {
ip_address: "\x2a\x00\x79\xe0\x2e\x87\x00\x06\xb7\x28\x67\x45\x7a\xdd\x01\x53"
port: 1234
>
address_candidates: <
ip_address: "\001\002\003\004"
port: 1234
>
address_candidates: < ip_address: "\001\002\003\004" port: 1234 >
>
supports_client_introduction_ack: true
>
@@ -679,11 +678,13 @@ TEST(OfflineFramesTest, CanGenerateBwuIntroduction) {
client_introduction: <
endpoint_id: "ABC"
supports_disabling_encryption: false
last_endpoint_id: "DEF"
>
>
>)pb";
auto response = FromBytes(ForBwuIntroduction(
std::string(kEndpointId), false /* supports_disabling_encryption */));
auto response =
FromBytes(ForBwuIntroduction(std::string(kEndpointId), "DEF",
false /* supports_disabling_encryption */));
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
@@ -722,7 +723,6 @@ TEST(OfflineFramesTest, CanGenerateDisconnection) {
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
constexpr absl::string_view kExpected =
R"pb(
@@ -732,9 +732,11 @@ TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_REQUEST
upgrade_path_info: <
medium: WIFI_HOTSPOT
upgrade_path_request: <
mediums: WIFI_HOTSPOT
medium_meta_data: <
supports_5_ghz: true
medium_role: < support_wifi_hotspot_client: true >
>
>
@@ -745,7 +747,9 @@ TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
mediums.push_back(Medium::WIFI_HOTSPOT);
MediumRole medium_role;
medium_role.set_support_wifi_hotspot_client(true);
auto response = FromBytes(ForBwuPathRequest(mediums, medium_role));
auto response =
FromBytes(ForBwuPathRequest(Medium::WIFI_HOTSPOT, mediums, medium_role,
/*supports_5_ghz=*/true));
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
@@ -19,6 +19,8 @@
#include <regex> //NOLINT
#include <string>
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "connections/implementation/internal_payload.h"
#include "connections/implementation/offline_frames.h"
@@ -26,9 +28,12 @@
#include "connections/medium_selector.h"
#include "internal/platform/exception.h"
#include "internal/platform/logging.h"
#include "internal/platform/service_address.h"
#include "sharing/internal/base/utf_string_conversions.h"
namespace nearby {
namespace connections {
namespace parser {
namespace {
@@ -72,7 +77,12 @@ constexpr int kWifiDirectPinMinLength = 0;
constexpr int kWifiDirectPinMaxLength = 16;
inline bool WithinRange(int value, int min, int max) {
return value >= min && value < max;
return value >= min && value <= max;
}
bool IsValidWifiLanServiceAddress(const ServiceAddress& service_address) {
return !service_address.IsLoopbackAddress() &&
!service_address.IsLinkLocalAddress();
}
Exception EnsureValidConnectionRequestFrame(
@@ -140,16 +150,25 @@ Exception EnsureValidPayloadTransferControlFrame(
return {Exception::kSuccess};
}
bool CheckForIllegalCharacters(std::string toBeValidated,
bool CheckForIllegalCharacters(absl::string_view toBeValidated,
const absl::string_view illegalPatterns[],
size_t illegalPatternsSize) {
if (toBeValidated.empty()) {
return false;
}
// Null bytes are rejected to prevent null-byte injection attacks. C-style
// APIs (like system file operations) treat '\0' as a string terminator,
// whereas C++ strings can contain them. This discrepancy can lead to
// validation bypasses (e.g., validating "file.sh\0.png" as a PNG but
// creating "file.sh" on disk).
if (absl::StrContains(toBeValidated, '\0') ||
!nearby::utils::IsStringUtf8(toBeValidated)) {
return true;
}
for (int index = 0; index < illegalPatternsSize; index++) {
if (toBeValidated.find(std::string(illegalPatterns[index])) !=
std::string::npos) {
if (absl::StrContains(toBeValidated, illegalPatterns[index])) {
return true;
}
}
@@ -178,20 +197,21 @@ Exception EnsureValidPayloadTransferFrame(const PayloadTransferFrame& frame) {
location::nearby::connections::PayloadTransferFrame::PayloadHeader::
FILE) {
if (frame.payload_header().has_file_name()) {
if (CheckForIllegalCharacters(frame.payload_header().file_name(),
kIllegalFileNamePatterns,
const std::string& file_name = frame.payload_header().file_name();
if (CheckForIllegalCharacters(file_name, kIllegalFileNamePatterns,
kIllegalFileNamePatternsSize)) {
LOG(ERROR) << "File name " << frame.payload_header().file_name()
<< " has illegal characters";
LOG(ERROR) << "File name (hex) " << absl::BytesToHexString(file_name)
<< " has illegal characters or invalid UTF-8";
return {Exception::kIllegalCharacters};
}
}
if (frame.payload_header().has_parent_folder()) {
if (CheckForIllegalCharacters(frame.payload_header().parent_folder(),
kIllegalParentFolderPatterns,
const std::string& parent_folder = frame.payload_header().parent_folder();
if (CheckForIllegalCharacters(parent_folder, kIllegalParentFolderPatterns,
kIllegalParentFolderPatternsSize)) {
LOG(ERROR) << "Parent folder " << frame.payload_header().parent_folder()
<< " has illegal characters";
LOG(ERROR) << "Parent folder (hex) "
<< absl::BytesToHexString(parent_folder)
<< " has illegal characters or invalid UTF-8";
return {Exception::kIllegalCharacters};
}
}
@@ -234,21 +254,29 @@ Exception EnsureValidBandwidthUpgradeWifiHotspotPathAvailableFrame(
!WithinRange(wifi_hotspot_credentials.password().length(),
kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength))
return {Exception::kInvalidProtocolBuffer};
if (!wifi_hotspot_credentials.has_gateway() &&
wifi_hotspot_credentials.address_candidates_size() == 0)
if ((!wifi_hotspot_credentials.has_gateway() ||
wifi_hotspot_credentials.gateway().empty()) &&
wifi_hotspot_credentials.address_candidates_size() == 0) {
return {Exception::kInvalidProtocolBuffer};
const std::regex ip4_pattern(std::string(kIpv4PatternString).c_str());
if (!wifi_hotspot_credentials.gateway().empty() &&
!(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern))) {
return {Exception::kInvalidProtocolBuffer};
}
for (const auto& address_candidate :
wifi_hotspot_credentials.address_candidates()) {
if (!address_candidate.has_ip_address() || !address_candidate.has_port()) {
const std::regex ip4_pattern(std::string(kIpv4PatternString).c_str());
if (wifi_hotspot_credentials.has_gateway() &&
!wifi_hotspot_credentials.gateway().empty()) {
if (!(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern))) {
return {Exception::kInvalidProtocolBuffer};
}
if (address_candidate.ip_address().size() != 4 &&
address_candidate.ip_address().size() != 16) {
if (!wifi_hotspot_credentials.has_port() ||
!WithinRange(wifi_hotspot_credentials.port(), 1, 65535)) {
return {Exception::kInvalidProtocolBuffer};
}
}
for (const auto& address_candidate :
wifi_hotspot_credentials.address_candidates()) {
ServiceAddress service_address;
if (!ServiceAddressFromProto(address_candidate, service_address)) {
return {Exception::kInvalidProtocolBuffer};
}
}
@@ -265,6 +293,29 @@ Exception EnsureValidBandwidthUpgradeWifiLanPathAvailableFrame(
return {Exception::kInvalidProtocolBuffer};
}
if (wifi_lan_socket.has_ip_address()) {
location::nearby::connections::ServiceAddress proto;
proto.set_ip_address(wifi_lan_socket.ip_address());
proto.set_port(wifi_lan_socket.wifi_port());
ServiceAddress service_address;
if (!ServiceAddressFromProto(proto, service_address)) {
return {Exception::kInvalidProtocolBuffer};
}
if (!IsValidWifiLanServiceAddress(service_address)) {
return {Exception::kInvalidProtocolBuffer};
}
}
for (const auto& address_candidate : wifi_lan_socket.address_candidates()) {
ServiceAddress service_address;
if (!ServiceAddressFromProto(address_candidate, service_address)) {
return {Exception::kInvalidProtocolBuffer};
}
if (!IsValidWifiLanServiceAddress(service_address)) {
return {Exception::kInvalidProtocolBuffer};
}
}
// For backwards compatibility reasons, no other fields should be null-checked
// for this frame. Parameter checking (eg. must be within this range) is fine.
return {Exception::kSuccess};
@@ -292,7 +343,7 @@ Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame(
std::string(kWifiDirectSsidPatternString).c_str());
bool ssid_valid =
wifi_direct_credentials.has_ssid() &&
wifi_direct_credentials.ssid().length() < kWifiDirectSsidMaxLength &&
wifi_direct_credentials.ssid().length() <= kWifiDirectSsidMaxLength &&
std::regex_match(wifi_direct_credentials.ssid(), ssid_pattern);
bool password_valid =
wifi_direct_credentials.has_password() &&
@@ -300,8 +351,7 @@ Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame(
kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength);
bool device_name_valid =
wifi_direct_credentials.has_device_name() &&
wifi_direct_credentials.device_name().length() <
kWifiDirectSsidMaxLength;
wifi_direct_credentials.device_name().length() < kWifiDirectSsidMaxLength;
bool pin_valid =
wifi_direct_credentials.has_pin() &&
WithinRange(wifi_direct_credentials.pin().length(),
@@ -36,6 +36,7 @@ using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame;
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::connections::PayloadTransferFrame;
using ::location::nearby::connections::V1Frame;
constexpr absl::string_view kEndpointId{"ABC"};
constexpr absl::string_view kEndpointName{"XYZ"};
@@ -122,7 +123,7 @@ TEST_F(OfflineFramesConnectionRequestTest,
ValidatesAsFailWithEmptyEndpointIdInConnectionRequestFrame) {
connection_info_.local_endpoint_id = "";
std::string bytes = ForConnectionRequestConnections({}, connection_info_);
location::nearby::connections::OfflineFrame frame;
OfflineFrame frame;
frame.ParseFromString(bytes);
frame.mutable_v1()->mutable_connection_request()->set_endpoint_id("");
ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id());
@@ -179,7 +180,8 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame;
OsInfo os_info;
std::string bytes = ForConnectionResponse(kStatusAccepted, os_info);
std::string bytes =
ForConnectionResponse(kStatusAccepted, os_info, "device_name");
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
@@ -192,7 +194,8 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame;
OsInfo os_info;
std::string bytes = ForConnectionResponse(kStatusAccepted, os_info);
std::string bytes =
ForConnectionResponse(kStatusAccepted, os_info, "device_name");
offline_frame.ParseFromString(bytes);
auto* v1_frame = offline_frame.mutable_v1();
@@ -208,7 +211,7 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame;
OsInfo os_info;
std::string bytes = ForConnectionResponse(-1, os_info);
std::string bytes = ForConnectionResponse(-1, os_info, "device_name");
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
@@ -365,6 +368,92 @@ TEST(OfflineFramesValidatorTest,
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithNonUtf8FilePath) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_total_size(100);
header.set_file_name(std::string("hello\xffworld"));
header.set_parent_folder(std::string());
chunk.set_body("payload data");
chunk.set_offset(0);
chunk.set_flags(1);
OfflineFrame offline_frame;
std::string bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest,
ValidatesAsFailedTypeFileWithNonUtf8ParentFolder) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_total_size(100);
header.set_file_name(std::string("valid.txt"));
header.set_parent_folder(std::string("folder\xff"));
chunk.set_body("payload data");
chunk.set_offset(0);
chunk.set_flags(1);
OfflineFrame offline_frame;
std::string bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithNullInFilePath) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_total_size(100);
header.set_file_name(std::string("hello\0world", 11));
header.set_parent_folder(std::string());
chunk.set_body("payload data");
chunk.set_offset(0);
chunk.set_flags(1);
OfflineFrame offline_frame;
std::string bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest,
ValidatesAsFailedTypeFileWithNullInParentFolder) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_total_size(100);
header.set_file_name(std::string("valid.txt"));
header.set_parent_folder(std::string("folder\0name", 11));
chunk.set_body("payload data");
chunk.set_offset(0);
chunk.set_flags(1);
OfflineFrame offline_frame;
std::string bytes = ForDataPayloadTransfer(header, chunk);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_EQ(ret_value.value, Exception::kIllegalCharacters);
}
TEST(OfflineFramesValidatorTest, ValidatesAsFailWithNullPayloadTransferFrame) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
@@ -677,6 +766,86 @@ TEST(OfflineFramesValidatorTest,
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateHotspotUpgradeFrameWithLargePortCandidateFails) {
OfflineFrame offline_frame;
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
credentials;
credentials.set_ssid(kSsid);
credentials.set_password(kPassword);
credentials.set_frequency(kHotspotFrequency);
auto* candidate = credentials.mutable_address_candidates()->Add();
candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4));
candidate->set_port(70000);
std::string bytes = ForBwuWifiHotspotPathAvailable(
std::move(credentials), kSupportsDisablingEncryption);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateHotspotUpgradeFrameWithFallbackInvalidPortFails) {
OfflineFrame offline_frame;
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
credentials;
credentials.set_ssid(kSsid);
credentials.set_password(kPassword);
credentials.set_frequency(kHotspotFrequency);
credentials.set_gateway(std::string(kWifiHotspotGateway));
credentials.set_port(70000);
std::string bytes = ForBwuWifiHotspotPathAvailable(
std::move(credentials), kSupportsDisablingEncryption);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateHotspotUpgradeFrameWithEmptyGatewayAndNoCandidatesFails) {
OfflineFrame offline_frame;
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
credentials;
credentials.set_ssid(kSsid);
credentials.set_password(kPassword);
credentials.set_frequency(kHotspotFrequency);
credentials.set_gateway("");
std::string bytes = ForBwuWifiHotspotPathAvailable(
std::move(credentials), kSupportsDisablingEncryption);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateHotspotUpgradeFrameWithNoGatewayAndNoCandidatesFails) {
OfflineFrame offline_frame;
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials
credentials;
credentials.set_ssid(kSsid);
credentials.set_password(kPassword);
credentials.set_frequency(kHotspotFrequency);
// Do not set gateway
// Do not set address candidates
std::string bytes = ForBwuWifiHotspotPathAvailable(
std::move(credentials), kSupportsDisablingEncryption);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithAddressCandidatesSucceeds) {
OfflineFrame offline_frame;
@@ -694,6 +863,144 @@ TEST(OfflineFramesValidatorTest,
EXPECT_TRUE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithLoopbackAddressCandidateFails) {
OfflineFrame offline_frame;
std::vector<ServiceAddress> address_candidates = {
{{127, 0, 0, 1}, kPort},
};
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithLinkLocalAddressCandidateFails) {
OfflineFrame offline_frame;
std::vector<ServiceAddress> address_candidates = {
{{169, 254, 1, 1}, kPort},
};
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithInvalidIpAddressSizeCandidateFails) {
OfflineFrame offline_frame;
std::vector<ServiceAddress> address_candidates = {
{{1, 2, 3}, kPort},
};
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithZeroPortCandidateFails) {
OfflineFrame offline_frame;
std::vector<ServiceAddress> address_candidates = {
{{192, 168, 1, 1}, 0},
};
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
offline_frame.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithLargePortCandidateFails) {
OfflineFrame offline_frame;
std::vector<ServiceAddress> address_candidates = {
{{192, 168, 1, 1}, kPort},
};
std::string bytes = ForBwuWifiLanPathAvailable(address_candidates);
offline_frame.ParseFromString(bytes);
auto* negotiation =
offline_frame.mutable_v1()->mutable_bandwidth_upgrade_negotiation();
auto* wifi_lan_socket =
negotiation->mutable_upgrade_path_info()->mutable_wifi_lan_socket();
if (wifi_lan_socket->address_candidates_size() > 0) {
wifi_lan_socket->mutable_address_candidates(0)->set_port(70000);
}
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithFallbackLoopbackAddressFails) {
OfflineFrame offline_frame;
offline_frame.set_version(OfflineFrame::V1);
auto* v1_frame = offline_frame.mutable_v1();
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
negotiation->set_event_type(
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
wifi_lan_socket->set_ip_address(std::string({127, 0, 0, 1}));
wifi_lan_socket->set_wifi_port(kPort);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithFallbackLinkLocalAddressFails) {
OfflineFrame offline_frame;
offline_frame.set_version(OfflineFrame::V1);
auto* v1_frame = offline_frame.mutable_v1();
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
negotiation->set_event_type(
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
wifi_lan_socket->set_ip_address(std::string({169, 254, 1, 1}));
wifi_lan_socket->set_wifi_port(kPort);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidateWifiLanUpgradeFrameWithFallbackInvalidPortFails) {
OfflineFrame offline_frame;
offline_frame.set_version(OfflineFrame::V1);
auto* v1_frame = offline_frame.mutable_v1();
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
auto* negotiation = v1_frame->mutable_bandwidth_upgrade_negotiation();
negotiation->set_event_type(
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
auto* upgrade_path_info = negotiation->mutable_upgrade_path_info();
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
wifi_lan_socket->set_ip_address(std::string({192, 168, 1, 1}));
wifi_lan_socket->set_wifi_port(70000);
auto ret_value = EnsureValidOfflineFrame(offline_frame);
EXPECT_FALSE(ret_value.Ok());
}
TEST(OfflineFramesValidatorTest,
ValidatesAsFailWithNullBandwidthUpgradeNegotiationFrame) {
OfflineFrame offline_frame;
@@ -765,18 +1072,35 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame_2;
std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"};
std::string wifi_direct_pin_wrong_length = "abcefghijklmnopqrstuvwxyz";
std::string wifi_direct_pin_wrong_length = "01234567890123456";
std::string bytes = ForBwuWifiDirectPathAvailable(
wifi_direct_ssid, std::string(kWifiDirectPassword), kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
std::string(kGateway), std::string(kWifiDirectDeviceName),
wifi_direct_pin_wrong_length);
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
std::string(kWifiDirectDeviceName), wifi_direct_pin_wrong_length);
offline_frame_1.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame_1);
EXPECT_FALSE(ret_value.Ok());
std::string wifi_direct_ssid_64_length = "DIRECT-A0-" + std::string(54, 'A');
bytes = ForBwuWifiDirectPathAvailable(
wifi_direct_ssid_64_length, std::string(kWifiDirectPassword), kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
std::string(kWifiDirectDeviceName), /*pin=*/"01234567890123456");
offline_frame_2.ParseFromString(bytes);
ret_value = EnsureValidOfflineFrame(offline_frame_2);
EXPECT_FALSE(ret_value.Ok());
std::string wifi_direct_pin_16_length = "0123456789012345";
bytes = ForBwuWifiDirectPathAvailable(
std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
std::string(kWifiDirectDeviceName), wifi_direct_pin_16_length);
offline_frame_2.ParseFromString(bytes);
ret_value = EnsureValidOfflineFrame(offline_frame_2);
EXPECT_TRUE(ret_value.Ok());
std::string wifi_direct_ssid_wrong_length =
std::string{kWifiDirectSsid} + "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
std::string wifi_direct_device_name_wrong_length =
@@ -784,9 +1108,8 @@ TEST(OfflineFramesValidatorTest,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
bytes = ForBwuWifiDirectPathAvailable(
wifi_direct_ssid_wrong_length, std::string(kWifiDirectPassword), kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
std::string(kGateway), wifi_direct_device_name_wrong_length,
std::string(kWifiDirectPin));
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
wifi_direct_device_name_wrong_length, std::string(kWifiDirectPin));
offline_frame_2.ParseFromString(bytes);
ret_value = EnsureValidOfflineFrame(offline_frame_2);
@@ -807,9 +1130,8 @@ TEST(OfflineFramesValidatorTest,
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
std::string bytes = ForBwuWifiDirectPathAvailable(
std::string(kWifiDirectSsid), long_wifi_direct_password, kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
std::string(kGateway), std::string(kWifiDirectDeviceName),
long_wifi_direct_pin);
kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway),
std::string(kWifiDirectDeviceName), long_wifi_direct_pin);
offline_frame_2.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame_2);
@@ -307,6 +307,9 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
<< bluetooth_classic_advertiser_client_id_;
}
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
ble_medium_.StopAdvertising(client->GetAdvertisingServiceId());
ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
@@ -316,9 +319,6 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
client->GetAdvertisingServiceId());
}
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableAwdl)) {
awdl_medium_.StopAdvertising(client->GetAdvertisingServiceId());
@@ -1238,8 +1238,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
client_proxy, local_endpoint_id,
options.listening_endpoint_type));
client_proxy, options.listening_endpoint_type));
if (bluetooth_result.has_error()) {
LOG(WARNING)
<< "Failed to start listening for incoming connections on Bluetooth";
@@ -1266,8 +1265,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
client_proxy, local_endpoint_id,
options.listening_endpoint_type))) {
client_proxy, options.listening_endpoint_type))) {
LOG(WARNING) << "Failed to start listening for incoming L2CAP "
"connections on ble";
} else {
@@ -1278,8 +1276,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler,
this, client_proxy, local_endpoint_id,
options.listening_endpoint_type))) {
this, client_proxy, options.listening_endpoint_type))) {
LOG(WARNING) << "Failed to start listening for incoming L2CAP "
"connections on ble";
} else {
@@ -1295,8 +1292,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
client_proxy, local_endpoint_id,
options.listening_endpoint_type))) {
client_proxy, options.listening_endpoint_type))) {
LOG(WARNING)
<< "Failed to start listening for incoming connections on ble_v2";
} else {
@@ -1307,8 +1303,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::BleConnectionAcceptedHandler, this,
client_proxy, local_endpoint_id,
options.listening_endpoint_type))) {
client_proxy, options.listening_endpoint_type))) {
LOG(WARNING)
<< "Failed to start listening for incoming connections on ble";
} else {
@@ -1327,7 +1322,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl(
std::string(service_id),
absl::bind_front(
&P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler, this,
client_proxy, local_endpoint_id, "",
client_proxy, std::string(local_endpoint_id),
options.listening_endpoint_type));
if (wifi_lan_result.has_error()) {
LOG(WARNING)
@@ -1680,8 +1675,7 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl(
restarted_mediums.push_back(AWDL);
operation_result_with_mediums.push_back(
GetOperationResultWithMediumByResultCode(
client, AWDL, update_index,
OperationResultCode::DETAIL_SUCCESS));
client, AWDL, update_index, OperationResultCode::DETAIL_SUCCESS));
} else {
ErrorOr<Medium> awdl_result =
StartAwdlDiscovery(client, std::string(service_id));
@@ -1739,15 +1733,8 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl(
}
void P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_info,
NearbyDevice::Type device_type, const std::string& service_id,
BluetoothSocket socket) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
ClientProxy* client, NearbyDevice::Type device_type,
const std::string& service_id, BluetoothSocket socket) {
RunOnPcpHandlerThread(
"p2p-bt-on-incoming-connection",
[this, client, service_id, socket = std::move(socket), device_type]()
@@ -1782,8 +1769,7 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBluetoothAdvertising(
service_id,
absl::bind_front(
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
client, NearbyDevice::Type::kConnectionsDevice));
if (accept_result.has_error()) {
error = {Error(accept_result.error().operation_result_code().value())};
}
@@ -1987,15 +1973,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl(
}
void P2pClusterPcpHandler::BleConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_info,
NearbyDevice::Type device_type, BleSocket socket,
ClientProxy* client, NearbyDevice::Type device_type, BleSocket socket,
const std::string& service_id) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
RunOnPcpHandlerThread(
"p2p-ble-on-incoming-connection",
[this, client, service_id, device_type,
@@ -2010,15 +1989,8 @@ void P2pClusterPcpHandler::BleConnectionAcceptedHandler(
}
void P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_info,
NearbyDevice::Type device_type, BleL2capSocket socket,
ClientProxy* client, NearbyDevice::Type device_type, BleL2capSocket socket,
const std::string& service_id) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept L2CAP callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
RunOnPcpHandlerThread(
"p2p-ble-l2cap-on-incoming-connection",
[this, client, service_id, device_type,
@@ -2033,15 +2005,8 @@ void P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler(
}
void P2pClusterPcpHandler::BleConnectionAcceptedHandler2(
ClientProxy* client, absl::string_view local_endpoint_info,
NearbyDevice::Type device_type, std::unique_ptr<mediums::BleSocket> socket,
const std::string& service_id) {
if (socket == nullptr || !socket->IsValid()) {
LOG(WARNING) << "Invalid socket in accept callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
ClientProxy* client, NearbyDevice::Type device_type,
std::unique_ptr<mediums::BleSocket> socket, const std::string& service_id) {
RunOnPcpHandlerThread(
"p2p-ble-on-incoming-connection",
[this, client, service_id, device_type, socket = std::move(socket)]()
@@ -2101,15 +2066,13 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
service_id,
absl::bind_front(
&P2pClusterPcpHandler::BleConnectionAcceptedHandler2, this,
client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
client, NearbyDevice::Type::kConnectionsDevice));
} else {
ble_l2cap_result = ble_medium_.StartAcceptingL2capConnections(
service_id,
absl::bind_front(
&P2pClusterPcpHandler::BleL2capConnectionAcceptedHandler, this,
client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
client, NearbyDevice::Type::kConnectionsDevice));
}
}
@@ -2118,13 +2081,13 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
ble_result = ble_medium_.StartAcceptingConnections(
service_id,
absl::bind_front(&P2pClusterPcpHandler::BleConnectionAcceptedHandler2,
this, client, local_endpoint_info.AsStringView(),
this, client,
NearbyDevice::Type::kConnectionsDevice));
} else {
ble_result = ble_medium_.StartAcceptingConnections(
service_id,
absl::bind_front(&P2pClusterPcpHandler::BleConnectionAcceptedHandler,
this, client, local_endpoint_info.AsStringView(),
this, client,
NearbyDevice::Type::kConnectionsDevice));
}
if (ble_result.has_error() && ble_l2cap_result.has_error()) {
@@ -2169,8 +2132,7 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartBleAdvertising(
service_id,
absl::bind_front(
&P2pClusterPcpHandler::BluetoothConnectionAcceptedHandler, this,
client, local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
client, NearbyDevice::Type::kConnectionsDevice));
if (accept_result.has_error()) {
LOG(WARNING)
<< "In BT StartBleAdvertising("
@@ -2430,23 +2392,16 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl(
}
void P2pClusterPcpHandler::AwdlConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_id,
absl::string_view local_endpoint_info, NearbyDevice::Type device_type,
const std::string& service_id, AwdlSocket socket) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
ClientProxy* client, const std::string& local_endpoint_id,
NearbyDevice::Type device_type, const std::string& service_id,
AwdlSocket socket) {
RunOnPcpHandlerThread(
"p2p-awdl-on-incoming-connection",
[this, client, local_endpoint_id, service_id, device_type,
socket = std::move(socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable {
std::string remote_service_name = std::string(local_endpoint_id);
auto channel = std::make_unique<AwdlEndpointChannel>(
service_id, /*channel_name=*/remote_service_name, socket);
ByteArray remote_service_name_byte{remote_service_name};
service_id, /*channel_name=*/local_endpoint_id, socket);
ByteArray remote_service_name_byte{local_endpoint_id};
OnIncomingConnection(client, remote_service_name_byte,
std::move(channel), AWDL, device_type);
@@ -2454,23 +2409,16 @@ void P2pClusterPcpHandler::AwdlConnectionAcceptedHandler(
}
void P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler(
ClientProxy* client, absl::string_view local_endpoint_id,
absl::string_view local_endpoint_info, NearbyDevice::Type device_type,
const std::string& service_id, WifiLanSocket socket) {
if (!socket.IsValid()) {
LOG(WARNING) << "Invalid socket in accept callback("
<< absl::BytesToHexString(local_endpoint_info)
<< "), client=" << client->GetClientId();
return;
}
ClientProxy* client, const std::string& local_endpoint_id,
NearbyDevice::Type device_type, const std::string& service_id,
WifiLanSocket socket) {
RunOnPcpHandlerThread(
"p2p-wifi-on-incoming-connection",
[this, client, local_endpoint_id, service_id, device_type,
socket = std::move(socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable {
std::string remote_service_name = std::string(local_endpoint_id);
auto channel = std::make_unique<WifiLanEndpointChannel>(
service_id, /*channel_name=*/remote_service_name, socket);
ByteArray remote_service_name_byte{remote_service_name};
service_id, /*channel_name=*/local_endpoint_id, socket);
ByteArray remote_service_name_byte{local_endpoint_id};
OnIncomingConnection(client, remote_service_name_byte,
std::move(channel), WIFI_LAN, device_type);
@@ -2490,7 +2438,6 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartAwdlAdvertising(
service_id,
absl::bind_front(&P2pClusterPcpHandler::AwdlConnectionAcceptedHandler,
this, client, local_endpoint_id,
local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
if (awdl_result.has_error()) {
LOG(WARNING)
@@ -2608,7 +2555,6 @@ ErrorOr<Medium> P2pClusterPcpHandler::StartWifiLanAdvertising(
service_id, nsd_service_info,
absl::bind_front(&P2pClusterPcpHandler::WifiLanConnectionAcceptedHandler,
this, client, local_endpoint_id,
local_endpoint_info.AsStringView(),
NearbyDevice::Type::kConnectionsDevice));
if (wifi_lan_result.has_error()) {
LOG(WARNING) << "In StartWifiLanAdvertising("
@@ -40,10 +40,13 @@
#include "connections/implementation/mediums/bluetooth_classic.h"
#include "connections/implementation/mediums/bluetooth_radio.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/mediums/webrtc.h"
#include "connections/implementation/mediums/wifi_direct.h"
#include "connections/implementation/mediums/wifi_hotspot.h"
#include "connections/implementation/mediums/wifi_lan.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/webrtc_state.h"
#include "connections/implementation/wifi_lan_service_info.h"
#include "connections/medium_selector.h"
#include "connections/out_of_band_connection_metadata.h"
#include "connections/power_level.h"
@@ -54,13 +57,10 @@
#include "internal/platform/ble.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/wifi_lan.h"
#include "connections/implementation/mediums/webrtc.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/wifi_lan_service_info.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/expected.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/wifi_lan.h"
namespace nearby {
namespace connections {
@@ -192,7 +192,6 @@ class P2pClusterPcpHandler : public BasePcpHandler {
const std::string& service_id,
BluetoothDevice& device);
void BluetoothConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
const std::string& service_id,
BluetoothSocket socket);
@@ -232,19 +231,16 @@ class P2pClusterPcpHandler : public BasePcpHandler {
bool fast_advertisement);
void BleLegacyDeviceDiscoveredHandler();
void BleConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
BleSocket socket,
const std::string& service_id);
void BleL2capConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
BleL2capSocket socket,
const std::string& service_id);
// The refactor version of BleConnectionAcceptedHandler() and
// BleL2capConnectionAcceptedHandler above.
void BleConnectionAcceptedHandler2(ClientProxy* client,
absl::string_view local_endpoint_info,
NearbyDevice::Type device_type,
std::unique_ptr<mediums::BleSocket> socket,
const std::string& service_id);
@@ -265,8 +261,7 @@ class P2pClusterPcpHandler : public BasePcpHandler {
void AwdlServiceLostHandler(ClientProxy* client, NsdServiceInfo service_info,
const std::string& service_id);
void AwdlConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_id,
absl::string_view local_endpoint_info,
const std::string& local_endpoint_id,
NearbyDevice::Type device_type,
const std::string& service_id,
AwdlSocket socket);
@@ -290,8 +285,7 @@ class P2pClusterPcpHandler : public BasePcpHandler {
NsdServiceInfo service_info,
const std::string& service_id);
void WifiLanConnectionAcceptedHandler(ClientProxy* client,
absl::string_view local_endpoint_id,
absl::string_view local_endpoint_info,
const std::string& local_endpoint_id,
NearbyDevice::Type device_type,
const std::string& service_id,
WifiLanSocket socket);
@@ -157,6 +157,7 @@ message ConnectionResponseFrame {
optional int32 safe_to_disconnect_version = 7;
optional LocationHint location_hint = 8;
optional int32 keep_alive_timeout_millis = 9;
optional string wifi_direct_device_name = 10;
}
message PayloadTransferFrame {