diff --git a/connections/clients/windows/dart/core_adapter_dart.cc b/connections/clients/windows/dart/core_adapter_dart.cc index 50a4174a..e7df875f 100644 --- a/connections/clients/windows/dart/core_adapter_dart.cc +++ b/connections/clients/windows/dart/core_adapter_dart.cc @@ -345,6 +345,7 @@ void StartAdvertisingDart(Core *pCore, const char *service_id, ? "0000FE2C-0000-1000-8000-00805F9B34FB" : ""; advertising_options.allowed.wifi_lan = options_dart.enable_wifi_lan; + advertising_options.allowed.wifi_hotspot = options_dart.enable_wifi_hotspot; advertising_options.allowed.web_rtc = options_dart.enable_web_rtc; ConnectionListenerW listener; @@ -435,6 +436,7 @@ void RequestConnectionDart(Core *pCore, const char *endpoint_id, connection_options.allowed.bluetooth = options_dart.enable_bluetooth; connection_options.allowed.ble = options_dart.enable_ble; connection_options.allowed.wifi_lan = options_dart.enable_wifi_lan; + connection_options.allowed.wifi_hotspot = options_dart.enable_wifi_hotspot; connection_options.allowed.web_rtc = options_dart.enable_web_rtc; ConnectionListenerW listener; diff --git a/connections/clients/windows/dart/core_adapter_dart.h b/connections/clients/windows/dart/core_adapter_dart.h index 8d1972dd..1481b80a 100644 --- a/connections/clients/windows/dart/core_adapter_dart.h +++ b/connections/clients/windows/dart/core_adapter_dart.h @@ -46,6 +46,7 @@ struct ConnectionOptionsDart { int64_t use_low_power_mode; int64_t discover_fast_advertisements; int64_t enable_wifi_lan; + int64_t enable_wifi_hotspot; int64_t enable_nfc; int64_t enable_wifi_aware; int64_t enable_web_rtc; diff --git a/connections/clients/windows/medium_selector_w.h b/connections/clients/windows/medium_selector_w.h index 83e3ef6e..9cf056c3 100644 --- a/connections/clients/windows/medium_selector_w.h +++ b/connections/clients/windows/medium_selector_w.h @@ -1,77 +1,81 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ -#define THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ - -#include "proto/connections_enums.pb.h" - -namespace location::nearby::windows { - -using MediumW = location::nearby::proto::connections::Medium; - -// Generic type: allows definition of a feature T for every Medium. -template -struct MediumSelectorW { - T bluetooth; - T ble; - T web_rtc; - T wifi_lan; - - constexpr MediumSelectorW() = default; - constexpr MediumSelectorW(const MediumSelectorW&) = default; - constexpr MediumSelectorW& operator=(const MediumSelectorW&) = default; - constexpr bool Any(const T& value) const { - return bluetooth == value || ble == value || web_rtc == value || - wifi_lan == value; - } - - constexpr bool All(const T& value) const { - return bluetooth == value && ble == value && web_rtc == value && - wifi_lan == value; - } - - constexpr int Count(const T& value) const { - int count = 0; - if (bluetooth == value) ++count; - if (ble == value) ++count; - if (wifi_lan == value) ++count; - if (web_rtc == value) ++count; - return count; - } - - constexpr MediumSelectorW& SetAll(const T& value) { - bluetooth = value; - ble = value; - web_rtc = value; - wifi_lan = value; - return *this; - } - - std::vector GetMediums(const T& value) const { - std::vector mediums; - // Mediums are sorted in order of decreasing preference. - if (wifi_lan == value) mediums.push_back(MediumW::WIFI_LAN); - if (web_rtc == value) mediums.push_back(MediumW::WEB_RTC); - if (bluetooth == value) mediums.push_back(MediumW::BLUETOOTH); - if (ble == value) mediums.push_back(MediumW::BLE); - return mediums; - } -}; - -// Feature On/Off switch for mediums. -using BooleanMediumSelectorW = MediumSelectorW; - -} // namespace location::nearby::windows - -#endif // THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ + +#include "proto/connections_enums.pb.h" + +namespace location::nearby::windows { + +using MediumW = location::nearby::proto::connections::Medium; + +// Generic type: allows definition of a feature T for every Medium. +template +struct MediumSelectorW { + T bluetooth; + T ble; + T web_rtc; + T wifi_lan; + T wifi_hotspot; + + constexpr MediumSelectorW() = default; + constexpr MediumSelectorW(const MediumSelectorW&) = default; + constexpr MediumSelectorW& operator=(const MediumSelectorW&) = default; + constexpr bool Any(const T& value) const { + return bluetooth == value || ble == value || web_rtc == value || + wifi_lan == value || wifi_hotspot == value; + } + + constexpr bool All(const T& value) const { + return bluetooth == value && ble == value && web_rtc == value && + wifi_lan == value && wifi_hotspot == value; + } + + constexpr int Count(const T& value) const { + int count = 0; + if (bluetooth == value) ++count; + if (ble == value) ++count; + if (wifi_lan == value) ++count; + if (wifi_hotspot == value) ++count; + if (web_rtc == value) ++count; + return count; + } + + constexpr MediumSelectorW& SetAll(const T& value) { + bluetooth = value; + ble = value; + web_rtc = value; + wifi_lan = value; + wifi_hotspot = value; + return *this; + } + + std::vector GetMediums(const T& value) const { + std::vector mediums; + // Mediums are sorted in order of decreasing preference. + if (wifi_lan == value) mediums.push_back(MediumW::WIFI_LAN); + if (wifi_hotspot == value) mediums.push_back(MediumW::WIFI_HOTSPOT); + if (web_rtc == value) mediums.push_back(MediumW::WEB_RTC); + if (bluetooth == value) mediums.push_back(MediumW::BLUETOOTH); + if (ble == value) mediums.push_back(MediumW::BLE); + return mediums; + } +}; + +// Feature On/Off switch for mediums. +using BooleanMediumSelectorW = MediumSelectorW; + +} // namespace location::nearby::windows + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_CLIENTS_WINDOWS_MEDIUM_SELECTOR_W_H_ diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 45838f11..8078dba2 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -67,6 +67,8 @@ cc_library( "service_controller_router.cc", "webrtc_bwu_handler.cc", "webrtc_endpoint_channel.cc", + "wifi_hotspot_bwu_handler.cc", + "wifi_hotspot_endpoint_channel.cc", "wifi_lan_bwu_handler.cc", "wifi_lan_endpoint_channel.cc", "wifi_lan_service_info.cc", @@ -105,6 +107,8 @@ cc_library( "service_id_constants.h", "webrtc_bwu_handler.h", "webrtc_endpoint_channel.h", + "wifi_hotspot_bwu_handler.h", + "wifi_hotspot_endpoint_channel.h", "wifi_lan_bwu_handler.h", "wifi_lan_endpoint_channel.h", "wifi_lan_service_info.h", @@ -214,6 +218,7 @@ cc_test( "payload_manager_test.cc", "pcp_manager_test.cc", "service_controller_router_test.cc", + "wifi_hotspot_test.cc", "wifi_lan_service_info_test.cc", ], defines = ["NO_WEBRTC"], diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index e7984550..af2fae1a 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -171,6 +171,9 @@ void BasePcpHandler::OptionsAllowed(const BooleanMediumSelector& allowed, if (allowed.wifi_lan) { result << proto::connections::Medium_Name(Medium::WIFI_LAN) << " "; } + if (allowed.wifi_hotspot) { + result << proto::connections::Medium_Name(Medium::WIFI_HOTSPOT) << " "; + } result << "}"; } @@ -218,6 +221,7 @@ BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums( mediumSelector.ble = intersection.contains(Medium::BLE); mediumSelector.web_rtc = intersection.contains(Medium::WEB_RTC); mediumSelector.wifi_lan = intersection.contains(Medium::WIFI_LAN); + mediumSelector.wifi_hotspot = intersection.contains(Medium::WIFI_HOTSPOT); return mediumSelector; } diff --git a/connections/implementation/bwu_manager.cc b/connections/implementation/bwu_manager.cc index 7190ed83..6e79722f 100644 --- a/connections/implementation/bwu_manager.cc +++ b/connections/implementation/bwu_manager.cc @@ -26,6 +26,7 @@ #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #include "connections/implementation/webrtc_bwu_handler.h" +#include "connections/implementation/wifi_hotspot_bwu_handler.h" #include "connections/implementation/wifi_lan_bwu_handler.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" @@ -74,6 +75,7 @@ BwuManager::BwuManager( if (config_.allow_upgrade_to.All(false)) { config_.allow_upgrade_to.web_rtc = true; config_.allow_upgrade_to.wifi_lan = true; + config_.allow_upgrade_to.wifi_hotspot = true; } if (!handlers.empty()) { handlers_ = std::move(handlers); @@ -97,6 +99,11 @@ void BwuManager::InitBwuHandlers() { .incoming_connection_cb = absl::bind_front(&BwuManager::OnIncomingConnection, this), }; + if (config_.allow_upgrade_to.wifi_hotspot) { + handlers_.emplace( + Medium::WIFI_HOTSPOT, + std::make_unique(*mediums_, notifications)); + } if (config_.allow_upgrade_to.wifi_lan) { handlers_.emplace(Medium::WIFI_LAN, std::make_unique( *mediums_, notifications)); @@ -167,6 +174,21 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, NEARBY_LOGS(INFO) << "InitiateBwuForEndpoint for endpoint " << endpoint_id << " with medium " << proto::connections::Medium_Name(proposed_medium); + + auto channel = channel_manager_->GetChannelForEndpoint(endpoint_id); + Medium channel_medium = + channel ? channel->GetMedium() : Medium::UNKNOWN_MEDIUM; + + if ((channel_medium == Medium::WIFI_LAN) && + (proposed_medium == Medium::WIFI_HOTSPOT)) { + NEARBY_LOGS(INFO) + << "Current medium is WIFI_LAN and proposed upgrade medium is " + ":WIFI_HOTSPOT. Don't do the BWU because connecting to " + "WIFI_HOTSPOT will destroy WIFI_LAN which will lead BWU fail"; + return; + } + + SetBwuMediumForEndpoint(endpoint_id, proposed_medium); BwuHandler* handler = GetHandlerForMedium(proposed_medium); if (!handler) { @@ -188,9 +210,6 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, CancelRetryUpgradeAlarm(endpoint_id); - auto channel = channel_manager_->GetChannelForEndpoint(endpoint_id); - Medium channel_medium = - channel ? channel->GetMedium() : Medium::UNKNOWN_MEDIUM; client->GetAnalyticsRecorder().OnBandwidthUpgradeStarted( endpoint_id, channel_medium, proposed_medium, proto::connections::INCOMING, client->GetConnectionToken(endpoint_id)); @@ -592,10 +611,11 @@ void BwuManager::RunUpgradeProtocol( void BwuManager::ProcessBwuPathAvailableEvent( ClientProxy* client, const string& endpoint_id, const UpgradePathInfo& upgrade_path_info) { + Medium medium = + parser::UpgradePathInfoMediumToMedium(upgrade_path_info.medium()); NEARBY_LOGS(INFO) << "ProcessBwuPathAvailableEvent for endpoint " << endpoint_id << " medium " - << parser::UpgradePathInfoMediumToMedium( - upgrade_path_info.medium()); + << proto::connections::Medium_Name(medium); if (in_progress_upgrades_.contains(endpoint_id)) { NEARBY_LOGS(ERROR) << "BwuManager received a duplicate bandwidth upgrade for endpoint " @@ -787,8 +807,9 @@ void BwuManager::RunUpgradeFailedProtocol( const UpgradePathInfo& upgrade_path_info) { NEARBY_LOGS(INFO) << "RunUpgradeFailedProtocol for endpoint " << endpoint_id << " medium " - << parser::UpgradePathInfoMediumToMedium( - upgrade_path_info.medium()); + << proto::connections::Medium_Name( + parser::UpgradePathInfoMediumToMedium( + upgrade_path_info.medium())); // We attempted to connect to the new medium that the remote device has set up // for us but we failed. We need to let the remote device know so that they // can pick another medium for us to try. @@ -1056,8 +1077,9 @@ void BwuManager::ProcessUpgradeFailureEvent( const UpgradePathInfo& upgrade_info) { NEARBY_LOGS(INFO) << "ProcessUpgradeFailureEvent for endpoint " << endpoint_id << " from medium: " - << parser::UpgradePathInfoMediumToMedium( - upgrade_info.medium()); + << proto::connections::Medium_Name( + parser::UpgradePathInfoMediumToMedium( + upgrade_info.medium())); // The remote device failed to upgrade to the new medium we set up for them. // That's alright! We'll just try the next available medium (if there is one). in_progress_upgrades_.erase(endpoint_id); @@ -1154,6 +1176,9 @@ std::vector BwuManager::StripOutUnavailableMediums( for (Medium m : mediums) { bool available = false; switch (m) { + case Medium::WIFI_HOTSPOT: + available = mediums_->GetWifiHotspot().IsAvailable(); + break; case Medium::WIFI_LAN: available = mediums_->GetWifiLan().IsAvailable(); break; diff --git a/connections/implementation/mediums/wifi_hotspot.cc b/connections/implementation/mediums/wifi_hotspot.cc index 12ef13c5..d9ac9080 100644 --- a/connections/implementation/mediums/wifi_hotspot.cc +++ b/connections/implementation/mediums/wifi_hotspot.cc @@ -171,14 +171,14 @@ bool WifiHotspot::StartAcceptingConnections( accept_loops_runner_.Execute( "wifi-hotspot-accept", [callback = std::move(callback), - server_socket = std::move(owned_server_socket)]() mutable { + server_socket = std::move(owned_server_socket), service_id]() mutable { while (true) { WifiHotspotSocket client_socket = server_socket.Accept(); if (!client_socket.IsValid()) { server_socket.Close(); break; } - callback.accepted_cb(std::move(client_socket)); + callback.accepted_cb(service_id, std::move(client_socket)); } }); diff --git a/connections/implementation/mediums/wifi_hotspot.h b/connections/implementation/mediums/wifi_hotspot.h index ab0e2cfe..10b43d92 100644 --- a/connections/implementation/mediums/wifi_hotspot.h +++ b/connections/implementation/mediums/wifi_hotspot.h @@ -31,8 +31,8 @@ class WifiHotspot { public: // Callback that is invoked when a new connection is accepted. struct AcceptedConnectionCallback { - std::function accepted_cb = - DefaultCallback(); + std::function + accepted_cb = DefaultCallback(); }; WifiHotspot() : is_hotspot_started_(false), is_connected_to_hotspot_(false) {} diff --git a/connections/implementation/offline_frames_validator.cc b/connections/implementation/offline_frames_validator.cc index 7f2bd15e..13ef0111 100644 --- a/connections/implementation/offline_frames_validator.cc +++ b/connections/implementation/offline_frames_validator.cc @@ -14,7 +14,9 @@ #include "connections/implementation/offline_frames_validator.h" +#include #include //NOLINT +#include #include "connections/implementation/internal_payload.h" #include "connections/implementation/offline_frames.h" diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index 81609e5e..caa02cbf 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -24,9 +24,9 @@ #include "connections/implementation/mediums/utils.h" #include "connections/implementation/webrtc_endpoint_channel.h" #include "connections/implementation/wifi_lan_endpoint_channel.h" +#include "internal/platform/crypto.h" #include "internal/platform/nsd_service_info.h" #include "internal/platform/types.h" -#include "internal/platform/crypto.h" #include "proto/connections_enums.pb.h" namespace location { @@ -58,6 +58,7 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( bluetooth_medium_(mediums->GetBluetoothClassic()), ble_medium_(mediums->GetBle()), wifi_lan_medium_(mediums->GetWifiLan()), + wifi_hotspot_medium_(mediums->GetWifiHotspot()), webrtc_medium_(mediums->GetWebRtc()), injected_bluetooth_device_store_(injected_bluetooth_device_store) {} diff --git a/connections/implementation/p2p_cluster_pcp_handler.h b/connections/implementation/p2p_cluster_pcp_handler.h index 54fbb30d..b9478850 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.h +++ b/connections/implementation/p2p_cluster_pcp_handler.h @@ -16,6 +16,7 @@ #define CORE_INTERNAL_P2P_CLUSTER_PCP_HANDLER_H_ #include +#include #include #include "connections/implementation/base_pcp_handler.h" @@ -29,8 +30,8 @@ #include "connections/implementation/mediums/bluetooth_classic.h" #include "connections/implementation/mediums/mediums.h" #ifdef NO_WEBRTC -#include "connections/implementation/mediums/webrtc_stub.h" #include "connections/implementation/mediums/webrtc_socket_stub.h" +#include "connections/implementation/mediums/webrtc_stub.h" #else #include "connections/implementation/mediums/webrtc.h" #include "connections/implementation/mediums/webrtc_socket.h" @@ -38,8 +39,8 @@ #include "connections/implementation/pcp.h" #include "connections/implementation/wifi_lan_service_info.h" #include "connections/strategy.h" -#include "internal/platform/byte_array.h" #include "internal/platform/bluetooth_classic.h" +#include "internal/platform/byte_array.h" #include "internal/platform/wifi_lan.h" namespace location { @@ -197,6 +198,7 @@ class P2pClusterPcpHandler : public BasePcpHandler { BluetoothClassic& bluetooth_medium_; Ble& ble_medium_; WifiLan& wifi_lan_medium_; + WifiHotspot& wifi_hotspot_medium_; mediums::WebRtc& webrtc_medium_; InjectedBluetoothDeviceStore& injected_bluetooth_device_store_; std::int64_t bluetooth_classic_discoverer_client_id_{0}; diff --git a/connections/implementation/p2p_point_to_point_pcp_handler.cc b/connections/implementation/p2p_point_to_point_pcp_handler.cc index 1ff1dd74..630d6e8c 100644 --- a/connections/implementation/p2p_point_to_point_pcp_handler.cc +++ b/connections/implementation/p2p_point_to_point_pcp_handler.cc @@ -28,6 +28,9 @@ P2pPointToPointPcpHandler::P2pPointToPointPcpHandler( std::vector P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; + if (mediums_->GetWifiHotspot().IsAvailable()) { + mediums.push_back(proto::connections::WIFI_HOTSPOT); + } if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } diff --git a/connections/implementation/p2p_star_pcp_handler.cc b/connections/implementation/p2p_star_pcp_handler.cc index 53363313..0577bf9d 100644 --- a/connections/implementation/p2p_star_pcp_handler.cc +++ b/connections/implementation/p2p_star_pcp_handler.cc @@ -16,6 +16,8 @@ #include +#include "internal/platform/logging.h" + namespace location { namespace nearby { namespace connections { @@ -31,6 +33,9 @@ P2pStarPcpHandler::P2pStarPcpHandler( std::vector P2pStarPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; + if (mediums_->GetWifiHotspot().IsAvailable()) { + mediums.push_back(proto::connections::WIFI_HOTSPOT); + } if (mediums_->GetWifiLan().IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } diff --git a/connections/implementation/wifi_hotspot_bwu_handler.cc b/connections/implementation/wifi_hotspot_bwu_handler.cc new file mode 100644 index 00000000..a597f35f --- /dev/null +++ b/connections/implementation/wifi_hotspot_bwu_handler.cc @@ -0,0 +1,163 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "connections/implementation/wifi_hotspot_bwu_handler.h" + +#include +#include +#include +#include + +#include "absl/functional/bind_front.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/mediums/utils.h" +#include "connections/implementation/offline_frames.h" +#include "connections/implementation/wifi_hotspot_endpoint_channel.h" +#include "internal/platform/wifi_hotspot.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiHotspotBwuHandler::WifiHotspotBwuHandler(Mediums& mediums, + BwuNotifications notifications) + : BaseBwuHandler(std::move(notifications)), mediums_(mediums) {} + +// Called by BWU initiator. Set up WifiHotspot upgraded medium for this +// endpoint, and returns a upgrade path info (SSID, Password, Gateway used as +// IPAddress, Port) for remote party to perform connection. +ByteArray WifiHotspotBwuHandler::HandleInitializeUpgradedMediumForEndpoint( + ClientProxy* client, const std::string& upgrade_service_id, + const std::string& endpoint_id) { + // Create SoftAP + if (!wifi_hotspot_medium_.StartWifiHotspot()) { + NEARBY_LOGS(INFO) << "Failed to start Wifi Hotspot!"; + return {}; + } + + if (!wifi_hotspot_medium_.IsAcceptingConnections(upgrade_service_id)) { + if (!wifi_hotspot_medium_.StartAcceptingConnections( + upgrade_service_id, + { + .accepted_cb = absl::bind_front( + &WifiHotspotBwuHandler::OnIncomingWifiHotspotConnection, + this, client), + })) { + NEARBY_LOGS(ERROR) + << "WifiHotspotBwuHandler couldn't initiate WifiHotspot upgrade for " + << "service " << upgrade_service_id << " and endpoint " << endpoint_id + << " because it failed to start listening for incoming WifiLan " + "connections."; + return {}; + } + NEARBY_LOGS(INFO) + << "WifiHotspotBwuHandler successfully started listening for incoming " + "WifiHotspot connections while upgrading endpoint " + << endpoint_id; + } + + // Note: Credentials are not generated until Medium StartWifiHotspot() is + // called and the server socket is created. Be careful moving this codeblock + // around. + HotspotCredentials* hotspot_crendential = + 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(); + + NEARBY_LOGS(INFO) << "Start SoftAP with SSID:" << ssid + << ", Password:" << password << ", Port:" << port + << ", Gateway:" << gateway; + + return parser::ForBwuWifiHotspotPathAvailable(ssid, password, port, gateway, + false); +} + +void WifiHotspotBwuHandler::HandleRevertInitiatorStateForService( + const std::string& upgrade_service_id) { + wifi_hotspot_medium_.StopAcceptingConnections(upgrade_service_id); + wifi_hotspot_medium_.StopWifiHotspot(); + wifi_hotspot_medium_.DisconnectWifiHotspot(); + + NEARBY_LOGS(INFO) + << "WifiHotspotBwuHandler successfully reverted all states for " + << "upgrade service ID " << upgrade_service_id; +} + +// Called by BWU target. Retrieves a new medium info from incoming message, +// and establishes connection over WifiHotspot using this info. +std::unique_ptr +WifiHotspotBwuHandler::CreateUpgradedEndpointChannel( + ClientProxy* client, const std::string& service_id, + const std::string& endpoint_id, const UpgradePathInfo& upgrade_path_info) { + if (!upgrade_path_info.has_wifi_hotspot_credentials()) { + NEARBY_LOGS(INFO) << "No Hotspot Credential"; + return nullptr; + } + const UpgradePathInfo::WifiHotspotCredentials& upgrade_path_info_credentials = + upgrade_path_info.wifi_hotspot_credentials(); + + const std::string& ssid = upgrade_path_info_credentials.ssid(); + const std::string& password = upgrade_path_info_credentials.password(); + const std::string& gateway = upgrade_path_info_credentials.gateway(); + std::int32_t port = upgrade_path_info_credentials.port(); + + NEARBY_LOGS(INFO) << "Received Hotspot credential SSID: " << ssid + << ", Password:" << password << ", Port:" << port + << ", Gateway:" << gateway; + + if (!wifi_hotspot_medium_.ConnectWifiHotspot(ssid, password)) { + NEARBY_LOGS(ERROR) << "Connect to Hotspot failed"; + return nullptr; + } + + WifiHotspotSocket socket = wifi_hotspot_medium_.Connect( + service_id, gateway, port, client->GetCancellationFlag(endpoint_id)); + if (!socket.IsValid()) { + NEARBY_LOGS(ERROR) + << "WifiHotspotBwuHandler failed to connect to the WifiHotspot service(" + << gateway << ":" << port << ") for endpoint " << endpoint_id; + return nullptr; + } + + NEARBY_LOGS(VERBOSE) + << "WifiHotspotBwuHandler successfully connected to WifiHotspot service (" + << gateway << ":" << port << ") while upgrading endpoint " << endpoint_id; + + // Create a new WifiHotspotEndpointChannel. + auto channel = std::make_unique( + service_id, /*channel_name=*/service_id, socket); + + return channel; +} + +// Accept Connection Callback. +void WifiHotspotBwuHandler::OnIncomingWifiHotspotConnection( + ClientProxy* client, const std::string& upgrade_service_id, + WifiHotspotSocket socket) { + auto channel = std::make_unique( + upgrade_service_id, /*channel_name=*/upgrade_service_id, socket); + std::unique_ptr connection( + new IncomingSocketConnection{ + .socket = std::make_unique( + upgrade_service_id, socket), + .channel = std::move(channel), + }); + bwu_notifications_.incoming_connection_cb(client, std::move(connection)); +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/implementation/wifi_hotspot_bwu_handler.h b/connections/implementation/wifi_hotspot_bwu_handler.h new file mode 100644 index 00000000..27762a95 --- /dev/null +++ b/connections/implementation/wifi_hotspot_bwu_handler.h @@ -0,0 +1,79 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ +#define CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ + +#include + +#include "connections/implementation/base_bwu_handler.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/endpoint_channel_manager.h" +#include "connections/implementation/mediums/mediums.h" + +namespace location { +namespace nearby { +namespace connections { + +// Defines the set of methods that need to be implemented to handle the +// per-Medium-specific operations needed to upgrade an EndpointChannel. +class WifiHotspotBwuHandler : public BaseBwuHandler { + public: + explicit WifiHotspotBwuHandler(Mediums& mediums, + BwuNotifications notifications); + + private: + class WifiHotspotIncomingSocket : public BwuHandler::IncomingSocket { + public: + explicit WifiHotspotIncomingSocket(const std::string& name, + WifiHotspotSocket socket) + : name_(name), socket_(socket) {} + + std::string ToString() override { return name_; } + void Close() override { socket_.Close(); } + + private: + std::string name_; + WifiHotspotSocket socket_; + }; + + // BwuHandler implementation: + std::unique_ptr CreateUpgradedEndpointChannel( + ClientProxy* client, const std::string& service_id, + const std::string& endpoint_id, + const UpgradePathInfo& upgrade_path_info) final; + Medium GetUpgradeMedium() const final { return Medium::WIFI_HOTSPOT; } + void OnEndpointDisconnect(ClientProxy* client, + const std::string& endpoint_id) final {} + + // BaseBwuHandler implementation: + ByteArray HandleInitializeUpgradedMediumForEndpoint( + ClientProxy* client, const std::string& upgrade_service_id, + const std::string& endpoint_id) final; + void HandleRevertInitiatorStateForService( + const std::string& upgrade_service_id) final; + + void OnIncomingWifiHotspotConnection(ClientProxy* client, + const std::string& upgrade_service_id, + WifiHotspotSocket socket); + + Mediums& mediums_; + WifiHotspot& wifi_hotspot_medium_{mediums_.GetWifiHotspot()}; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ diff --git a/connections/implementation/wifi_hotspot_endpoint_channel.cc b/connections/implementation/wifi_hotspot_endpoint_channel.cc new file mode 100644 index 00000000..90dba8e1 --- /dev/null +++ b/connections/implementation/wifi_hotspot_endpoint_channel.cc @@ -0,0 +1,49 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "connections/implementation/wifi_hotspot_endpoint_channel.h" + +#include +#include + +#include "internal/platform/logging.h" +#include "internal/platform/wifi_hotspot.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiHotspotEndpointChannel::WifiHotspotEndpointChannel( + const std::string& service_id, const std::string& channel_name, + WifiHotspotSocket socket) + : BaseEndpointChannel(service_id, channel_name, &socket.GetInputStream(), + &socket.GetOutputStream()), + socket_(std::move(socket)) {} + +proto::connections::Medium WifiHotspotEndpointChannel::GetMedium() const { + return proto::connections::Medium::WIFI_HOTSPOT; +} + +void WifiHotspotEndpointChannel::CloseImpl() { + Exception status = socket_.Close(); + if (!status.Ok()) { + NEARBY_LOGS(INFO) + << "Failed to close underlying socket for WifiHotspotEndpointChannel " + << GetName() << " : exception = " << status.value; + } +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/implementation/wifi_hotspot_endpoint_channel.h b/connections/implementation/wifi_hotspot_endpoint_channel.h new file mode 100644 index 00000000..49ae12ab --- /dev/null +++ b/connections/implementation/wifi_hotspot_endpoint_channel.h @@ -0,0 +1,53 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ + +#include + +#include "connections/implementation/base_endpoint_channel.h" +#include "internal/platform/wifi_hotspot.h" + +namespace location { +namespace nearby { +namespace connections { + +class WifiHotspotEndpointChannel final : public BaseEndpointChannel { + public: + // Creates both outgoing and incoming WifiHotspot channels. + WifiHotspotEndpointChannel(const std::string& service_id, + const std::string& channel_name, + WifiHotspotSocket socket); + // Not copyable or movable + WifiHotspotEndpointChannel(const WifiHotspotEndpointChannel&) = delete; + WifiHotspotEndpointChannel& operator=(const WifiHotspotEndpointChannel&) = + delete; + WifiHotspotEndpointChannel(WifiHotspotEndpointChannel&&) = delete; + WifiHotspotEndpointChannel& operator=(WifiHotspotEndpointChannel&&) = delete; + + proto::connections::Medium GetMedium() const override; + + private: + void CloseImpl() override; + + WifiHotspotSocket socket_; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/wifi_hotspot_test.cc b/connections/implementation/wifi_hotspot_test.cc new file mode 100644 index 00000000..41296bc1 --- /dev/null +++ b/connections/implementation/wifi_hotspot_test.cc @@ -0,0 +1,56 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "connections/implementation/wifi_hotspot_bwu_handler.h" +#include "connections/implementation/wifi_hotspot_endpoint_channel.h" + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" + +namespace location { +namespace nearby { +namespace connections { + +TEST(WifiHotspotTest, CanCreateBwuHandler) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_bwu_handler.cc +} + +TEST(WifiHotspotTest, CanInitializeUpgradedMediumForEndpoint) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_bwu_handler.cc +} + +TEST(WifiHotspotTest, CanRevert) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_bwu_handler.cc +} + +TEST(WifiHotspotTest, CanCreateUpgradedEndpointChannel) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_bwu_handler.cc +} + +TEST(WifiHotspotTest, CanOnIncomingWifiHotspotConnection) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_bwu_handler.cc +} + +TEST(WifiHotspotTest, CanCreateEndpointChannel) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_endpoint_channel.cc +} + +TEST(WifiHotspotTest, CanGetMedium) { + // TODO(b/227482970): Add test coverage for wifi_hotspot_endpoint_channel.cc +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/connections/medium_selector.h b/connections/medium_selector.h index 3a5064fa..dede1b8d 100644 --- a/connections/medium_selector.h +++ b/connections/medium_selector.h @@ -29,18 +29,19 @@ struct MediumSelector { T ble; T web_rtc; T wifi_lan; + T wifi_hotspot; constexpr MediumSelector() = default; constexpr MediumSelector(const MediumSelector&) = default; constexpr MediumSelector& operator=(const MediumSelector&) = default; constexpr bool Any(T value) const { return bluetooth == value || ble == value || web_rtc == value || - wifi_lan == value; + wifi_lan == value || wifi_hotspot == value; } constexpr bool All(T value) const { return bluetooth == value && ble == value && web_rtc == value && - wifi_lan == value; + wifi_lan == value && wifi_hotspot == value; } constexpr int Count(T value) const { @@ -48,6 +49,7 @@ struct MediumSelector { if (bluetooth == value) count++; if (ble == value) count++; if (wifi_lan == value) count++; + if (wifi_hotspot == value) count++; if (web_rtc == value) count++; return count; } @@ -57,12 +59,14 @@ struct MediumSelector { ble = value; web_rtc = value; wifi_lan = value; + wifi_hotspot = value; return *this; } std::vector GetMediums(T value) const { std::vector mediums; // Mediums are sorted in order of decreasing preference. + if (wifi_hotspot == value) mediums.push_back(Medium::WIFI_HOTSPOT); if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN); if (web_rtc == value) mediums.push_back(Medium::WEB_RTC); if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH); diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc index 095ccd40..bdd5f748 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc @@ -20,6 +20,10 @@ namespace location { namespace nearby { namespace windows { +namespace { + constexpr int kMaxRetries = 3; +} // namespace + WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {} WifiHotspotServerSocket::~WifiHotspotServerSocket() { Close(); } @@ -176,7 +180,7 @@ std::vector WifiHotspotServerSocket::GetIpAddresses() const { std::string ipv4_s = winrt::to_string(host_name.ToString()); if (HasEnding(ipv4_s, ".1")) { - // std::string ipv4_b_s = ipaddr_dotdecimal_to_4bytes_string(ipv4_s); + NEARBY_LOGS(INFO) << "Found Hotspot IP: " << ipv4_s; result.push_back(ipv4_s); } } @@ -185,17 +189,19 @@ std::vector WifiHotspotServerSocket::GetIpAddresses() const { } std::string WifiHotspotServerSocket::GetHotspotIpAddresses() const { - auto host_names = NetworkInformation::GetHostNames(); - for (auto host_name : host_names) { - if (host_name.IPInformation() != nullptr && - host_name.IPInformation().NetworkAdapter() != nullptr && - host_name.Type() == HostNameType::Ipv4) { - std::string ipv4_s = winrt::to_string(host_name.ToString()); - if (HasEnding(ipv4_s, ".1")) { - // TODO(b/228541380): replace when we find a better way to identifying - // the hotspot address - NEARBY_LOGS(INFO) << "Found Hotspot IP: " << ipv4_s; - return ipv4_s; + for (int i = 0; i < kMaxRetries; i++) { + auto host_names = NetworkInformation::GetHostNames(); + for (auto host_name : host_names) { + if (host_name.IPInformation() != nullptr && + host_name.IPInformation().NetworkAdapter() != nullptr && + host_name.Type() == HostNameType::Ipv4) { + std::string ipv4_s = winrt::to_string(host_name.ToString()); + if (HasEnding(ipv4_s, ".1")) { + // TODO(b/228541380): replace when we find a better way to identifying + // the hotspot address + NEARBY_LOGS(INFO) << "Found Hotspot IP: " << ipv4_s; + return ipv4_s; + } } } }