diff --git a/Package.swift b/Package.swift index 2412cd33..321d0af2 100644 --- a/Package.swift +++ b/Package.swift @@ -432,6 +432,7 @@ let package = Package( "connections/implementation/payload_manager_test.cc", "connections/implementation/offline_frames_validator_test.cc", "connections/implementation/service_controller_router_test.cc", + "connections/implementation/wifi_direct_bwu_test.cc", "connections/implementation/wifi_hotspot_test.cc", "connections/implementation/analytics/analytics_recorder_test.cc", "connections/implementation/analytics/throughput_recorder_test.cc", diff --git a/connections/clients/windows/connection_options_w.h b/connections/clients/windows/connection_options_w.h index 753662f0..11a4bcc3 100644 --- a/connections/clients/windows/connection_options_w.h +++ b/connections/clients/windows/connection_options_w.h @@ -22,7 +22,7 @@ namespace location::nearby::windows { extern "C" { -#define MAX_MEDIUMS 5 +#define MAX_MEDIUMS 6 // Feature On/Off switch for mediums. using BooleanMediumSelector = MediumSelectorW; diff --git a/connections/clients/windows/medium_selector_w.h b/connections/clients/windows/medium_selector_w.h index 15321380..8ae801dd 100644 --- a/connections/clients/windows/medium_selector_w.h +++ b/connections/clients/windows/medium_selector_w.h @@ -28,18 +28,19 @@ struct MediumSelectorW { T web_rtc; T wifi_lan; T wifi_hotspot; + T wifi_direct; constexpr MediumSelectorW() = default; constexpr MediumSelectorW(const MediumSelectorW&) = default; constexpr MediumSelectorW& operator=(const MediumSelectorW&) = default; constexpr bool Any(const T& value) const { return bluetooth == value || ble == value || web_rtc == value || - wifi_lan == value || wifi_hotspot == value; + wifi_lan == value || wifi_hotspot == value || wifi_direct == value; } constexpr bool All(const T& value) const { return bluetooth == value && ble == value && web_rtc == value && - wifi_lan == value && wifi_hotspot == value; + wifi_lan == value && wifi_hotspot == value && wifi_direct == value; } constexpr int Count(const T& value) const { @@ -48,6 +49,7 @@ struct MediumSelectorW { if (ble == value) ++count; if (wifi_lan == value) ++count; if (wifi_hotspot == value) ++count; + if (wifi_direct == value) ++count; if (web_rtc == value) ++count; return count; } @@ -58,6 +60,7 @@ struct MediumSelectorW { web_rtc = value; wifi_lan = value; wifi_hotspot = value; + wifi_direct = value; return *this; } @@ -65,6 +68,7 @@ struct MediumSelectorW { std::vector mediums; // Mediums are sorted in order of decreasing preference. if (wifi_lan == value) mediums.push_back(MediumW::WIFI_LAN); + if (wifi_direct == value) mediums.push_back(MediumW::WIFI_DIRECT); if (wifi_hotspot == value) mediums.push_back(MediumW::WIFI_HOTSPOT); if (web_rtc == value) mediums.push_back(MediumW::WEB_RTC); if (bluetooth == value) mediums.push_back(MediumW::BLUETOOTH); diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 4d1ce4f8..b782d0b6 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -67,6 +67,8 @@ cc_library( "pcp_manager.cc", "service_controller_router.cc", "webrtc_endpoint_channel.cc", + "wifi_direct_bwu_handler.cc", + "wifi_direct_endpoint_channel.cc", "wifi_hotspot_bwu_handler.cc", "wifi_hotspot_endpoint_channel.cc", "wifi_lan_bwu_handler.cc", @@ -114,6 +116,8 @@ cc_library( "service_controller_router.h", "service_id_constants.h", "webrtc_endpoint_channel.h", + "wifi_direct_bwu_handler.h", + "wifi_direct_endpoint_channel.h", "wifi_hotspot_bwu_handler.h", "wifi_hotspot_endpoint_channel.h", "wifi_lan_bwu_handler.h", @@ -241,6 +245,7 @@ cc_test( "payload_manager_test.cc", "pcp_manager_test.cc", "service_controller_router_test.cc", + "wifi_direct_bwu_test.cc", "wifi_hotspot_test.cc", "wifi_lan_service_info_test.cc", ], diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index 3b5081cf..ab789067 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -179,6 +179,9 @@ void BasePcpHandler::OptionsAllowed(const BooleanMediumSelector& allowed, if (allowed.wifi_hotspot) { result << proto::connections::Medium_Name(Medium::WIFI_HOTSPOT) << " "; } + if (allowed.wifi_direct) { + result << proto::connections::Medium_Name(Medium::WIFI_DIRECT) << " "; + } result << "}"; } @@ -234,6 +237,7 @@ BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums( mediumSelector.web_rtc = intersection.contains(Medium::WEB_RTC); mediumSelector.wifi_lan = intersection.contains(Medium::WIFI_LAN); mediumSelector.wifi_hotspot = intersection.contains(Medium::WIFI_HOTSPOT); + mediumSelector.wifi_direct = intersection.contains(Medium::WIFI_DIRECT); return mediumSelector; } diff --git a/connections/implementation/bwu_manager.cc b/connections/implementation/bwu_manager.cc index 40b93bd3..d653dda4 100644 --- a/connections/implementation/bwu_manager.cc +++ b/connections/implementation/bwu_manager.cc @@ -31,6 +31,7 @@ #else #include "connections/implementation/webrtc_bwu_handler.h" #endif +#include "connections/implementation/wifi_direct_bwu_handler.h" #include "connections/implementation/wifi_hotspot_bwu_handler.h" #include "connections/implementation/wifi_lan_bwu_handler.h" #include "internal/platform/byte_array.h" @@ -108,6 +109,11 @@ void BwuManager::InitBwuHandlers() { Medium::WIFI_HOTSPOT, std::make_unique(*mediums_, notifications)); } + if (config_.allow_upgrade_to.wifi_direct) { + handlers_.emplace( + Medium::WIFI_DIRECT, + std::make_unique(*mediums_, notifications)); + } if (config_.allow_upgrade_to.wifi_lan) { handlers_.emplace(Medium::WIFI_LAN, std::make_unique( *mediums_, notifications)); @@ -391,16 +397,24 @@ void BwuManager::RevertBwuMediumForEndpoint(const std::string& service_id, // unless the BWU Medium is Hotspot. The client needs to disconnect from // Hotspot, then it can restore the previous AP connection right away. if (!IsInitiatorUpgradeServiceId(service_id)) { - if (medium == Medium::WIFI_HOTSPOT) { + if (medium == Medium::WIFI_HOTSPOT || medium == Medium::WIFI_DIRECT) { handler->RevertResponderState(service_id); } - return; } handler->RevertInitiatorState(service_id, endpoint_id); } +bool BwuManager::IsUpgradeOngoing(const std::string& endpoint_id) { + CountDownLatch latch(1); + RunOnBwuManagerThread("is_upgrade_ongoing", [&latch]() { + latch.CountDown(); + }); + latch.Await(); + return in_progress_upgrades_.contains(endpoint_id); +} + Medium BwuManager::GetBwuMediumForEndpoint( const std::string& endpoint_id) const { if (!FeatureFlags::GetInstance().GetFlags().support_multiple_bwu_mediums) { @@ -1219,6 +1233,9 @@ std::vector BwuManager::StripOutUnavailableMediums( case Medium::WIFI_LAN: available = mediums_->GetWifiLan().IsAvailable(); break; + case Medium::WIFI_DIRECT: + available = mediums_->GetWifiDirect().IsGOAvailable(); + break; case Medium::WIFI_HOTSPOT: available = mediums_->GetWifiHotspot().IsAPAvailable(); break; diff --git a/connections/implementation/bwu_manager.h b/connections/implementation/bwu_manager.h index 005c3d31..fc62339c 100644 --- a/connections/implementation/bwu_manager.h +++ b/connections/implementation/bwu_manager.h @@ -114,6 +114,9 @@ class BwuManager : public EndpointManager::FrameProcessor { // ClientProxy objects are deleted. void ShutdownExecutors(); + // Check if BWU is on going for a specific Endpoint + bool IsUpgradeOngoing(const std::string& endpoint_id); + private: static constexpr absl::Duration kReadClientIntroductionFrameTimeout = absl::Seconds(5); diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index 8a45b047..eec09d27 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -42,6 +42,7 @@ constexpr absl::string_view kEndpointId1 = "Endpoint1"; constexpr absl::string_view kEndpointId2 = "Endpoint2"; constexpr absl::string_view kEndpointId3 = "Endpoint3"; constexpr absl::string_view kEndpointId4 = "Endpoint4"; +constexpr absl::string_view kEndpointId5 = "Endpoint5"; class BwuManagerTest : public ::testing::Test { protected: @@ -49,20 +50,25 @@ class BwuManagerTest : public ::testing::Test { // Set up fake BWU handlers for WebRTC and WifiLAN. absl::flat_hash_map> handlers; auto fake_web_rtc = std::make_unique(Medium::WEB_RTC); - auto fake_wifi_lan = - std::make_unique(Medium::WIFI_LAN); + auto fake_wifi_lan = std::make_unique(Medium::WIFI_LAN); + auto fake_wifi_direct = + std::make_unique(Medium::WIFI_DIRECT); auto fake_wifi_hotspot = std::make_unique(Medium::WIFI_HOTSPOT); fake_web_rtc_bwu_handler_ = fake_web_rtc.get(); fake_wifi_lan_bwu_handler_ = fake_wifi_lan.get(); + fake_wifi_direct_bwu_handler_ = fake_wifi_direct.get(); fake_wifi_hotspot_bwu_handler_ = fake_wifi_hotspot.get(); handlers.emplace(Medium::WEB_RTC, std::move(fake_web_rtc)); handlers.emplace(Medium::WIFI_LAN, std::move(fake_wifi_lan)); + handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct)); handlers.emplace(Medium::WIFI_HOTSPOT, std::move(fake_wifi_hotspot)); BwuManager::Config config; - config.allow_upgrade_to = BooleanMediumSelector{ - .web_rtc = true, .wifi_lan = true, .wifi_hotspot = true}; + config.allow_upgrade_to = BooleanMediumSelector{.web_rtc = true, + .wifi_lan = true, + .wifi_hotspot = true, + .wifi_direct = true}; bwu_manager_ = std::make_unique(mediums_, em_, ecm_, std::move(handlers), config); @@ -101,6 +107,9 @@ class BwuManagerTest : public ::testing::Test { case Medium::WIFI_LAN: handler = fake_wifi_lan_bwu_handler_; break; + case Medium::WIFI_DIRECT: + handler = fake_wifi_direct_bwu_handler_; + break; case Medium::WIFI_HOTSPOT: handler = fake_wifi_hotspot_bwu_handler_; break; @@ -138,11 +147,58 @@ class BwuManagerTest : public ::testing::Test { Mediums mediums_; FakeBwuHandler* fake_web_rtc_bwu_handler_ = nullptr; FakeBwuHandler* fake_wifi_lan_bwu_handler_ = nullptr; + FakeBwuHandler* fake_wifi_direct_bwu_handler_ = nullptr; FakeBwuHandler* fake_wifi_hotspot_bwu_handler_ = nullptr; std::unique_ptr bwu_manager_; PacketMetaData packet_meta_data_; }; +TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { + ClientProxy client; + EndpointChannelManager ecm; + EndpointManager em(&ecm); + Mediums mediums; + BwuManager::Config config; + config.allow_upgrade_to.SetAll(false); + absl::flat_hash_map> handlers; + auto bwu_manager = std::make_unique(mediums, em, ecm, + std::move(handlers), config); + + auto channel1 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), + std::move(channel1)); + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), + Medium::WIFI_LAN); + EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + + auto channel2 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId2), + std::move(channel2)); + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2), + Medium::WIFI_HOTSPOT); + EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2))); + + auto channel3 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId3), + std::move(channel3)); + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3), + Medium::WIFI_DIRECT); + EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3))); + + auto channel4 = std::make_unique( + Medium::WEB_RTC, std::string(kServiceIdA)); + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId4), + std::move(channel4)); + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4), + Medium::BLUETOOTH); + EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4))); + + bwu_manager->Shutdown(); +} + class BwuManagerTestParam : public BwuManagerTest, public ::testing::WithParamInterface { protected: @@ -167,6 +223,7 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Success) { 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( @@ -237,9 +294,8 @@ TEST_P(BwuManagerTestParam, fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); } -TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoMediumHandler) { - // Try to upgrade to a medium without a handler (WIFI_HOTSPOT is not support - // in these tests). Should just early return with no action. +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); @@ -248,6 +304,7 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoMediumHandler) { 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) { @@ -265,6 +322,7 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) { 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, @@ -420,13 +478,12 @@ TEST_F(BwuManagerTest, EXPECT_EQ(kEndpointId1, fake_wifi_lan_bwu_handler_->disconnect_calls()[0].endpoint_id); - // With the support_multiple_bwu_mediums flag enabled, we have more - // granular per-service tracking. So, we can revert for each service when - // the last endpoint of that medium for the service goes down. - ASSERT_EQ(1u, fake_wifi_lan_bwu_handler_->handle_revert_calls().size()); - EXPECT_EQ( - upgrade_service_id_A, - fake_wifi_lan_bwu_handler_->handle_revert_calls()[0].service_id); + // With the support_multiple_bwu_mediums flag enabled, we have more + // granular per-service tracking. So, we can revert for each service when + // the last endpoint of that medium for the service goes down. + ASSERT_EQ(1u, fake_wifi_lan_bwu_handler_->handle_revert_calls().size()); + EXPECT_EQ(upgrade_service_id_A, + fake_wifi_lan_bwu_handler_->handle_revert_calls()[0].service_id); } { CountDownLatch latch(1); @@ -504,10 +561,13 @@ TEST_F( CreateInitialEndpoint(kServiceIdA, kEndpointId2, Medium::BLUETOOTH); CreateInitialEndpoint(kServiceIdB, kEndpointId3, Medium::BLUETOOTH); CreateInitialEndpoint(kServiceIdB, kEndpointId4, Medium::BLUETOOTH); + CreateInitialEndpoint(kServiceIdB, kEndpointId5, Medium::BLUETOOTH); FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH, /*upgrade_medium=*/Medium::WEB_RTC); FullyUpgradeEndpoint(kEndpointId4, /*initial_medium=*/Medium::BLUETOOTH, /*upgrade_medium=*/Medium::WIFI_HOTSPOT); + FullyUpgradeEndpoint(kEndpointId5, /*initial_medium=*/Medium::BLUETOOTH, + /*upgrade_medium=*/Medium::WIFI_DIRECT); FullyUpgradeEndpoint(kEndpointId2, /*initial_medium=*/Medium::BLUETOOTH, /*upgrade_medium=*/Medium::WIFI_LAN); FullyUpgradeEndpoint(kEndpointId3, /*initial_medium=*/Medium::BLUETOOTH, @@ -522,9 +582,11 @@ TEST_F( EXPECT_TRUE(fake_web_rtc_bwu_handler_->disconnect_calls().empty()); EXPECT_TRUE(fake_wifi_lan_bwu_handler_->disconnect_calls().empty()); EXPECT_TRUE(fake_wifi_hotspot_bwu_handler_->disconnect_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->disconnect_calls().empty()); EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_revert_calls().empty()); EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_revert_calls().empty()); EXPECT_TRUE(fake_wifi_hotspot_bwu_handler_->handle_revert_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_revert_calls().empty()); { CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1)); @@ -544,6 +606,8 @@ TEST_F( EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_revert_calls().empty()); EXPECT_TRUE(fake_wifi_hotspot_bwu_handler_->disconnect_calls().empty()); EXPECT_TRUE(fake_wifi_hotspot_bwu_handler_->handle_revert_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->disconnect_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_revert_calls().empty()); } { CountDownLatch latch(1); @@ -601,6 +665,25 @@ TEST_F( upgrade_service_id_B, fake_wifi_hotspot_bwu_handler_->handle_revert_calls()[0].service_id); } + { + CountDownLatch latch(1); + ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId5)); + bwu_manager_->OnEndpointDisconnect(&client_, upgrade_service_id_B, + std::string(kEndpointId5), latch); + + // We reverted a WifiDirect channel; no additional WebRTC calls expected. + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->disconnect_calls().size()); + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_revert_calls().size()); + + // No more WifiDirect channels for service B; expect revert call. + ASSERT_EQ(1u, fake_wifi_direct_bwu_handler_->disconnect_calls().size()); + EXPECT_EQ(kEndpointId5, + fake_wifi_direct_bwu_handler_->disconnect_calls()[0].endpoint_id); + ASSERT_EQ(1u, fake_wifi_direct_bwu_handler_->handle_revert_calls().size()); + EXPECT_EQ( + upgrade_service_id_B, + fake_wifi_direct_bwu_handler_->handle_revert_calls()[0].service_id); + } } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagEnabled) { @@ -630,11 +713,11 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagEnabled) { std::string(kEndpointId3), &client_, Medium::WEB_RTC, packet_meta_data_); - // With the flag enabled, we can safely revert WebRTC just for service B - // because service B has no active WebRTC endpoints. - ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_revert_calls().size()); - EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdB), - fake_web_rtc_bwu_handler_->handle_revert_calls()[0].service_id); + // With the flag enabled, we can safely revert WebRTC just for service B + // because service B has no active WebRTC endpoints. + ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_revert_calls().size()); + EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdB), + fake_web_rtc_bwu_handler_->handle_revert_calls()[0].service_id); } TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) { @@ -671,6 +754,38 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) { EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_revert_calls().empty()); } +TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { + FeatureFlags::GetMutableFlagsForTesting().support_multiple_bwu_mediums = true; + OfflineFrame frame; + CreateInitialEndpoint(kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + + ByteArray bytes = parser::ForBwuWifiDirectPathAvailable( + /*ssid=*/"Direct-12345678", /*password=*/"87654321", /*port=*/2143, + /*frequency=*/2412, /*supports_disabling_encryption=*/false, + /*gateway=*/"123.234.23.1"); + frame.ParseFromString(std::string(bytes)); + + ::location::nearby::connections::V1Frame* v1_frame = frame.mutable_v1(); + ::location::nearby::connections::BandwidthUpgradeNegotiationFrame* sub_frame = + v1_frame->mutable_bandwidth_upgrade_negotiation(); + ::location::nearby::connections:: + BandwidthUpgradeNegotiationFrame_UpgradePathInfo* upgrade_path_info = + sub_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_supports_client_introduction_ack(false); + bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_, + Medium::BLUETOOTH, packet_meta_data_); + CountDownLatch latch(1); + bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, + std::string(kEndpointId1), latch); + + ASSERT_EQ(fake_wifi_direct_bwu_handler_->disconnect_calls().size(), 1u); + EXPECT_EQ(kEndpointId1, + fake_wifi_direct_bwu_handler_->disconnect_calls()[0].endpoint_id); + // This is called by the RESPONDER--call RevertInitiatorState only when + // BWU Medium is Hotspot or WifiDirect. + ASSERT_EQ(fake_wifi_direct_bwu_handler_->handle_revert_calls().size(), 1u); +} + TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) { FeatureFlags::GetMutableFlagsForTesting().support_multiple_bwu_mediums = true; diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index 3e6b4614..9f577c78 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -140,16 +140,20 @@ class FakeBwuHandler : public BaseBwuHandler { case proto::connections::WEB_RTC: return parser::ForBwuWebrtcPathAvailable(/*peer_id=*/"peer-id", LocationHint{}); - case proto::connections::UNKNOWN_MEDIUM: - case proto::connections::MDNS: case proto::connections::WIFI_HOTSPOT: return parser::ForBwuWifiHotspotPathAvailable( /*ssid=*/"Direct-357a2d8c", /*password=*/"b592f7d3", /*port=*/1234, /*gateway=*/"123.234.23.1", false); + case proto::connections::WIFI_DIRECT: + return parser::ForBwuWifiDirectPathAvailable( + /*ssid=*/"Direct-12345678", /*password=*/"87654321", /*port=*/2143, + /*frequency=*/2412, /*supports_disabling_encryption=*/false, + /*gateway=*/"123.234.23.1"); + case proto::connections::UNKNOWN_MEDIUM: + case proto::connections::MDNS: case proto::connections::BLE: case proto::connections::WIFI_AWARE: case proto::connections::NFC: - case proto::connections::WIFI_DIRECT: case proto::connections::BLE_L2CAP: case proto::connections::USB: return ByteArray{}; diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index d78fc10c..4b4c928a 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -232,7 +232,8 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, const std::string& password, std::int32_t port, std::int32_t frequency, - bool supports_disabling_encryption) { + bool supports_disabling_encryption, + const std::string& gateway) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -252,6 +253,7 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, wifi_direct_credentials->set_password(password); wifi_direct_credentials->set_port(port); wifi_direct_credentials->set_frequency(frequency); + wifi_direct_credentials->set_gateway(gateway); return ToBytes(std::move(frame)); } diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index 53eb8d4f..1d79111d 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -73,7 +73,8 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, const std::string& password, std::int32_t port, std::int32_t frequency, - bool supports_disabling_encryption); + bool supports_disabling_encryption, + const std::string& gateway); ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, const std::string& mac_address); ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index d3240110..4c41af14 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -294,7 +294,8 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { ssid: "DIRECT-A0-0123456789AB" password: "password" port: 1000 - frequency: 1000 + frequency: 2412 + gateway: "192.168.1.1" > supports_disabling_encryption: false supports_client_introduction_ack: true @@ -302,7 +303,7 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { > >)pb"; ByteArray bytes = ForBwuWifiDirectPathAvailable( - "DIRECT-A0-0123456789AB", "password", 1000, 1000, false); + "DIRECT-A0-0123456789AB", "password", 1000, 2412, false, "192.168.1.1"); auto response = FromBytes(bytes); ASSERT_TRUE(response.ok()); OfflineFrame message = FromBytes(bytes).result(); diff --git a/connections/implementation/offline_frames_validator_test.cc b/connections/implementation/offline_frames_validator_test.cc index ffae3d8d..62dae891 100644 --- a/connections/implementation/offline_frames_validator_test.cc +++ b/connections/implementation/offline_frames_validator_test.cc @@ -14,14 +14,15 @@ #include "connections/implementation/offline_frames_validator.h" +#include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/implementation/offline_frames.h" +#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "internal/platform/byte_array.h" namespace location { @@ -43,7 +44,8 @@ constexpr absl::string_view kPassword = "password"; constexpr absl::string_view kWifiHotspotGateway = "0.0.0.0"; constexpr absl::string_view kWifiDirectSsid = "DIRECT-A0-0123456789AB"; constexpr absl::string_view kWifiDirectPassword = "WIFIDIRECT123456"; -constexpr int kWifiDirectFrequency = 1000; +constexpr absl::string_view kGateway = "192.168.1.1"; +constexpr int kWifiDirectFrequency = 2412; constexpr int kPort = 1000; constexpr bool kSupportsDisablingEncryption = true; constexpr std::array kMediums = { @@ -54,19 +56,19 @@ constexpr std::array kMediums = { constexpr int kKeepAliveIntervalMillis = 1000; constexpr int kKeepAliveTimeoutMillis = 5000; -class OfflineFramesConnectionRequestTest : public testing::Test { +class OfflineFramesConnectionRequestTest : public testing::Test { protected: ConnectionInfo connection_info_{std::string(kEndpointId), - ByteArray{std::string(kEndpointName)}, - kNonce, - kSupports5ghz, - std::string(kBssid), - kApFrequency, - std::string(kIp4Bytes), - std::vector>( - kMediums.begin(), kMediums.end()), - kKeepAliveIntervalMillis, - kKeepAliveTimeoutMillis}; + ByteArray{std::string(kEndpointName)}, + kNonce, + kSupports5ghz, + std::string(kBssid), + kApFrequency, + std::string(kIp4Bytes), + std::vector>( + kMediums.begin(), kMediums.end()), + kKeepAliveIntervalMillis, + kKeepAliveTimeoutMillis}; }; TEST_F(OfflineFramesConnectionRequestTest, @@ -82,7 +84,7 @@ TEST_F(OfflineFramesConnectionRequestTest, } TEST_F(OfflineFramesConnectionRequestTest, - ValidatesAsFailWithNullConnectionRequestFrame) { + ValidatesAsFailWithNullConnectionRequestFrame) { OfflineFrame offline_frame; ByteArray bytes = ForConnectionRequest(connection_info_); @@ -97,7 +99,7 @@ TEST_F(OfflineFramesConnectionRequestTest, } TEST_F(OfflineFramesConnectionRequestTest, - ValidatesAsFailWithNullEndpointIdInConnectionRequestFrame) { + ValidatesAsFailWithNullEndpointIdInConnectionRequestFrame) { OfflineFrame offline_frame; connection_info_.local_endpoint_id = ""; @@ -110,7 +112,7 @@ TEST_F(OfflineFramesConnectionRequestTest, } TEST_F(OfflineFramesConnectionRequestTest, - ValidatesAsFailWithNullEndpointInfoInConnectionRequestFrame) { + ValidatesAsFailWithNullEndpointInfoInConnectionRequestFrame) { OfflineFrame offline_frame; connection_info_.local_endpoint_info = ByteArray{""}; @@ -123,7 +125,7 @@ TEST_F(OfflineFramesConnectionRequestTest, } TEST_F(OfflineFramesConnectionRequestTest, - ValidatesAsOkWithNullBssidInConnectionRequestFrame) { + ValidatesAsOkWithNullBssidInConnectionRequestFrame) { OfflineFrame offline_frame; connection_info_.bssid = ""; @@ -136,7 +138,7 @@ TEST_F(OfflineFramesConnectionRequestTest, } TEST_F(OfflineFramesConnectionRequestTest, - ValidatesAsOkWithNullMediumsInConnectionRequestFrame) { + ValidatesAsOkWithNullMediumsInConnectionRequestFrame) { OfflineFrame offline_frame; connection_info_.supported_mediums = {}; @@ -595,7 +597,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkBandwidthUpgradeWifiDirect) { ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption); + kWifiDirectFrequency, kSupportsDisablingEncryption, + std::string(kGateway)); offline_frame.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -611,7 +614,7 @@ TEST(OfflineFramesValidatorTest, // Anything less than -1 is invalid ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -2, - kSupportsDisablingEncryption); + kSupportsDisablingEncryption, std::string(kGateway)); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -619,9 +622,9 @@ TEST(OfflineFramesValidatorTest, ASSERT_FALSE(ret_value.Ok()); // But -1 itself is not invalid - bytes = ForBwuWifiDirectPathAvailable(std::string(kWifiDirectSsid), - std::string(kWifiDirectPassword), kPort, - -1, kSupportsDisablingEncryption); + bytes = ForBwuWifiDirectPathAvailable( + std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -1, + kSupportsDisablingEncryption, std::string(kGateway)); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -637,7 +640,8 @@ TEST(OfflineFramesValidatorTest, std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"}; ByteArray bytes = ForBwuWifiDirectPathAvailable( wifi_direct_ssid, std::string(kWifiDirectPassword), kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption); + kWifiDirectFrequency, kSupportsDisablingEncryption, + std::string(kGateway)); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -648,7 +652,8 @@ TEST(OfflineFramesValidatorTest, std::string{kWifiDirectSsid} + "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; bytes = ForBwuWifiDirectPathAvailable( wifi_direct_ssid_wrong_length, std::string(kWifiDirectPassword), kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption); + kWifiDirectFrequency, kSupportsDisablingEncryption, + std::string(kGateway)); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -664,7 +669,8 @@ TEST(OfflineFramesValidatorTest, std::string short_wifi_direct_password{"Test"}; ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), short_wifi_direct_password, kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption); + kWifiDirectFrequency, kSupportsDisablingEncryption, + std::string(kGateway)); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -676,7 +682,8 @@ TEST(OfflineFramesValidatorTest, "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"; bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), long_wifi_direct_password, kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption); + kWifiDirectFrequency, kSupportsDisablingEncryption, + std::string(kGateway)); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index fe9f6489..9a264ca3 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -27,9 +27,7 @@ #include "connections/implementation/bluetooth_endpoint_channel.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/mediums/utils.h" -#include "connections/implementation/webrtc_endpoint_channel.h" #include "connections/implementation/wifi_lan_endpoint_channel.h" -#include "internal/platform/crypto.h" #include "internal/platform/nsd_service_info.h" #include "internal/platform/types.h" #include "proto/connections_enums.pb.h" @@ -65,6 +63,7 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( ble_v2_medium_(mediums->GetBleV2()), wifi_lan_medium_(mediums->GetWifiLan()), wifi_hotspot_medium_(mediums->GetWifiHotspot()), + wifi_direct_medium_(mediums->GetWifiDirect()), webrtc_medium_(mediums->GetWebRtc()), injected_bluetooth_device_store_(injected_bluetooth_device_store) {} diff --git a/connections/implementation/p2p_cluster_pcp_handler.h b/connections/implementation/p2p_cluster_pcp_handler.h index ccacef3c..c94f23f6 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.h +++ b/connections/implementation/p2p_cluster_pcp_handler.h @@ -34,14 +34,10 @@ #include "connections/implementation/mediums/webrtc_stub.h" #else #include "connections/implementation/mediums/webrtc.h" -#include "connections/implementation/mediums/webrtc_socket.h" #endif #include "connections/implementation/pcp.h" #include "connections/implementation/wifi_lan_service_info.h" -#include "connections/strategy.h" -#include "internal/platform/bluetooth_classic.h" #include "internal/platform/byte_array.h" -#include "internal/platform/wifi_lan.h" namespace location { namespace nearby { @@ -229,6 +225,7 @@ class P2pClusterPcpHandler : public BasePcpHandler { BleV2& ble_v2_medium_; WifiLan& wifi_lan_medium_; WifiHotspot& wifi_hotspot_medium_; + WifiDirect& wifi_direct_medium_; mediums::WebRtc& webrtc_medium_; InjectedBluetoothDeviceStore& injected_bluetooth_device_store_; std::int64_t bluetooth_classic_discoverer_client_id_{0}; diff --git a/connections/implementation/p2p_point_to_point_pcp_handler.cc b/connections/implementation/p2p_point_to_point_pcp_handler.cc index a933a291..deec0a1a 100644 --- a/connections/implementation/p2p_point_to_point_pcp_handler.cc +++ b/connections/implementation/p2p_point_to_point_pcp_handler.cc @@ -33,6 +33,10 @@ P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } + if (mediums_->GetWifi().IsAvailable() && + mediums_->GetWifiDirect().IsGCAvailable()) { + mediums.push_back(proto::connections::WIFI_DIRECT); + } if (mediums_->GetWifi().IsAvailable() && mediums_->GetWifiHotspot().IsClientAvailable()) { mediums.push_back(proto::connections::WIFI_HOTSPOT); diff --git a/connections/implementation/p2p_star_pcp_handler.cc b/connections/implementation/p2p_star_pcp_handler.cc index 7b65aee4..7f1357aa 100644 --- a/connections/implementation/p2p_star_pcp_handler.cc +++ b/connections/implementation/p2p_star_pcp_handler.cc @@ -36,6 +36,10 @@ P2pStarPcpHandler::GetConnectionMediumsByPriority() { if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } + if (mediums_->GetWifi().IsAvailable() && + mediums_->GetWifiDirect().IsGCAvailable()) { + mediums.push_back(proto::connections::WIFI_DIRECT); + } if (mediums_->GetWifi().IsAvailable() && mediums_->GetWifiHotspot().IsClientAvailable()) { mediums.push_back(proto::connections::WIFI_HOTSPOT); diff --git a/connections/implementation/wifi_direct_bwu_handler.cc b/connections/implementation/wifi_direct_bwu_handler.cc new file mode 100644 index 00000000..8fc09ace --- /dev/null +++ b/connections/implementation/wifi_direct_bwu_handler.cc @@ -0,0 +1,158 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "connections/implementation/wifi_direct_bwu_handler.h" + +#include +#include +#include +#include + +#include "absl/functional/bind_front.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/offline_frames.h" +#include "connections/implementation/wifi_direct_endpoint_channel.h" +#include "internal/platform/wifi_direct.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiDirectBwuHandler::WifiDirectBwuHandler(Mediums& mediums, + BwuNotifications notifications) + : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} + +ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( + ClientProxy* client, const std::string& upgrade_service_id, + const std::string& endpoint_id) { + // Create WifiDirect GO + if (!wifi_direct_medium_.StartWifiDirect()) { + NEARBY_LOGS(INFO) << "Failed to start Wifi Direct!"; + return {}; + } + + if (!wifi_direct_medium_.IsAcceptingConnections(upgrade_service_id)) { + if (!wifi_direct_medium_.StartAcceptingConnections( + upgrade_service_id, + { + .accepted_cb = absl::bind_front( + &WifiDirectBwuHandler::OnIncomingWifiDirectConnection, this, + client), + })) { + NEARBY_LOGS(ERROR) + << "WifiDirectBwuHandler couldn't initiate WifiDirect upgrade for " + << "service " << upgrade_service_id << " and endpoint " << endpoint_id + << " because it failed to start listening for incoming WifiLan " + "connections."; + return {}; + } + NEARBY_LOGS(INFO) + << "WifiDirectBwuHandler successfully started listening for incoming " + "WifiDirect connections while upgrading endpoint " + << endpoint_id; + } + + // Note: Credentials are not generated until Medium StartWifiDirect() is + // called and the server socket is created. Be careful moving this codeblock + // around. + HotspotCredentials* wifi_direct_crendential = + wifi_direct_medium_.GetCredentials(upgrade_service_id); + std::string ssid = wifi_direct_crendential->GetSSID(); + std::string password = wifi_direct_crendential->GetPassword(); + std::string gateway = wifi_direct_crendential->GetGateway(); + int port = wifi_direct_crendential->GetPort(); + int freq = wifi_direct_crendential->GetFrequency(); + + NEARBY_LOGS(INFO) << "Start WifiDirect GO with SSID: " << ssid + << ", Password: " << password << ", Port: " << port + << ", Gateway: " << gateway << "Frequency: " << freq; + + bool disabling_encryption = + (client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint); + return parser::ForBwuWifiDirectPathAvailable( + ssid, password, port, freq, + /* supports_disabling_encryption */ disabling_encryption, gateway); +} + +void WifiDirectBwuHandler::HandleRevertInitiatorStateForService( + const std::string& upgrade_service_id) { + wifi_direct_medium_.StopAcceptingConnections(upgrade_service_id); + wifi_direct_medium_.StopWifiDirect(); + wifi_direct_medium_.DisconnectWifiDirect(); + + NEARBY_LOGS(INFO) + << "WifiDirectBwuHandler successfully reverted all states for " + << "upgrade service ID " << upgrade_service_id; +} + +std::unique_ptr +WifiDirectBwuHandler::CreateUpgradedEndpointChannel( + ClientProxy* client, const std::string& service_id, + const std::string& endpoint_id, const UpgradePathInfo& upgrade_path_info) { + if (!upgrade_path_info.has_wifi_direct_credentials()) { + NEARBY_LOGS(INFO) << "No WifiDirect Credential"; + return nullptr; + } + const UpgradePathInfo::WifiDirectCredentials& upgrade_path_info_credentials = + upgrade_path_info.wifi_direct_credentials(); + + const std::string& ssid = upgrade_path_info_credentials.ssid(); + const std::string& password = upgrade_path_info_credentials.password(); + std::int32_t port = upgrade_path_info_credentials.port(); + const std::string& gateway = upgrade_path_info_credentials.gateway(); + + NEARBY_LOGS(INFO) << "Received WifiDirect credential SSID: " << ssid + << ", Password:" << password << ", Port:" << port + << ", Gateway:" << gateway; + + if (!wifi_direct_medium_.ConnectWifiDirect(ssid, password)) { + NEARBY_LOGS(ERROR) << "Connect to WifiDiret GO failed"; + return nullptr; + } + + WifiHotspotSocket socket = wifi_direct_medium_.Connect( + service_id, gateway, port, client->GetCancellationFlag(endpoint_id)); + if (!socket.IsValid()) { + NEARBY_LOGS(ERROR) + << "WifiDirectBwuHandler failed to connect to the WifiDirect service(" + << port << ") for endpoint " << endpoint_id; + return nullptr; + } + + NEARBY_LOGS(VERBOSE) + << "WifiDirectBwuHandler successfully connected to WifiDirect service (" + << port << ") while upgrading endpoint " << endpoint_id; + + // Create a new WifiDirectEndpointChannel. + return std::make_unique( + service_id, /*channel_name=*/service_id, socket); +} + +void WifiDirectBwuHandler::OnIncomingWifiDirectConnection( + ClientProxy* client, const std::string& upgrade_service_id, + WifiHotspotSocket socket) { + auto channel = std::make_unique( + upgrade_service_id, /*channel_name=*/upgrade_service_id, socket); + std::unique_ptr connection( + new IncomingSocketConnection{ + .socket = std::make_unique( + upgrade_service_id, socket), + .channel = std::move(channel), + }); + bwu_notifications_.incoming_connection_cb(client, std::move(connection)); +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/implementation/wifi_direct_bwu_handler.h b/connections/implementation/wifi_direct_bwu_handler.h new file mode 100644 index 00000000..ffc28f36 --- /dev/null +++ b/connections/implementation/wifi_direct_bwu_handler.h @@ -0,0 +1,90 @@ +// Copyright 2022 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_WIFI_DIRECT_BWU_HANDLER_H_ +#define CORE_INTERNAL_WIFI_DIRECT_BWU_HANDLER_H_ + +#include +#include + +#include "connections/implementation/base_bwu_handler.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/mediums/mediums.h" + +namespace location { +namespace nearby { +namespace connections { + +// Defines the set of methods that need to be implemented to handle the +// per-Medium-specific operations needed to upgrade an EndpointChannel. +class WifiDirectBwuHandler : public BaseBwuHandler { + public: + explicit WifiDirectBwuHandler(Mediums& mediums, + BwuNotifications notifications); + + private: + class WifiDirectIncomingSocket : public BwuHandler::IncomingSocket { + public: + // explicit WifiDirectIncomingSocket(const std::string& name, + explicit WifiDirectIncomingSocket(absl::string_view name, + WifiHotspotSocket socket) + : name_(name), socket_(socket) {} + + std::string ToString() override { return name_; } + void Close() override { socket_.Close(); } + + private: + std::string name_; + WifiHotspotSocket socket_; + }; + + // Called by BWU target. Retrieves a new medium info from incoming message, + // Windows doesn't support WIFIDirect as GC because phone side uses simplified + // WFD protocol to established connection while WINRT follow the standard WFD + // spec to achieve the connection. So return fail to stop the upgrade request + // from phone side. + std::unique_ptr CreateUpgradedEndpointChannel( + ClientProxy* client, const std::string& service_id, + const std::string& endpoint_id, + const UpgradePathInfo& upgrade_path_info) final; + Medium GetUpgradeMedium() const final { return Medium::WIFI_DIRECT; } + void OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id) final {} + + // Called by BWU initiator. Set up WifiDirect upgraded medium for this + // endpoint, and returns a upgrade path info (SSID, Password, Gateway used as + // IPAddress, Port) for remote party to perform connection. + ByteArray HandleInitializeUpgradedMediumForEndpoint( + ClientProxy* client, const std::string& upgrade_service_id, + const std::string& endpoint_id) final; + + // Revert the upgrade when the procedure fails or disconnection is called. + void HandleRevertInitiatorStateForService( + const std::string& upgrade_service_id) final; + + // Accept Connection Callback. + void OnIncomingWifiDirectConnection(ClientProxy* client, + const std::string& upgrade_service_id, + WifiHotspotSocket socket); + + Mediums& mediums_; + Wifi& wifi_medium_ = mediums_.GetWifi(); + WifiDirect& wifi_direct_medium_ = mediums_.GetWifiDirect(); +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_DIRECT_BWU_HANDLER_H_ diff --git a/connections/implementation/wifi_direct_bwu_test.cc b/connections/implementation/wifi_direct_bwu_test.cc new file mode 100644 index 00000000..bd59cbc7 --- /dev/null +++ b/connections/implementation/wifi_direct_bwu_test.cc @@ -0,0 +1,126 @@ +// Copyright 2022 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 +#include + +#include "gtest/gtest.h" +#include "connections/implementation/bwu_handler.h" +#include "connections/implementation/wifi_direct_bwu_handler.h" +#include "internal/platform/medium_environment.h" + +namespace location { +namespace nearby { +namespace connections { + +namespace { +constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); +} // namespace + +class WifiDirectTest : public testing::Test { + protected: + WifiDirectTest() { env_.Start(); } + ~WifiDirectTest() override { env_.Stop(); } + + MediumEnvironment& env_{MediumEnvironment::Instance()}; +}; + +TEST_F(WifiDirectTest, CanCreateBwuHandler) { + BwuHandler::BwuNotifications notifications = {.incoming_connection_cb = {}}; + ClientProxy client; + Mediums mediums; + + auto handler = std::make_unique(mediums, notifications); + + handler->InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"B", + /*endpoint_id=*/"2"); + handler->RevertInitiatorState(); + SUCCEED(); + handler.reset(); +} + +TEST_F(WifiDirectTest, SoftAPBWUInit_STACreateEndpointChannel) { + CountDownLatch start_latch(1); + CountDownLatch accept_latch(1); + CountDownLatch end_latch(1); + + BwuHandler::BwuNotifications notifications_1{ + .incoming_connection_cb = + [&accept_latch, &end_latch]( + ClientProxy* client, + std::unique_ptr + mutable_connection) { + NEARBY_LOGS(WARNING) << "Server socket connection accept call back"; + std::shared_ptr connection( + mutable_connection.release()); + accept_latch.CountDown(); + EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); + NEARBY_LOGS(WARNING) << "Test is done. Close the socket"; + connection->channel->Close(); + connection->socket->Close(); + }, + }; + BwuHandler::BwuNotifications notifications_2 = {.incoming_connection_cb = {}}; + ClientProxy wifi_direct_go, wifi_direct_gc; + Mediums mediums_1, mediums_2; + ExceptionOr upgrade_frame; + + auto handler_1 = + std::make_unique(mediums_1, notifications_1); + + SingleThreadExecutor server_executor; + server_executor.Execute( + [&handler_1, &wifi_direct_go, &upgrade_frame, &start_latch]() { + ByteArray upgrade_path_available_frame = + handler_1->InitializeUpgradedMediumForEndpoint(&wifi_direct_go, + /*service_id=*/"A", + /*endpoint_id=*/"1"); + EXPECT_FALSE(upgrade_path_available_frame.Empty()); + + upgrade_frame = parser::FromBytes(upgrade_path_available_frame); + start_latch.CountDown(); + }); + + SingleThreadExecutor client_executor; + // Wait till wifi_direct_go started and then connect to it + EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); + EXPECT_FALSE(mediums_2.GetWifiDirect().IsConnectedToGO()); + std::unique_ptr handler_2 = + std::make_unique(mediums_2, notifications_2); + + client_executor.Execute([&handler_2, &wifi_direct_gc, &upgrade_frame, + &accept_latch, &end_latch, &mediums_2]() { + auto bwu_frame = + upgrade_frame.result().v1().bandwidth_upgrade_negotiation(); + + std::unique_ptr new_channel = + handler_2->CreateUpgradedEndpointChannel( + &wifi_direct_gc, /*service_id=*/"A", + /*endpoint_id=*/"1", bwu_frame.upgrade_path_info()); + EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); + EXPECT_EQ(new_channel->GetMedium(), + proto::connections::Medium::WIFI_DIRECT); + EXPECT_TRUE(mediums_2.GetWifiDirect().IsConnectedToGO()); + handler_2->RevertResponderState(/*service_id=*/"A"); + end_latch.CountDown(); + }); + + EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); + EXPECT_FALSE(mediums_2.GetWifiDirect().IsConnectedToGO()); +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/implementation/wifi_direct_endpoint_channel.cc b/connections/implementation/wifi_direct_endpoint_channel.cc new file mode 100644 index 00000000..07cdcbc1 --- /dev/null +++ b/connections/implementation/wifi_direct_endpoint_channel.cc @@ -0,0 +1,49 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "connections/implementation/wifi_direct_endpoint_channel.h" + +#include +#include + +#include "internal/platform/logging.h" +#include "internal/platform/wifi_direct.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiDirectEndpointChannel::WifiDirectEndpointChannel( + const std::string& service_id, const std::string& channel_name, + WifiHotspotSocket socket) + : BaseEndpointChannel(service_id, channel_name, &socket.GetInputStream(), + &socket.GetOutputStream()), + socket_(std::move(socket)) {} + +proto::connections::Medium WifiDirectEndpointChannel::GetMedium() const { + return proto::connections::Medium::WIFI_DIRECT; +} + +void WifiDirectEndpointChannel::CloseImpl() { + Exception status = socket_.Close(); + if (!status.Ok()) { + NEARBY_LOGS(INFO) + << "Failed to close underlying socket for WifiDirectEndpointChannel " + << GetName() << " : exception = " << status.value; + } +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/implementation/wifi_direct_endpoint_channel.h b/connections/implementation/wifi_direct_endpoint_channel.h new file mode 100644 index 00000000..9d39cab7 --- /dev/null +++ b/connections/implementation/wifi_direct_endpoint_channel.h @@ -0,0 +1,53 @@ +// Copyright 2022 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_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ + +#include + +#include "connections/implementation/base_endpoint_channel.h" +#include "internal/platform/wifi_hotspot.h" + +namespace location { +namespace nearby { +namespace connections { + +class WifiDirectEndpointChannel final : public BaseEndpointChannel { + public: + // Creates both outgoing and incoming WifiDirect channels. + WifiDirectEndpointChannel(const std::string& service_id, + const std::string& channel_name, + WifiHotspotSocket socket); + // Not copyable or movable + WifiDirectEndpointChannel(const WifiDirectEndpointChannel&) = delete; + WifiDirectEndpointChannel& operator=(const WifiDirectEndpointChannel&) = + delete; + WifiDirectEndpointChannel(WifiDirectEndpointChannel&&) = delete; + WifiDirectEndpointChannel& operator=(WifiDirectEndpointChannel&&) = delete; + + proto::connections::Medium GetMedium() const override; + + private: + void CloseImpl() override; + + WifiHotspotSocket socket_; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ diff --git a/connections/medium_selector.h b/connections/medium_selector.h index 502ed387..0572c63e 100644 --- a/connections/medium_selector.h +++ b/connections/medium_selector.h @@ -30,15 +30,16 @@ struct MediumSelector { T web_rtc; T wifi_lan; T wifi_hotspot; + T wifi_direct; constexpr bool Any(T value) const { return bluetooth == value || ble == value || web_rtc == value || - wifi_lan == value || wifi_hotspot == value; + wifi_lan == value || wifi_hotspot == value || wifi_direct == value; } constexpr bool All(T value) const { return bluetooth == value && ble == value && web_rtc == value && - wifi_lan == value && wifi_hotspot == value; + wifi_lan == value && wifi_hotspot == value && wifi_direct == value; } constexpr int Count(T value) const { @@ -47,6 +48,7 @@ struct MediumSelector { if (ble == value) count++; if (wifi_lan == value) count++; if (wifi_hotspot == value) count++; + if (wifi_direct == value) count++; if (web_rtc == value) count++; return count; } @@ -57,6 +59,7 @@ struct MediumSelector { web_rtc = value; wifi_lan = value; wifi_hotspot = value; + wifi_direct = value; return *this; } @@ -64,6 +67,7 @@ struct MediumSelector { std::vector mediums; // Mediums are sorted in order of decreasing preference. if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN); + if (wifi_direct == value) mediums.push_back(Medium::WIFI_DIRECT); if (wifi_hotspot == value) mediums.push_back(Medium::WIFI_HOTSPOT); if (web_rtc == value) mediums.push_back(Medium::WEB_RTC); if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH);