diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 7900afb0..f4832e49 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -270,6 +270,7 @@ cc_test( "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index fb7fc357..3d4d21ef 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -19,8 +19,10 @@ #include #include "gtest/gtest.h" +#include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" #include "connections/connection_options.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" @@ -32,8 +34,10 @@ #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #include "connections/listeners.h" +#include "connections/medium_selector.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" +#include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/feature_flags.h" #include "internal/proto/analytics/connections_log.pb.h" @@ -60,6 +64,25 @@ constexpr absl::string_view kEndpointId3 = "Endpoint3"; constexpr absl::string_view kEndpointId4 = "Endpoint4"; constexpr absl::string_view kEndpointId5 = "Endpoint5"; +BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials +CreateWifiHotspotCredentials() { + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid("Direct-357a2d8c"); + credentials.set_password("b592f7d3"); + credentials.set_port(1234); + credentials.set_frequency(2412); + credentials.set_gateway("123.234.23.1"); + auto* candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string( + "\xfe\x80\\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 16)); + candidate->set_port(1234); + candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address("\x7b\xea\x17\x01"); + candidate->set_port(2412); + return credentials; +} + class BwuManagerTest : public ::testing::Test { protected: BwuManagerTest() { @@ -928,9 +951,9 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) { ExceptionOr hotspot_path_available_frame = parser::FromBytes(parser::ForBwuWifiHotspotPathAvailable( - /*ssid=*/"Direct-357a2d8c", /*password=*/"b592f7d3", - /*port=*/1234, /*frequency=*/2412, /*gateway=*/"123.234.23.1", - false)); + CreateWifiHotspotCredentials(), + /*supports_disabling_encryption=*/false)); + ASSERT_TRUE(hotspot_path_available_frame.ok()); OfflineFrame frame = hotspot_path_available_frame.result(); frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); @@ -995,8 +1018,8 @@ TEST_F(BwuManagerTest, BlockBwuFrameBeforeAccept) { ExceptionOr hotspot_path_available_frame2 = parser::FromBytes(parser::ForBwuWifiHotspotPathAvailable( - /*ssid=*/"Direct-357a2d8c", /*password=*/"b592f7d3", - /*port=*/1234, /*frequency=*/2412, /*gateway=*/"123.234.23.1", true)); + CreateWifiHotspotCredentials(), + /*supports_disabling_encryption=*/true)); OfflineFrame frame2 = hotspot_path_available_frame2.result(); frame2.set_version(OfflineFrame::V1); auto* v1_frame2 = frame2.mutable_v1(); @@ -1018,8 +1041,8 @@ TEST_F(BwuManagerTest, BlockBwuFrameBeforeAccept) { TEST_F(BwuManagerTest, BlockBwuFrameFromAdvertiser) { ExceptionOr hotspot_path_available_frame = parser::FromBytes(parser::ForBwuWifiHotspotPathAvailable( - /*ssid=*/"Direct-357a2d8c", /*password=*/"b592f7d3", - /*port=*/1234, /*frequency=*/2412, /*gateway=*/"123.234.23.1", true)); + CreateWifiHotspotCredentials(), + /*supports_disabling_encryption=*/true)); OfflineFrame frame = hotspot_path_available_frame.result(); frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index c75b02ad..e17fb876 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -152,11 +152,25 @@ class FakeBwuHandler : public BaseBwuHandler { return parser::ForBwuWebrtcPathAvailable( /*peer_id=*/"peer-id", location::nearby::connections::LocationHint{}); - case location::nearby::proto::connections::WIFI_HOTSPOT: - return parser::ForBwuWifiHotspotPathAvailable( - /*ssid=*/"Direct-357a2d8c", /*password=*/"b592f7d3", - /*port=*/1234, /*frequency=*/2412, /*gateway=*/"123.234.23.1", - false); + case location::nearby::proto::connections::WIFI_HOTSPOT: { + location::nearby::connections::BandwidthUpgradeNegotiationFrame:: + UpgradePathInfo::WifiHotspotCredentials credentials; + credentials.set_ssid("Direct-357a2d8c"); + credentials.set_password("b592f7d3"); + credentials.set_port(1234); + credentials.set_frequency(2412); + credentials.set_gateway("123.234.23.1"); + auto* candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string( + "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", + 16)); + candidate->set_port(1234); + candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address("\x7b\xea\x17\x01"); + candidate->set_port(2412); + return parser::ForBwuWifiHotspotPathAvailable(std::move(credentials), + false); + } case location::nearby::proto::connections::WIFI_DIRECT: return parser::ForBwuWifiDirectPathAvailable( /*ssid=*/"Direct-12345678", /*password=*/"87654321", /*port=*/2143, diff --git a/connections/implementation/mediums/wifi_hotspot.cc b/connections/implementation/mediums/wifi_hotspot.cc index 9e98e8f3..6d91e27e 100644 --- a/connections/implementation/mediums/wifi_hotspot.cc +++ b/connections/implementation/mediums/wifi_hotspot.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "absl/strings/string_view.h" #include "absl/time/clock.h" @@ -256,7 +257,8 @@ bool WifiHotspot::IsAcceptingConnectionsLocked(const std::string& service_id) { } ErrorOr WifiHotspot::Connect( - const std::string& service_id, const ServiceAddress& service_address, + const std::string& service_id, + const std::vector& service_addresses, CancellationFlag* cancellation_flag) { MutexLock lock(&mutex_); if (service_id.empty()) { @@ -264,6 +266,11 @@ ErrorOr WifiHotspot::Connect( "service_id is empty."; return {Error(OperationResultCode::NEARBY_LOCAL_CLIENT_STATE_WRONG)}; } + if (service_addresses.empty()) { + LOG(INFO) << "No service address found for service_id: " << service_id; + return {Error( + OperationResultCode::MEDIUM_UNAVAILABLE_WIFI_HOTSPOT_NOT_AVAILABLE)}; + } if (!IsClientAvailableLocked()) { LOG(INFO) << "Can't create client WifiHotspot socket [service_id=" @@ -288,13 +295,18 @@ ErrorOr WifiHotspot::Connect( // Socket to return. To allow for NRVO to work, it has to be a single object. WifiHotspotSocket socket; for (int i = 0; i < wifi_hotspot_max_connection_retries; ++i) { - if (cancellation_flag->Cancelled()) { - LOG(INFO) << "connect to service has been cancelled."; - return {Error( - OperationResultCode:: - CLIENT_CANCELLATION_CANCEL_WIFI_HOTSPOT_OUTGOING_CONNECTION)}; + for (const auto& service_address : service_addresses) { + if (cancellation_flag->Cancelled()) { + LOG(INFO) << "connect to service has been cancelled."; + return {Error( + OperationResultCode:: + CLIENT_CANCELLATION_CANCEL_WIFI_HOTSPOT_OUTGOING_CONNECTION)}; + } + socket = medium_.ConnectToService(service_address, cancellation_flag); + if (socket.IsValid()) { + break; + } } - socket = medium_.ConnectToService(service_address, cancellation_flag); if (socket.IsValid()) { break; } diff --git a/connections/implementation/mediums/wifi_hotspot.h b/connections/implementation/mediums/wifi_hotspot.h index 92bcf45b..11b0bd3e 100644 --- a/connections/implementation/mediums/wifi_hotspot.h +++ b/connections/implementation/mediums/wifi_hotspot.h @@ -16,6 +16,7 @@ #define CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_H_ #include +#include #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" @@ -74,10 +75,10 @@ class WifiHotspot { // bandwidth upgradation. // Returns socket instance. On success, WifiHotspotSocket.IsValid() return // true. - ErrorOr Connect(const std::string& service_id, - const ServiceAddress& service_address, - CancellationFlag* cancellation_flag) - ABSL_LOCKS_EXCLUDED(mutex_); + ErrorOr Connect( + const std::string& service_id, + const std::vector& service_addresses, + CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_); // Gets SoftAP ssid + password + ip address + gateway + port etc for remote // services on the network to identify and connect to this service. diff --git a/connections/implementation/mediums/wifi_hotspot_test.cc b/connections/implementation/mediums/wifi_hotspot_test.cc index ab31e1fd..0f571edf 100644 --- a/connections/implementation/mediums/wifi_hotspot_test.cc +++ b/connections/implementation/mediums/wifi_hotspot_test.cc @@ -120,11 +120,11 @@ TEST_P(WifiHotspotTest, CanStartHotspotThatOtherConnect) { }; CancellationFlag flag; ErrorOr socket_result = - wifi_hotspot_b->Connect(service_id, service_address, &flag); + wifi_hotspot_b->Connect(service_id, {service_address}, &flag); EXPECT_TRUE(socket_result.has_error()); socket_result = wifi_hotspot_b->Connect( - service_id, hotspot_credentials->GetAddressCandidates().back(), &flag); + service_id, hotspot_credentials->GetAddressCandidates(), &flag); EXPECT_TRUE(socket_result.has_value()); EXPECT_TRUE(socket_result.value().IsValid()); @@ -155,7 +155,7 @@ TEST_P(WifiHotspotTest, CanStartHotspotThatOtherCanCancelConnect) { CancellationFlag flag(true); ErrorOr socket_result = wifi_hotspot_b->Connect( - service_id, hotspot_credentials->GetAddressCandidates().back(), &flag); + service_id, hotspot_credentials->GetAddressCandidates(), &flag); // If FeatureFlag is disabled, Cancelled is false as no-op. if (!feature_flags.enable_cancellation_flag) { diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index c2143fad..246d3377 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -258,12 +258,10 @@ ByteArray ForPayloadAckPayloadTransfer(std::int64_t payload_id) { return ToBytes(std::move(frame)); } -ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, - const std::string& password, - std::int32_t port, - std::int32_t frequency, - const std::string& gateway, - bool supports_disabling_encryption) { +ByteArray ForBwuWifiHotspotPathAvailable( + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials, + bool supports_disabling_encryption) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -279,12 +277,7 @@ ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, supports_disabling_encryption); auto* wifi_hotspot_credentials = upgrade_path_info->mutable_wifi_hotspot_credentials(); - wifi_hotspot_credentials->set_ssid(ssid); - wifi_hotspot_credentials->set_password(password); - wifi_hotspot_credentials->set_port(port); - wifi_hotspot_credentials->set_frequency(frequency); - wifi_hotspot_credentials->set_gateway(gateway); - + *wifi_hotspot_credentials = std::move(credentials); return ToBytes(std::move(frame)); } diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index 47dc3ac7..59798d70 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -75,12 +75,10 @@ ByteArray ForPayloadAckPayloadTransfer(std::int64_t payload_id); ByteArray ForBwuIntroduction(const std::string& endpoint_id, bool supports_disabling_encryption); ByteArray ForBwuIntroductionAck(); -ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, - const std::string& password, - std::int32_t port, - std::int32_t frequency, - const std::string& gateway, - bool supports_disabling_encryption); +ByteArray ForBwuWifiHotspotPathAvailable( + location::nearby::connections::BandwidthUpgradeNegotiationFrame:: + UpgradePathInfo::WifiHotspotCredentials credentials, + bool supports_disabling_encryption); ByteArray ForBwuWifiLanPathAvailable( const std::vector& ip_addresses, std::int32_t port); ByteArray ForBwuAwdlPathAvailable(const std::string& service_name, diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index 57ad4915..936e9547 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "gmock/gmock.h" @@ -35,6 +36,7 @@ namespace connections { namespace parser { namespace { +using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::OsInfo; using ::location::nearby::connections::PayloadTransferFrame; @@ -396,14 +398,33 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) { port: 1234 gateway: "0.0.0.0" frequency: 2412 + address_candidates: < + ip_address: "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1" + port: 1234 + > + address_candidates: < ip_address: "\xc0\xa8\x00\x01" port: 5678 > > supports_disabling_encryption: false supports_client_introduction_ack: true > > >)pb"; - ByteArray bytes = ForBwuWifiHotspotPathAvailable( - "ssid", "password", 1234, /*frequency=*/2412, "0.0.0.0", false); + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid("ssid"); + credentials.set_password("password"); + credentials.set_port(1234); + credentials.set_frequency(2412); + credentials.set_gateway("0.0.0.0"); + auto* address_candidate = credentials.add_address_candidates(); + address_candidate->set_ip_address(std::string( + "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 16)); + address_candidate->set_port(1234); + address_candidate = credentials.add_address_candidates(); + address_candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4)); + address_candidate->set_port(5678); + ByteArray bytes = + ForBwuWifiHotspotPathAvailable(std::move(credentials), false); auto response = FromBytes(bytes); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); diff --git a/connections/implementation/offline_frames_validator.cc b/connections/implementation/offline_frames_validator.cc index 2356309a..0c058fbc 100644 --- a/connections/implementation/offline_frames_validator.cc +++ b/connections/implementation/offline_frames_validator.cc @@ -232,13 +232,24 @@ Exception EnsureValidBandwidthUpgradeWifiHotspotPathAvailableFrame( !WithinRange(wifi_hotspot_credentials.password().length(), kWifiPasswordSsidMinLength, kWifiPasswordSsidMaxLength)) return {Exception::kInvalidProtocolBuffer}; - if (!wifi_hotspot_credentials.has_gateway()) + if (!wifi_hotspot_credentials.has_gateway() && + wifi_hotspot_credentials.address_candidates_size() == 0) return {Exception::kInvalidProtocolBuffer}; const std::regex ip4_pattern(std::string(kIpv4PatternString).c_str()); - const std::regex ip6_pattern(std::string(kIpv6PatternString).c_str()); - if (!(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern) || - std::regex_match(wifi_hotspot_credentials.gateway(), ip6_pattern))) - return {Exception::kInvalidProtocolBuffer}; + if (!wifi_hotspot_credentials.gateway().empty() && + !(std::regex_match(wifi_hotspot_credentials.gateway(), ip4_pattern))) { + return {Exception::kInvalidProtocolBuffer}; + } + for (const auto& address_candidate : + wifi_hotspot_credentials.address_candidates()) { + if (!address_candidate.has_ip_address() || !address_candidate.has_port()) { + return {Exception::kInvalidProtocolBuffer}; + } + if (address_candidate.ip_address().size() != 4 && + address_candidate.ip_address().size() != 16) { + return {Exception::kInvalidProtocolBuffer}; + } + } // For backwards compatibility reasons, no other fields should be null-checked // for this frame. Parameter checking (eg. must be within this range) is fine. diff --git a/connections/implementation/offline_frames_validator_test.cc b/connections/implementation/offline_frames_validator_test.cc index c963cc28..3b97dc19 100644 --- a/connections/implementation/offline_frames_validator_test.cc +++ b/connections/implementation/offline_frames_validator_test.cc @@ -16,18 +16,23 @@ #include #include +#include #include "gtest/gtest.h" #include "absl/strings/string_view.h" +#include "connections/connection_options.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" +#include "connections/medium_selector.h" #include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" namespace nearby { namespace connections { namespace parser { namespace { +using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::OsInfo; using ::location::nearby::connections::PayloadTransferFrame; @@ -588,12 +593,18 @@ TEST(OfflineFramesValidatorTest, } TEST(OfflineFramesValidatorTest, - ValidatesAsOkWithValidBandwidthUpgradeNegotiationFrame) { + ValidateHotspotUpgradeFrameWithGatewaySucceeds) { OfflineFrame offline_frame; + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(kSsid); + credentials.set_password(kPassword); + credentials.set_port(kPort); + credentials.set_frequency(kHotspotFrequency); + credentials.set_gateway(kWifiHotspotGateway); ByteArray bytes = ForBwuWifiHotspotPathAvailable( - std::string(kSsid), std::string(kPassword), kPort, kHotspotFrequency, - std::string(kWifiHotspotGateway), kSupportsDisablingEncryption); + std::move(credentials), kSupportsDisablingEncryption); offline_frame.ParseFromString(std::string(bytes)); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -601,13 +612,87 @@ TEST(OfflineFramesValidatorTest, EXPECT_TRUE(ret_value.Ok()); } +TEST(OfflineFramesValidatorTest, + ValidateHotspotUpgradeFrameWithAddressCandidatesSucceeds) { + OfflineFrame offline_frame; + + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(kSsid); + credentials.set_password(kPassword); + credentials.set_frequency(kHotspotFrequency); + auto* candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string( + "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 16)); + candidate->set_port(kPort); + candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4)); + candidate->set_port(kPort); + ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::move(credentials), kSupportsDisablingEncryption); + offline_frame.ParseFromString(std::string(bytes)); + + auto ret_value = EnsureValidOfflineFrame(offline_frame); + + EXPECT_TRUE(ret_value.Ok()); +} + +TEST(OfflineFramesValidatorTest, + ValidateHotspotUpgradeFrameWithInvlaidAddressCandidatesLengthFails) { + OfflineFrame offline_frame; + + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(kSsid); + credentials.set_password(kPassword); + credentials.set_frequency(kHotspotFrequency); + auto* candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string( + "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 12)); + candidate->set_port(kPort); + ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::move(credentials), kSupportsDisablingEncryption); + offline_frame.ParseFromString(std::string(bytes)); + + auto ret_value = EnsureValidOfflineFrame(offline_frame); + + EXPECT_FALSE(ret_value.Ok()); +} + +TEST(OfflineFramesValidatorTest, + ValidateHotspotUpgradeFrameWithAddressCandidatesNoPortFails) { + OfflineFrame offline_frame; + + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(kSsid); + credentials.set_password(kPassword); + credentials.set_frequency(kHotspotFrequency); + auto* candidate = credentials.mutable_address_candidates()->Add(); + candidate->set_ip_address(std::string( + "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 16)); + ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::move(credentials), kSupportsDisablingEncryption); + offline_frame.ParseFromString(std::string(bytes)); + + auto ret_value = EnsureValidOfflineFrame(offline_frame); + + EXPECT_FALSE(ret_value.Ok()); +} + TEST(OfflineFramesValidatorTest, ValidatesAsFailWithNullBandwidthUpgradeNegotiationFrame) { OfflineFrame offline_frame; + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(kSsid); + credentials.set_password(kPassword); + credentials.set_port(kPort); + credentials.set_frequency(kHotspotFrequency); + credentials.set_gateway(kWifiHotspotGateway); ByteArray bytes = ForBwuWifiHotspotPathAvailable( - std::string(kSsid), std::string(kPassword), kPort, kHotspotFrequency, - std::string(kWifiHotspotGateway), kSupportsDisablingEncryption); + std::move(credentials), kSupportsDisablingEncryption); offline_frame.ParseFromString(std::string(bytes)); auto* v1_frame = offline_frame.mutable_v1(); diff --git a/connections/implementation/wifi_hotspot_bwu_handler.cc b/connections/implementation/wifi_hotspot_bwu_handler.cc index 46440175..458f92d9 100644 --- a/connections/implementation/wifi_hotspot_bwu_handler.cc +++ b/connections/implementation/wifi_hotspot_bwu_handler.cc @@ -33,11 +33,13 @@ #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/offline_frames.h" +#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/implementation/wifi_hotspot_endpoint_channel.h" #include "connections/strategy.h" #include "internal/base/masker.h" #include "internal/platform/byte_array.h" #include "internal/platform/expected.h" +#include "internal/platform/implementation/wifi_utils.h" #include "internal/platform/logging.h" #include "internal/platform/wifi_credential.h" #include "internal/platform/wifi_hotspot.h" @@ -46,6 +48,7 @@ namespace nearby { namespace connections { namespace { +using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::proto::connections::OperationResultCode; std::vector GatewayToAddressBytes(const std::string& gateway) { @@ -106,18 +109,42 @@ ByteArray WifiHotspotBwuHandler::HandleInitializeUpgradedMediumForEndpoint( wifi_hotspot_medium_.GetCredentials(upgrade_service_id); std::string ssid = hotspot_crendential->GetSSID(); std::string password = hotspot_crendential->GetPassword(); - std::string gateway = hotspot_crendential->GetGateway(); - std::int32_t port = hotspot_crendential->GetPort(); std::int32_t frequency = hotspot_crendential->GetFrequency(); LOG(INFO) << "Start SoftAP with SSID:" << ssid - << ", Password:" << masker::Mask(password) << ", Port:" << port - << ", Gateway:" << gateway << ", Frequency:" << frequency; + << ", Password:" << masker::Mask(password) + << ", Frequency:" << frequency; + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials + credentials; + credentials.set_ssid(ssid); + credentials.set_password(password); + credentials.set_frequency(frequency); + const std::vector& address_candidates = + hotspot_crendential->GetAddressCandidates(); + for (const auto& service_address : address_candidates) { + // service address must be either 4 bytes (IPv4) or 16 bytes (IPv6). + if (service_address.address.size() != 4 && + service_address.address.size() != 16) { + LOG(WARNING) << "Invalid service address size: " + << service_address.address.size(); + continue; + } + auto* service_address_proto = credentials.add_address_candidates(); + service_address_proto->set_ip_address(std::string( + service_address.address.begin(), service_address.address.end())); + service_address_proto->set_port(service_address.port); + } + const ServiceAddress& last_service_address = address_candidates.back(); + // We assume the last service address is IPv4. + credentials.set_gateway(WifiUtils::GetHumanReadableIpAddress( + std::string(last_service_address.address.begin(), + last_service_address.address.end()))); + credentials.set_port(last_service_address.port); bool disabling_encryption = (client->GetAdvertisingOptions().strategy == Strategy::kP2pPointToPoint); return parser::ForBwuWifiHotspotPathAvailable( - ssid, password, port, frequency, gateway, + std::move(credentials), /* supports_disabling_encryption */ disabling_encryption); } @@ -148,15 +175,44 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel( HotspotCredentials hotspot_credentials; hotspot_credentials.SetSSID(upgrade_path_info_credentials.ssid()); hotspot_credentials.SetPassword(upgrade_path_info_credentials.password()); - hotspot_credentials.SetGateway(upgrade_path_info_credentials.gateway()); - hotspot_credentials.SetPort(upgrade_path_info_credentials.port()); hotspot_credentials.SetFrequency(upgrade_path_info_credentials.frequency()); + std::vector service_addresses; + for (const auto& service_address : + upgrade_path_info_credentials.address_candidates()) { + // service address must be either 4 bytes (IPv4) or 16 bytes (IPv6). + if (service_address.ip_address().size() != 4 && + service_address.ip_address().size() != 16) { + LOG(WARNING) << "Invalid service address size: " + << service_address.ip_address().size(); + continue; + } + service_addresses.push_back(ServiceAddress{ + .address = {service_address.ip_address().begin(), + service_address.ip_address().end()}, + .port = static_cast(service_address.port()), + }); + } + // Add gateway and port to address candidates if address candidates is empty. + if (service_addresses.empty() && + upgrade_path_info_credentials.has_gateway()) { + std::vector address_bytes = + GatewayToAddressBytes(upgrade_path_info_credentials.gateway()); + if (!address_bytes.empty()) { + service_addresses.push_back(ServiceAddress{ + .address = std::move(address_bytes), + .port = static_cast(upgrade_path_info_credentials.port())}); + } + } + if (service_addresses.empty()) { + LOG(ERROR) << "No service address found."; + return {Error( + OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL)}; + } + hotspot_credentials.SetAddressCandidates(std::move(service_addresses)); LOG(INFO) << "Received Hotspot credential SSID: " << hotspot_credentials.GetSSID() << ", Password:" << masker::Mask(hotspot_credentials.GetPassword()) - << ", Port:" << hotspot_credentials.GetPort() - << ", Gateway:" << hotspot_credentials.GetGateway() << ", Frequency:" << hotspot_credentials.GetFrequency(); if (!wifi_hotspot_medium_.ConnectWifiHotspot(hotspot_credentials)) { @@ -165,23 +221,18 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel( OperationResultCode::CONNECTIVITY_WIFI_HOTSPOT_INVALID_CREDENTIAL)}; } - ServiceAddress service_address; - service_address.address = - GatewayToAddressBytes(hotspot_credentials.GetGateway()); - service_address.port = hotspot_credentials.GetPort(); ErrorOr socket_result = wifi_hotspot_medium_.Connect( - service_id, service_address, client->GetCancellationFlag(endpoint_id)); + service_id, hotspot_credentials.GetAddressCandidates(), + client->GetCancellationFlag(endpoint_id)); if (socket_result.has_error()) { - LOG(ERROR) - << "WifiHotspotBwuHandler failed to connect to the WifiHotspot service(" - << hotspot_credentials.GetGateway() << ":" - << hotspot_credentials.GetPort() << ") for endpoint " << endpoint_id; + LOG(ERROR) << "WifiHotspotBwuHandler failed to connect to the WifiHotspot " + "service for endpoint " + << endpoint_id; return {Error(socket_result.error().operation_result_code().value())}; } VLOG(1) - << "WifiHotspotBwuHandler successfully connected to WifiHotspot service (" - << hotspot_credentials.GetGateway() << ":" - << hotspot_credentials.GetPort() << ") while upgrading endpoint " + << "WifiHotspotBwuHandler successfully connected to WifiHotspot service " + "while upgrading endpoint " << endpoint_id; // Create a new WifiHotspotEndpointChannel. diff --git a/internal/platform/implementation/g3/wifi_hotspot.cc b/internal/platform/implementation/g3/wifi_hotspot.cc index bd3e7179..47b7cb17 100644 --- a/internal/platform/implementation/g3/wifi_hotspot.cc +++ b/internal/platform/implementation/g3/wifi_hotspot.cc @@ -29,7 +29,6 @@ #include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_hotspot.h" -#include "internal/platform/implementation/wifi_utils.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" #include "internal/platform/prng.h" @@ -219,9 +218,8 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( // First, find an instance of remote medium, that exposed this service. auto& env = MediumEnvironment::Instance(); auto* remote_medium = static_cast( - env.GetWifiHotspotMedium({}, WifiUtils::GetHumanReadableIpAddress( - {service_address.address.data(), - service_address.address.size()}))); + env.GetWifiHotspotMedium({}, std::string(service_address.address.begin(), + service_address.address.end()))); if (remote_medium == nullptr) { return {}; } diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc index 20625ff8..e03f67f7 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -86,8 +87,18 @@ void WifiHotspotServerSocket::PopulateHotspotCredentials( "addresses configured on computer."; return; } - hotspot_credentials.SetGateway(hotspot_ipaddr); - hotspot_credentials.SetPort(GetPort()); + std::vector hotspot_ipaddr_bytes; + uint32_t address_int = inet_addr(hotspot_ipaddr.c_str()); + if (address_int != INADDR_NONE) { + hotspot_ipaddr_bytes.resize(4); + std::memcpy(hotspot_ipaddr_bytes.data(), + reinterpret_cast(&address_int), 4); + } + ServiceAddress service_address = { + .address = hotspot_ipaddr_bytes, + .port = static_cast(GetPort()), + }; + hotspot_credentials.SetAddressCandidates({service_address}); } bool WifiHotspotServerSocket::Listen(int port, bool dual_stack) { diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index 0137efef..2c865a4e 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "absl/container/flat_hash_set.h" #include "absl/status/status.h" @@ -50,6 +51,15 @@ #include "internal/test/fake_clock.h" namespace nearby { +namespace { +std::string LastAddressCandidateToString( + const std::vector& address_candidates) { + if (address_candidates.empty()) return ""; + return std::string(address_candidates.back().address.begin(), + address_candidates.back().address.end()); +} +} // namespace + MediumEnvironment& MediumEnvironment::Instance() { alignas(MediumEnvironment) static char storage[sizeof(MediumEnvironment)]; @@ -1045,7 +1055,9 @@ api::WifiHotspotMedium* MediumEnvironment::GetWifiHotspotMedium( if (info.is_ap && info.hotspot_credentials) { if ((info.hotspot_credentials->GetSSID() == ssid) || (!ip_address.empty() && - (info.hotspot_credentials->GetGateway() == ip_address))) { + LastAddressCandidateToString( + info.hotspot_credentials->GetAddressCandidates()) == + ip_address)) { LOG(INFO) << "Found Remote WifiHotspot medium=" << medium_found; return medium_found; } diff --git a/internal/platform/wifi_credential.h b/internal/platform/wifi_credential.h index 76bb7d6c..5f900fc0 100644 --- a/internal/platform/wifi_credential.h +++ b/internal/platform/wifi_credential.h @@ -21,7 +21,6 @@ #include #include "proto/connections_enums.pb.h" -#include "internal/platform/implementation/wifi_utils.h" namespace nearby { @@ -52,33 +51,7 @@ class HotspotCredentials { std::string GetPassword() const { return password_; } void SetPassword(const std::string& password) { password_ = password; } - // Get/Set Gateway and Port have been superceded by Get/SetAddressCandidates. - - // Gets IP Address in string format. - // This is the IP address at which the service is provided. - std::string GetGateway() const { - if (gateway_.empty() && !address_candidates_.empty()) { - return WifiUtils::GetHumanReadableIpAddress( - {reinterpret_cast( - address_candidates_.back().address.data()), - address_candidates_.back().address.size()}); - } - return gateway_; - } - void SetGateway(const std::string& gateway) { gateway_ = gateway; } - - // Gets the Port number - int GetPort() const { - if (port_ == 0 && !address_candidates_.empty()) { - return address_candidates_.back().port; - } - return port_; - } - - // Set port_ - void SetPort(const int port) { port_ = port; } - - std::vector GetAddressCandidates() const { + const std::vector& GetAddressCandidates() const { return address_candidates_; } void SetAddressCandidates(std::vector address_candidates) {