Renew DHCP lease on hotspot connection.

PiperOrigin-RevId: 817375675
This commit is contained in:
Francis Tsui
2025-10-09 16:11:58 -07:00
committed by Copybara-Service
parent 346769d54f
commit 0d207bc95b
7 changed files with 88 additions and 52 deletions
@@ -289,6 +289,7 @@ cc_library(
deps = [
":comm",
":crypto", # build_cleaner: keep
":network_info",
":string_utils",
":types",
"//connections/implementation/flags:connections_flags",
@@ -18,7 +18,6 @@
#include <windows.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <combaseapi.h>
// clang-format on
#include <algorithm>
@@ -28,6 +27,7 @@
#include <utility>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/logging.h"
@@ -53,22 +53,10 @@ void AddIpUnicastAddresses(IP_ADAPTER_UNICAST_ADDRESS* unicast_addresses,
unicast_addresses = unicast_addresses->Next;
}
LOG(INFO) << "Added to interface: " << net_interface.index << ", "
<< net_interface.ipv4_addresses.size()
<< " v4 addresses, "
<< net_interface.ipv4_addresses.size() << " v4 addresses, "
<< net_interface.ipv6_addresses.size() << " v6 addresses.";
}
std::string GuidToString(GUID guid) {
std::wstring guid_str;
guid_str.resize(39);
int guid_size = StringFromGUID2(guid, guid_str.data(), guid_str.size());
if (guid_size != 0) {
guid_str.resize(guid_size - 1);
return string_utils::WideStringToString(guid_str);
}
return "";
}
} // namespace
bool NetworkInfo::Refresh() {
@@ -112,9 +100,9 @@ bool NetworkInfo::Refresh() {
continue;
}
auto it = result.insert(result.end(), InterfaceInfo{
.index = next_address->IfIndex,
.guid = next_address->NetworkGuid,
});
.index = next_address->IfIndex,
.luid = next_address->Luid,
});
if (next_address->IfType == IF_TYPE_ETHERNET_CSMACD) {
it->type = InterfaceType::kEthernet;
VLOG(1) << "Found ethernet interface: " << next_address->AdapterName
@@ -144,16 +132,16 @@ std::vector<NetworkInfo::InterfaceInfo> NetworkInfo::GetInterfaces() const {
return interfaces_;
}
bool NetworkInfo::RenewIpv4Address(GUID interface_guid) const {
bool NetworkInfo::RenewIpv4Address(NET_LUID luid) const {
uint64_t index = 0;
{
absl::MutexLock lock(mutex_);
auto it = std::find_if(interfaces_.begin(), interfaces_.end(),
[&interface_guid](const InterfaceInfo& intf) {
return intf.guid == interface_guid;
[luid](const InterfaceInfo& intf) {
return intf.luid.Value == luid.Value;
});
if (it == interfaces_.end()) {
LOG(ERROR) << "Interface not found: " << GuidToString(interface_guid);
LOG(ERROR) << "Interface not found: " << absl::Hex(luid.Value);
return false;
}
index = it->index;
@@ -17,6 +17,7 @@
// clang-format off
#include <winsock2.h>
#include <ifdef.h>
// clang-format on
#include <cstdint>
@@ -35,14 +36,14 @@ enum InterfaceType {
};
// Class to track network interfaces details. These include the interface type,
// interface index, GUID and IP addresses.
// interface index, NET_LUID and IP addresses.
// This class is thread-safe.
class NetworkInfo {
public:
struct InterfaceInfo {
uint64_t index;
InterfaceType type;
GUID guid;
NET_LUID luid;
std::vector<sockaddr_storage> ipv4_addresses;
std::vector<sockaddr_storage> ipv6_addresses;
};
@@ -54,7 +55,7 @@ class NetworkInfo {
std::vector<InterfaceInfo> GetInterfaces() const;
// Renews the IPv4 address for the given interface.
// Returns true on success.
bool RenewIpv4Address(GUID interface_guid) const;
bool RenewIpv4Address(NET_LUID luid) const;
private:
mutable absl::Mutex mutex_;
@@ -33,7 +33,7 @@ TEST(NetworkInfoTest, RenewIpv4Address) {
if (net_interface.ipv4_addresses.empty()) {
LOG(INFO) << "Ipv6 only interface";
}
EXPECT_TRUE(network_info.RenewIpv4Address(net_interface.guid));
EXPECT_TRUE(network_info.RenewIpv4Address(net_interface.luid));
}
}
@@ -434,7 +434,7 @@ bool WifiHotspotMedium::ConnectWifiHotspot(
LOG(INFO) << "Connected to Hotspot successfully.";
// Make sure IP address is ready.
std::string ip_address;
bool has_address = false;
int64_t ip_address_max_retries = NearbyFlags::GetInstance().GetInt64Flag(
platform::config_package_nearby::nearby_platform_feature::
kWifiHotspotCheckIpMaxRetries);
@@ -447,32 +447,22 @@ bool WifiHotspotMedium::ConnectWifiHotspot(
<< "ms";
for (int i = 0; i < ip_address_max_retries; i++) {
LOG(INFO) << "Check IP address at attempt " << i;
std::vector<std::string> ip_addresses = GetWifiIpv4Addresses();
if (ip_addresses.empty()) {
if (!wifi_hotspot_native_.HasAssignedAddress()) {
// TODO: ftsui - Add flag to control this.
wifi_hotspot_native_.RenewIpv4Address();
Sleep(ip_address_retry_interval_millis);
continue;
}
// Need to filter out the APIPA address("169.254.x.x").
if (ip_addresses[0].starts_with("169.254.")) {
LOG(WARNING) << "Got APIPA address " << ip_addresses[0];
Sleep(ip_address_retry_interval_millis);
continue;
}
ip_address = ip_addresses[0];
has_address = true;
break;
}
if (ip_address.empty()) {
if (!has_address) {
LOG(INFO) << "Failed to get IP address from hotspot.";
wifi_hotspot_native_.RestoreWifiProfile();
return false;
}
LOG(INFO) << "Got IP address " << ip_address << " from hotspot.";
medium_status_ |= kMediumStatusConnected;
LOG(INFO) << "Connected to hotspot: " << hotspot_credentials->GetSSID();
@@ -18,6 +18,7 @@
#include <windows.h>
#include <winsock2.h>
#include <wlanapi.h>
#include <iphlpapi.h>
#include <cguid.h>
// clang-format on
@@ -70,6 +71,16 @@ constexpr char kProfileTemplate[] =
</security>
</MSM>
</WLANProfile>)";
std::string ReasonCodeToString(DWORD reason_code) {
std::wstring reason_str;
reason_str.resize(100);
WlanReasonCodeToString(reason_code, reason_str.size(), reason_str.data(),
/*pReserved=*/nullptr);
reason_str.resize(std::wcslen(reason_str.data()));
return string_utils::WideStringToString(reason_str);
}
} // namespace
WifiHotspotNative::WifiHotspotNative() {
@@ -104,7 +115,7 @@ bool WifiHotspotNative::ConnectToWifiNetwork(
HotspotCredentials* hotspot_credentials) {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << "No available WLAN Interface to use.";
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
{
@@ -128,7 +139,7 @@ bool WifiHotspotNative::ConnectToWifiNetwork(
bool WifiHotspotNative::DisconnectWifiNetwork() {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << "No available WLAN Interface to use.";
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
absl::MutexLock lock(mutex_);
@@ -146,7 +157,7 @@ bool WifiHotspotNative::DisconnectWifiNetwork() {
bool WifiHotspotNative::Scan(absl::string_view ssid) {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << "No available WLAN Interface to use.";
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
WlanNotificationContext context = {
@@ -204,7 +215,7 @@ void WifiHotspotNative::TriggerNetworkRefreshed() {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << "No available WLAN Interface to use.";
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return;
}
@@ -368,18 +379,18 @@ bool WifiHotspotNative::ConnectToWifiNetworkInternal(
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;
}
if (context.connection_code != WLAN_REASON_CODE_SUCCESS) {
LOG(ERROR) << "Failed to connect to Wifi hotspot, code: "
<< context.connection_code;
<< ReasonCodeToString(context.connection_code);
return false;
}
connect_latch_ = nullptr;
backup_profile_name_ = std::move(context.original_profile_name);
return true;
}
@@ -472,7 +483,7 @@ bool WifiHotspotNative::RemoveWlanProfile(GUID interface_guid,
bool WifiHotspotNative::RestoreWifiProfile() {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << "No available WLAN Interface to use.";
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
absl::MutexLock lock(mutex_);
@@ -492,4 +503,44 @@ bool WifiHotspotNative::RestoreWifiProfile() {
return ConnectToWifiNetworkInternal(interface_guid, backup_profile_name_);
}
bool WifiHotspotNative::HasAssignedAddress() {
if (!network_info_.Refresh()) {
return false;
}
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
NET_LUID luid;
ConvertInterfaceGuidToLuid(&interface_guid, &luid);
for (const auto& interface : network_info_.GetInterfaces()) {
if (interface.luid.Value != luid.Value) {
continue;
}
for (const auto& address : interface.ipv4_addresses) {
DCHECK(address.ss_family == AF_INET);
const sockaddr_in* ipv4_address =
reinterpret_cast<const sockaddr_in*>(&address);
// We ignore APIPA addresses since we won't be able to connect using that.
if (ipv4_address->sin_addr.S_un.S_un_b.s_b1 != 169 ||
ipv4_address->sin_addr.S_un.S_un_b.s_b2 != 254) {
return true;
}
}
}
return false;
}
bool WifiHotspotNative::RenewIpv4Address() const {
GUID interface_guid = GetInterfaceGuid();
if (interface_guid == GUID_NULL) {
LOG(ERROR) << __func__ << ": No available WLAN Interface to use.";
return false;
}
NET_LUID luid;
ConvertInterfaceGuidToLuid(&interface_guid, &luid);
return network_info_.RenewIpv4Address(luid);
}
} // namespace nearby::windows
@@ -25,16 +25,17 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "absl/base/nullability.h"
#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 "internal/platform/implementation/windows/network_info.h"
#include "internal/platform/wifi_credential.h"
namespace nearby {
namespace windows {
namespace nearby::windows {
class WifiHotspotNative {
public:
@@ -48,6 +49,10 @@ class WifiHotspotNative {
bool Scan(absl::string_view ssid) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if the interface has a non local scoped IPv4 address.
bool HasAssignedAddress();
bool RenewIpv4Address() const;
private:
// Context for WLAN notification callback.
struct WlanNotificationContext {
@@ -92,9 +97,9 @@ class WifiHotspotNative {
std::unique_ptr<CountDownLatch> connect_latch_;
std::unique_ptr<CountDownLatch> scan_latch_;
std::wstring backup_profile_name_;
NetworkInfo network_info_;
};
} // namespace windows
} // namespace nearby
} // namespace nearby::windows
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_WIFI_HOTSPOT_NATIVE_H_