Add retry to wifi hotspot connection.

PiperOrigin-RevId: 843792159
This commit is contained in:
Francis Tsui
2025-12-12 12:33:20 -08:00
committed by Copybara-Service
parent 506f00b275
commit 1ac3538d15
2 changed files with 76 additions and 73 deletions
@@ -35,9 +35,8 @@
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/windows/network_info.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/implementation/windows/wlan_client.h"
@@ -118,8 +117,7 @@ bool WifiHotspotNative::ConnectToWifiNetwork(absl::string_view ssid,
}
backup_profile_name_.clear();
if (!ConnectToWifiNetworkInternal(interface_guid,
string_utils::StringToWideString(
std::string(kHotspotProfileName)))) {
std::string(kHotspotProfileName))) {
RemoveCreatedWlanProfile(interface_guid);
return false;
}
@@ -145,13 +143,6 @@ bool WifiHotspotNative::DisconnectWifiNetwork() {
return true;
}
void WifiHotspotNative::TriggerConnected() {
if (connect_latch_ == nullptr) {
return;
}
connect_latch_->CountDown();
}
void WifiHotspotNative::WlanNotificationCallback(
PWLAN_NOTIFICATION_DATA wlan_notification_data, PVOID context) {
VLOG(1) << "WlanNotificationCallback is called with notification code "
@@ -179,11 +170,11 @@ void WifiHotspotNative::WlanNotificationCallback(
string_utils::WideStringToString(std::wstring(data->strProfileName));
LOG(INFO) << "Completed connection to profile: " << profile_name
<< " code: " << data->wlanReasonCode;
if (wlan_context->connecting_profile_name != data->strProfileName) {
if (wlan_context->connecting_profile_name != profile_name) {
break;
}
wlan_context->connection_code = data->wlanReasonCode;
wlan_context->wifi_hotspot_native.TriggerConnected();
wlan_context->connection_completed.Notify();
break;
}
case wlan_notification_acm_scan_list_refresh: {
@@ -199,8 +190,8 @@ void WifiHotspotNative::WlanNotificationCallback(
// Ignore if we already started connecting to new network, the disconnect
// event will not be the one we want.
if (!wlan_context->got_connecting_event) {
wlan_context->original_profile_name =
std::wstring(data->strProfileName);
wlan_context->original_profile_name = string_utils::WideStringToString(
std::wstring(data->strProfileName));
LOG(INFO) << "Disconnecting from previous profile: "
<< wlan_context->original_profile_name;
}
@@ -235,56 +226,73 @@ GUID WifiHotspotNative::GetInterfaceGuid() const {
}
bool WifiHotspotNative::ConnectToWifiNetworkInternal(
GUID interface_guid, const std::wstring& profile_name) {
GUID interface_guid, const std::string& profile_name) {
if (profile_name.empty()) {
LOG(ERROR) << "Profile name is empty.";
return false;
}
WlanNotificationContext context = {
.wifi_hotspot_native = *this,
.connecting_profile_name = profile_name,
};
if (!RegisterWlanNotificationCallback(&context)) {
LOG(ERROR) << "Failed to register WLAN notification callback.";
return false;
}
absl::Time deadline = absl::Now() + kConnectTimeout;
// Retry hotspot connection until timeout or error.
while (deadline > absl::Now()) {
WlanNotificationContext context = {
.connecting_profile_name = profile_name,
};
if (!RegisterWlanNotificationCallback(&context)) {
LOG(ERROR) << "Failed to register WLAN notification callback.";
return false;
}
connect_latch_ = std::make_unique<CountDownLatch>(1);
std::wstring wprofile_name = string_utils::StringToWideString(profile_name);
WLAN_CONNECTION_PARAMETERS parameters;
parameters.wlanConnectionMode = wlan_connection_mode_profile;
parameters.strProfile = wprofile_name.data();
parameters.pDot11Ssid = nullptr;
parameters.pDesiredBssidList = nullptr;
parameters.dot11BssType = dot11_BSS_type_infrastructure;
parameters.dwFlags = 0;
WLAN_CONNECTION_PARAMETERS parameters;
parameters.wlanConnectionMode = wlan_connection_mode_profile;
parameters.strProfile = profile_name.data();
parameters.pDot11Ssid = nullptr;
parameters.pDesiredBssidList = nullptr;
parameters.dot11BssType = dot11_BSS_type_infrastructure;
parameters.dwFlags = 0;
LOG(INFO) << "Begin connecting to WLAN profile " << profile_name;
DWORD result = WlanConnect(wlan_client_.GetHandle(), &interface_guid,
&parameters, /*pReserved=*/nullptr);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed to connect to WLAN profile " << profile_name;
UnregisterWlanNotificationCallback();
return false;
}
DWORD result = WlanConnect(wlan_client_.GetHandle(), &interface_guid,
&parameters, /*pReserved=*/nullptr);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed to connect to WLAN profile "
<< string_utils::WideStringToString(profile_name);
// Make sure that we connect to the expected profile.
bool notified =
context.connection_completed.WaitForNotificationWithDeadline(deadline);
UnregisterWlanNotificationCallback();
return false;
}
// Make sure that we connect to the expected profile.
ExceptionOr<bool> connect_result = connect_latch_->Await(kConnectTimeout);
UnregisterWlanNotificationCallback();
backup_profile_name_ = std::move(context.original_profile_name);
if (!connect_result.ok() || !connect_result.result()) {
LOG(ERROR) << "Connect to Wifi hotspot timed out.";
return false;
// Only backup original profile on first connection attempt and we did not
// just disconnect from the hotspot.
if (backup_profile_name_.empty() &&
context.original_profile_name != kHotspotProfileName) {
backup_profile_name_ = std::move(context.original_profile_name);
}
if (!notified) {
break;
}
if (context.connection_code == WLAN_REASON_CODE_SUCCESS) {
return true;
}
// If network is not found, try again.
if (context.connection_code != WLAN_REASON_CODE_NETWORK_NOT_AVAILABLE &&
context.connection_code != WLAN_REASON_CODE_USER_CANCELLED) {
LOG(ERROR) << "Failed to connect to Wifi hotspot, code: "
<< ReasonCodeToString(context.connection_code);
return false;
}
if (context.connection_code == WLAN_REASON_CODE_USER_CANCELLED) {
LOG(WARNING) << "Hotspot connection cancelled, trying again.";
} else {
LOG(WARNING) << "Hotspot not available, trying again.";
}
absl::SleepFor(absl::Seconds(1));
}
if (context.connection_code != WLAN_REASON_CODE_SUCCESS) {
LOG(ERROR) << "Failed to connect to Wifi hotspot, code: "
<< ReasonCodeToString(context.connection_code);
return false;
}
connect_latch_ = nullptr;
return true;
LOG(ERROR) << "Connect to Wifi hotspot timed out.";
return false;
}
bool WifiHotspotNative::RegisterWlanNotificationCallback(
@@ -346,28 +354,25 @@ bool WifiHotspotNative::SetWlanProfile(GUID interface_guid,
}
bool WifiHotspotNative::RemoveCreatedWlanProfile(GUID interface_guid) {
return RemoveWlanProfile(
interface_guid,
string_utils::StringToWideString(std::string(kHotspotProfileName)));
return RemoveWlanProfile(interface_guid, std::string(kHotspotProfileName));
}
bool WifiHotspotNative::RemoveWlanProfile(GUID interface_guid,
const std::wstring& profile_name) {
const std::string& profile_name) {
if (profile_name.empty()) {
return false;
}
std::wstring wprofile_name = string_utils::StringToWideString(profile_name);
DWORD result = WlanDeleteProfile(wlan_client_.GetHandle(), &interface_guid,
profile_name.data(), /*pReserved=*/nullptr);
wprofile_name.data(), /*pReserved=*/nullptr);
if (result != ERROR_SUCCESS && result != ERROR_NOT_FOUND) {
LOG(ERROR) << "Failed to remove WLAN profile "
<< string_utils::WideStringToString(profile_name)
LOG(ERROR) << "Failed to remove WLAN profile " << profile_name
<< " with reason " << result;
return false;
}
LOG(INFO) << "WLAN profile " << string_utils::WideStringToString(profile_name)
<< " removed successfully.";
LOG(INFO) << "WLAN profile " << profile_name << " removed successfully.";
return true;
}
@@ -31,7 +31,7 @@
#include "absl/base/thread_annotations.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/count_down_latch.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/implementation/windows/network_info.h"
#include "internal/platform/implementation/windows/wlan_client.h"
@@ -60,16 +60,16 @@ class WifiHotspotNative {
private:
// Context for WLAN notification callback.
struct WlanNotificationContext {
WifiHotspotNative& wifi_hotspot_native;
// This is reset to false when we start connecting to a new network, and set
// to true when we receive the connecting event.
bool got_connecting_event = false;
// Original profile name is captured when a disconnecting event is received
// before a connecting event.
std::wstring original_profile_name;
std::string original_profile_name;
// The profile name of the network we are trying to connect to.
std::wstring connecting_profile_name;
std::string connecting_profile_name;
WLAN_REASON_CODE connection_code = WLAN_REASON_CODE_UNKNOWN;
absl::Notification connection_completed;
};
static void WlanNotificationCallback(
@@ -78,7 +78,7 @@ class WifiHotspotNative {
absl::string_view password);
GUID GetInterfaceGuid() const;
bool ConnectToWifiNetworkInternal(GUID interface_guid,
const std::wstring& profile_name)
const std::string& profile_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool RegisterWlanNotificationCallback(
WlanNotificationContext* absl_nonnull context)
@@ -89,16 +89,14 @@ class WifiHotspotNative {
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool RemoveCreatedWlanProfile(GUID interface_guid)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool RemoveWlanProfile(GUID interface_guid, const std::wstring& profile_name)
bool RemoveWlanProfile(GUID interface_guid, const std::string& profile_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void TriggerConnected();
NetworkInfo& network_info_;
mutable absl::Mutex mutex_;
WlanClient wlan_client_;
std::unique_ptr<CountDownLatch> connect_latch_;
std::wstring backup_profile_name_;
std::string backup_profile_name_;
};
} // namespace nearby::windows