diff --git a/connections/implementation/bwu_manager.cc b/connections/implementation/bwu_manager.cc index 8c4521ab..8f93a3de 100644 --- a/connections/implementation/bwu_manager.cc +++ b/connections/implementation/bwu_manager.cc @@ -105,7 +105,11 @@ BwuManager::BwuManager( } if (config_.allow_upgrade_to.All(false)) { config_.allow_upgrade_to.web_rtc = true; - config_.allow_upgrade_to.wifi_direct = true; + if (NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kEnableWifiDirect)) { + config_.allow_upgrade_to.wifi_direct = true; + } config_.allow_upgrade_to.wifi_lan = true; config_.allow_upgrade_to.wifi_hotspot = true; if (NearbyFlags::GetInstance().GetBoolFlag( diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index c9e75345..0906d3ec 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -84,6 +84,9 @@ CreateWifiHotspotCredentials() { class BwuManagerTest : public ::testing::Test { protected: BwuManagerTest() { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableWifiDirect, + true); // Set up fake BWU handlers for WebRTC and WifiLAN. absl::flat_hash_map> handlers; auto fake_web_rtc = std::make_unique(Medium::WEB_RTC); @@ -202,6 +205,9 @@ class BwuManagerTest : public ::testing::Test { }; TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableWifiDirect, + true); ClientProxy client; EndpointChannelManager ecm; EndpointManager em(&ecm); @@ -915,9 +921,10 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); ByteArray bytes = parser::ForBwuWifiDirectPathAvailable( - /*ssid=*/"Direct-12345678", /*password=*/"87654321", /*port=*/2143, + /*ssid=*/"", /*password=*/"", /*port=*/2143, /*frequency=*/2412, /*supports_disabling_encryption=*/false, - /*gateway=*/"123.234.23.1"); + /*gateway=*/"123.234.23.1", /*service_name=*/"NC-WifiDirectTest", + /*pin=*/"b592f7d3"); frame.ParseFromString(std::string(bytes)); ::nearby::connections::V1Frame* v1_frame = frame.mutable_v1(); diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index 4381f75c..5c7b08d8 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -175,9 +175,10 @@ class FakeBwuHandler : public BaseBwuHandler { } case location::nearby::proto::connections::WIFI_DIRECT: return parser::ForBwuWifiDirectPathAvailable( - /*ssid=*/"Direct-12345678", /*password=*/"87654321", /*port=*/2143, + /*ssid=*/"", /*password=*/"", /*port=*/2143, /*frequency=*/2412, /*supports_disabling_encryption=*/false, - /*gateway=*/"123.234.23.1"); + /*gateway=*/"123.234.23.1", /*service_name=*/"NC-WifiDirectTest", + /*pin=*/"b592f7d3"); case location::nearby::proto::connections::UNKNOWN_MEDIUM: case location::nearby::proto::connections::MDNS: case location::nearby::proto::connections::BLE: diff --git a/connections/implementation/flags/nearby_connections_feature_flags.h b/connections/implementation/flags/nearby_connections_feature_flags.h index ade07be9..903b9dba 100644 --- a/connections/implementation/flags/nearby_connections_feature_flags.h +++ b/connections/implementation/flags/nearby_connections_feature_flags.h @@ -103,6 +103,9 @@ constexpr auto kEnableScanningForInstantOnLost = // Stop BLE_V2 scanning when upgrading to WIFI Hotspot or WFD. constexpr auto kEnableStopBleScanningOnWifiUpgrade = flags::Flag(kConfigPackage, "45687902", false); +// When true, enable Wi-Fi Direct in Nearby connections SDK. +constexpr auto kEnableWifiDirect = + flags::Flag(kConfigPackage, "45741157", false); // by default, enable Wi-Fi Hotspot client. constexpr auto kEnableWifiHotspotClient = flags::Flag(kConfigPackage, "45648734", true); @@ -120,7 +123,6 @@ constexpr auto kSafeToDisconnectVersion = // When true, use stable endpoint ID. constexpr auto kUseStableEndpointId = flags::Flag(kConfigPackage, "45639298", false); - } // namespace nearby_connections_feature } // namespace config_package_nearby } // namespace connections diff --git a/connections/implementation/mediums/mediums.cc b/connections/implementation/mediums/mediums.cc index c1a3be59..8dd6dccd 100644 --- a/connections/implementation/mediums/mediums.cc +++ b/connections/implementation/mediums/mediums.cc @@ -16,6 +16,13 @@ #include "connections/implementation/mediums/awdl.h" #include "connections/implementation/mediums/ble.h" +#include "connections/implementation/mediums/bluetooth_classic.h" +#include "connections/implementation/mediums/bluetooth_radio.h" +#include "connections/implementation/mediums/webrtc.h" +#include "connections/implementation/mediums/wifi.h" +#include "connections/implementation/mediums/wifi_direct.h" +#include "connections/implementation/mediums/wifi_hotspot.h" +#include "connections/implementation/mediums/wifi_lan.h" namespace nearby { namespace connections { diff --git a/connections/implementation/mediums/wifi_direct.cc b/connections/implementation/mediums/wifi_direct.cc index 4655b116..874f9031 100644 --- a/connections/implementation/mediums/wifi_direct.cc +++ b/connections/implementation/mediums/wifi_direct.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ namespace nearby { namespace connections { - namespace { using ::location::nearby::proto::connections::OperationResultCode; } // namespace @@ -102,14 +101,14 @@ bool WifiDirect::IsConnectedToGO() { return is_connected_to_go_; } -bool WifiDirect::ConnectWifiDirect(const std::string& ssid, - const std::string& password) { +bool WifiDirect::ConnectWifiDirect( + const WifiDirectCredentials& wifi_direct_credentials) { MutexLock lock(&mutex_); if (is_connected_to_go_) { LOG(INFO) << "No need to connect to GO because it is already connected."; return true; } - is_connected_to_go_ = medium_.ConnectWifiDirect(ssid, password); + is_connected_to_go_ = medium_.ConnectWifiDirect(wifi_direct_credentials); return is_connected_to_go_; } @@ -135,10 +134,7 @@ WifiDirectCredentials* WifiDirect::GetCredentials( << ". Use default credentials"; return crendential; } - crendential->SetGateway(it->second.GetIPAddress()); - crendential->SetIPAddress(it->second.GetIPAddress()); - crendential->SetPort(it->second.GetPort()); - + it->second.PopulateWifiDirectCredentials(*crendential); return crendential; } @@ -168,7 +164,7 @@ bool WifiDirect::StartAcceptingConnections( } // "port=0" to let the platform to select an available port for the socket - WifiDirectServerSocket server_socket = medium_.ListenForService(/*port=*/0); + WifiDirectServerSocket server_socket = medium_.ListenForService(); if (!server_socket.IsValid()) { LOG(INFO) << "Failed to start to listen on WifiDirect GO server for service_id=" @@ -258,8 +254,6 @@ ErrorOr WifiDirect::Connect( const std::string& service_id, const std::string& ip_address, int port, CancellationFlag* cancellation_flag) { MutexLock lock(&mutex_); - // Socket to return. To allow for NRVO to work, it has to be a single object. - WifiDirectSocket socket; if (service_id.empty()) { LOG(INFO) << "Refusing to create client WifiDirect socket because " @@ -281,6 +275,8 @@ ErrorOr WifiDirect::Connect( CLIENT_CANCELLATION_CANCEL_WIFI_DIRECT_OUTGOING_CONNECTION)}; } + // Socket to return. To allow for NRVO to work, it has to be a single object. + WifiDirectSocket socket; socket = medium_.ConnectToService(ip_address, port, cancellation_flag); if (!socket.IsValid()) { LOG(INFO) << "Failed to Connect via WifiDirect Server [service_id=" diff --git a/connections/implementation/mediums/wifi_direct.h b/connections/implementation/mediums/wifi_direct.h index 69935fbc..df2849b6 100644 --- a/connections/implementation/mediums/wifi_direct.h +++ b/connections/implementation/mediums/wifi_direct.h @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/multi_thread_executor.h" @@ -51,7 +52,7 @@ class WifiDirect { // If WifiDirect Group Owner started bool IsGOStarted() ABSL_LOCKS_EXCLUDED(mutex_); - // Start WifiDirect Group Owner. Returns true if AutoGO is successfully + // Start WifiDirect Group Owner. Returns true if WifiDirect GO is successfully // started. bool StartWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_); // Stop WifiDirect Group Owner @@ -60,7 +61,7 @@ class WifiDirect { // If WifiDirect Group Client connects to Group Owner bool IsConnectedToGO() ABSL_LOCKS_EXCLUDED(mutex_); // WifiDirect Group Client request to connect to the Group Owner - bool ConnectWifiDirect(const std::string& ssid, const std::string& password) + bool ConnectWifiDirect(const WifiDirectCredentials& wifi_direct_credentials) ABSL_LOCKS_EXCLUDED(mutex_); // WifiDirect Group Client request to disconnect from the Group Owner bool DisconnectWifiDirect() ABSL_LOCKS_EXCLUDED(mutex_); @@ -118,7 +119,6 @@ class WifiDirect { absl::flat_hash_map server_sockets_ ABSL_GUARDED_BY(mutex_); }; - } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/wifi_direct_test.cc b/connections/implementation/mediums/wifi_direct_test.cc index 72ec500e..930f3df1 100644 --- a/connections/implementation/mediums/wifi_direct_test.cc +++ b/connections/implementation/mediums/wifi_direct_test.cc @@ -1,5 +1,5 @@ -// Copyright 2020 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ #include "absl/strings/string_view.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/medium_environment.h" #include "internal/platform/wifi_credential.h" #include "internal/platform/wifi_direct.h" @@ -42,8 +43,8 @@ constexpr FeatureFlags kTestCases[] = { }; constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; -constexpr absl::string_view kSsid{"Direct-357a2d8c"}; -constexpr absl::string_view kPassword{"12345678"}; +constexpr absl::string_view kServiceName{"NC-WifiDirectTest"}; +constexpr absl::string_view kPin{"12345678"}; constexpr absl::string_view kIp = "123.234.23.1"; constexpr const size_t kPort = 20; @@ -85,11 +86,14 @@ TEST_F(WifiDirectTest, CanStartStopGO) { } TEST_F(WifiDirectTest, GCCanConnectDisconnectGO) { - std::string ssid(kSsid); - std::string password(kPassword); + WifiDirectCredentials wifi_direct_credentials; + std::string service_name(kServiceName); + std::string pin(kPin); + wifi_direct_credentials.SetServiceName(service_name); + wifi_direct_credentials.SetPin(pin); WifiDirect wifi_direct_a; - EXPECT_FALSE(wifi_direct_a.ConnectWifiDirect(ssid, password)); + EXPECT_FALSE(wifi_direct_a.ConnectWifiDirect(wifi_direct_credentials)); EXPECT_TRUE(wifi_direct_a.DisconnectWifiDirect()); } @@ -110,9 +114,7 @@ TEST_P(WifiDirectTest, CanStartGOThatOtherConnect) { WifiDirectCredentials* wifi_direct_credentials = wifi_direct_a.GetCredentials(service_id); - EXPECT_TRUE( - wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials->GetSSID(), - wifi_direct_credentials->GetPassword())); + EXPECT_TRUE(wifi_direct_b.ConnectWifiDirect(*wifi_direct_credentials)); EXPECT_TRUE(wifi_direct_b.IsConnectedToGO()); WifiDirectSocket socket_client; @@ -150,9 +152,7 @@ TEST_P(WifiDirectTest, CanStartGOThatOtherCanCancelConnect) { WifiDirectCredentials* wifi_direct_credentials = wifi_direct_a.GetCredentials(service_id); - EXPECT_TRUE( - wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials->GetSSID(), - wifi_direct_credentials->GetPassword())); + EXPECT_TRUE(wifi_direct_b.ConnectWifiDirect(*wifi_direct_credentials)); WifiDirectSocket socket_client; EXPECT_FALSE(socket_client.IsValid()); @@ -180,10 +180,12 @@ TEST_F(WifiDirectTest, CanStartGOTheOtherFailConnect) { EXPECT_TRUE(wifi_direct_a.StartWifiDirect()); - std::string ssid(kSsid); - std::string password(kPassword); - - EXPECT_FALSE(wifi_direct_b.ConnectWifiDirect(ssid, password)); + WifiDirectCredentials wifi_direct_credentials; + std::string service_name(kServiceName); + std::string pin(kPin); + wifi_direct_credentials.SetServiceName(service_name); + wifi_direct_credentials.SetPin(pin); + EXPECT_FALSE(wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials)); EXPECT_TRUE(wifi_direct_b.DisconnectWifiDirect()); EXPECT_TRUE(wifi_direct_a.StopWifiDirect()); } diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index a6a240fd..1168a5cc 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -369,7 +369,9 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, std::int32_t port, std::int32_t frequency, bool supports_disabling_encryption, - const std::string& gateway) { + const std::string& gateway, + const std::string& service_name, + const std::string& pin) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -390,6 +392,8 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, wifi_direct_credentials->set_port(port); wifi_direct_credentials->set_frequency(frequency); wifi_direct_credentials->set_gateway(gateway); + wifi_direct_credentials->set_service_name(service_name); + wifi_direct_credentials->set_pin(pin); return ToBytes(std::move(frame)); } diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index 59798d70..bbf15dbe 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -94,7 +94,9 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, std::int32_t port, std::int32_t frequency, bool supports_disabling_encryption, - const std::string& gateway); + const std::string& gateway, + const std::string& service_name, + const std::string& pin); ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, MacAddress mac_address); ByteArray ForBwuWebrtcPathAvailable( diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index 3c4945b9..9ec2377e 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -536,11 +536,13 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { upgrade_path_info: < medium: WIFI_DIRECT wifi_direct_credentials: < - ssid: "DIRECT-A0-0123456789AB" - password: "password" + ssid: "" + password: "" port: 1000 frequency: 2412 gateway: "192.168.1.1" + service_name: "NC-WifiDirectTest" + pin: "b592f7d3" > supports_disabling_encryption: false supports_client_introduction_ack: true @@ -548,7 +550,8 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { > >)pb"; ByteArray bytes = ForBwuWifiDirectPathAvailable( - "DIRECT-A0-0123456789AB", "password", 1000, 2412, false, "192.168.1.1"); + "", "", 1000, 2412, false, "192.168.1.1", + "NC-WifiDirectTest", "b592f7d3"); auto response = FromBytes(bytes); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); diff --git a/connections/implementation/offline_frames_validator.cc b/connections/implementation/offline_frames_validator.cc index c53afded..813d0b87 100644 --- a/connections/implementation/offline_frames_validator.cc +++ b/connections/implementation/offline_frames_validator.cc @@ -68,6 +68,8 @@ constexpr absl::string_view kWifiDirectSsidPatternString{ constexpr int kWifiDirectSsidMaxLength = 32; constexpr int kWifiPasswordSsidMinLength = 8; constexpr int kWifiPasswordSsidMaxLength = 64; +constexpr int kWifiDirectPinMinLength = 4; +constexpr int kWifiDirectPinMaxLength = 16; inline bool WithinRange(int value, int min, int max) { return value >= min && value < max; @@ -282,25 +284,36 @@ Exception EnsureValidBandwidthUpgradeWifiAwarePathAvailableFrame( Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame( const WifiDirectCredentials& wifi_direct_credentials) { - const std::regex ssid_pattern( - std::string(kWifiDirectSsidPatternString).c_str()); - if (!wifi_direct_credentials.has_ssid() || - !(wifi_direct_credentials.ssid().length() < kWifiDirectSsidMaxLength && - std::regex_match(wifi_direct_credentials.ssid(), ssid_pattern))) - return {Exception::kInvalidProtocolBuffer}; - - if (!wifi_direct_credentials.has_password() || - !WithinRange(wifi_direct_credentials.password().length(), - kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength)) - return {Exception::kInvalidProtocolBuffer}; - if (!wifi_direct_credentials.has_frequency() || wifi_direct_credentials.frequency() < -1) return {Exception::kInvalidProtocolBuffer}; + const std::regex ssid_pattern( + std::string(kWifiDirectSsidPatternString).c_str()); + bool ssid_valid = + wifi_direct_credentials.has_ssid() && + wifi_direct_credentials.ssid().length() < kWifiDirectSsidMaxLength && + std::regex_match(wifi_direct_credentials.ssid(), ssid_pattern); + bool password_valid = + wifi_direct_credentials.has_password() && + WithinRange(wifi_direct_credentials.password().length(), + kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength); + bool service_name_valid = + wifi_direct_credentials.has_service_name() && + wifi_direct_credentials.service_name().length() < + kWifiDirectSsidMaxLength; + bool pin_valid = + wifi_direct_credentials.has_pin() && + WithinRange(wifi_direct_credentials.pin().length(), + kWifiDirectPinMinLength, kWifiDirectPinMaxLength); + + if ((ssid_valid && password_valid) || (service_name_valid && pin_valid)) + return {Exception::kSuccess}; + + return {Exception::kInvalidProtocolBuffer}; + // For backwards compatibility reasons, no other fields should be null-checked // for this frame. Parameter checking (eg. must be within this range) is fine. - return {Exception::kSuccess}; } Exception EnsureValidBandwidthUpgradeBluetoothPathAvailableFrame( diff --git a/connections/implementation/offline_frames_validator_test.cc b/connections/implementation/offline_frames_validator_test.cc index 5c27c940..f0a63ff6 100644 --- a/connections/implementation/offline_frames_validator_test.cc +++ b/connections/implementation/offline_frames_validator_test.cc @@ -51,6 +51,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 absl::string_view kWifiDirectServiceName = "NC-WifiDirectTest"; +constexpr absl::string_view kWifiDirectPin = "b592f7d3"; constexpr absl::string_view kGateway = "192.168.1.1"; constexpr int kWifiDirectFrequency = 2412; constexpr int kPort = 1000; @@ -726,8 +728,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkBandwidthUpgradeWifiDirect) { ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, - kWifiDirectFrequency, kSupportsDisablingEncryption, - std::string(kGateway)); + kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), + std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); offline_frame.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -743,7 +745,8 @@ TEST(OfflineFramesValidatorTest, // Anything less than -1 is invalid ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -2, - kSupportsDisablingEncryption, std::string(kGateway)); + kSupportsDisablingEncryption, std::string(kGateway), + std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -753,7 +756,8 @@ TEST(OfflineFramesValidatorTest, // But -1 itself is not invalid bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -1, - kSupportsDisablingEncryption, std::string(kGateway)); + kSupportsDisablingEncryption, std::string(kGateway), + std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -767,10 +771,12 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame_2; std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"}; + std::string wifi_direct_pin_wrong_length = "abc"; ByteArray bytes = ForBwuWifiDirectPathAvailable( wifi_direct_ssid, std::string(kWifiDirectPassword), kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, - std::string(kGateway)); + std::string(kGateway), std::string(kWifiDirectServiceName), + wifi_direct_pin_wrong_length); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -779,10 +785,14 @@ TEST(OfflineFramesValidatorTest, std::string wifi_direct_ssid_wrong_length = std::string{kWifiDirectSsid} + "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; + std::string wifi_direct_service_name_wrong_length = + std::string{kWifiDirectServiceName} + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; bytes = ForBwuWifiDirectPathAvailable( wifi_direct_ssid_wrong_length, std::string(kWifiDirectPassword), kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, - std::string(kGateway)); + std::string(kGateway), wifi_direct_service_name_wrong_length, + std::string(kWifiDirectPin)); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -796,10 +806,12 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame_2; std::string short_wifi_direct_password{"Test"}; + std::string short_wifi_direct_pin{"abc"}; ByteArray bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), short_wifi_direct_password, kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, - std::string(kGateway)); + std::string(kGateway), std::string(kWifiDirectServiceName), + short_wifi_direct_pin); offline_frame_1.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -809,10 +821,14 @@ TEST(OfflineFramesValidatorTest, std::string long_wifi_direct_password = std::string{kWifiDirectSsid} + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"; + std::string long_wifi_direct_pin = + std::string{kWifiDirectPin} + + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"; bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), long_wifi_direct_password, kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, - std::string(kGateway)); + std::string(kGateway), std::string(kWifiDirectServiceName), + long_wifi_direct_pin); offline_frame_2.ParseFromString(std::string(bytes)); ret_value = EnsureValidOfflineFrame(offline_frame_2); diff --git a/connections/implementation/p2p_point_to_point_pcp_handler.cc b/connections/implementation/p2p_point_to_point_pcp_handler.cc index 7f639f6e..88dc877d 100644 --- a/connections/implementation/p2p_point_to_point_pcp_handler.cc +++ b/connections/implementation/p2p_point_to_point_pcp_handler.cc @@ -49,9 +49,13 @@ P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(location::nearby::proto::connections::WIFI_LAN); } - if (mediums_->GetWifi().IsAvailable() && - mediums_->GetWifiDirect().IsGCAvailable()) { - mediums.push_back(location::nearby::proto::connections::WIFI_DIRECT); + if (NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_connections_feature:: + kEnableWifiDirect)) { + if (mediums_->GetWifi().IsAvailable() && + mediums_->GetWifiDirect().IsGCAvailable()) { + mediums.push_back(location::nearby::proto::connections::WIFI_DIRECT); + } } if (mediums_->GetWifi().IsAvailable() && mediums_->GetWifiHotspot().IsClientAvailable()) { diff --git a/connections/implementation/p2p_point_to_point_pcp_handler_test.cc b/connections/implementation/p2p_point_to_point_pcp_handler_test.cc index 94b9c86f..7997c5dd 100644 --- a/connections/implementation/p2p_point_to_point_pcp_handler_test.cc +++ b/connections/implementation/p2p_point_to_point_pcp_handler_test.cc @@ -83,6 +83,12 @@ constexpr BooleanMediumSelector kTestCases[] = { .wifi_lan = true, .wifi_hotspot = true, }, + BooleanMediumSelector{ + .bluetooth = true, + .ble = true, + .wifi_lan = true, + .wifi_direct = true, + }, BooleanMediumSelector{ .bluetooth = true, .ble = true, @@ -100,6 +106,9 @@ class P2pPointToPointPcpHandlerTest LOG(INFO) << "SetUp: begin"; NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature::kEnableAwdl, true); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableWifiDirect, + true); if (advertising_options_.allowed.ble) { LOG(INFO) << "SetUp: BLE enabled"; } diff --git a/connections/implementation/p2p_star_pcp_handler.cc b/connections/implementation/p2p_star_pcp_handler.cc index e1b5c728..c5e4205c 100644 --- a/connections/implementation/p2p_star_pcp_handler.cc +++ b/connections/implementation/p2p_star_pcp_handler.cc @@ -44,10 +44,6 @@ P2pStarPcpHandler::GetConnectionMediumsByPriority() { if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(location::nearby::proto::connections::WIFI_LAN); } - if (mediums_->GetWifi().IsAvailable() && - mediums_->GetWifiDirect().IsGCAvailable()) { - mediums.push_back(location::nearby::proto::connections::WIFI_DIRECT); - } if (mediums_->GetWifi().IsAvailable() && mediums_->GetWifiHotspot().IsClientAvailable()) { mediums.push_back(location::nearby::proto::connections::WIFI_HOTSPOT); diff --git a/connections/implementation/proto/offline_wire_formats.proto b/connections/implementation/proto/offline_wire_formats.proto index f9d8d3ff..71ce3ba3 100644 --- a/connections/implementation/proto/offline_wire_formats.proto +++ b/connections/implementation/proto/offline_wire_formats.proto @@ -329,10 +329,16 @@ message BandwidthUpgradeNegotiationFrame { // Windows only supports WifiDirect with Service Discovey. Its // credentials is the service_name/pin. optional string service_name = 7; - // The pin is exactly 8 digits. The first 7 digits are the PIN. The last 1 - // digit is a checksum calculated using a specific algorithm (CRC-8). The + // WifiDirect spec requires that pin is exactly 8 digits. The first 7 + // digits are the PIN. The last 1 digit is a checksum calculated using a + // specific algorithm (CRC-8). However, the Windows WinRT + // WiFiDirectServiceAdvertiser::ConnectAsync() that we use does NOT + // enforce the CRC-8 checksum for a WPS PIN because: 1. The ConnectAsync + // PIN is NOT necessarily a WPS PIN. 2. WPS PIN validation is performed by + // the Wi-Fi driver/firmware. 3. WFDS connections often bypass or replace + // WPS PIN authentication // pin is exchanged in the connection handshake stage, but we create and - // save it beforw starting GO, so we can send it to GC side for + // save it before starting GO, so we can send it to GC side for // authentication. optional string pin = 8; } diff --git a/connections/implementation/service_controller_router_test.cc b/connections/implementation/service_controller_router_test.cc index 9cdd465c..982c4922 100644 --- a/connections/implementation/service_controller_router_test.cc +++ b/connections/implementation/service_controller_router_test.cc @@ -1431,6 +1431,9 @@ TEST(ServiceControllerRouterCheckHpRealtekDeviceTest, TEST(ServiceControllerRouterCheckHpRealtekDeviceTest, notHPRealtekDevice_defaultBwuConfig) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableWifiDirect, + true); ServiceControllerRouter router( absl::AnyInvocable{[]() { return false; }}); auto service_controller = router.GetServiceController(); diff --git a/connections/implementation/wifi_direct_bwu_handler.cc b/connections/implementation/wifi_direct_bwu_handler.cc index a015bb7e..126c7610 100644 --- a/connections/implementation/wifi_direct_bwu_handler.cc +++ b/connections/implementation/wifi_direct_bwu_handler.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -41,12 +41,14 @@ namespace { using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::proto::connections::OperationResultCode; } // namespace - WifiDirectBwuHandler::WifiDirectBwuHandler( Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), mediums_(mediums) {} +// Called by BWU initiator. Set up WifiDirect upgraded medium for this +// endpoint, and returns an upgrade path info (ServiceName, Pin for Wifi WPS, +// Gateway used as IPAddress, Port) for remote party to perform connection. ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { @@ -82,19 +84,29 @@ ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( wifi_direct_medium_.GetCredentials(upgrade_service_id); std::string ssid = wifi_direct_crendential->GetSSID(); std::string password = wifi_direct_crendential->GetPassword(); + std::string service_name = wifi_direct_crendential->GetServiceName(); + std::string pin = wifi_direct_crendential->GetPin(); std::string gateway = wifi_direct_crendential->GetGateway(); int port = wifi_direct_crendential->GetPort(); int freq = wifi_direct_crendential->GetFrequency(); - LOG(INFO) << "Start WifiDirect GO with SSID: " << ssid - << ", Password: " << masker::Mask(password) << ", Port: " << port - << ", Gateway: " << gateway << ", Frequency: " << freq; + if (ssid.empty()) { + LOG(INFO) << "Start WifiDirect GO with ServiceName: " << service_name + << ", pin: " << masker::Mask(pin) << ", Port: " << port + << ", Gateway: " << gateway << ", Frequency: " << freq; + } else { + LOG(INFO) << "Start WifiDirect GO with SSID: " << ssid + << ", Password: " << masker::Mask(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); + /* supports_disabling_encryption */ disabling_encryption, gateway, + service_name, pin); } void WifiDirectBwuHandler::HandleRevertInitiatorStateForService( @@ -124,14 +136,34 @@ WifiDirectBwuHandler::CreateUpgradedEndpointChannel( const std::string& ssid = upgrade_path_info_credentials.ssid(); const std::string& password = upgrade_path_info_credentials.password(); + const std::string& service_name = + upgrade_path_info_credentials.service_name(); + const std::string& pin = upgrade_path_info_credentials.pin(); std::int32_t port = upgrade_path_info_credentials.port(); const std::string& gateway = upgrade_path_info_credentials.gateway(); + std::int32_t freq = upgrade_path_info_credentials.frequency(); - LOG(INFO) << "Received WifiDirect credential SSID: " << ssid - << ", Password:" << masker::Mask(password) << ", Port:" << port - << ", Gateway:" << gateway; + WifiDirectCredentials wifi_direct_credentials; + wifi_direct_credentials.SetSSID(ssid); + wifi_direct_credentials.SetPassword(password); + wifi_direct_credentials.SetServiceName(service_name); + wifi_direct_credentials.SetPin(pin); + wifi_direct_credentials.SetPort(port); + wifi_direct_credentials.SetGateway(gateway); + wifi_direct_credentials.SetFrequency(freq); - if (!wifi_direct_medium_.ConnectWifiDirect(ssid, password)) { + if (ssid.empty()) { + LOG(INFO) << "Received WifiDirect credential ServiceName: " << service_name + << ", pin: " << masker::Mask(pin) << ", Port: " << port + << ", Gateway: " << gateway << ", Frequency: " << freq; + } else { + LOG(INFO) << "Received WifiDirect credential SSID: " << ssid + << ", Password: " << masker::Mask(password) + << ", Port: " << port << ", Gateway: " << gateway + << ", Frequency: " << freq; + } + + if (!wifi_direct_medium_.ConnectWifiDirect(wifi_direct_credentials)) { LOG(ERROR) << "Connect to WifiDiret GO failed"; return {Error( OperationResultCode::CONNECTIVITY_WIFI_DIRECT_INVALID_CREDENTIAL)}; @@ -148,7 +180,7 @@ WifiDirectBwuHandler::CreateUpgradedEndpointChannel( VLOG(1) << "WifiDirectBwuHandler successfully connected to WifiDirect service (" - << port << ") while upgrading endpoint " << endpoint_id; + << gateway << ":" << port << ") while upgrading endpoint " << endpoint_id; // Create a new WifiDirectEndpointChannel. return {std::make_unique( @@ -168,6 +200,5 @@ void WifiDirectBwuHandler::OnIncomingWifiDirectConnection( }); NotifyOnIncomingConnection(client, std::move(connection)); } - } // namespace connections } // namespace nearby diff --git a/connections/implementation/wifi_direct_bwu_handler.h b/connections/implementation/wifi_direct_bwu_handler.h index 242704dd..34623d83 100644 --- a/connections/implementation/wifi_direct_bwu_handler.h +++ b/connections/implementation/wifi_direct_bwu_handler.h @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,12 +23,10 @@ #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/mediums.h" -#include "connections/implementation/mediums/wifi.h" #include "connections/implementation/mediums/wifi_direct.h" #include "internal/platform/byte_array.h" #include "internal/platform/expected.h" #include "internal/platform/wifi_direct.h" -#include "utility" namespace nearby { namespace connections { @@ -89,7 +87,6 @@ class WifiDirectBwuHandler : public BaseBwuHandler { WifiDirectSocket socket); Mediums& mediums_; - Wifi& wifi_medium_ = mediums_.GetWifi(); WifiDirect& wifi_direct_medium_ = mediums_.GetWifiDirect(); }; diff --git a/connections/implementation/wifi_direct_bwu_test.cc b/connections/implementation/wifi_direct_bwu_test.cc index 4f653816..92b06878 100644 --- a/connections/implementation/wifi_direct_bwu_test.cc +++ b/connections/implementation/wifi_direct_bwu_test.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,7 +30,6 @@ #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" -#include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" #include "internal/platform/single_thread_executor.h" @@ -85,18 +84,12 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { mutable_connection) { LOG(INFO) << "Server socket connection accept call back, Socket name: " << mutable_connection->socket->ToString(); - std::shared_ptr connection( - mutable_connection.release()); accept_latch.CountDown(); EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); - - connection->channel->Close(); - connection->socket->Close(); }); SingleThreadExecutor wfd_go_executor; - wfd_go_executor.Execute([&wfd_go_bwu_handler, &wifi_direct_go, &upgrade_frame, - &start_latch]() { + wfd_go_executor.Execute([&]() { ByteArray upgrade_path_available_frame = wfd_go_bwu_handler->InitializeUpgradedMediumForEndpoint( &wifi_direct_go, std::string(kServiceID), std::string(kEndpointID)); diff --git a/internal/platform/feature_flags.h b/internal/platform/feature_flags.h index 6d0e4de2..8b492396 100644 --- a/internal/platform/feature_flags.h +++ b/internal/platform/feature_flags.h @@ -118,6 +118,7 @@ class FeatureFlags { std::uint32_t connection_max_frame_length = 1048576; std::uint32_t blocking_queue_stream_queue_capacity = 10; bool support_web_rtc_non_cellular_medium = false; + std::uint32_t wifi_direct_default_port = 63034; }; static const FeatureFlags& GetInstance() { diff --git a/internal/platform/implementation/g3/wifi_direct.cc b/internal/platform/implementation/g3/wifi_direct.cc index be911626..5b154f47 100644 --- a/internal/platform/implementation/g3/wifi_direct.cc +++ b/internal/platform/implementation/g3/wifi_direct.cc @@ -19,12 +19,14 @@ #include #include +#include "absl/functional/any_invocable.h" #include "absl/log/check.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/platform/cancellation_flag.h" +#include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/logging.h" @@ -110,6 +112,14 @@ Exception WifiDirectServerSocket::DoClose() { return {Exception::kSuccess}; } +void WifiDirectServerSocket::PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) { + absl::MutexLock lock(mutex_); + wifi_direct_credentials.SetGateway(ip_address_); + wifi_direct_credentials.SetPort(port_); +} + + // Code for WifiDirectMedium WifiDirectMedium::WifiDirectMedium() { auto& env = MediumEnvironment::Instance(); @@ -125,13 +135,13 @@ bool WifiDirectMedium::StartWifiDirect( WifiDirectCredentials* wifi_direct_credentials) { absl::MutexLock lock(mutex_); - std::string ssid = absl::StrCat("DIRECT-", Prng().NextUint32()); - wifi_direct_credentials->SetSSID(ssid); - std::string password = absl::StrFormat("%08x", Prng().NextUint32()); - wifi_direct_credentials->SetPassword(password); + std::string service_name = absl::StrCat("NC-", Prng().NextUint32()); + wifi_direct_credentials->SetServiceName(service_name); + std::string pin = absl::StrFormat("%04x", Prng().NextUint32()); + wifi_direct_credentials->SetPin(pin); - LOG(INFO) << "G3 StartWifiDirect GO: ssid=" << ssid - << ", password:" << password; + LOG(INFO) << "G3 StartWifiDirect GO: service_name:" << service_name + << ", pin:" << pin; auto& env = MediumEnvironment::Instance(); env.UpdateWifiDirectMediumForStartOrConnect(*this, wifi_direct_credentials, @@ -152,24 +162,24 @@ bool WifiDirectMedium::StopWifiDirect() { } bool WifiDirectMedium::ConnectWifiDirect( - WifiDirectCredentials* wifi_direct_credentials) { + const WifiDirectCredentials& wifi_direct_credentials) { absl::MutexLock lock(mutex_); - LOG(INFO) << "G3 ConnectWifiDirect : ssid=" - << wifi_direct_credentials->GetSSID() - << ", password:" << wifi_direct_credentials->GetPassword(); + LOG(INFO) << "G3 ConnectWifiDirect : service_name:" + << wifi_direct_credentials.GetServiceName() + << ", pin:" << wifi_direct_credentials.GetPin(); auto& env = MediumEnvironment::Instance(); auto* remote_medium = static_cast( - env.GetWifiDirectMedium(wifi_direct_credentials->GetSSID(), {})); + env.GetWifiDirectMedium(wifi_direct_credentials.GetServiceName(), "")); if (!remote_medium) { - env.UpdateWifiDirectMediumForStartOrConnect(*this, wifi_direct_credentials, + env.UpdateWifiDirectMediumForStartOrConnect(*this, &wifi_direct_credentials, /*is_go=*/false, /*enabled=*/false); return false; } - env.UpdateWifiDirectMediumForStartOrConnect(*this, wifi_direct_credentials, + env.UpdateWifiDirectMediumForStartOrConnect(*this, &wifi_direct_credentials, /*is_go=*/false, /*enabled=*/true); return true; @@ -198,7 +208,7 @@ std::unique_ptr WifiDirectMedium::ConnectToService( auto* remote_medium = static_cast(env.GetWifiDirectMedium({}, ip_address)); if (remote_medium == nullptr) { - return nullptr; + return {}; } WifiDirectServerSocket* server_socket = nullptr; @@ -214,21 +224,32 @@ std::unique_ptr WifiDirectMedium::ConnectToService( LOG(ERROR) << "G3 WifiDirect Failed to find WifiDirect Server " "socket: socket_name=" << socket_name; - return nullptr; + return {}; } } if (cancellation_flag->Cancelled()) { LOG(ERROR) << "G3 WifiDirect Connect: Has been cancelled: socket_name=" << socket_name; - return nullptr; + return {}; } + CancellationFlagListener listener(cancellation_flag, [&server_socket]() { + LOG(INFO) << "G3 WifiDirect Cancel Connect."; + if (server_socket != nullptr) { + server_socket->Close(); + } + }); + auto socket = std::make_unique(); // Finally, Request to connect to this socket. - - server_socket->Connect(*socket); - LOG(INFO) << "G3 WifiDirect GC ConnectToService: connected: socket=" + if (!server_socket->Connect(*socket)) { + LOG(ERROR) << "G3 WifiDirect Failed to connect to existing WifiDirect " + "Server socket: name=" + << socket_name; + return {}; + } + LOG(INFO) << "G3 WifiDirect ConnectToService: connected: socket=" << socket.get(); return socket; } @@ -247,9 +268,10 @@ std::unique_ptr WifiDirectMedium::ListenForService( dot_decimal_ip.pop_back(); server_socket->SetIPAddress(dot_decimal_ip); - server_socket->SetPort(port == 0 ? env.GetFakePort() : port); - std::string socket_name = WifiDirectServerSocket::GetName( - server_socket->GetIPAddress(), server_socket->GetPort()); + int port_to_use = port == 0 ? env.GetFakePort() : port; + server_socket->SetPort(port_to_use); + std::string socket_name = + WifiDirectServerSocket::GetName(dot_decimal_ip, port_to_use); server_socket->SetCloseNotifier([this, socket_name]() { absl::MutexLock lock(mutex_); server_sockets_.erase(socket_name); diff --git a/internal/platform/implementation/g3/wifi_direct.h b/internal/platform/implementation/g3/wifi_direct.h index 0ff75f65..f53d1b7e 100644 --- a/internal/platform/implementation/g3/wifi_direct.h +++ b/internal/platform/implementation/g3/wifi_direct.h @@ -15,17 +15,26 @@ #ifndef PLATFORM_IMPL_G3_WIFI_DIRECT_H_ #define PLATFORM_IMPL_G3_WIFI_DIRECT_H_ +#include #include #include #include #include +#include +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" #include "internal/platform/implementation/g3/socket_base.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace g3 { @@ -112,6 +121,12 @@ class WifiDirectServerSocket : public api::WifiDirectServerSocket { // Calls close_notifier if it was previously set, and marks socket as closed. Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + // Populates the provided `wifi_direct_credentials` with the IP address + // and port of this server socket. + void PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) override + ABSL_LOCKS_EXCLUDED(mutex_); + private: // Retrieves IP addresses from local machine std::vector GetIpAddresses() const; @@ -158,7 +173,7 @@ class WifiDirectMedium : public api::WifiDirectMedium { bool StopWifiDirect() override; // Discoverer connects to the WiFiDirect GO bool ConnectWifiDirect( - WifiDirectCredentials* wifi_direct_credentials) override; + const WifiDirectCredentials& wifi_direct_credentials) override; // Discoverer disconnects from the WiFiDirect GO bool DisconnectWifiDirect() override; diff --git a/internal/platform/implementation/wifi_direct.h b/internal/platform/implementation/wifi_direct.h index aa23e8da..0d267b29 100644 --- a/internal/platform/implementation/wifi_direct.h +++ b/internal/platform/implementation/wifi_direct.h @@ -15,11 +15,15 @@ #ifndef PLATFORM_API_WIFI_DIRECT_H_ #define PLATFORM_API_WIFI_DIRECT_H_ +#include #include #include #include +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "internal/platform/cancellation_flag.h" +#include "internal/platform/exception.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" #include "internal/platform/wifi_credential.h" @@ -67,6 +71,11 @@ class WifiDirectServerSocket { // Returns Exception::kIo on error, Exception::kSuccess otherwise. virtual Exception Close() = 0; + + // Populates the WifiDirect credentials with the server socket's service + // addresses and ports. + virtual void PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) = 0; }; // Container of operations that can be performed over the WifiLan medium. @@ -104,7 +113,7 @@ class WifiDirectMedium { // Client device connect to a softAP with specified credential. virtual bool ConnectWifiDirect( - WifiDirectCredentials* wifi_direct_credentials) = 0; + const WifiDirectCredentials& wifi_direct_credentials) = 0; virtual bool DisconnectWifiDirect() = 0; // Returns the port range as a pair of min and max port. diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index 17e98502..04a67ac6 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -74,8 +74,8 @@ #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/implementation/windows/submittable_executor.h" #include "internal/platform/implementation/windows/timer.h" -#include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi.h" +#include "internal/platform/implementation/windows/wifi_direct.h" #include "internal/platform/implementation/windows/wifi_hotspot.h" #include "internal/platform/implementation/windows/wifi_lan.h" #include "internal/platform/logging.h" @@ -284,7 +284,7 @@ ImplementationPlatform::CreateWifiHotspotMedium() { std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { - return nullptr; + return std::make_unique(); } // TODO(b/261663238) replace with real implementation. diff --git a/internal/platform/implementation/windows/wifi_direct.h b/internal/platform/implementation/windows/wifi_direct.h index 5a147e11..154c13e1 100644 --- a/internal/platform/implementation/windows/wifi_direct.h +++ b/internal/platform/implementation/windows/wifi_direct.h @@ -29,18 +29,20 @@ // Nearby connections headers #include "absl/base/nullability.h" #include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/types/optional.h" -#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/windows/nearby_client_socket.h" #include "internal/platform/implementation/windows/nearby_server_socket.h" +#include "internal/platform/implementation/windows/socket_address.h" #include "internal/platform/implementation/windows/submittable_executor.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" +#include "internal/platform/wifi_credential.h" // WinRT headers #include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h" @@ -78,10 +80,10 @@ using ::winrt::Windows::Foundation::AsyncStatus; using ::winrt::Windows::Foundation::IInspectable; // WifiDirectSocket wraps the socket functions to read and write stream. -// In WiFi HOTSPOT, A WifiDirectSocket will be passed to +// On WiFiDirect GO serverside, a WifiDirectSocket will be passed to // StartAcceptingConnections's callback when Winsock Server Socket receives a -// new connection. When call API to connect to remote WiFi Hotspot service, also -// will return a WifiDirectSocket to caller. +// new connection. When client side call API to connect to remote WiFi +// WifiDirect GO service, it will return a WifiDirectServiceSocket to caller. class WifiDirectSocket : public api::WifiDirectSocket { public: WifiDirectSocket(); @@ -113,42 +115,6 @@ class WifiDirectSocket : public api::WifiDirectSocket { } private: - // A simple wrapper to handle input stream of socket - class SocketInputStream : public InputStream { - public: - explicit SocketInputStream(NearbyClientSocket* absl_nonnull client_socket) - : client_socket_(client_socket) {} - ~SocketInputStream() override = default; - - ExceptionOr Read(std::int64_t size) override { - return client_socket_->Read(size); - } - ExceptionOr Skip(size_t offset) override { - return client_socket_->Skip(offset); - } - Exception Close() override { return client_socket_->Close(); } - - private: - NearbyClientSocket* absl_nonnull const client_socket_; - }; - - // A simple wrapper to handle output stream of socket - class SocketOutputStream : public OutputStream { - public: - explicit SocketOutputStream(NearbyClientSocket* absl_nonnull client_socket) - : client_socket_(client_socket) {} - ~SocketOutputStream() override = default; - - Exception Write(const ByteArray& data) override { - return client_socket_->Write(data); - } - Exception Flush() override { return client_socket_->Flush(); } - Exception Close() override { return client_socket_->Close(); } - - private: - NearbyClientSocket* absl_nonnull const client_socket_; - }; - absl_nonnull std::unique_ptr client_socket_; SocketInputStream input_stream_; SocketOutputStream output_stream_; @@ -158,15 +124,14 @@ class WifiDirectSocket : public api::WifiDirectSocket { // server socket accepts connection from clients. class WifiDirectServerSocket : public api::WifiDirectServerSocket { public: - explicit WifiDirectServerSocket(int port = 0); - WifiDirectServerSocket(const WifiDirectServerSocket&) = default; - WifiDirectServerSocket(WifiDirectServerSocket&&) = default; + WifiDirectServerSocket() = default; ~WifiDirectServerSocket() override; - WifiDirectServerSocket& operator=(const WifiDirectServerSocket&) = default; + WifiDirectServerSocket(WifiDirectServerSocket&&) = default; WifiDirectServerSocket& operator=(WifiDirectServerSocket&&) = default; std::string GetIPAddress() const override; - int GetPort() const override; + + int GetPort() const override { return server_socket_.GetPort(); } // Blocks until either: // - at least one incoming connection request is available, or @@ -179,83 +144,69 @@ class WifiDirectServerSocket : public api::WifiDirectServerSocket { // Called by the server side of a connection before passing ownership of // WifiDirectServerSocker to user, to track validity of a pointer to // this server socket. - void SetCloseNotifier(absl::AnyInvocable notifier); + void SetCloseNotifier(absl::AnyInvocable notifier) { + server_socket_.SetCloseNotifier(std::move(notifier)); + } // Returns Exception::kIo on error, Exception::kSuccess otherwise. Exception Close() override; - // Binds to local port - bool Listen(bool dual_stack, std::string& ip_address); + // Populates the provided `wifi_direct_credentials` with the IP address + // and port of this server socket. + void PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) override; - NearbyServerSocket server_socket_; + void SetIPAddress(std::string ip_address); + + // Binds to local port + bool Listen(int port, bool dual_stack); private: - // Retrieves hotspot IP address from local machine + // Retrieves WifiDirect GO IP address from local machine std::string GetWifiDirectIpAddress() const; - const int port_; mutable absl::Mutex mutex_; - - // Close notifier - absl::AnyInvocable close_notifier_ = nullptr; + absl::CondVar is_listen_ready_; + bool is_listen_started_ ABSL_GUARDED_BY(mutex_) = false; // IP addresses of the server socket. std::string wifi_direct_ipaddr_ = {}; bool closed_ = false; + NearbyServerSocket server_socket_; }; -class WifiDirectDiscovered { - public: - explicit WifiDirectDiscovered(const DeviceInformation& device_info); - - ~WifiDirectDiscovered() = default; - WifiDirectDiscovered(WifiDirectDiscovered&&) = default; - WifiDirectDiscovered& operator=(WifiDirectDiscovered&&) = default; - - std::string GetId() { return id_; } - DeviceInformation GetDeviceInformation() { - return windows_wifi_direct_device_; - } - - private: - DeviceInformation windows_wifi_direct_device_; - - // Once the device is lost, we can no longer access it's id. - std::string id_; - - // Once the device is lost, we can no longer access it's mac address. - // std::string name_; -}; - -class WifiDirectMedium { +class WifiDirectMedium : public api::WifiDirectMedium { public: WifiDirectMedium(); - ~WifiDirectMedium(); + ~WifiDirectMedium() override; // WifiDirectMedium is neither copyable nor movable. WifiDirectMedium(const WifiDirectMedium&) = delete; WifiDirectMedium& operator=(const WifiDirectMedium&) = delete; // If the WiFi Adaptor supports to start WifiDirect Service GO. - bool IsInterfaceValid() const; + bool IsInterfaceValid() const override; // Discoverer connects to server socket std::unique_ptr ConnectToService( absl::string_view ip_address, int port, - CancellationFlag* cancellation_flag); + CancellationFlag* cancellation_flag) override; // Advertiser starts to listen on server socket - std::unique_ptr ListenForService(int port); + std::unique_ptr ListenForService( + int port) override; - // Starts to advertising - bool StartWifiDirect(); - // Stops to advertising - bool StopWifiDirect(); - // Connects to a WifiDirect - bool ConnectWifiDirect(); - // Disconnects from a WifiDirect - bool DisconnectWifiDirect(); + // Advertiser start WiFiDirect GO with specific Credentials. + bool StartWifiDirect(WifiDirectCredentials* wifi_direct_credentials) override; + // Advertiser stop the current WiFiDirect GO. + bool StopWifiDirect() override; + // Discoverer connects to the WifiDirect GO as GC. + bool ConnectWifiDirect( + const WifiDirectCredentials& wifi_direct_credentials) override; + // Discoverer disconnects from the connected WifiDirect GO. + bool DisconnectWifiDirect() override; - absl::optional> GetDynamicPortRange() { + absl::optional> GetDynamicPortRange() + override { return absl::nullopt; } @@ -263,7 +214,7 @@ class WifiDirectMedium { enum Value : char { kMediumStatusIdle = 0, kMediumStatusAccepting = (1 << 0), - kMediumStatusServiceStarted = (1 << 1), + kMediumStatusGOStarted = (1 << 1), kMediumStatusConnecting = (1 << 2), kMediumStatusConnected = (1 << 3), }; @@ -273,9 +224,9 @@ class WifiDirectMedium { bool IsIdle() { return medium_status_ == kMediumStatusIdle; } // Advertiser is accepting connection on server socket bool IsAccepting() { return (medium_status_ & kMediumStatusAccepting) != 0; } - // Advertiser started WifiDirect - bool IsServiceStarted() { - return (medium_status_ & kMediumStatusServiceStarted) != 0; + // Advertiser started WifiDirect GO + bool IsGOStarted() { + return (medium_status_ & kMediumStatusGOStarted) != 0; } // Discoverer is connecting with the WifiDirect bool IsConnecting() { @@ -326,6 +277,9 @@ class WifiDirectMedium { IInspectable inspectable); fire_and_forget Watcher_DeviceStopped(DeviceWatcher sender, IInspectable inspectable); + + WifiDirectCredentials* credentials_go_ = nullptr; + WifiDirectCredentials credentials_gc_; std::string ip_address_local_; std::string ip_address_remote_; @@ -334,12 +288,6 @@ class WifiDirectMedium { // Keep the server socket listener pointer WifiDirectServerSocket* server_socket_ptr_ ABSL_GUARDED_BY(mutex_) = nullptr; SubmittableExecutor listener_executor_; - - absl::flat_hash_map> - discovered_devices_by_id_; - - absl::flat_hash_map> - connection_requested_devices_by_id_; }; } // namespace nearby::windows diff --git a/internal/platform/implementation/windows/wifi_direct_medium.cc b/internal/platform/implementation/windows/wifi_direct_medium.cc index 9c4066b7..c6ed7775 100644 --- a/internal/platform/implementation/windows/wifi_direct_medium.cc +++ b/internal/platform/implementation/windows/wifi_direct_medium.cc @@ -19,24 +19,25 @@ #include #include +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/flags/nearby_platform_feature_flags.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/windows/socket_address.h" -#include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi_direct.h" #include "internal/platform/logging.h" +#include "internal/platform/prng.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace windows { namespace { -constexpr std::wstring_view kServiceName = L"QuickShare"; -constexpr std::wstring_view kPin = L"1234"; constexpr int kWaitingForConnectionTimeoutSeconds = 90; // seconds } // namespace @@ -193,11 +194,12 @@ std::unique_ptr WifiDirectMedium::ConnectToService( // Advertiser starts to listen on server socket std::unique_ptr WifiDirectMedium::ListenForService( int port) { - LOG(INFO) << "WifiDirectMedium::ListenForService"; + LOG(INFO) << __func__ + << " :Start to listen connection from WiFiDirect client."; absl::MutexLock lock(mutex_); - if (!IsServiceStarted()) { - LOG(WARNING) << "WifiDirect service is not started, skip."; + if (!IsGOStarted()) { + LOG(WARNING) << "WifiDirect GO is not started, skip."; return nullptr; } // check current status @@ -207,14 +209,14 @@ std::unique_ptr WifiDirectMedium::ListenForService( return nullptr; } - auto server_socket = std::make_unique(port); + auto server_socket = std::make_unique(); server_socket_ptr_ = server_socket.get(); // Start to listen on server socket in a separate thread. Before GC // connects to GO, GO doesn't have IP address. BWU calls this API right away // after it starts GO, we need to spin out the following logic to another // thread to avoid blocking BWU sending out of band upgrade frame to GC. - listener_executor_.Execute([this]() mutable { + listener_executor_.Execute([this, port]() mutable { absl::MutexLock lock(mutex_); bool dual_stack = NearbyFlags::GetInstance().GetBoolFlag( platform::config_package_nearby::nearby_platform_feature:: @@ -239,9 +241,12 @@ std::unique_ptr WifiDirectMedium::ListenForService( LOG(INFO) << "IP address is ready."; } } - + server_socket_ptr_->SetIPAddress(ip_address_local_); + if (port == 0) { + port = FeatureFlags::GetInstance().GetFlags().wifi_direct_default_port; + } if (server_socket_ptr_ && - server_socket_ptr_->Listen(dual_stack, ip_address_local_)) { + server_socket_ptr_->Listen(port, dual_stack)) { medium_status_ |= kMediumStatusAccepting; // Setup close notifier after listen started. @@ -267,17 +272,27 @@ std::unique_ptr WifiDirectMedium::ListenForService( return server_socket; } -bool WifiDirectMedium::StartWifiDirect() { +bool WifiDirectMedium::StartWifiDirect( + WifiDirectCredentials* wifi_direct_credentials) { LOG(INFO) << "WifiDirectMedium::StartWifiDirect"; absl::MutexLock lock(mutex_); - if (IsServiceStarted()) { - LOG(WARNING) << "Already started WifiDirect service, skip."; + if (IsGOStarted()) { + LOG(WARNING) << "Already started WifiDirect GO, skip."; return true; } + credentials_go_ = wifi_direct_credentials; + Prng prng; + std::string pin = absl::StrFormat("%04x", prng.NextUint32()); + credentials_go_->SetPin(pin); + + std::string service_name = "NC-" + std::to_string(prng.NextUint32()); + credentials_go_->SetServiceName(service_name); + LOG(INFO) << "service_name:pin " << service_name << ":" << pin; + // Create Advertiser object - advertiser_ = WiFiDirectServiceAdvertiser(kServiceName); + advertiser_ = WiFiDirectServiceAdvertiser(winrt::to_hstring(service_name)); advertisement_status_changed_token_ = advertiser_.AdvertisementStatusChanged( {this, &WifiDirectMedium::OnAdvertisementStatusChanged}); auto_accept_session_connected_token_ = advertiser_.AutoAcceptSessionConnected( @@ -290,7 +305,7 @@ bool WifiDirectMedium::StartWifiDirect() { advertiser_.ServiceStatus(WiFiDirectServiceStatus::Available); // Config Methods WiFiDirectServiceConfigurationMethod config_method; - if (kPin.empty()) { + if (pin.empty()) { config_method = WiFiDirectServiceConfigurationMethod::Default; // NOLINT } else { config_method = WiFiDirectServiceConfigurationMethod::PinDisplay; @@ -306,7 +321,7 @@ bool WifiDirectMedium::StartWifiDirect() { WiFiDirectServiceAdvertisementStatus::Created) || (advertiser_.AdvertisementStatus() == WiFiDirectServiceAdvertisementStatus::Started)) { - medium_status_ |= kMediumStatusServiceStarted; + medium_status_ |= kMediumStatusGOStarted; return true; } LOG(ERROR) << "Start WifiDirect GO failed."; @@ -331,7 +346,7 @@ bool WifiDirectMedium::StartWifiDirect() { bool WifiDirectMedium::StopWifiDirect() { LOG(INFO) << "WifiDirectMedium::StopWifiDirect"; absl::MutexLock lock(mutex_); - if (!IsServiceStarted()) { + if (!IsGOStarted()) { LOG(WARNING) << "Cannot stop Service because no Service is started."; return true; } @@ -348,9 +363,11 @@ bool WifiDirectMedium::StopWifiDirect() { device_info_ = nullptr; session_ = nullptr; } - medium_status_ &= (~kMediumStatusServiceStarted); + medium_status_ &= (~kMediumStatusGOStarted); medium_status_ &= (~kMediumStatusConnected); server_socket_ptr_ = nullptr; + ip_address_local_.clear(); + ip_address_remote_.clear(); listener_executor_.Shutdown(); return true; } catch (std::exception exception) { @@ -465,10 +482,12 @@ fire_and_forget WifiDirectMedium::OnSessionRequested( absl::MutexLock lock(mutex_); WiFiDirectServiceSession session = nullptr; - if (kPin.empty()) { + auto pin = credentials_go_->GetPin(); + if (pin.empty()) { session = advertiser_.ConnectAsync(device_info_).get(); // NOLINT } else { - session = advertiser_.ConnectAsync(device_info_, kPin).get(); + session = advertiser_.ConnectAsync(device_info_, winrt::to_hstring(pin)) + .get(); } LOG(INFO) << "GO: TryEnqueue: Wait for ConnectAsync finish"; if (!session) { @@ -519,7 +538,8 @@ fire_and_forget WifiDirectMedium::OnSessionRequested( } } -bool WifiDirectMedium::ConnectWifiDirect() { +bool WifiDirectMedium::ConnectWifiDirect( + const WifiDirectCredentials& credentials) { LOG(INFO) << "WifiDirectMedium::ConnectWifiDirect"; absl::MutexLock lock(mutex_); if (IsConnecting()) { @@ -533,10 +553,9 @@ bool WifiDirectMedium::ConnectWifiDirect() { return false; } - discovered_devices_by_id_.clear(); - connection_requested_devices_by_id_.clear(); - - winrt::hstring device_selector = WiFiDirectService::GetSelector(kServiceName); + credentials_gc_ = credentials; + winrt::hstring device_selector = WiFiDirectService::GetSelector( + winrt::to_hstring(credentials_gc_.GetServiceName())); const winrt::param::iterable requested_properties = winrt::single_threaded_vector({ winrt::to_hstring("System.Devices.WiFiDirectServices.ServiceAddress"), @@ -590,7 +609,8 @@ fire_and_forget WifiDirectMedium::Watcher_DeviceAdded( service_.PreferGroupOwnerMode(false); WiFiDirectServiceSession session = nullptr; - if (kPin.empty()) { + auto pin = credentials_gc_.GetPin(); + if (pin.empty()) { session = service_.ConnectAsync().get(); // NOLINT } else { auto prov_info = co_await service_.GetProvisioningInfoAsync( @@ -605,7 +625,7 @@ fire_and_forget WifiDirectMedium::Watcher_DeviceAdded( << ConfigMethodToString( prov_info.SelectedConfigurationMethod()); - session = service_.ConnectAsync(kPin).get(); + session = service_.ConnectAsync(winrt::to_hstring(pin)).get(); } if (!session) { @@ -702,7 +722,9 @@ bool WifiDirectMedium::DisconnectWifiDirect() { device_watcher_ = nullptr; service_ = nullptr; session_ = nullptr; - return true; + ip_address_local_.clear(); + ip_address_remote_.clear(); + return true; } catch (std::exception exception) { LOG(ERROR) << __func__ << ": Stop WifiDirect GC failed. Exception: " << exception.what(); diff --git a/internal/platform/implementation/windows/wifi_direct_server_socket.cc b/internal/platform/implementation/windows/wifi_direct_server_socket.cc index 8a0e6df3..f534af4c 100644 --- a/internal/platform/implementation/windows/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_direct_server_socket.cc @@ -20,21 +20,20 @@ #include // Nearby connections headers -#include "absl/functional/any_invocable.h" #include "absl/synchronization/mutex.h" +#include "absl/time/time.h" #include "internal/platform/exception.h" +#include "internal/platform/feature_flags.h" #include "internal/platform/implementation/wifi_direct.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Connectivity.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h" #include "internal/platform/implementation/windows/socket_address.h" -#include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi_direct.h" #include "internal/platform/logging.h" +#include "internal/platform/wifi_credential.h" namespace nearby::windows { - -WifiDirectServerSocket::WifiDirectServerSocket(int port) : port_(port) {} +namespace { +constexpr int kWaitingForServerSocketReadyTimeoutSeconds = 90; // seconds +} // namespace WifiDirectServerSocket::~WifiDirectServerSocket() { Close(); } @@ -42,9 +41,29 @@ std::string WifiDirectServerSocket::GetIPAddress() const { return wifi_direct_ipaddr_; } -int WifiDirectServerSocket::GetPort() const { return server_socket_.GetPort(); } +void WifiDirectServerSocket::SetIPAddress(std::string ip_address) { + absl::MutexLock lock(&mutex_); + if (ip_address.empty()) { + return; + } + wifi_direct_ipaddr_ = ip_address; +} std::unique_ptr WifiDirectServerSocket::Accept() { + absl::MutexLock lock(&mutex_); + if (!is_listen_started_) { + LOG(INFO) << __func__ + << ": Server socket is not started, wait for server socket is " + "ready."; + is_listen_ready_.WaitWithTimeout( + &mutex_, absl::Seconds(kWaitingForServerSocketReadyTimeoutSeconds)); + if (!is_listen_started_) { + LOG(INFO) << __func__ + << ": Server socket failed to start within timeout."; + return nullptr; + } + } + auto client_socket = server_socket_.Accept(); if (client_socket == nullptr) { return nullptr; @@ -54,9 +73,16 @@ std::unique_ptr WifiDirectServerSocket::Accept() { return std::make_unique(std::move(client_socket)); } -void WifiDirectServerSocket::SetCloseNotifier( - absl::AnyInvocable notifier) { - close_notifier_ = std::move(notifier); +void WifiDirectServerSocket::PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) { + wifi_direct_credentials.SetGateway(wifi_direct_ipaddr_); + if (GetPort() != 0) { + wifi_direct_credentials.SetPort(GetPort()); + } else { + wifi_direct_credentials.SetPort(FeatureFlags::GetInstance() + .GetFlags() + .wifi_direct_default_port); + } } Exception WifiDirectServerSocket::Close() { @@ -64,35 +90,31 @@ Exception WifiDirectServerSocket::Close() { if (closed_) { return {Exception::kSuccess}; } - + wifi_direct_ipaddr_.clear(); + is_listen_started_ = false; server_socket_.Close(); closed_ = true; - if (close_notifier_ != nullptr) { - close_notifier_(); - } - LOG(INFO) << __func__ << ": Close completed succesfully."; return {Exception::kSuccess}; } -bool WifiDirectServerSocket::Listen(bool dual_stack, std::string& ip_address) { - // Get current IP addresses of the device. - if (ip_address.empty()) { - return false; - } - wifi_direct_ipaddr_ = ip_address; - LOG(INFO) << "Listen wifi_direct on IP:port " << ip_address << ":" << port_; +bool WifiDirectServerSocket::Listen(int port, bool dual_stack) { + LOG(INFO) << "Listen wifi_direct on IP:port " << wifi_direct_ipaddr_ << ":" + << port; SocketAddress address(dual_stack); - if (!SocketAddress::FromString(address, ip_address, port_)) { - LOG(ERROR) << "Failed to parse wifi_direct IP address: " << ip_address - << " and port: " << port_; + if (!SocketAddress::FromString(address, wifi_direct_ipaddr_, port)) { + LOG(ERROR) << "Failed to parse wifi_direct IP address."; return false; } if (!server_socket_.Listen(address)) { LOG(ERROR) << "Failed to listen socket."; return false; } + LOG(INFO) << "Notify the server socket is started."; + absl::MutexLock lock(&mutex_); + is_listen_started_ = true; + is_listen_ready_.SignalAll(); return true; } diff --git a/internal/platform/implementation/windows/wifi_direct_test.cc b/internal/platform/implementation/windows/wifi_direct_test.cc index 5f1977e5..9be5e148 100644 --- a/internal/platform/implementation/windows/wifi_direct_test.cc +++ b/internal/platform/implementation/windows/wifi_direct_test.cc @@ -23,6 +23,7 @@ #include "absl/time/time.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/logging.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace windows { @@ -35,9 +36,11 @@ TEST(WifiDirectMedium, DISABLED_StartWifiDirect) { if (run_test) { winrt::init_apartment(); + WifiDirectCredentials credentials; WifiDirectMedium wifi_direct_medium; - EXPECT_TRUE(wifi_direct_medium.StartWifiDirect()); + EXPECT_TRUE(wifi_direct_medium.IsInterfaceValid()); + EXPECT_TRUE(wifi_direct_medium.StartWifiDirect(&credentials)); while (true) { LOG(INFO) << "Enter \"s\" to stop test:"; @@ -60,8 +63,19 @@ TEST(WifiDirectMedium, DISABLED_ConnectWifiDirect) { std::cin >> run_test; if (run_test) { + WifiDirectCredentials credentials; WifiDirectMedium wifi_direct_medium; - EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect()); + + LOG(INFO) << "Enter WifiDirect Service Name to be connected: "; + std::string service_name; + std::cin >> service_name; + LOG(INFO) << "Enter pin: "; + std::string pin; + std::cin >> pin; + credentials.SetServiceName(service_name); + credentials.SetPin(pin); + + EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect(credentials)); absl::SleepFor(absl::Seconds(2)); while (true) { @@ -86,9 +100,12 @@ TEST(WifiDirectMedium, DISABLED_WifiDirectServerStartListen) { if (run_test) { winrt::init_apartment(); + WifiDirectCredentials credentials; WifiDirectMedium wifi_direct_medium; - EXPECT_TRUE(wifi_direct_medium.StartWifiDirect()); + EXPECT_TRUE(wifi_direct_medium.IsInterfaceValid()); + EXPECT_TRUE(wifi_direct_medium.StartWifiDirect(&credentials)); + absl::SleepFor(absl::Seconds(1)); std::unique_ptr server_socket = wifi_direct_medium.ListenForService(/*port=*/1234); @@ -121,9 +138,19 @@ TEST(WifiDirectMedium, DISABLED_WifiDirectConnectToServiceServer) { if (run_test) { winrt::init_apartment(); + WifiDirectCredentials credentials; WifiDirectMedium wifi_direct_medium; - EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect()); + LOG(INFO) << "Enter WifiDirect Service Name to be connected: "; + std::string service_name; + std::cin >> service_name; + LOG(INFO) << "Enter pin: "; + std::string pin; + std::cin >> pin; + credentials.SetServiceName(service_name); + credentials.SetPin(pin); + + EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect(credentials)); absl::SleepFor(absl::Seconds(1)); std::unique_ptr client_socket = wifi_direct_medium.ConnectToService( diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index 2c865a4e..02d4c815 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -958,15 +958,15 @@ void MediumEnvironment::RegisterWifiDirectMedium( } api::WifiDirectMedium* MediumEnvironment::GetWifiDirectMedium( - absl::string_view ssid, absl::string_view ip_address) { + absl::string_view service_name, absl::string_view ip_address) { MutexLock lock(&mutex_); for (auto& medium_info : wifi_direct_mediums_) { auto* medium_found = medium_info.first; auto& info = medium_info.second; if (info.is_go && info.is_active) { - if ((info.wifi_direct_credentials->GetSSID() == ssid) || + if ((info.wifi_direct_credentials->GetServiceName() == service_name) || (!ip_address.empty() && - (info.wifi_direct_credentials->GetIPAddress() == ip_address))) { + (info.wifi_direct_credentials->GetGateway() == ip_address))) { LOG(INFO) << "Found Remote WifiDirect medium=" << medium_found; return medium_found; } @@ -995,8 +995,9 @@ void MediumEnvironment::UpdateWifiDirectMediumForStartOrConnect( if (wifi_direct_credentials) { LOG(INFO) << "Update WifiDirect medium for GO: this=" << this << "; medium=" << &medium << role_status - << "; ssid=" << wifi_direct_credentials->GetSSID() - << "; password=" << wifi_direct_credentials->GetPassword(); + << "; service_name=" + << wifi_direct_credentials->GetServiceName() + << "; pin=" << wifi_direct_credentials->GetPin(); } else { LOG(INFO) << "Reset WifiDirect medium for GO: this=" << this << "; medium=" << &medium << role_status; @@ -1031,7 +1032,8 @@ void MediumEnvironment::UnregisterWifiDirectMedium( if (!enabled_) return; RunOnMediumEnvironmentThread([this, &medium]() { MutexLock lock(&mutex_); - wifi_direct_mediums_.extract(&medium); + auto item = wifi_direct_mediums_.extract(&medium); + if (item.empty()) return; LOG(INFO) << "Unregistered WifiDirect medium:" << &medium; }); } @@ -1064,6 +1066,7 @@ api::WifiHotspotMedium* MediumEnvironment::GetWifiHotspotMedium( } } + LOG(INFO) << "Can't find WifiHotspot medium!"; return nullptr; } diff --git a/internal/platform/medium_environment.h b/internal/platform/medium_environment.h index 0833e1f5..9346a8f1 100644 --- a/internal/platform/medium_environment.h +++ b/internal/platform/medium_environment.h @@ -295,7 +295,7 @@ class MediumEnvironment { // Returns WifiDirect medium that matches ssid or IP address with the role of // the Medium. Returns nullptr if not found. - api::WifiDirectMedium* GetWifiDirectMedium(absl::string_view ssid, + api::WifiDirectMedium* GetWifiDirectMedium(absl::string_view service_name, absl::string_view ip_address); // Updates credential and Medium role(GO or GC) to indicate the current diff --git a/internal/platform/wifi_credential.h b/internal/platform/wifi_credential.h index b619223c..af394908 100644 --- a/internal/platform/wifi_credential.h +++ b/internal/platform/wifi_credential.h @@ -90,6 +90,16 @@ class WifiDirectCredentials { std::string GetPassword() const { return password_; } void SetPassword(const std::string& password) { password_ = password; } + // Get/Set Service Name. + std::string GetServiceName() const { return service_name_; } + void SetServiceName(const std::string& service_name) { + service_name_ = service_name; + } + + // Get/Set Pin. + std::string GetPin() const { return pin_; } + void SetPin(const std::string& pin) { pin_ = pin; } + // Gets IP Address, which is in byte sequence, in network order. For example, // for "192.168.1.1", it'll be byte(129)+byte(168)+byte(1)+byte(1). Now only // ipv4 is supported. @@ -121,8 +131,15 @@ class WifiDirectCredentials { } private: + // There are 2 types of WifiDirectAuthType. + // 1. Without Service Discovery: the credentials are ssid/password. + // 2. With Service Discovery: the credentials are service_name/pin. + // Android supports type 1 and 2 in the future, but Windows only supports the + // second type. std::string ssid_; std::string password_; + std::string service_name_; + std::string pin_; std::string ip_address_; std::string gateway_ = "0.0.0.0"; int port_ = 0; diff --git a/internal/platform/wifi_direct.h b/internal/platform/wifi_direct.h index 04f93d95..33b6900f 100644 --- a/internal/platform/wifi_direct.h +++ b/internal/platform/wifi_direct.h @@ -15,14 +15,24 @@ #ifndef PLATFORM_PUBLIC_WIFI_DIRECT_H_ #define PLATFORM_PUBLIC_WIFI_DIRECT_H_ +#include #include #include #include +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/exception.h" #include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/wifi_direct.h" +#include "internal/platform/input_stream.h" #include "internal/platform/logging.h" +#include "internal/platform/mutex.h" #include "internal/platform/mutex_lock.h" +#include "internal/platform/output_stream.h" +#include "internal/platform/wifi_credential.h" namespace nearby { @@ -99,16 +109,11 @@ class WifiDirectServerSocket final { std::unique_ptr socket) : impl_(std::move(socket)) {} - // Returns ip address. - std::string GetIPAddress() const { - CHECK(impl_); - return impl_->GetIPAddress(); - } - - // Returns port. - int GetPort() const { - CHECK(impl_); - return impl_->GetPort(); + // Populates the WifiDirect credentials with the server socket's service + // addresses and ports. + void PopulateWifiDirectCredentials( + WifiDirectCredentials& wifi_direct_credentials) { + impl_->PopulateWifiDirectCredentials(wifi_direct_credentials); } // Blocks until either: @@ -158,8 +163,8 @@ class WifiDirectMedium { // Returns a new WifiDirectServerSocket. // On Success, WifiDirectServerSocket::IsValid() returns true. - WifiDirectServerSocket ListenForService(int port = 0) { - return WifiDirectServerSocket(impl_->ListenForService(port)); + WifiDirectServerSocket ListenForService() { + return WifiDirectServerSocket(impl_->ListenForService(/*port=*/0)); } // Returns the port range as a pair of min and max port. @@ -173,11 +178,10 @@ class WifiDirectMedium { } bool StopWifiDirect() { return impl_->StopWifiDirect(); } - bool ConnectWifiDirect(absl::string_view ssid, absl::string_view password) { + bool ConnectWifiDirect(const WifiDirectCredentials& wifi_direct_credentials) { MutexLock lock(&mutex_); - wifi_direct_credentials_.SetSSID(std::string(ssid)); - wifi_direct_credentials_.SetPassword(std::string(password)); - return impl_->ConnectWifiDirect(&wifi_direct_credentials_); + wifi_direct_credentials_ = wifi_direct_credentials; + return impl_->ConnectWifiDirect(wifi_direct_credentials_); } bool DisconnectWifiDirect() { return impl_->DisconnectWifiDirect(); } diff --git a/internal/platform/wifi_direct_test.cc b/internal/platform/wifi_direct_test.cc index e7f045e7..f8ecb636 100644 --- a/internal/platform/wifi_direct_test.cc +++ b/internal/platform/wifi_direct_test.cc @@ -14,12 +14,22 @@ #include "internal/platform/wifi_direct.h" -#include +#include +#include #include #include "gtest/gtest.h" #include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/exception.h" +#include "internal/platform/feature_flags.h" +#include "internal/platform/input_stream.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/output_stream.h" +#include "internal/platform/single_thread_executor.h" +#include "internal/platform/wifi_credential.h" namespace nearby { namespace { @@ -35,22 +45,37 @@ constexpr FeatureFlags kTestCases[] = { }, }; -constexpr absl::string_view kSsid = "Direct-357a2d8c"; -constexpr absl::string_view kPassword = "b592f7d3"; +constexpr absl::string_view kServiceName = "NC-WifiDirectTest"; +constexpr absl::string_view kPin = "b592f7d3"; constexpr absl::string_view kIp = "123.234.23.1"; constexpr const size_t kPort = 20; constexpr absl::string_view kData = "ABCD"; constexpr const size_t kChunkSize = 10; -constexpr absl::Duration kWaitDuration = absl::Milliseconds(100); + +TEST(WifiDirectCredentialsTest, SetGetServiceName) { + std::string service_name(kServiceName); + WifiDirectCredentials wifi_direct_credentials; + wifi_direct_credentials.SetServiceName(service_name); + + EXPECT_EQ(wifi_direct_credentials.GetServiceName(), kServiceName); +} + +TEST(WifiDirectCredentialsTest, SetGetPin) { + std::string pin(kPin); + WifiDirectCredentials wifi_direct_credentials; + wifi_direct_credentials.SetPin(pin); + + EXPECT_EQ(wifi_direct_credentials.GetPin(), kPin); +} + class WifiDirectMediumTest : public testing::TestWithParam { protected: - WifiDirectMediumTest() { env_.Start(); } - ~WifiDirectMediumTest() override { - absl::SleepFor(kWaitDuration); - EXPECT_TRUE(env_.IsWifiDirectMediumsEmpty()); + WifiDirectMediumTest() { env_.Stop(); + env_.Start(); } + ~WifiDirectMediumTest() override { env_.Stop(); } MediumEnvironment& env_{MediumEnvironment::Instance()}; }; @@ -70,7 +95,7 @@ TEST_F(WifiDirectMediumTest, ConstructorDestructorWorks) { EXPECT_NE(&wifi_direct_a.GetImpl(), &wifi_direct_b.GetImpl()); } -TEST_F(WifiDirectMediumTest, CanStartStopDirect) { +TEST_F(WifiDirectMediumTest, CanStartStopWifiDirect) { WifiDirectMedium wifi_direct_a; ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); @@ -82,11 +107,14 @@ TEST_F(WifiDirectMediumTest, CanStartStopDirect) { EXPECT_TRUE(wifi_direct_a.StopWifiDirect()); } -TEST_F(WifiDirectMediumTest, CanConnectDisconnectDirect) { +TEST_F(WifiDirectMediumTest, CanConnectDisconnectWifiDirect) { WifiDirectMedium wifi_direct_a; + WifiDirectCredentials credentials; + credentials.SetServiceName(std::string(kServiceName)); + credentials.SetPin(std::string(kPin)); ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); - EXPECT_FALSE(wifi_direct_a.ConnectWifiDirect(kSsid, kPassword)); + EXPECT_FALSE(wifi_direct_a.ConnectWifiDirect(credentials)); EXPECT_TRUE(wifi_direct_a.DisconnectWifiDirect()); } @@ -102,17 +130,17 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanConnect) { WifiDirectCredentials* wifi_direct_credentials = wifi_direct_a.GetCredential(); auto* medium_a = - env_.GetWifiDirectMedium(wifi_direct_credentials->GetSSID(), {}); + env_.GetWifiDirectMedium(wifi_direct_credentials->GetServiceName(), {}); EXPECT_NE(medium_a, nullptr); - EXPECT_TRUE( - wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials->GetSSID(), - wifi_direct_credentials->GetPassword())); + EXPECT_TRUE(wifi_direct_b.ConnectWifiDirect(*wifi_direct_credentials)); WifiDirectServerSocket server_socket = wifi_direct_a.ListenForService(); EXPECT_TRUE(server_socket.IsValid()); - auto ip_addr = server_socket.GetIPAddress(); - EXPECT_FALSE(absl::EndsWith(ip_addr, ".")); - wifi_direct_credentials->SetIPAddress(ip_addr); + server_socket.PopulateWifiDirectCredentials(*wifi_direct_credentials); + std::string wifi_direct_a_ip_addr = wifi_direct_credentials->GetGateway(); + EXPECT_FALSE(absl::EndsWith(wifi_direct_a_ip_addr, ".")); + int wifi_direct_a_port = wifi_direct_credentials->GetPort(); + EXPECT_NE(wifi_direct_a_port, 0); WifiDirectSocket socket_a; WifiDirectSocket socket_b; @@ -124,14 +152,16 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanConnect) { SingleThreadExecutor server_executor; SingleThreadExecutor client_executor; client_executor.Execute( - [&wifi_direct_b, &socket_b, &server_socket, &flag]() { + [&wifi_direct_b, &socket_b, &server_socket, wifi_direct_a_ip_addr, + wifi_direct_a_port, &flag]() { socket_b = wifi_direct_b.ConnectToService(kIp, kPort, &flag); EXPECT_FALSE(socket_b.IsValid()); socket_b = wifi_direct_b.ConnectToService( - server_socket.GetIPAddress(), kPort, &flag); + wifi_direct_a_ip_addr, kPort, &flag); EXPECT_FALSE(socket_b.IsValid()); + socket_b = wifi_direct_b.ConnectToService( - server_socket.GetIPAddress(), server_socket.GetPort(), &flag); + wifi_direct_a_ip_addr, wifi_direct_a_port, &flag); if (!socket_b.IsValid()) { server_socket.Close(); } @@ -163,7 +193,7 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanConnect) { EXPECT_TRUE(wifi_direct_b.DisconnectWifiDirect()); EXPECT_TRUE(wifi_direct_a.StopWifiDirect()); auto* medium_b = - env_.GetWifiDirectMedium(wifi_direct_credentials->GetSSID(), {}); + env_.GetWifiDirectMedium(wifi_direct_credentials->GetServiceName(), {}); EXPECT_EQ(medium_b, nullptr); } @@ -178,13 +208,13 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanCancelConnect) { EXPECT_TRUE(wifi_direct_a.StartWifiDirect()); WifiDirectCredentials* wifi_direct_credentials = wifi_direct_a.GetCredential(); - EXPECT_TRUE( - wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials->GetSSID(), - wifi_direct_credentials->GetPassword())); + EXPECT_TRUE(wifi_direct_b.ConnectWifiDirect(*wifi_direct_credentials)); WifiDirectServerSocket server_socket = wifi_direct_a.ListenForService(); EXPECT_TRUE(server_socket.IsValid()); - wifi_direct_credentials->SetIPAddress(server_socket.GetIPAddress()); + server_socket.PopulateWifiDirectCredentials(*wifi_direct_credentials); + std::string wifi_direct_a_ip_addr = wifi_direct_credentials->GetGateway(); + int wifi_direct_a_port = wifi_direct_credentials->GetPort(); WifiDirectSocket socket_a; WifiDirectSocket socket_b; @@ -197,11 +227,12 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanCancelConnect) { SingleThreadExecutor server_executor; SingleThreadExecutor client_executor; client_executor.Execute( - [&wifi_direct_b, &socket_b, &server_socket, &flag]() { + [&wifi_direct_b, &socket_b, &server_socket, wifi_direct_a_ip_addr, + wifi_direct_a_port, &flag]() { socket_b = wifi_direct_b.ConnectToService(kIp, kPort, &flag); EXPECT_FALSE(socket_b.IsValid()); socket_b = wifi_direct_b.ConnectToService( - server_socket.GetIPAddress(), server_socket.GetPort(), &flag); + wifi_direct_a_ip_addr, wifi_direct_a_port, &flag); if (!socket_b.IsValid()) { server_socket.Close(); } @@ -225,8 +256,8 @@ TEST_P(WifiDirectMediumTest, CanStartDirectGOThatOtherCanCancelConnect) { server_socket.Close(); { CancellationFlag flag(true); - socket_c = wifi_direct_b.ConnectToService(server_socket.GetIPAddress(), - server_socket.GetPort(), &flag); + socket_c = wifi_direct_b.ConnectToService(wifi_direct_a_ip_addr, + wifi_direct_a_port, &flag); EXPECT_FALSE(socket_c.IsValid()); } @@ -241,8 +272,11 @@ TEST_F(WifiDirectMediumTest, CanStartDirectGOThatOtherFailConnect) { ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); ASSERT_TRUE(wifi_direct_b.IsInterfaceValid()); EXPECT_TRUE(wifi_direct_a.StartWifiDirect()); + WifiDirectCredentials wifi_direct_credentials; + wifi_direct_credentials.SetServiceName(std::string(kServiceName)); + wifi_direct_credentials.SetPin(std::string(kPin)); - EXPECT_FALSE(wifi_direct_b.ConnectWifiDirect(kSsid, kPassword)); + EXPECT_FALSE(wifi_direct_b.ConnectWifiDirect(wifi_direct_credentials)); EXPECT_TRUE(wifi_direct_b.DisconnectWifiDirect()); EXPECT_TRUE(wifi_direct_a.StopWifiDirect());