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