diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index c2a52ba4..ba1a6247 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -194,11 +194,23 @@ std::vector BasePcpHandler::GetConnectionInfoFromResult( BleConnectionInfo info("", "", "", {}); connection_infos.push_back(info); } else if (medium == location::nearby::proto::connections::WIFI_LAN) { - std::pair ip_port_pair = - mediums_->GetWifiLan().GetCredentials(std::string(service_id)); + std::pair, int> upgrade_candidates = + mediums_->GetWifiLan().GetUpgradeAddressCandidates( + std::string(service_id)); + const std::vector& ip_addresses = upgrade_candidates.first; + std::string ip_address; + // Only use IPv4 address. IPv4 addresses are always at the end of the + // list. + if (!ip_addresses.empty()) { + ip_address = ip_addresses.back(); + if (ip_address.size() != 4) { + ip_address.clear(); + } + } + int port = upgrade_candidates.second; WifiLanConnectionInfo info( - ip_port_pair.first, - absl::StrCat(absl::Hex(ip_port_pair.second, absl::kZeroPad16)), "", + ip_address, + absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "", {}); connection_infos.push_back(info); } diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index d4802955..fb7fc357 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -957,7 +957,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Wlan) { CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); ExceptionOr wlan_path_available_frame = parser::FromBytes( - parser::ForBwuWifiLanPathAvailable(/*ip_address=*/"ABCD", + parser::ForBwuWifiLanPathAvailable(/*ip_addresses=*/{"ABCD"}, /*port=*/1234)); OfflineFrame frame = wlan_path_available_frame.result(); frame.set_version(OfflineFrame::V1); diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index 36962621..c75b02ad 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -145,7 +145,7 @@ class FakeBwuHandler : public BaseBwuHandler { /*mac_address=*/mac_address); } case location::nearby::proto::connections::WIFI_LAN: - return parser::ForBwuWifiLanPathAvailable(/*ip_address=*/"ABCD", + return parser::ForBwuWifiLanPathAvailable(/*ip_addresses=*/{"ABCD"}, /*port=*/1234); case location::nearby::proto::connections::WEB_RTC: case location::nearby::proto::connections::WEB_RTC_NON_CELLULAR: diff --git a/connections/implementation/mediums/wifi_lan.cc b/connections/implementation/mediums/wifi_lan.cc index f8037d09..6520138a 100644 --- a/connections/implementation/mediums/wifi_lan.cc +++ b/connections/implementation/mediums/wifi_lan.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" @@ -603,15 +604,15 @@ ExceptionOr WifiLan::CreateOutgoingMultiplexSocketLocked( return ExceptionOr(Exception::kFailed); } -std::pair WifiLan::GetCredentials( +std::pair, int> WifiLan::GetUpgradeAddressCandidates( const std::string& service_id) { MutexLock lock(&mutex_); const auto& it = server_sockets_.find(service_id); if (it == server_sockets_.end()) { - return std::pair(); + return std::pair, int>(); } - return std::pair(it->second.GetIPAddress(), - it->second.GetPort()); + return {medium_.GetUpgradeAddressCandidates(it->second), + it->second.GetPort()}; } std::string WifiLan::GenerateServiceType(const std::string& service_id) { diff --git a/connections/implementation/mediums/wifi_lan.h b/connections/implementation/mediums/wifi_lan.h index 4c3917d7..ecae5243 100644 --- a/connections/implementation/mediums/wifi_lan.h +++ b/connections/implementation/mediums/wifi_lan.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" @@ -109,12 +110,14 @@ class WifiLan { CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_); - // Gets ip address + port for remote services on the network to identify and - // connect to this service. - // - // Credential is for the currently-hosted Wifi ServerSocket (if any). - std::pair GetCredentials(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); + // Returns the list of ip address candidates that can be used to connect to + // this device for bandwidth upgrade + port number the service is listening + // on. + // The candidates list is ordered to have IPv6 addresses first, then IPv4. + // Both IPv4 and IPv6 adddresses are represented as network order byte + // sequence. + std::pair, int> GetUpgradeAddressCandidates( + const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); private: struct AdvertisingInfo { diff --git a/connections/implementation/mediums/wifi_lan_test.cc b/connections/implementation/mediums/wifi_lan_test.cc index 357f689d..09736bc9 100644 --- a/connections/implementation/mediums/wifi_lan_test.cc +++ b/connections/implementation/mediums/wifi_lan_test.cc @@ -73,12 +73,14 @@ TEST_P(WifiLanTest, AdvertiseSameServiceNameReusesPort) { NsdServiceInfo nsd_service_info; nsd_service_info.SetServiceName(std::string(kServiceInfoName)); wifi_lan_server.StartAdvertising(service_id, nsd_service_info, {}); - auto [address, port] = wifi_lan_server.GetCredentials(service_id); + auto [addresses, port] = + wifi_lan_server.GetUpgradeAddressCandidates(service_id); wifi_lan_server.StopAdvertising(service_id); wifi_lan_server.StopAcceptingConnections(service_id); wifi_lan_server.StartAdvertising(service_id, nsd_service_info, {}); - auto [address2, port2] = wifi_lan_server.GetCredentials(service_id); + auto [addresses2, port2] = + wifi_lan_server.GetUpgradeAddressCandidates(service_id); EXPECT_EQ(port, port2); env_.Stop(); } @@ -95,13 +97,15 @@ TEST_P(WifiLanTest, AdvertiseDifferentServiceNameUsesDifferentPort) { NsdServiceInfo nsd_service_info; nsd_service_info.SetServiceName(std::string(kServiceInfoName)); wifi_lan_server.StartAdvertising(service_id, nsd_service_info, {}); - auto [address, port] = wifi_lan_server.GetCredentials(service_id); + auto [addresses, port] = + wifi_lan_server.GetUpgradeAddressCandidates(service_id); wifi_lan_server.StopAdvertising(service_id); wifi_lan_server.StopAcceptingConnections(service_id); nsd_service_info.SetServiceName("ServiceInfoName2"); wifi_lan_server.StartAdvertising(service_id, nsd_service_info, {}); - auto [address2, port2] = wifi_lan_server.GetCredentials(service_id); + auto [addresses2, port2] = + wifi_lan_server.GetUpgradeAddressCandidates(service_id); EXPECT_NE(port, port2); env_.Stop(); } @@ -313,13 +317,15 @@ TEST_P(WifiLanTest, CanConnectWithIpAddressAndPort) { accept_latch.CountDown(); })); - auto server_credentials = wifi_lan_server.GetCredentials(service_id); - ASSERT_FALSE(server_credentials.first.empty()); - ASSERT_NE(server_credentials.second, 0); + auto server_candidates = + wifi_lan_server.GetUpgradeAddressCandidates(service_id); + ASSERT_FALSE(server_candidates.first.empty()); + ASSERT_NE(server_candidates.second, 0); CancellationFlag flag; - ErrorOr socket_for_client_result = wifi_lan_client.Connect( - service_id, server_credentials.first, server_credentials.second, &flag); + ErrorOr socket_for_client_result = + wifi_lan_client.Connect(service_id, server_candidates.first.front(), + server_candidates.second, &flag); EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); EXPECT_TRUE(wifi_lan_server.StopAcceptingConnections(service_id)); EXPECT_TRUE(wifi_lan_server.StopAdvertising(service_id)); diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index 4fa042e8..c2143fad 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -19,6 +19,7 @@ #include #include +#include "absl/strings/str_cat.h" #include "connections/connection_options.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/internal_payload.h" @@ -29,6 +30,7 @@ #include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/logging.h" #include "internal/platform/mac_address.h" namespace nearby { @@ -286,8 +288,18 @@ ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, return ToBytes(std::move(frame)); } -ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, - std::int32_t port) { +ByteArray ForBwuWifiLanPathAvailable( + const std::vector& ip_addresses, std::int32_t port) { + // For compatibility with Android versions, only use IPv4 address. + // IPv4 addresses are always at the end of the list. + std::string ip_address = ip_addresses.back(); + if (ip_address.size() != 4) { + return {}; + } + VLOG(1) << "WifiLanBwuPath retrieved WIFI_LAN credentials. IP addr: " + << absl::Hex(ip_address[0]) << "." << absl::Hex(ip_address[1]) << "." + << absl::Hex(ip_address[2]) << "." << absl::Hex(ip_address[3]) + << ", Port: " << port; OfflineFrame frame; frame.set_version(OfflineFrame::V1); diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index b3cf6410..47dc3ac7 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -81,8 +81,8 @@ ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, std::int32_t frequency, const std::string& gateway, bool supports_disabling_encryption); -ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, - std::int32_t port); +ByteArray ForBwuWifiLanPathAvailable( + const std::vector& ip_addresses, std::int32_t port); ByteArray ForBwuAwdlPathAvailable(const std::string& service_name, const std::string& service_type, const std::string& password, diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index 788031f5..57ad4915 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -425,7 +425,7 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) { > > >)pb"; - ByteArray bytes = ForBwuWifiLanPathAvailable("\x01\x02\x03\x04", 1234); + ByteArray bytes = ForBwuWifiLanPathAvailable({"\x01\x02\x03\x04"}, 1234); auto response = FromBytes(bytes); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); diff --git a/connections/implementation/wifi_lan_bwu_handler.cc b/connections/implementation/wifi_lan_bwu_handler.cc index 93e89a6b..3d87c887 100644 --- a/connections/implementation/wifi_lan_bwu_handler.cc +++ b/connections/implementation/wifi_lan_bwu_handler.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include "absl/functional/bind_front.h" #include "connections/implementation/base_bwu_handler.h" @@ -66,7 +67,8 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel( std::int32_t port = upgrade_path_info_socket.wifi_port(); VLOG(1) << "WifiLanBwuHandler is attempting to connect to " - << "available WifiLan service (" << ip_address << ":" << port + << "available WifiLan service (" + << WifiUtils::GetHumanReadableIpAddress(ip_address) << ":" << port << ") for endpoint " << endpoint_id; ErrorOr socket_result = wifi_lan_medium_.Connect( @@ -79,8 +81,8 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel( } VLOG(1) << "WifiLanBwuHandler successfully connected to WifiLan service (" - << ip_address << ":" << port << ") while upgrading endpoint " - << endpoint_id; + << WifiUtils::GetHumanReadableIpAddress(ip_address) << ":" << port + << ") while upgrading endpoint " << endpoint_id; // Create a new WifiLanEndpointChannel. auto channel = std::make_unique( @@ -121,25 +123,21 @@ ByteArray WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( << endpoint_id; } - // Note: Credentials are not populated until StartAcceptingConnections() is + // Address candidates are not populated until StartAcceptingConnections() is // called and the server socket is created. Be careful moving this codeblock // around. - auto credential = wifi_lan_medium_.GetCredentials(upgrade_service_id); - auto ip_address = credential.first; - auto port = credential.second; - if (ip_address.empty()) { + std::pair, int> upgrade_candidates = + wifi_lan_medium_.GetUpgradeAddressCandidates(upgrade_service_id); + const std::vector& ip_addresses = upgrade_candidates.first; + int port = upgrade_candidates.second; + if (ip_addresses.empty()) { LOG(INFO) << "WifiLanBwuHandler couldn't initiate the wifi_lan upgrade for " << "service " << upgrade_service_id << " and endpoint " << endpoint_id - << " because the wifi_lan ip address were unable to be obtained."; + << " because there are no available ip addresses."; return {}; } - - LOG(INFO) << "WifiLanBwuHandler retrieved WIFI_LAN credentials. IP addr: " - << ip_address[0] << "." << ip_address[1] << "." << ip_address[2] - << "." << ip_address[3] << ", Port: " << port; - - return parser::ForBwuWifiLanPathAvailable(ip_address, port); + return parser::ForBwuWifiLanPathAvailable(ip_addresses, port); } void WifiLanBwuHandler::HandleRevertInitiatorStateForService( diff --git a/internal/platform/implementation/apple/wifi_lan.h b/internal/platform/implementation/apple/wifi_lan.h index f7939a48..cf0628b2 100644 --- a/internal/platform/implementation/apple/wifi_lan.h +++ b/internal/platform/implementation/apple/wifi_lan.h @@ -124,6 +124,7 @@ class WifiLanMedium : public api::WifiLanMedium { std::unique_ptr ConnectToService( const std::string& ip_address, int port, CancellationFlag* cancellation_flag) override; std::unique_ptr ListenForService(int port) override; + std::vector GetUpgradeAddressCandidates(const api::WifiLanServerSocket& server_socket) override; private: GNCNWFramework* medium_; diff --git a/internal/platform/implementation/apple/wifi_lan.mm b/internal/platform/implementation/apple/wifi_lan.mm index 3cfe23af..96a8b94b 100644 --- a/internal/platform/implementation/apple/wifi_lan.mm +++ b/internal/platform/implementation/apple/wifi_lan.mm @@ -183,5 +183,10 @@ std::unique_ptr WifiLanMedium::ListenForService(int po return nil; } +std::vector WifiLanMedium::GetUpgradeAddressCandidates( + const api::WifiLanServerSocket& server_socket) { + return { server_socket.GetIPAddress() }; +} + } // namespace apple } // namespace nearby diff --git a/internal/platform/implementation/g3/wifi_lan.cc b/internal/platform/implementation/g3/wifi_lan.cc index b8b530c1..9e64829a 100644 --- a/internal/platform/implementation/g3/wifi_lan.cc +++ b/internal/platform/implementation/g3/wifi_lan.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "absl/log/check.h" #include "absl/synchronization/mutex.h" @@ -281,5 +282,10 @@ std::unique_ptr WifiLanMedium::ListenForService( return server_socket; } +std::vector WifiLanMedium::GetUpgradeAddressCandidates( + const api::WifiLanServerSocket& server_socket) { + return { server_socket.GetIPAddress() }; +} + } // namespace g3 } // namespace nearby diff --git a/internal/platform/implementation/g3/wifi_lan.h b/internal/platform/implementation/g3/wifi_lan.h index fb4b1c24..72dd4efd 100644 --- a/internal/platform/implementation/g3/wifi_lan.h +++ b/internal/platform/implementation/g3/wifi_lan.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" @@ -206,6 +207,9 @@ class WifiLanMedium : public api::WifiLanMedium { return std::nullopt; } + std::vector GetUpgradeAddressCandidates( + const api::WifiLanServerSocket& server_socket) override; + private: struct AdvertisingInfo { bool Empty() const { return service_types.empty(); } diff --git a/internal/platform/implementation/wifi_lan.h b/internal/platform/implementation/wifi_lan.h index b967f4aa..066c206a 100644 --- a/internal/platform/implementation/wifi_lan.h +++ b/internal/platform/implementation/wifi_lan.h @@ -16,6 +16,7 @@ #define PLATFORM_API_WIFI_LAN_H_ #include +#include #include "absl/functional/any_invocable.h" #include "internal/platform/cancellation_flag.h" @@ -151,6 +152,15 @@ class WifiLanMedium { // Returns the port range as a pair of min and max port. virtual absl::optional> GetDynamicPortRange() = 0; + + // Returns the list of ip address candidates that can be used to connect to + // this device for bandwidth upgrade. + // `server_socket` is the socket that is currently listening for service + // requests. + // Returned adddress list is sorted so IPv6 addresses are first. Both IPv4 + // and IPv6 addresses are represented as network order byte sequence. + virtual std::vector GetUpgradeAddressCandidates( + const WifiLanServerSocket& server_socket) = 0; }; } // namespace api diff --git a/internal/platform/implementation/windows/wifi_lan.h b/internal/platform/implementation/windows/wifi_lan.h index 663f4885..a468cea8 100644 --- a/internal/platform/implementation/windows/wifi_lan.h +++ b/internal/platform/implementation/windows/wifi_lan.h @@ -250,6 +250,9 @@ class WifiLanMedium : public api::WifiLanMedium { return absl::nullopt; } + std::vector GetUpgradeAddressCandidates( + const api::WifiLanServerSocket& server_socket) override; + private: // Nsd status static const int kMediumStatusIdle = 0; diff --git a/internal/platform/implementation/windows/wifi_lan_medium.cc b/internal/platform/implementation/windows/wifi_lan_medium.cc index cc6e1d87..ee5ab38d 100644 --- a/internal/platform/implementation/windows/wifi_lan_medium.cc +++ b/internal/platform/implementation/windows/wifi_lan_medium.cc @@ -45,11 +45,13 @@ #include "internal/platform/exception.h" #include "internal/platform/feature_flags.h" #include "internal/platform/flags/nearby_platform_feature_flags.h" +#include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.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/string_utils.h" +#include "internal/platform/implementation/windows/network_info.h" #include "internal/platform/implementation/windows/socket_address.h" +#include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/implementation/windows/utils.h" #include "internal/platform/logging.h" #include "internal/platform/nsd_service_info.h" @@ -780,4 +782,40 @@ bool WifiLanMedium::IsConnectableIpAddress(NsdServiceInfo& nsd_service_info, return false; } +std::vector WifiLanMedium::GetUpgradeAddressCandidates( + const api::WifiLanServerSocket& server_socket) { + const NetworkInfo& network_info = NetworkInfo::GetNetworkInfo(); + std::vector ip_addresses; + std::vector ipv4_addresses; + for (const auto& net_interface : network_info.GetInterfaces()) { + // Only use wifi and ethernet interfaces for upgrade. + if (net_interface.type != InterfaceType::kWifi && + net_interface.type != InterfaceType::kEthernet) { + continue; + } + for (const auto& ipv6_address : net_interface.ipv6_addresses) { + SocketAddress address(ipv6_address); + // Link local addresses cannot be used for upgrade since we can't tell + // which interface on the remote device the address is valid. + if (address.IsV6LinkLocal()) { + continue; + } + ip_addresses.push_back( + std::string(reinterpret_cast( + &address.ipv6_address()->sin6_addr.u.Byte[0]), + 16)); + } + for (const auto& ipv4address : net_interface.ipv4_addresses) { + auto address = reinterpret_cast(&ipv4address); + ipv4_addresses.push_back(std::string( + reinterpret_cast(&address->sin_addr.S_un.S_un_b.s_b1), + 4)); + } + } + // Append v4 addresses to the end of the list. + ip_addresses.insert(ip_addresses.end(), ipv4_addresses.begin(), + ipv4_addresses.end()); + return ip_addresses; +} + } // namespace nearby::windows diff --git a/internal/platform/implementation/windows/wifi_lan_server_socket.cc b/internal/platform/implementation/windows/wifi_lan_server_socket.cc index 06db6c4e..42e2e89a 100644 --- a/internal/platform/implementation/windows/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_lan_server_socket.cc @@ -45,10 +45,7 @@ WifiLanServerSocket::~WifiLanServerSocket() { Close(); } // Returns the first IP address. std::string WifiLanServerSocket::GetIPAddress() const { - // The result of this function is used in BWU to let the remote side know - // which IP to connect to. - // server_socket_ is not bound to any addresses. So we need to pick an - // IP address from the list of available addresses. + // Just pick an IP address from the list of available addresses. std::vector ip_addresses = GetIpv4Addresses(); if (ip_addresses.empty()) { LOG(ERROR) << "No IP addresses found."; diff --git a/internal/platform/wifi_lan.cc b/internal/platform/wifi_lan.cc index 92b760b4..2dfea8f0 100644 --- a/internal/platform/wifi_lan.cc +++ b/internal/platform/wifi_lan.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "absl/container/flat_hash_map.h" #include "internal/platform/cancellation_flag.h" @@ -201,4 +202,9 @@ WifiLanSocket WifiLanMedium::ConnectToService( impl_->ConnectToService(ip_address, port, cancellation_flag)); } +std::vector WifiLanMedium::GetUpgradeAddressCandidates( + const WifiLanServerSocket& server_socket) { + return impl_->GetUpgradeAddressCandidates(server_socket.GetImpl()); +} + } // namespace nearby diff --git a/internal/platform/wifi_lan.h b/internal/platform/wifi_lan.h index 60902d4f..0ad0845a 100644 --- a/internal/platform/wifi_lan.h +++ b/internal/platform/wifi_lan.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" @@ -178,6 +179,7 @@ class WifiLanServerSocket final { bool IsValid() const { return impl_ != nullptr; } api::WifiLanServerSocket& GetImpl() { return *impl_; } + const api::WifiLanServerSocket& GetImpl() const { return *impl_; } private: std::shared_ptr impl_; @@ -267,6 +269,15 @@ class WifiLanMedium { api::WifiLanMedium& GetImpl() { return *impl_; } + // Returns the list of ip address candidates that can be used to connect to + // this device for bandwidth upgrade. + // `server_socket` is the socket that is currently listening for service + // requests. + // Returned adddress list is sorted so IPv6 addresses are first. Both IPv4 + // and IPv6 addresses are represented as network order byte sequence. + std::vector GetUpgradeAddressCandidates( + const WifiLanServerSocket& server_socket); + private: Mutex mutex_; std::unique_ptr impl_;