diff --git a/cpp/core/core.h b/cpp/core/core.h index a191d13d..e5bf78e2 100644 --- a/cpp/core/core.h +++ b/cpp/core/core.h @@ -110,7 +110,8 @@ class Core { // available. // Possible status codes include: // Status::kSuccess if endpoint injection was attempted. - // Status::kError if bluetooth_mac_address is malformed. + // Status::kError if endpoint_id, endpoint_info, or + // remote_bluetooth_mac_address are malformed. // Status::kOutOfOrderApiCall if the app is not discovering. void InjectEndpoint(absl::string_view service_id, OutOfBandConnectionMetadata metadata, diff --git a/cpp/core/internal/BUILD b/cpp/core/internal/BUILD index 1e649fae..9ce76017 100644 --- a/cpp/core/internal/BUILD +++ b/cpp/core/internal/BUILD @@ -27,6 +27,7 @@ cc_library( "encryption_runner.cc", "endpoint_channel_manager.cc", "endpoint_manager.cc", + "injected_bluetooth_device_store.cc", "internal_payload.cc", "internal_payload_factory.cc", "offline_frames.cc", @@ -60,6 +61,7 @@ cc_library( "endpoint_channel.h", "endpoint_channel_manager.h", "endpoint_manager.h", + "injected_bluetooth_device_store.h", "internal_payload.h", "internal_payload_factory.h", "offline_frames.h", @@ -84,12 +86,13 @@ cc_library( "//core:__pkg__", ], deps = [ + ":message_lite", "//core:core_types", - "//core/internal:message_lite", "//core/internal/mediums", "//core/internal/mediums:utils", "//core/internal/mediums/webrtc", "//proto/connections:offline_wire_formats_portable_proto", + "//platform/api:comm", "//platform/base", "//platform/base:util", "//platform/public:comm", @@ -163,6 +166,7 @@ cc_test( "encryption_runner_test.cc", "endpoint_channel_manager_test.cc", "endpoint_manager_test.cc", + "injected_bluetooth_device_store_test.cc", "internal_payload_factory_test.cc", "offline_frames_test.cc", "offline_frames_validator_test.cc", @@ -183,6 +187,7 @@ cc_test( "//platform/base", "//platform/base:test_util", "//platform/impl/g3", # build_cleaner: keep + "//platform/public:comm", "//platform/public:logging", "//platform/public:types", "//proto:connections_enums_portable_proto", diff --git a/cpp/core/internal/base_endpoint_channel.cc b/cpp/core/internal/base_endpoint_channel.cc index e6674bf3..6e7fd219 100644 --- a/cpp/core/internal/base_endpoint_channel.cc +++ b/cpp/core/internal/base_endpoint_channel.cc @@ -248,6 +248,8 @@ std::string BaseEndpointChannel::GetType() const { return absl::StrCat(subtype, "WIFI_HOTSPOT"); case proto::connections::Medium::WIFI_LAN: return absl::StrCat(subtype, "WIFI_LAN"); + case proto::connections::Medium::WEB_RTC: + return absl::StrCat(subtype, "WEB_RTC"); default: return "UNKNOWN"; } diff --git a/cpp/core/internal/injected_bluetooth_device_store.cc b/cpp/core/internal/injected_bluetooth_device_store.cc new file mode 100644 index 00000000..e270e54b --- /dev/null +++ b/cpp/core/internal/injected_bluetooth_device_store.cc @@ -0,0 +1,102 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "core/internal/injected_bluetooth_device_store.h" + +#include + +#include "core/internal/bluetooth_device_name.h" +#include "platform/api/bluetooth_classic.h" +#include "platform/base/bluetooth_utils.h" + +namespace location { +namespace nearby { +namespace connections { +namespace { + +// api::BluetoothDevice implementation which stores a name and address passed to +// its constructor and trivially returns them to implement virtual functions. +class InjectedBluetoothDevice : public api::BluetoothDevice { + public: + InjectedBluetoothDevice(const std::string& name, + const std::string& mac_address) + : name_(name), mac_address_(mac_address) {} + + ~InjectedBluetoothDevice() override = default; + + // api::BluetoothDevice: + std::string GetName() const override { + return name_; + } + + std::string GetMacAddress() const override { + return mac_address_; + } + + private: + const std::string name_; + const std::string mac_address_; +}; + +} // namespace + +InjectedBluetoothDeviceStore::InjectedBluetoothDeviceStore() = default; + +InjectedBluetoothDeviceStore::~InjectedBluetoothDeviceStore() = default; + +BluetoothDevice +InjectedBluetoothDeviceStore::CreateInjectedBluetoothDevice( + const ByteArray& remote_bluetooth_mac_address, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const ByteArray& service_id_hash, + Pcp pcp) { + std::string remote_bluetooth_mac_address_str = + BluetoothUtils::ToString(remote_bluetooth_mac_address); + + // Valid MAC address is required. + if (remote_bluetooth_mac_address_str.empty()) + return BluetoothDevice(/*device=*/nullptr); + + // Non-empty endpoint info is required. + if (endpoint_info.Empty()) + return BluetoothDevice(/*device=*/nullptr); + + BluetoothDeviceName name(BluetoothDeviceName::Version::kV1, + pcp, + endpoint_id, + service_id_hash, + endpoint_info, + /*uwb_address=*/ByteArray(), + WebRtcState::kConnectable); + + // Note: BluetoothDeviceName internally verifies that |endpoint_id| and + // |service_id_hash| are valid; the check below will fail if they are + // malformed. + if (!name.IsValid()) + return BluetoothDevice(/*device=*/nullptr); + + auto injected_device = std::make_unique( + static_cast(name), remote_bluetooth_mac_address_str); + BluetoothDevice device_to_return(injected_device.get()); + + // Store underlying device to ensure that it is kept alive for future use. + devices_.emplace_back(std::move(injected_device)); + + return device_to_return; +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/injected_bluetooth_device_store.h b/cpp/core/internal/injected_bluetooth_device_store.h new file mode 100644 index 00000000..c2805c87 --- /dev/null +++ b/cpp/core/internal/injected_bluetooth_device_store.h @@ -0,0 +1,71 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CORE_INTERNAL_INJECTED_BLUETOOTH_DEVICE_STORE_H_ +#define CORE_INTERNAL_INJECTED_BLUETOOTH_DEVICE_STORE_H_ + +#include +#include + +#include "core/internal/pcp.h" +#include "platform/base/byte_array.h" +#include "platform/public/bluetooth_adapter.h" + +namespace location { +namespace nearby { +namespace connections { + +// Creates and stores BluetoothDevice objects which have been "injected" (i.e., +// passed to Nearby Connections manually by the client instead of through the +// normal discovery flow). +class InjectedBluetoothDeviceStore { + public: + InjectedBluetoothDeviceStore(); + ~InjectedBluetoothDeviceStore(); + + // Creates an injected BluetoothDevice given the provided parameters: + // |remote_bluetooth_mac_address|: A 6-byte MAC address. + // |endpoint_id|: A string of length 4. + // |endpoint_info|: A non-empty ByteArray whose length is <=131 bytes. + // |service_id_hash|: A ByteArray whose length is 3. + // |pcp|: PCP value to be used for the connection to this device. + // + // If the provided parameters are malformed or of incorrect length, this + // function returns an invalid BluetoothDevice. Clients should use + // BluetoothDevice::IsValid() with the returned device to verify that the + // parameters were successfully processed. + // + // Note that successfully-injected devices stay valid for the lifetime of the + // InjectedBluetoothDeviceStore and are not cleared until this object is + // deleted. + BluetoothDevice CreateInjectedBluetoothDevice( + const ByteArray& remote_bluetooth_mac_address, + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const ByteArray& service_id_hash, + Pcp pcp); + + private: + // Devices created by this class. BluetoothDevice objects returned by + // CreateInjectedBluetoothDevice() store pointers to underlying + // api::BluetoothDevice objects, so this maintains these underlying devices + // to ensure that they are not deleted before they are referenced. + std::vector> devices_; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_INJECTED_BLUETOOTH_DEVICE_STORE_H_ diff --git a/cpp/core/internal/injected_bluetooth_device_store_test.cc b/cpp/core/internal/injected_bluetooth_device_store_test.cc new file mode 100644 index 00000000..87ae4266 --- /dev/null +++ b/cpp/core/internal/injected_bluetooth_device_store_test.cc @@ -0,0 +1,121 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "core/internal/injected_bluetooth_device_store.h" + +#include + +#include "core/internal/bluetooth_device_name.h" +#include "platform/base/bluetooth_utils.h" +#include "platform/base/byte_array.h" +#include "platform/public/bluetooth_adapter.h" +#include "gtest/gtest.h" + +namespace location { +namespace nearby { +namespace connections { +namespace { + +constexpr std::array + kTestRemoteBluetoothMacAddress{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}; +constexpr std::array kTestEndpointInfo {0xcd, 0xef}; +constexpr std::array kTestServiceIdHash{0x01, 0x23, 0x45}; + +const char kTestEndpointId[] = "abcd"; + +class InjectedBluetoothDeviceStoreTest : public testing::Test { + protected: + InjectedBluetoothDeviceStore store_; +}; + +TEST_F(InjectedBluetoothDeviceStoreTest, Success) { + ByteArray remote_bluetooth_mac_address(kTestRemoteBluetoothMacAddress); + ByteArray endpoint_info(kTestEndpointInfo); + ByteArray service_id_hash(kTestServiceIdHash); + + BluetoothDevice device = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, kTestEndpointId, endpoint_info, + service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_TRUE(device.IsValid()); + + EXPECT_EQ(BluetoothUtils::ToString(remote_bluetooth_mac_address), + device.GetMacAddress()); + + BluetoothDeviceName name(device.GetName()); + EXPECT_TRUE(name.IsValid()); + EXPECT_EQ(kTestEndpointId, name.GetEndpointId()); + EXPECT_EQ(endpoint_info, name.GetEndpointInfo()); + EXPECT_EQ(service_id_hash, name.GetServiceIdHash()); + EXPECT_EQ(Pcp::kP2pPointToPoint, name.GetPcp()); +} + +TEST_F(InjectedBluetoothDeviceStoreTest, Fail_InvalidBluetoothMac) { + // Use address with only 1 byte. + ByteArray remote_bluetooth_mac_address(std::array{0x00}); + ByteArray endpoint_info(kTestEndpointInfo); + ByteArray service_id_hash(kTestServiceIdHash); + + BluetoothDevice device = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, kTestEndpointId, endpoint_info, + service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_FALSE(device.IsValid()); +} + +TEST_F(InjectedBluetoothDeviceStoreTest, Fail_InvalidEndpointId) { + ByteArray remote_bluetooth_mac_address(kTestRemoteBluetoothMacAddress); + ByteArray endpoint_info(kTestEndpointInfo); + ByteArray service_id_hash(kTestServiceIdHash); + + // Use empty endpoint ID. + BluetoothDevice device1 = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, /*endpoint_id=*/std::string(), + endpoint_info, service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_FALSE(device1.IsValid()); + + // Use endpoint ID of wrong length. + const std::string too_long_endpoint_id = "abcde"; + BluetoothDevice device2 = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, too_long_endpoint_id, endpoint_info, + service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_FALSE(device2.IsValid()); +} + +TEST_F(InjectedBluetoothDeviceStoreTest, Fail_EmptyEndpointInfo) { + ByteArray remote_bluetooth_mac_address(kTestRemoteBluetoothMacAddress); + // Use empty endpoint info. + ByteArray endpoint_info; + ByteArray service_id_hash(kTestServiceIdHash); + + BluetoothDevice device = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, kTestEndpointId, endpoint_info, + service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_FALSE(device.IsValid()); +} + +TEST_F(InjectedBluetoothDeviceStoreTest, Fail_InvalidServiceIdHash) { + ByteArray remote_bluetooth_mac_address(kTestRemoteBluetoothMacAddress); + ByteArray endpoint_info(kTestEndpointInfo); + // Use address with only 1 byte. + ByteArray service_id_hash(std::array{0x00}); + + BluetoothDevice device = store_.CreateInjectedBluetoothDevice( + remote_bluetooth_mac_address, kTestEndpointId, endpoint_info, + service_id_hash, Pcp::kP2pPointToPoint); + EXPECT_FALSE(device.IsValid()); +} + +} // namespace +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/offline_service_controller.h b/cpp/core/internal/offline_service_controller.h index a38181db..1c29b83d 100644 --- a/cpp/core/internal/offline_service_controller.h +++ b/cpp/core/internal/offline_service_controller.h @@ -23,6 +23,7 @@ #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" +#include "core/internal/injected_bluetooth_device_store.h" #include "core/internal/mediums/mediums.h" #include "core/internal/payload_manager.h" #include "core/internal/pcp_manager.h" @@ -87,8 +88,9 @@ class OfflineServiceController : public ServiceController { PayloadManager payload_manager_{endpoint_manager_}; BwuManager bwu_manager_{ mediums_, endpoint_manager_, channel_manager_, {}, {}}; + InjectedBluetoothDeviceStore injected_bluetooth_device_store_; PcpManager pcp_manager_{mediums_, channel_manager_, endpoint_manager_, - bwu_manager_}; + bwu_manager_, injected_bluetooth_device_store_}; }; } // namespace connections diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.cc b/cpp/core/internal/p2p_cluster_pcp_handler.cc index 457f8e35..5e1ef4ca 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler.cc @@ -51,6 +51,7 @@ bool P2pClusterPcpHandler::ShouldAcceptBluetoothConnections( P2pClusterPcpHandler::P2pClusterPcpHandler( Mediums* mediums, EndpointManager* endpoint_manager, EndpointChannelManager* endpoint_channel_manager, BwuManager* bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, Pcp pcp) : BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, bwu_manager, pcp), @@ -58,7 +59,8 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( bluetooth_medium_(mediums->GetBluetoothClassic()), ble_medium_(mediums->GetBle()), wifi_lan_medium_(mediums->GetWifiLan()), - webrtc_medium_(mediums->GetWebRtc()) {} + webrtc_medium_(mediums->GetWebRtc()), + injected_bluetooth_device_store_(injected_bluetooth_device_store) {} // Returns a vector or mediums sorted in order or decreasing priority for // all the supported mediums. @@ -638,21 +640,20 @@ Status P2pClusterPcpHandler::InjectEndpointImpl( NEARBY_LOG(INFO, "InjectEndpoint"); // Bluetooth is the only supported out-of-band connection medium. if (metadata.medium != Medium::BLUETOOTH) { - NEARBY_LOG(WARNING, "StartDiscoveryImpl: Only Bluetooth is supported"); + NEARBY_LOG(WARNING, "InjectEndpointImpl: Only Bluetooth is supported"); return {Status::kError}; } - std::string remote_bluetooth_mac_address = - BluetoothUtils::ToString(metadata.remote_bluetooth_mac_address); - if (remote_bluetooth_mac_address.empty()) { - NEARBY_LOG(WARNING, "StartDiscoveryImpl: Missing Bluetooth MAC"); - return {Status::kError}; - } + BluetoothDevice remote_bluetooth_device = + injected_bluetooth_device_store_.CreateInjectedBluetoothDevice( + metadata.remote_bluetooth_mac_address, + metadata.endpoint_id, + metadata.endpoint_info, + GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength), + GetPcp()); - auto remote_bluetooth_device = - GetRemoteBluetoothDevice(remote_bluetooth_mac_address); if (!remote_bluetooth_device.IsValid()) { - NEARBY_LOG(WARNING, "StartDiscoveryImpl: Invalid Bluetooth MAC"); + NEARBY_LOG(WARNING, "InjectEndpointImpl: Invalid parameters"); return {Status::kError}; } diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.h b/cpp/core/internal/p2p_cluster_pcp_handler.h index 5b0b1ed8..e60c527d 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core/internal/p2p_cluster_pcp_handler.h @@ -25,6 +25,7 @@ #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" +#include "core/internal/injected_bluetooth_device_store.h" #include "core/internal/mediums/bluetooth_classic.h" #include "core/internal/mediums/mediums.h" #include "core/internal/mediums/webrtc.h" @@ -51,10 +52,11 @@ namespace connections { // connects over Bluetooth. class P2pClusterPcpHandler : public BasePcpHandler { public: - P2pClusterPcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, - BwuManager* bwu_manager, - Pcp pcp = Pcp::kP2pCluster); + P2pClusterPcpHandler( + Mediums* mediums, EndpointManager* endpoint_manager, + EndpointChannelManager* channel_manager, BwuManager* bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, + Pcp pcp = Pcp::kP2pCluster); ~P2pClusterPcpHandler() override = default; protected: @@ -218,6 +220,7 @@ class P2pClusterPcpHandler : public BasePcpHandler { Ble& ble_medium_; WifiLan& wifi_lan_medium_; mediums::WebRtc& webrtc_medium_; + InjectedBluetoothDeviceStore& injected_bluetooth_device_store_; }; } // namespace connections diff --git a/cpp/core/internal/p2p_cluster_pcp_handler_test.cc b/cpp/core/internal/p2p_cluster_pcp_handler_test.cc index a9572c2a..74b7e961 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler_test.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler_test.cc @@ -17,6 +17,7 @@ #include #include "core/internal/bwu_manager.h" +#include "core/internal/injected_bluetooth_device_store.h" #include "core/options.h" #include "platform/base/medium_environment.h" #include "platform/public/count_down_latch.h" @@ -77,7 +78,8 @@ TEST_P(P2pClusterPcpHandlerTest, CanConstructOne) { EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(mediums, em, ecm, {}, {}); - P2pClusterPcpHandler handler(&mediums, &em, &ecm, &bwu); + InjectedBluetoothDeviceStore ibds; + P2pClusterPcpHandler handler(&mediums, &em, &ecm, &bwu, ibds); env_.Stop(); } @@ -91,8 +93,10 @@ TEST_P(P2pClusterPcpHandlerTest, CanConstructMultiple) { EndpointManager em_b(&ecm_b); BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {}); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); + InjectedBluetoothDeviceStore ibds_a; + InjectedBluetoothDeviceStore ibds_b; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b); env_.Stop(); } @@ -103,7 +107,8 @@ TEST_P(P2pClusterPcpHandlerTest, CanAdvertise) { EndpointChannelManager ecm_a; EndpointManager em_a(&ecm_a); BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); + InjectedBluetoothDeviceStore ibds_a; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); EXPECT_EQ( handler_a.StartAdvertising(&client_a_, service_id_, options_, {.endpoint_info = ByteArray{endpoint_name}}), @@ -122,8 +127,10 @@ TEST_P(P2pClusterPcpHandlerTest, CanDiscover) { EndpointManager em_b(&ecm_b); BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {}); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); + InjectedBluetoothDeviceStore ibds_a; + InjectedBluetoothDeviceStore ibds_b; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b); CountDownLatch latch(1); EXPECT_EQ( handler_a.StartAdvertising(&client_a_, service_id_, options_, @@ -166,8 +173,10 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { {.allow_upgrade_to = {.bluetooth = true}}); BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {.allow_upgrade_to = {.bluetooth = true}}); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); + InjectedBluetoothDeviceStore ibds_a; + InjectedBluetoothDeviceStore ibds_b; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b); CountDownLatch discover_latch(1); CountDownLatch connect_latch(2); struct DiscoveredInfo { diff --git a/cpp/core/internal/p2p_point_to_point_pcp_handler.cc b/cpp/core/internal/p2p_point_to_point_pcp_handler.cc index 1bc0fa6a..2ac80e78 100644 --- a/cpp/core/internal/p2p_point_to_point_pcp_handler.cc +++ b/cpp/core/internal/p2p_point_to_point_pcp_handler.cc @@ -20,9 +20,10 @@ namespace connections { P2pPointToPointPcpHandler::P2pPointToPointPcpHandler( Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, BwuManager& bwu_manager, Pcp pcp) + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, Pcp pcp) : P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, bwu_manager, - pcp) {} + injected_bluetooth_device_store, pcp) {} std::vector P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { diff --git a/cpp/core/internal/p2p_point_to_point_pcp_handler.h b/cpp/core/internal/p2p_point_to_point_pcp_handler.h index 7c11b438..fa6ac46c 100644 --- a/cpp/core/internal/p2p_point_to_point_pcp_handler.h +++ b/cpp/core/internal/p2p_point_to_point_pcp_handler.h @@ -34,10 +34,11 @@ namespace connections { // and connects over Bluetooth. class P2pPointToPointPcpHandler : public P2pStarPcpHandler { public: - P2pPointToPointPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, - Pcp pcp = Pcp::kP2pPointToPoint); + P2pPointToPointPcpHandler( + Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, + Pcp pcp = Pcp::kP2pPointToPoint); protected: std::vector GetConnectionMediumsByPriority() diff --git a/cpp/core/internal/p2p_star_pcp_handler.cc b/cpp/core/internal/p2p_star_pcp_handler.cc index a7b140bf..72cd9add 100644 --- a/cpp/core/internal/p2p_star_pcp_handler.cc +++ b/cpp/core/internal/p2p_star_pcp_handler.cc @@ -20,12 +20,13 @@ namespace location { namespace nearby { namespace connections { -P2pStarPcpHandler::P2pStarPcpHandler(Mediums& mediums, - EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, Pcp pcp) +P2pStarPcpHandler::P2pStarPcpHandler( + Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, Pcp pcp) : P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, - &bwu_manager, pcp) {} + &bwu_manager, injected_bluetooth_device_store, + pcp) {} std::vector P2pStarPcpHandler::GetConnectionMediumsByPriority() { diff --git a/cpp/core/internal/p2p_star_pcp_handler.h b/cpp/core/internal/p2p_star_pcp_handler.h index a5362a14..cc01c717 100644 --- a/cpp/core/internal/p2p_star_pcp_handler.h +++ b/cpp/core/internal/p2p_star_pcp_handler.h @@ -37,10 +37,11 @@ namespace connections { // and connects over Bluetooth. class P2pStarPcpHandler : public P2pClusterPcpHandler { public: - P2pStarPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, - BwuManager& bwu_manager, - Pcp pcp = Pcp::kP2pStar); + P2pStarPcpHandler( + Mediums& mediums, EndpointManager& endpoint_manager, + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store, + Pcp pcp = Pcp::kP2pStar); protected: std::vector GetConnectionMediumsByPriority() diff --git a/cpp/core/internal/pcp_manager.cc b/cpp/core/internal/pcp_manager.cc index 4b8da2ed..a811527a 100644 --- a/cpp/core/internal/pcp_manager.cc +++ b/cpp/core/internal/pcp_manager.cc @@ -23,17 +23,20 @@ namespace location { namespace nearby { namespace connections { -PcpManager::PcpManager(Mediums& mediums, - EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager, - BwuManager& bwu_manager) { +PcpManager::PcpManager( + Mediums& mediums, EndpointChannelManager& channel_manager, + EndpointManager& endpoint_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store) { handlers_[Pcp::kP2pCluster] = std::make_unique( - &mediums, &endpoint_manager, &channel_manager, &bwu_manager); + &mediums, &endpoint_manager, &channel_manager, &bwu_manager, + injected_bluetooth_device_store); handlers_[Pcp::kP2pStar] = std::make_unique( - mediums, endpoint_manager, channel_manager, bwu_manager); + mediums, endpoint_manager, channel_manager, bwu_manager, + injected_bluetooth_device_store); handlers_[Pcp::kP2pPointToPoint] = - std::make_unique(mediums, endpoint_manager, - channel_manager, bwu_manager); + std::make_unique( + mediums, endpoint_manager, channel_manager, bwu_manager, + injected_bluetooth_device_store); } void PcpManager::DisconnectFromEndpointManager() { diff --git a/cpp/core/internal/pcp_manager.h b/cpp/core/internal/pcp_manager.h index a303fb03..16708d62 100644 --- a/cpp/core/internal/pcp_manager.h +++ b/cpp/core/internal/pcp_manager.h @@ -22,6 +22,7 @@ #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" +#include "core/internal/injected_bluetooth_device_store.h" #include "core/internal/mediums/mediums.h" #include "core/listeners.h" #include "core/options.h" @@ -44,7 +45,8 @@ namespace connections { class PcpManager { public: PcpManager(Mediums& mediums, EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager, BwuManager& bwu_manager); + EndpointManager& endpoint_manager, BwuManager& bwu_manager, + InjectedBluetoothDeviceStore& injected_bluetooth_device_store); ~PcpManager(); Status StartAdvertising(ClientProxy* client, const string& service_id, diff --git a/cpp/core/internal/service_controller_router.cc b/cpp/core/internal/service_controller_router.cc index 53cc2b71..966fbfbd 100644 --- a/cpp/core/internal/service_controller_router.cc +++ b/cpp/core/internal/service_controller_router.cc @@ -31,7 +31,18 @@ namespace location { namespace nearby { namespace connections { namespace { +// Length of a MAC address, which consists of 6 bytes uniquely identifying a +// hardware interface. const std::size_t kMacAddressLength = 6u; + +// Length used for an endpoint ID, which identifies a device discovery and +// associated connection request. +const std::size_t kEndpointIdLength = 4u; + +// Maximum length for information describing an endpoint; this information is +// advertised by one device and can be used by the other device to identify the +// advertiser. +const std::size_t kMaxEndpointInfoLength = 131u; } // namespace ServiceControllerRouter::~ServiceControllerRouter() { @@ -122,6 +133,17 @@ void ServiceControllerRouter::InjectEndpoint( return; } + if (metadata.endpoint_id.size() != kEndpointIdLength) { + callback.result_cb({Status::kError}); + return; + } + + if (metadata.endpoint_info.Empty() || + metadata.endpoint_info.size() > kMaxEndpointInfoLength) { + callback.result_cb({Status::kError}); + return; + } + if (!ClientHasAcquiredServiceController(client) || !client->IsDiscovering()) { callback.result_cb({Status::kOutOfOrderApiCall}); diff --git a/cpp/core/internal/service_controller_router_test.cc b/cpp/core/internal/service_controller_router_test.cc index 40266651..5af7331b 100644 --- a/cpp/core/internal/service_controller_router_test.cc +++ b/cpp/core/internal/service_controller_router_test.cc @@ -42,6 +42,8 @@ namespace connections { namespace { using ::testing::Return; constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; +constexpr std::array kFakeInjectedEndpointInfo = {'g', 'h', 'i'}; +const char kFakeInejctedEndpointId[] = "abcd"; } // namespace // This class must be in the same namespace as ServiceControllerRouter for @@ -270,6 +272,8 @@ class ServiceControllerRouterTest : public testing::Test { }; const OutOfBandConnectionMetadata kOutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, + .endpoint_id = kFakeInejctedEndpointId, + .endpoint_info = ByteArray(kFakeInjectedEndpointInfo), .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }; diff --git a/cpp/core/internal/simulation_user.h b/cpp/core/internal/simulation_user.h index d26ca7a4..14152bf0 100644 --- a/cpp/core/internal/simulation_user.h +++ b/cpp/core/internal/simulation_user.h @@ -21,6 +21,7 @@ #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel_manager.h" #include "core/internal/endpoint_manager.h" +#include "core/internal/injected_bluetooth_device_store.h" #include "core/internal/payload_manager.h" #include "core/internal/pcp_manager.h" #include "core/options.h" @@ -151,7 +152,8 @@ class SimulationUser { EndpointChannelManager ecm_; EndpointManager em_{&ecm_}; BwuManager bwu_{mediums_, em_, ecm_, {}, {}}; - PcpManager mgr_{mediums_, ecm_, em_, bwu_}; + InjectedBluetoothDeviceStore injected_bluetooth_device_store_; + PcpManager mgr_{mediums_, ecm_, em_, bwu_, injected_bluetooth_device_store_}; PayloadManager pm_{em_}; }; diff --git a/cpp/core/options.h b/cpp/core/options.h index 4ddb89c4..100e80e3 100644 --- a/cpp/core/options.h +++ b/cpp/core/options.h @@ -142,6 +142,19 @@ struct OutOfBandConnectionMetadata { // Medium to use for the out-of-band connection. Medium medium; + // Endpoint ID to use for the injected connection; will be included in the + // endpoint_found_cb callback. Must be exactly 4 bytes and should be randomly- + // generated such that no two IDs are identical. + std::string endpoint_id; + + // Endpoint info to use for the injected connection; will be included in the + // endpoint_found_cb callback. Should uniquely identify the InjectEndpoint() + // call so that the client which made the call can verify the endpoint + // that was found is the one that was injected. + // + // Cannot be empty, and must be <131 bytes. + ByteArray endpoint_info; + // Used for Bluetooth connections. ByteArray remote_bluetooth_mac_address; }; diff --git a/cpp/platform/api/BUILD b/cpp/platform/api/BUILD index 22ca17e5..313b8f00 100644 --- a/cpp/platform/api/BUILD +++ b/cpp/platform/api/BUILD @@ -59,6 +59,7 @@ cc_library( "wifi_lan.h", ], visibility = [ + "//core/internal:__subpackages__", "//platform/base:__pkg__", "//platform/impl:__subpackages__", "//platform/public:__pkg__",