Re-implement Windows WifiDirect with Windows.Devices.WiFiDirect Namespace.

PiperOrigin-RevId: 931324779
This commit is contained in:
hai007
2026-06-12 14:13:03 -07:00
committed by Copybara-Service
parent a8e604bbe4
commit 728a7050a3
5 changed files with 824 additions and 573 deletions
@@ -61,7 +61,9 @@ constexpr absl::string_view kWifiDirectSsidPatternString{
constexpr int kWifiDirectSsidMaxLength = 32;
constexpr int kWifiPasswordSsidMinLength = 8;
constexpr int kWifiPasswordSsidMaxLength = 64;
constexpr int kWifiDirectPinMinLength = 4;
// We may use Push Button for WPS, so no pin is required, the min length should
// be 0.
constexpr int kWifiDirectPinMinLength = 0;
constexpr int kWifiDirectPinMaxLength = 16;
inline bool WithinRange(int value, int min, int max) {
@@ -302,7 +304,6 @@ Exception EnsureValidBandwidthUpgradeWifiDirectPathAvailableFrame(
if ((ssid_valid && password_valid) || (device_name_valid && pin_valid))
return {Exception::kSuccess};
return {Exception::kInvalidProtocolBuffer};
// For backwards compatibility reasons, no other fields should be null-checked
@@ -765,7 +765,7 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame_2;
std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"};
std::string wifi_direct_pin_wrong_length = "abc";
std::string wifi_direct_pin_wrong_length = "abcefghijklmnopqrstuvwxyz";
std::string bytes = ForBwuWifiDirectPathAvailable(
wifi_direct_ssid, std::string(kWifiDirectPassword), kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
@@ -799,33 +799,20 @@ TEST(OfflineFramesValidatorTest,
OfflineFrame offline_frame_1;
OfflineFrame offline_frame_2;
std::string short_wifi_direct_password{"Test"};
std::string short_wifi_direct_pin{"abc"};
std::string bytes = ForBwuWifiDirectPathAvailable(
std::string(kWifiDirectSsid), short_wifi_direct_password, kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
std::string(kGateway), std::string(kWifiDirectDeviceName),
short_wifi_direct_pin);
offline_frame_1.ParseFromString(bytes);
auto ret_value = EnsureValidOfflineFrame(offline_frame_1);
ASSERT_FALSE(ret_value.Ok());
std::string long_wifi_direct_password =
std::string{kWifiDirectSsid} +
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
std::string long_wifi_direct_pin =
std::string{kWifiDirectPin} +
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
bytes = ForBwuWifiDirectPathAvailable(
std::string bytes = ForBwuWifiDirectPathAvailable(
std::string(kWifiDirectSsid), long_wifi_direct_password, kPort,
kWifiDirectFrequency, kSupportsDisablingEncryption,
std::string(kGateway), std::string(kWifiDirectDeviceName),
long_wifi_direct_pin);
offline_frame_2.ParseFromString(bytes);
ret_value = EnsureValidOfflineFrame(offline_frame_2);
auto ret_value = EnsureValidOfflineFrame(offline_frame_2);
EXPECT_FALSE(ret_value.Ok());
}
@@ -17,15 +17,13 @@
// Windows headers
#include <windows.h>
#include <winsock2.h>
#include <wlanapi.h>
// Standard C/C++ headers
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
// Nearby connections headers
#include "absl/base/nullability.h"
@@ -35,6 +33,7 @@
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/wifi_direct.h"
#include "internal/platform/implementation/windows/nearby_client_socket.h"
@@ -46,8 +45,9 @@
#include "internal/platform/wifi_credential.h"
// WinRT headers
#include "internal/platform/implementation/windows/generated/winrt/base.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.WiFiDirect.Services.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.WiFiDirect.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.h"
@@ -55,33 +55,55 @@
#include "internal/platform/implementation/windows/generated/winrt/Windows.Security.Cryptography.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Storage.Streams.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.System.h"
#include "internal/platform/implementation/windows/generated/winrt/base.h"
namespace nearby::windows {
// Windows.Devices.WiFiDirect Namespace contains classes that support connecting
// to associated Wi-Fi Direct devices and associated endpoints for PCs, tablets,
// and phones.
// https://learn.microsoft.com/en-us/uwp/api/windows.devices.wifidirect?view=winrt-22000
using ::winrt::event_token;
using ::winrt::fire_and_forget;
using ::winrt::Windows::Devices::WiFiDirect::
WiFiDirectAdvertisementListenStateDiscoverability;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectAdvertisementPublisher;
using ::winrt::Windows::Devices::WiFiDirect::
WiFiDirectAdvertisementPublisherStatus;
using ::winrt::Windows::Devices::WiFiDirect::
WiFiDirectAdvertisementPublisherStatusChangedEventArgs;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConfigurationMethod;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionListener;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionParameters;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionRequest;
using ::winrt::Windows::Devices::WiFiDirect::
WiFiDirectConnectionRequestedEventArgs;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectDevice;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectDeviceSelectorType;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectPairingProcedure;
using ::winrt::Windows::Devices::Enumeration::DeviceInformation;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationCollection;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationKind;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationPairing;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
using ::winrt::Windows::Devices::Enumeration::DevicePairingKinds;
using ::winrt::Windows::Devices::Enumeration::DevicePairingProtectionLevel;
using ::winrt::Windows::Devices::Enumeration::DevicePairingRequestedEventArgs;
using ::winrt::Windows::Devices::Enumeration::DevicePairingResult;
using ::winrt::Windows::Devices::Enumeration::DevicePairingResultStatus;
using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResult;
using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResultStatus;
using ::winrt::Windows::Devices::Enumeration::DeviceWatcher;
using ::winrt::Windows::Devices::WiFiDirect::Services::WiFiDirectService;
using ::winrt::Windows::Devices::WiFiDirect::Services::
WiFiDirectServiceAdvertisementStatus;
using ::winrt::Windows::Devices::WiFiDirect::Services::
WiFiDirectServiceAdvertiser;
using ::winrt::Windows::Devices::WiFiDirect::Services::
WiFiDirectServiceAutoAcceptSessionConnectedEventArgs;
using ::winrt::Windows::Devices::WiFiDirect::Services::
WiFiDirectServiceConfigurationMethod;
using ::winrt::Windows::Devices::WiFiDirect::Services::WiFiDirectServiceSession;
using ::winrt::Windows::Devices::WiFiDirect::Services::
WiFiDirectServiceSessionRequestedEventArgs;
using ::winrt::Windows::Devices::WiFiDirect::Services::WiFiDirectServiceStatus;
using ::winrt::Windows::Foundation::AsyncStatus;
using ::winrt::Windows::Foundation::IAsyncOperation;
using ::winrt::Windows::Foundation::IInspectable;
using ::winrt::Windows::Foundation::Collections::IVectorView;
using ::winrt::Windows::Networking::EndpointPair;
// WifiDirectSocket wraps the socket functions to read and write stream.
// On WiFiDirect GO serverside, a WifiDirectSocket will be passed to
// On WiFiDirect GO server side, a WifiDirectSocket will be passed to
// StartAcceptingConnections's callback when Winsock Server Socket receives a
// new connection. When client side call API to connect to remote WiFi
// WifiDirect GO service, it will return a WifiDirectServiceSocket to caller.
@@ -177,6 +199,26 @@ class WifiDirectServerSocket : public api::WifiDirectServerSocket {
bool server_socket_accepted_connection_ = false;
};
class WifiDirectDeviceDiscovered {
public:
explicit WifiDirectDeviceDiscovered(
const DeviceInformation& device_info);
~WifiDirectDeviceDiscovered() = default;
WifiDirectDeviceDiscovered(WifiDirectDeviceDiscovered&&) = default;
WifiDirectDeviceDiscovered& operator=(WifiDirectDeviceDiscovered&&) = default;
std::string GetId() { return id_; }
DeviceInformation GetDeviceInformation() {
return windows_wifi_direct_device_;
}
private:
DeviceInformation windows_wifi_direct_device_;
std::string id_;
};
// Container of operations that can be performed over the WifiLan medium.
class WifiDirectMedium : public api::WifiDirectMedium {
public:
WifiDirectMedium();
@@ -217,54 +259,46 @@ class WifiDirectMedium : public api::WifiDirectMedium {
const override;
private:
// Medium status
enum Value : char {
kMediumStatusIdle = 0,
kMediumStatusAccepting = (1 << 0),
kMediumStatusGOStarted = (1 << 1),
kMediumStatusBeaconing = (1 << 1),
kMediumStatusConnecting = (1 << 2),
kMediumStatusConnected = (1 << 3),
};
// Medium Status
int medium_status_ = kMediumStatusIdle;
bool IsWifiDirectServiceSupported();
bool IsWifiDirectSupported();
bool IsIdle() { return medium_status_ == kMediumStatusIdle; }
// Advertiser is accepting connection on server socket
bool IsAccepting() { return (medium_status_ & kMediumStatusAccepting) != 0; }
// Advertiser started WifiDirect GO
bool IsGOStarted() {
return (medium_status_ & kMediumStatusGOStarted) != 0;
}
// Discoverer is connecting with the WifiDirect
// GO is starated and sending beacon
bool IsBeaconing() { return (medium_status_ & kMediumStatusBeaconing) != 0; }
// GC is connecting to the GO
bool IsConnecting() {
return (medium_status_ & kMediumStatusConnecting) != 0;
}
// Discoverer is connected with the WifiDirect
// GC is connected to the GO
bool IsConnected() { return (medium_status_ & kMediumStatusConnected) != 0; }
// Converts WiFiDirectServiceConfigurationMethod enum to a string.
static std::string ConfigMethodToString(
WiFiDirectServiceConfigurationMethod config_method);
// Advertising properties
WiFiDirectAdvertisementPublisher publisher_{nullptr};
WiFiDirectConnectionListener listener_{nullptr};
WiFiDirectDevice wifi_direct_device_{nullptr};
WiFiDirectServiceAdvertiser advertiser_ = nullptr;
WiFiDirectService service_ = nullptr;
WiFiDirectServiceSession session_ = nullptr;
winrt::Windows::System::DispatcherQueueController controller_ = nullptr;
winrt::Windows::System::DispatcherQueue dispatcher_queue_ = nullptr;
DeviceInformation device_info_ = nullptr;
fire_and_forget OnStatusChanged(
WiFiDirectAdvertisementPublisher sender,
WiFiDirectAdvertisementPublisherStatusChangedEventArgs event);
event_token publisher_status_changed_token_;
fire_and_forget OnAdvertisementStatusChanged(
WiFiDirectServiceAdvertiser sender, IInspectable const& event);
fire_and_forget OnAutoAcceptSessionConnected(
WiFiDirectServiceAdvertiser sender,
WiFiDirectServiceAutoAcceptSessionConnectedEventArgs const& args);
fire_and_forget OnSessionRequested(
WiFiDirectServiceAdvertiser const& sender,
WiFiDirectServiceSessionRequestedEventArgs const& args);
fire_and_forget OnConnectionRequested(
WiFiDirectConnectionListener const& sender,
WiFiDirectConnectionRequestedEventArgs const& event);
event_token connection_requested_token_;
event_token advertisement_status_changed_token_;
event_token auto_accept_session_connected_token_;
event_token session_requested_token_;
bool IsAepPaired(winrt::hstring device_id);
// Discovery properties
DeviceWatcher device_watcher_{nullptr};
@@ -280,24 +314,43 @@ class WifiDirectMedium : public api::WifiDirectMedium {
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate);
fire_and_forget Watcher_DeviceRemoved(
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate);
fire_and_forget Watcher_DeviceEnumerationCompleted(DeviceWatcher sender,
IInspectable inspectable);
fire_and_forget Watcher_DeviceStopped(DeviceWatcher sender,
IInspectable inspectable);
fire_and_forget Watcher_DeviceEnumerationCompleted(
DeviceWatcher sender, IInspectable inspectable);
fire_and_forget Watcher_DeviceStopped(
DeviceWatcher sender, IInspectable inspectable);
fire_and_forget OnPairingRequested(
DeviceInformationCustomPairing const& sender,
DevicePairingRequestedEventArgs const& e);
void OnConnectionStatusChanged(
WiFiDirectDevice const& sender,
winrt::Windows::Foundation::IInspectable const& e);
// IAsyncOperation<bool> RequestPairDeviceAsync(
bool RequestPairDeviceAsync(DeviceInformationPairing pairing,
int group_owner_intent,
WiFiDirectConfigurationMethod config_method);
std::unique_ptr<CountDownLatch> connection_latch_;
absl::Mutex mutex_;
absl::flat_hash_map<winrt::hstring,
std::unique_ptr<WifiDirectDeviceDiscovered>>
discovered_devices_by_id_;
absl::flat_hash_map<winrt::hstring,
std::unique_ptr<WifiDirectDeviceDiscovered>>
connection_requested_devices_by_id_;
bool is_interface_valid_ = false;
WifiDirectCredentials* credentials_go_ = nullptr;
WifiDirectCredentials credentials_gc_;
std::string ip_address_local_;
std::string ip_address_remote_;
absl::Mutex mutex_;
absl::CondVar is_ip_address_ready_;
// Keep the server socket listener pointer
WifiDirectServerSocket* server_socket_ptr_ ABSL_GUARDED_BY(mutex_) = nullptr;
SubmittableExecutor listener_executor_;
};
} // namespace nearby::windows
#endif // PLATFORM_IMPL_WINDOWS_WIFI_DIRECT_H_
File diff suppressed because it is too large Load Diff
@@ -25,6 +25,7 @@
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/wifi_direct.h"
#include "internal/platform/implementation/windows/network_info.h"
#include "internal/platform/implementation/windows/socket_address.h"
#include "internal/platform/implementation/windows/wifi_direct.h"
#include "internal/platform/logging.h"
@@ -32,7 +33,7 @@
namespace nearby::windows {
namespace {
constexpr int kWaitingForServerSocketReadyTimeoutSeconds = 90; // seconds
constexpr int kWaitingForServerSocketReadyTimeoutSeconds = 60; // seconds
} // namespace
WifiDirectServerSocket::~WifiDirectServerSocket() { Close(); }
@@ -50,27 +51,32 @@ void WifiDirectServerSocket::SetIPAddress(std::string ip_address) {
}
std::unique_ptr<api::WifiDirectSocket> WifiDirectServerSocket::Accept() {
absl::MutexLock lock(mutex_);
if (server_socket_accepted_connection_) {
LOG(INFO) << "Server socket has already accepted a connection. Return.";
return nullptr;
}
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.";
{
absl::MutexLock lock(&mutex_);
if (closed_) return nullptr;
if (server_socket_accepted_connection_) {
LOG(INFO) << "Server socket has already accepted a connection. Return.";
return nullptr;
}
LOG(INFO) << "Check if server socket is ready.";
if (!is_listen_started_) {
LOG(INFO) <<"Server socket is not started, wait for server socket is "
"ready.";
is_listen_ready_.WaitWithTimeout(
&mutex_, absl::Seconds(kWaitingForServerSocketReadyTimeoutSeconds));
if (closed_ || !is_listen_started_) {
LOG(INFO) << ": Server socket failed to start or was closed.";
return nullptr;
}
}
}
LOG(INFO) << "Start to accept connection from WiFiDirect client.";
auto client_socket = server_socket_.Accept();
if (client_socket == nullptr) {
LOG(INFO) << "Accept server socket failed.";
absl::MutexLock lock(&mutex_);
if (closed_ || client_socket == nullptr) {
LOG(INFO) << "Accept server socket failed or closed.";
return nullptr;
}
@@ -80,9 +86,45 @@ std::unique_ptr<api::WifiDirectSocket> WifiDirectServerSocket::Accept() {
return std::make_unique<WifiDirectSocket>(std::move(client_socket));
}
std::string GetWifiDirectGOAddresses() {
for (int i = 0; i < 3; i++) {
// Force refresh network info since assignment of the well known
// static IP address to the hotspot interface does not trigger the IP
// interface change notification in network_monitor.cc.
NetworkInfo::GetNetworkInfo().Refresh();
for (const auto& net_interface :
NetworkInfo::GetNetworkInfo().GetInterfaces()) {
if (net_interface.type == InterfaceType::kWifiHotspot) {
LOG(INFO) << "Found Wifi Hotspot interface, index: "
<< net_interface.index;
for (const SocketAddress& ipaddress : net_interface.ipv6_addresses) {
LOG(INFO) << "Found ipv6 address: " << ipaddress.ToString();
// IPv6 link-local addresses are allowed and preferred since it skips
// the DHCP wait time.
}
for (const SocketAddress& ipaddress : net_interface.ipv4_addresses) {
LOG(INFO) << "Found ipv4 address: " << ipaddress.ToString();
// Skip link-local IPv4 addresses.
if (ipaddress.IsV4LinkLocal()) {
LOG(INFO) << "Skip link-local IPv4 address: ";
continue;
}
return ipaddress.ToString();
}
}
}
LOG(WARNING)
<< "Failed to find Wifi Hotspot interface. Wait 500ms snd try again";
Sleep(500);
}
return "";
}
void WifiDirectServerSocket::PopulateWifiDirectCredentials(
WifiDirectCredentials& wifi_direct_credentials) {
wifi_direct_credentials.SetGateway(wifi_direct_ipaddr_);
std::string wifi_direct_ipaddr = GetWifiDirectGOAddresses();
wifi_direct_credentials.SetGateway(wifi_direct_ipaddr);
if (GetPort() != 0) {
wifi_direct_credentials.SetPort(GetPort());
} else {
@@ -93,15 +135,19 @@ void WifiDirectServerSocket::PopulateWifiDirectCredentials(
}
Exception WifiDirectServerSocket::Close() {
absl::MutexLock lock(mutex_);
if (closed_) {
return {Exception::kSuccess};
{
absl::MutexLock lock(mutex_);
if (closed_) {
return {Exception::kSuccess};
}
closed_ = true;
wifi_direct_ipaddr_.clear();
is_listen_started_ = false;
server_socket_accepted_connection_ = false;
is_listen_ready_.SignalAll();
}
wifi_direct_ipaddr_.clear();
is_listen_started_ = false;
server_socket_accepted_connection_ = false;
server_socket_.Close();
closed_ = true;
LOG(INFO) << __func__ << ": Close completed succesfully.";
return {Exception::kSuccess};