From dd2832d8b1da1d402e9b7630dfce7831c7827391 Mon Sep 17 00:00:00 2001 From: Francis Tsui Date: Tue, 26 Aug 2025 15:15:11 -0700 Subject: [PATCH] Move to Win32 APIs for network interface enumeration. PiperOrigin-RevId: 799739002 --- .../flags/nearby_platform_feature_flags.h | 3 + .../platform/implementation/windows/utils.cc | 222 ++++++++++++------ .../platform/implementation/windows/utils.h | 4 + .../implementation/windows/utils_test.cc | 11 + 4 files changed, 166 insertions(+), 74 deletions(-) diff --git a/internal/platform/flags/nearby_platform_feature_flags.h b/internal/platform/flags/nearby_platform_feature_flags.h index d5012375..846a9a21 100644 --- a/internal/platform/flags/nearby_platform_feature_flags.h +++ b/internal/platform/flags/nearby_platform_feature_flags.h @@ -81,6 +81,9 @@ constexpr auto kSocketSendBufferSize = constexpr auto kRunScheduledExecutorCallbackOnExecutorThread = flags::Flag(kConfigPackage, "45686494", false); +constexpr auto kEnableIpAddressesNative = + flags::Flag(kConfigPackage, "45722101", false); + } // namespace nearby_platform_feature } // namespace config_package_nearby } // namespace platform diff --git a/internal/platform/implementation/windows/utils.cc b/internal/platform/implementation/windows/utils.cc index a5b287fe..9d47a718 100644 --- a/internal/platform/implementation/windows/utils.cc +++ b/internal/platform/implementation/windows/utils.cc @@ -14,8 +14,12 @@ #include "internal/platform/implementation/windows/utils.h" +// clang-format off #include #include +#include +#include +// clang-format on // Standard C/C++ headers #include @@ -27,7 +31,9 @@ // Nearby connections headers #include "absl/strings/string_view.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" +#include "internal/platform/flags/nearby_platform_feature_flags.h" #include "internal/platform/implementation/crypto.h" #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/logging.h" @@ -46,6 +52,128 @@ using ::winrt::Windows::Networking::Connectivity::NetworkAdapter; using ::winrt::Windows::Networking::Connectivity::NetworkInformation; using ::winrt::Windows::Networking::Connectivity::NetworkTypes; +void GetIpv4AddressesWinRT(std::vector& wifi_addresses, + std::vector& ethernet_addresses, + std::vector& other_addresses) { + try { + auto host_names = NetworkInformation::GetHostNames(); + for (const auto& host_name : host_names) { + VLOG(1) << "host_name: " << winrt::to_string(host_name.ToString()); + if (host_name.IPInformation() != nullptr && + host_name.IPInformation().NetworkAdapter() != nullptr && + host_name.Type() == HostNameType::Ipv4) { + NetworkAdapter adapter = host_name.IPInformation().NetworkAdapter(); + if (adapter.NetworkItem().GetNetworkTypes() == NetworkTypes::None) { + // If we're not connected to a network, we don't want to add this + // address. + continue; + } + if (adapter.IanaInterfaceType() == Constants::kInterfaceTypeWifi) { + wifi_addresses.push_back(winrt::to_string(host_name.ToString())); + } else if (adapter.IanaInterfaceType() == + Constants::kInterfaceTypeEthernet) { + ethernet_addresses.push_back(winrt::to_string(host_name.ToString())); + } else { + other_addresses.push_back(winrt::to_string(host_name.ToString())); + } + } + } + } catch (std::exception exception) { + LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. Exception : " + << exception.what(); + } catch (const winrt::hresult_error& error) { + LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. WinRT exception: " + << error.code() << ": " << winrt::to_string(error.message()); + } catch (...) { + LOG(ERROR) << __func__ << ": Unknown exception."; + } +} + +void AddIpUnicastAddresses(IP_ADAPTER_UNICAST_ADDRESS* unicast_addresses, + std::vector& addresses) { + std::string address; + while (unicast_addresses != nullptr) { + DWORD size = INET6_ADDRSTRLEN; // Max IP address length. + address.resize(size); + if (WSAAddressToStringA(unicast_addresses->Address.lpSockaddr, + unicast_addresses->Address.iSockaddrLength, + /*lpProtocolInfo=*/nullptr, address.data(), + &size) != 0) { + LOG(ERROR) << __func__ << ": Cannot convert address to string."; + continue; + } + address.resize(size); + addresses.push_back(address); + unicast_addresses = unicast_addresses->Next; + } +} + +void GetIpAddressesNative(int family, std::vector& wifi_addresses, + std::vector& ethernet_addresses, + std::vector& other_addresses) { + static constexpr int kDefaultBufferSize = 15 * 1024; // default to 15K buffer + static constexpr int kMaxBufferSize = + 45 * 1024; // Try to increase buffer 2 times. + static constexpr ULONG kDefaultFlags = + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; + ULONG buffer_size = 0; + // A string to own the memory for IP_ADAPTER_ADDRESSES. + std::string address_buffer; + ULONG error_code = ERROR_NO_DATA; + IP_ADAPTER_ADDRESSES* addresses = nullptr; + do { + buffer_size += kDefaultBufferSize; + address_buffer.reserve(buffer_size); + addresses = reinterpret_cast(address_buffer.data()); + error_code = GetAdaptersAddresses( + family, kDefaultFlags, /*reserved=*/nullptr, addresses, &buffer_size); + } while (error_code == ERROR_BUFFER_OVERFLOW && + buffer_size <= kMaxBufferSize); + if (error_code != ERROR_NO_DATA && error_code != NO_ERROR) { + LOG(ERROR) << __func__ + << ": Cannot get adapter addresses. Error code: " << error_code; + return; + } + if (error_code == ERROR_NO_DATA) { + LOG(INFO) << __func__ << ": No IPv4 addresses found."; + return; + } + IP_ADAPTER_ADDRESSES* next_address = addresses; + while (next_address != nullptr) { + if (next_address->OperStatus == IfOperStatusUp) { + if (next_address->IfType == IF_TYPE_ETHERNET_CSMACD) { + VLOG(1) << "Found ethernet adater: " << next_address->AdapterName; + AddIpUnicastAddresses(next_address->FirstUnicastAddress, + ethernet_addresses); + } else if (next_address->IfType == IF_TYPE_IEEE80211) { + VLOG(1) << "Found wifi adapter: " << next_address->AdapterName; + AddIpUnicastAddresses(next_address->FirstUnicastAddress, + wifi_addresses); + } else if (next_address->IfType != IF_TYPE_SOFTWARE_LOOPBACK) { + // Skip loopback interfaces. + VLOG(1) << "Found other adapter: " << next_address->AdapterName; + AddIpUnicastAddresses(next_address->FirstUnicastAddress, + other_addresses); + } + } + next_address = next_address->Next; + } +} + +void GetIpv4Addresses(std::vector& wifi_addresses, + std::vector& ethernet_addresses, + std::vector& other_addresses) { + if (NearbyFlags::GetInstance().GetBoolFlag( + platform::config_package_nearby::nearby_platform_feature:: + kEnableIpAddressesNative)) { + GetIpAddressesNative(AF_INET, wifi_addresses, ethernet_addresses, + other_addresses); + } else { + GetIpv4AddressesWinRT(wifi_addresses, ethernet_addresses, other_addresses); + } +} + } // namespace std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) { @@ -100,52 +228,6 @@ std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) { return std::string(ipv4_b, 4); } -std::vector GetIpv4Addresses() { - std::vector result; - std::vector wifi_addresses; - std::vector ethernet_addresses; - std::vector other_addresses; - - try { - auto host_names = NetworkInformation::GetHostNames(); - for (const auto& host_name : host_names) { - if (host_name.IPInformation() != nullptr && - host_name.IPInformation().NetworkAdapter() != nullptr && - host_name.Type() == HostNameType::Ipv4) { - NetworkAdapter adapter = host_name.IPInformation().NetworkAdapter(); - if (adapter.NetworkItem().GetNetworkTypes() == NetworkTypes::None) { - // If we're not connected to a network, we don't want to add this - // address. - continue; - } - if (adapter.IanaInterfaceType() == Constants::kInterfaceTypeWifi) { - wifi_addresses.push_back(winrt::to_string(host_name.ToString())); - } else if (adapter.IanaInterfaceType() == - Constants::kInterfaceTypeEthernet) { - ethernet_addresses.push_back(winrt::to_string(host_name.ToString())); - } else { - other_addresses.push_back(winrt::to_string(host_name.ToString())); - } - } - } - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. Exception : " - << exception.what(); - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. WinRT exception: " - << error.code() << ": " << winrt::to_string(error.message()); - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - } - - result.insert(result.end(), wifi_addresses.begin(), wifi_addresses.end()); - result.insert(result.end(), ethernet_addresses.begin(), - ethernet_addresses.end()); - result.insert(result.end(), other_addresses.begin(), other_addresses.end()); - - return result; -} - std::vector Get4BytesIpv4Addresses() { std::vector result; std::vector ipv4_addresses = GetIpv4Addresses(); @@ -165,39 +247,31 @@ std::vector Get4BytesIpv4Addresses() { return result; } +std::vector GetIpv4Addresses() { + std::vector result; + GetIpv4Addresses(result, result, result); + return result; +} + std::vector GetWifiIpv4Addresses() { std::vector result; - - try { - auto host_names = NetworkInformation::GetHostNames(); - for (const auto& host_name : host_names) { - if (host_name.IPInformation() != nullptr && - host_name.IPInformation().NetworkAdapter() != nullptr && - host_name.Type() == HostNameType::Ipv4) { - NetworkAdapter adapter = host_name.IPInformation().NetworkAdapter(); - if (adapter.NetworkItem().GetNetworkTypes() == NetworkTypes::None) { - // If we're not connected to a network, we don't want to add this - // address. - continue; - } - if (adapter.IanaInterfaceType() == Constants::kInterfaceTypeWifi) { - result.push_back(winrt::to_string(host_name.ToString())); - } - } - } - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. Exception : " - << exception.what(); - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": Cannot get IPv4 addresses. WinRT exception: " - << error.code() << ": " << winrt::to_string(error.message()); - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - } - + std::vector ethernet_addresses; + std::vector other_addresses; + GetIpv4Addresses(result, ethernet_addresses, other_addresses); return result; } +void GetConnectedNetworks(bool& is_wifi_connected, bool& is_ethernet_connected, + bool& is_other_connected) { + std::vector wifi_addresses; + std::vector ethernet_addresses; + std::vector other_addresses; + GetIpv4Addresses(wifi_addresses, ethernet_addresses, other_addresses); + is_wifi_connected = !wifi_addresses.empty(); + is_ethernet_connected = !ethernet_addresses.empty(); + is_other_connected = !other_addresses.empty(); +} + Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid) { int64_t data1 = guid.Data1; int64_t data2 = guid.Data2; diff --git a/internal/platform/implementation/windows/utils.h b/internal/platform/implementation/windows/utils.h index 6f9e8cd5..69342da7 100644 --- a/internal/platform/implementation/windows/utils.h +++ b/internal/platform/implementation/windows/utils.h @@ -51,6 +51,10 @@ std::vector GetIpv4Addresses(); std::vector Get4BytesIpv4Addresses(); std::vector GetWifiIpv4Addresses(); +// Returns the connection state of the different network types. +void GetConnectedNetworks(bool& is_wifi_connected, bool& is_ethernet_connected, + bool& is_other_connected); + // Help methods to convert between Uuid and winrt::guid Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid); winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid); diff --git a/internal/platform/implementation/windows/utils_test.cc b/internal/platform/implementation/windows/utils_test.cc index 53de19af..aaf7da91 100644 --- a/internal/platform/implementation/windows/utils_test.cc +++ b/internal/platform/implementation/windows/utils_test.cc @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "internal/platform/byte_array.h" +#include "internal/platform/logging.h" #include "internal/platform/uuid.h" #include "winrt/Windows.Foundation.h" #include "winrt/base.h" @@ -180,5 +181,15 @@ TEST(UtilsTests, InspectableReader_ReadStringArray) { std::invalid_argument); } +TEST(UtilsTests, GetIpv4Addresses) { + LOG(ERROR) << "GetIpv4Addresses"; + std::vector addresses = GetIpv4Addresses(); + EXPECT_FALSE(addresses.empty()); + for (const auto& address : addresses) { + LOG(ERROR) << "address: " << address; + } + LOG(ERROR) << "GetIpv4Addresses done"; +} + } // namespace windows } // namespace nearby