[Nearby Connections] Plumb remote device information much deeper into the stack

This will be needed for the authentication transport as the verifier will need the information about the remote device. This CL is based on logic from
awadhera@ in cl/539175992 with additional unit test coverage.

PiperOrigin-RevId: 565037849
This commit is contained in:
Juliet Levesque
2023-09-13 06:59:50 -07:00
committed by Copybara-Service
parent fe9c9f90b6
commit 8be118a3d0
20 changed files with 712 additions and 33 deletions
@@ -39,6 +39,7 @@
#include "connections/implementation/endpoint_manager.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/mediums.h"
#include "connections/implementation/mock_device.h"
#include "connections/implementation/offline_frames.h"
#include "connections/implementation/pcp.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
@@ -71,9 +72,12 @@ using ::testing::_;
using ::testing::AtLeast;
using ::testing::Invoke;
using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::StrictMock;
constexpr absl::string_view kTestEndpointId = "REMOTETEST";
constexpr std::array<char, 6> kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'};
constexpr BooleanMediumSelector kTestCases[] = {
@@ -108,7 +112,7 @@ constexpr BooleanMediumSelector kTestCases[] = {
class FakePresenceDevice : public NearbyDevice {
public:
std::string GetEndpointId() const override { return "TEST"; }
std::string GetEndpointId() const override { return "LOCALTEST"; }
MOCK_METHOD(std::vector<ConnectionInfoVariant>, GetConnectionInfos, (),
(const override));
MOCK_METHOD(NearbyDevice::Type, GetType, (), (const override));
@@ -498,6 +502,10 @@ class BasePcpHandlerTest
std::move(output_b));
auto channel_b = std::make_unique<MockEndpointChannel>(std::move(input_b),
std::move(output_a));
ON_CALL(mock_device_, GetType)
.WillByDefault(Return(NearbyDevice::Type::kUnknownDevice));
ON_CALL(mock_device_, GetEndpointId)
.WillByDefault(Return(std::string(kTestEndpointId)));
// On initiator (A) side, we drop the first write, since this is a
// connection establishment packet, and we don't have the peer entity, just
// the peer channel. The rest of the exchange must happen for the benefit of
@@ -530,6 +538,46 @@ class BasePcpHandlerTest
return std::make_pair(std::move(channel_a), std::move(channel_b));
}
std::pair<std::unique_ptr<MockEndpointChannel>,
std::unique_ptr<MockEndpointChannel>>
SetupConnectionForConnectFailure(
location::nearby::proto::connections::Medium medium) { // NOLINT
auto [input_a, output_a] = CreatePipe();
auto [input_b, output_b] = CreatePipe();
auto channel_a = std::make_unique<MockEndpointChannel>(std::move(input_a),
std::move(output_b));
auto channel_b = std::make_unique<MockEndpointChannel>(std::move(input_b),
std::move(output_a));
ON_CALL(mock_device_, GetType)
.WillByDefault(Return(NearbyDevice::Type::kUnknownDevice));
ON_CALL(mock_device_, GetEndpointId)
.WillByDefault(Return(std::string(kTestEndpointId)));
// On initiator (A) side, we drop the first write, since this is a
// connection establishment packet, and we don't have the peer entity, just
// the peer channel. The rest of the exchange must happen for the benefit of
// DH key exchange.
EXPECT_CALL(*channel_a, Read())
.WillRepeatedly(Invoke(
[channel = channel_a.get()]() { return channel->DoRead(); }));
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_a, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false));
EXPECT_CALL(*channel_b, Read())
.WillRepeatedly(Invoke(
[channel = channel_b.get()]() { return channel->DoRead(); }));
EXPECT_CALL(*channel_b, Write(_))
.WillRepeatedly(
Invoke([channel = channel_b.get()](const ByteArray& data) {
return channel->DoWrite(data);
}));
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
.WillRepeatedly(Return(absl::Now()));
EXPECT_CALL(*channel_b, IsPaused).WillRepeatedly(Return(false));
return std::make_pair(std::move(channel_a), std::move(channel_b));
}
void RequestConnection(
const std::string& endpoint_id,
std::unique_ptr<MockEndpointChannel> channel_a,
@@ -601,6 +649,76 @@ class BasePcpHandlerTest
NEARBY_LOG(INFO, "Stopping Encryption Runner");
}
void RequestConnectionV3(
const NearbyDevice& remote_device,
std::unique_ptr<MockEndpointChannel> channel_a,
MockEndpointChannel* channel_b, ClientProxy* client,
MockPcpHandler* pcp_handler,
location::nearby::proto::connections::Medium connect_medium,
std::atomic_int* flag = nullptr,
Status expected_result = {Status::kSuccess}) {
ConnectionRequestInfo info{
.endpoint_info = ByteArray{"ABCD"},
.listener = connection_listener_,
};
ConnectionOptions connection_options{
.remote_bluetooth_mac_address = ByteArray{"\x12\x34\x56\x78\x9a\xbc"},
.keep_alive_interval_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis,
.keep_alive_timeout_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis,
};
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call);
EXPECT_CALL(*pcp_handler, CanSendOutgoingConnection)
.WillRepeatedly(Return(true));
EXPECT_CALL(*pcp_handler, GetStrategy)
.WillRepeatedly(Return(Strategy::kP2pCluster));
if (expected_result == Status{Status::kSuccess}) {
EXPECT_CALL(mock_connection_listener_.initiated_cb, Call).Times(1);
}
// Simulate successful discovery.
auto encryption_runner = std::make_unique<EncryptionRunner>();
auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client);
EXPECT_CALL(*pcp_handler, ConnectImpl)
.WillRepeatedly(
Invoke([&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(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
remote_device.GetEndpointId(),
info.endpoint_info,
"service",
discovered_medium,
WebRtcState::kUndefined,
},
MockContext{flag},
}));
}
auto other_client = std::make_unique<ClientProxy>();
// Run peer crypto in advance, if channel_b is provided.
// Otherwise stay in not-encrypted state.
if (channel_b != nullptr) {
encryption_runner->StartServer(
other_client.get(), remote_device.GetEndpointId(), channel_b, {});
}
EXPECT_EQ(pcp_handler->RequestConnectionV3(client, remote_device, info,
connection_options),
expected_result);
}
void RequestConnectionWifiLanFail(
const std::string& endpoint_id,
std::unique_ptr<MockEndpointChannel> channel_a,
@@ -704,6 +822,7 @@ class BasePcpHandlerTest
};
SetSafeToDisconnect set_safe_to_disconnect_{true};
MediumEnvironment& env_ = MediumEnvironment::Instance();
NiceMock<MockNearbyDevice> mock_device_;
};
TEST_P(BasePcpHandlerTest, ConstructorDestructorWorks) {
@@ -955,7 +1074,6 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) {
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) {
@@ -989,6 +1107,216 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) {
env_.Stop();
}
TEST_P(BasePcpHandlerTest, RequestConnectionV3) {
env_.Start();
ClientProxy client;
FakePresenceDeviceProvider provider;
EXPECT_CALL(provider.local_device_, GetType)
.WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice));
EXPECT_CALL(provider.local_device_, ToProtoBytes);
client.RegisterDeviceProvider(&provider);
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
StartDiscovery(&client, &pcp_handler);
auto mediums = pcp_handler.GetDiscoveryMediums(&client);
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
const auto& channel_b = channel_pair.second;
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
&client, &pcp_handler, connect_medium);
NEARBY_LOG(INFO, "RequestConnectionV3 complete");
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) {
env_.Start();
ClientProxy client;
FakePresenceDeviceProvider provider;
EXPECT_CALL(provider.local_device_, GetType)
.WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice));
client.RegisterDeviceProvider(&provider);
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
StartDiscovery(&client, &pcp_handler);
auto mediums = pcp_handler.GetDiscoveryMediums(&client);
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
const auto& channel_b = channel_pair.second;
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
ConnectionRequestInfo info{
.endpoint_info = ByteArray{"ABCD"},
.listener = connection_listener_,
};
ConnectionOptions connection_options{
.remote_bluetooth_mac_address = ByteArray{"\x12\x34\x56\x78\x9a\xbc"},
.keep_alive_interval_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis,
.keep_alive_timeout_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis,
};
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call);
EXPECT_CALL(pcp_handler, CanSendOutgoingConnection)
.WillRepeatedly(Return(true));
EXPECT_CALL(pcp_handler, GetStrategy)
.WillRepeatedly(Return(Strategy::kP2pCluster));
// Simulate successful discovery.
auto encryption_runner = std::make_unique<EncryptionRunner>();
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(&client);
EXPECT_CALL(pcp_handler, ConnectImpl)
.WillRepeatedly(Invoke(
[connect_medium](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
.medium = connect_medium,
.status = {Status::kError},
.endpoint_channel = nullptr,
};
}));
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler.OnEndpointFound(
&client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
mock_device_.GetEndpointId(),
info.endpoint_info,
"service",
discovered_medium,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
}
Status expected_result = {Status::kError};
EXPECT_EQ(pcp_handler.RequestConnectionV3(&client, mock_device_, info,
connection_options),
expected_result);
NEARBY_LOG(INFO, "RequestConnectionV3 complete");
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) {
env_.Start();
ClientProxy client;
FakePresenceDeviceProvider provider;
EXPECT_CALL(provider.local_device_, GetType)
.WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice));
client.RegisterDeviceProvider(&provider);
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
StartDiscovery(&client, &pcp_handler);
auto mediums = pcp_handler.GetDiscoveryMediums(&client);
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
const auto& channel_b = channel_pair.second;
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
ConnectionRequestInfo info{
.endpoint_info = ByteArray{"ABCD"},
.listener = connection_listener_,
};
ConnectionOptions connection_options{
.remote_bluetooth_mac_address = ByteArray{"\x12\x34\x56\x78\x9a\xbc"},
.keep_alive_interval_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis,
.keep_alive_timeout_millis =
FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis,
};
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call);
EXPECT_CALL(pcp_handler, CanSendOutgoingConnection)
.WillRepeatedly(Return(true));
EXPECT_CALL(pcp_handler, GetStrategy)
.WillRepeatedly(Return(Strategy::kP2pCluster));
// Simulate successful discovery.
auto encryption_runner = std::make_unique<EncryptionRunner>();
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(&client);
EXPECT_CALL(pcp_handler, ConnectImpl)
.WillRepeatedly(Invoke(
[connect_medium](ClientProxy* client,
MockPcpHandler::DiscoveredEndpoint* endpoint) {
return MockPcpHandler::ConnectImplResult{
.medium = connect_medium,
.status = {Status::kError},
.endpoint_channel = nullptr,
};
}));
for (const auto& discovered_medium : allowed_mediums) {
pcp_handler.OnEndpointFound(
&client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
std::string(kTestEndpointId),
info.endpoint_info,
"service",
discovered_medium,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
}
Status expected_result = {Status::kError};
EXPECT_EQ(pcp_handler.RequestConnection(&client, std::string(kTestEndpointId),
info, connection_options),
expected_result);
NEARBY_LOG(INFO, "RequestConnection complete");
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, IoError_RequestConnectionV3Fails) {
env_.Start();
ClientProxy client;
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
StartDiscovery(&client, &pcp_handler);
auto mediums = pcp_handler.GetDiscoveryMediums(&client);
auto connect_medium = mediums[mediums.size() - 1];
auto channel_pair = SetupConnection(connect_medium);
auto& channel_a = channel_pair.first;
auto& channel_b = channel_pair.second;
EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1));
EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1));
channel_b->broken_write_ = true;
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
&client, &pcp_handler, connect_medium, nullptr,
{Status::kEndpointIoError});
NEARBY_LOG(INFO, "RequestConnectionV3 complete");
channel_b->Close();
bwu.Shutdown();
pcp_handler.DisconnectFromEndpointManager();
env_.Stop();
}
TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) {
env_.Start();
std::string endpoint_id{"1234"};