diff --git a/cpp/core/internal/mediums/BUILD b/cpp/core/internal/mediums/BUILD index c9bfcd5a..5adca71c 100644 --- a/cpp/core/internal/mediums/BUILD +++ b/cpp/core/internal/mediums/BUILD @@ -95,6 +95,7 @@ cc_test( "lost_entity_tracker_test.cc", "uuid_test.cc", "wifi_lan_test.cc", + "wifi_lan_test_v2.cc", ], shard_count = 16, deps = [ diff --git a/cpp/core/internal/mediums/wifi_lan_test_v2.cc b/cpp/core/internal/mediums/wifi_lan_test_v2.cc new file mode 100644 index 00000000..587fbfc0 --- /dev/null +++ b/cpp/core/internal/mediums/wifi_lan_test_v2.cc @@ -0,0 +1,104 @@ +// Copyright 2020 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 + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "core/internal/mediums/wifi_lan_v2.h" +#include "platform/base/medium_environment.h" +#include "platform/public/logging.h" +#include "platform/public/wifi_lan_v2.h" + +namespace location { +namespace nearby { +namespace connections { +namespace { + +using FeatureFlags = FeatureFlags::Flags; + +constexpr FeatureFlags kTestCases[] = { + FeatureFlags{ + .enable_cancellation_flag = true, + }, + FeatureFlags{ + .enable_cancellation_flag = false, + }, +}; + +constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; +constexpr absl::string_view kServiceInfoName{ + "Simulated WifiLan service encrypted string #1"}; +constexpr absl::string_view kEndpointName{"Simulated endpoint name"}; +constexpr absl::string_view kEndpointInfoKey{"n"}; + +class WifiLanV2Test : public ::testing::TestWithParam { + protected: + WifiLanV2Test() { env_.Stop(); } + + MediumEnvironment& env_{MediumEnvironment::Instance()}; +}; + +TEST_F(WifiLanV2Test, CanConstructValidObject) { + env_.Start(); + WifiLanV2 wifi_lan_a; + WifiLanV2 wifi_lan_b; + std::string service_id(kServiceID); + + EXPECT_TRUE(wifi_lan_a.IsAvailable()); + EXPECT_TRUE(wifi_lan_b.IsAvailable()); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanStartAdvertising) { + env_.Start(); + WifiLanV2 wifi_lan_a; + std::string service_id(kServiceID); + std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; + + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(service_info_name); + nsd_service_info.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, nsd_service_info)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id)); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanStartMultipleAdvertising) { + env_.Start(); + WifiLanV2 wifi_lan_a; + std::string service_id(kServiceID); + std::string service_id_1(kServiceID); + std::string service_id_2("com.google.location.nearby.apps.test_1"); + std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; + + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(service_info_name); + nsd_service_info.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id_1, nsd_service_info)); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id_2, nsd_service_info)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id_1)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id_2)); + env_.Stop(); +} + +} // namespace +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/mediums/wifi_lan_v2.cc b/cpp/core/internal/mediums/wifi_lan_v2.cc index edfe44a9..22f501c1 100644 --- a/cpp/core/internal/mediums/wifi_lan_v2.cc +++ b/cpp/core/internal/mediums/wifi_lan_v2.cc @@ -36,6 +36,7 @@ WifiLanV2::~WifiLanV2() { bool WifiLanV2::IsAvailable() const { MutexLock lock(&mutex_); + return IsAvailableLocked(); } @@ -43,13 +44,67 @@ bool WifiLanV2::IsAvailableLocked() const { return medium_.IsValid(); } bool WifiLanV2::StartAdvertising(const std::string& service_id, NsdServiceInfo& nsd_service_info) { - return false; + MutexLock lock(&mutex_); + + if (!nsd_service_info.IsValid()) { + NEARBY_LOGS(INFO) + << "Refusing to turn on WifiLan advertising. nsd_service_info is not " + "valid."; + return false; + } + + if (IsAdvertisingLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Failed to WifiLan advertise because we're already advertising."; + return false; + } + + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) + << "Can't turn on WifiLan advertising. WifiLan is not available."; + return false; + } + + nsd_service_info.SetServiceType(GenerateServiceType(service_id)); + if (!medium_.StartAdvertising(nsd_service_info)) { + NEARBY_LOGS(INFO) + << "Failed to turn on WifiLan advertising with nsd_service_info=" + << &nsd_service_info + << ", service_name=" << nsd_service_info.GetServiceName() + << ", service_id=" << service_id; + return false; + } + + NEARBY_LOGS(INFO) << "Turned on WifiLan advertising with nsd_service_info=" + << &nsd_service_info + << ", service_name=" << nsd_service_info.GetServiceName() + << ", service_id=" << service_id; + advertising_info_.Add(service_id, std::move(nsd_service_info)); + return true; } -bool WifiLanV2::StopAdvertising(const std::string& service_id) { return false; } +bool WifiLanV2::StopAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); + + if (!IsAdvertisingLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Can't turn off WifiLan advertising; it is already off"; + return false; + } + + NEARBY_LOGS(INFO) << "Turned off WifiLan advertising with service_id=" + << service_id; + bool ret = + medium_.StopAdvertising(*advertising_info_.GetServiceInfo(service_id)); + // Reset our bundle of advertising state to mark that we're no longer + // advertising for specific service_id. + advertising_info_.Remove(service_id); + return ret; +} bool WifiLanV2::IsAdvertising(const std::string& service_id) { MutexLock lock(&mutex_); + return IsAdvertisingLocked(service_id); } diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.cc b/cpp/core/internal/p2p_cluster_pcp_handler.cc index f61da1dc..4ec6f496 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler.cc @@ -25,6 +25,7 @@ #include "core/internal/mediums/webrtc/webrtc_socket_wrapper.h" #include "core/internal/webrtc_endpoint_channel.h" #include "core/internal/wifi_lan_endpoint_channel.h" +#include "core/internal/wifi_lan_endpoint_channel_v2.h" #include "platform/base/nsd_service_info.h" #include "platform/base/types.h" #include "platform/public/crypto.h" @@ -59,6 +60,7 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( bluetooth_medium_(mediums->GetBluetoothClassic()), ble_medium_(mediums->GetBle()), wifi_lan_medium_(mediums->GetWifiLan()), + wifi_lan_medium_v2_(mediums->GetWifiLanV2()), webrtc_medium_(mediums->GetWebRtc()), injected_bluetooth_device_store_(injected_bluetooth_device_store) {} @@ -68,6 +70,9 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( std::vector P2pClusterPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; + if (wifi_lan_medium_v2_.IsAvailable()) { + mediums.push_back(proto::connections::WIFI_LAN); + } if (wifi_lan_medium_.IsAvailable()) { mediums.push_back(proto::connections::WIFI_LAN); } @@ -96,11 +101,20 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( WebRtcState web_rtc_state{WebRtcState::kUnconnectable}; if (options.allowed.wifi_lan) { - const ByteArray wifi_lan_hash = - GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); - proto::connections::Medium wifi_lan_medium = StartWifiLanAdvertising( - client, service_id, wifi_lan_hash, local_endpoint_id, - local_endpoint_info, web_rtc_state); + proto::connections::Medium wifi_lan_medium = + StartWifiLanV2Advertising(client, service_id, local_endpoint_id, + local_endpoint_info, web_rtc_state); + if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOGS(INFO) + << "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added"; + mediums_started_successfully.push_back(wifi_lan_medium); + } + } + + if (options.allowed.wifi_lan) { + proto::connections::Medium wifi_lan_medium = + StartWifiLanAdvertising(client, service_id, local_endpoint_id, + local_endpoint_info, web_rtc_state); if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added"); @@ -170,6 +184,10 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + wifi_lan_medium_v2_.StopAdvertising(client->GetAdvertisingServiceId()); + wifi_lan_medium_v2_.StopAcceptingConnections( + client->GetAdvertisingServiceId()); + return {Status::kSuccess}; } @@ -903,8 +921,8 @@ proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising( NEARBY_LOGS(INFO) << "In StartBluetoothAdvertising(" << absl::BytesToHexString(local_endpoint_info.data()) << "), client=" << client->GetClientId() - << " generated BluetoothDeviceName %s with service_id=" - << service_id; + << " generated BluetoothDeviceName " << device_name + << " with service_id=" << service_id; // Become Bluetooth discoverable. if (!bluetooth_medium_.TurnOnDiscoverability(device_name)) { @@ -1206,8 +1224,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising( ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, - const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) { + const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, + WebRtcState web_rtc_state) { // Start listening for connections before advertising in case a connection // request comes in very quickly. NEARBY_LOG(INFO, @@ -1254,13 +1272,17 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising( return proto::connections::UNKNOWN_MEDIUM; } NEARBY_LOGS(INFO) - << "In StartWifiLanAdvertising(%s), client=" << client->GetClientId() + << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() << " started listening for incoming WifiLan connections to service_id=" << service_id; } // Generate a WifiLanServiceInfo with which to become WifiLan discoverable. // TODO(b/169550050): Implement UWBAddress. + const ByteArray service_id_hash = + GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); WifiLanServiceInfo service_info{kWifiLanServiceInfoVersion, GetPcp(), local_endpoint_id, @@ -1285,8 +1307,10 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising( wifi_lan_medium_.StopAcceptingConnections(service_id); return proto::connections::UNKNOWN_MEDIUM; } - NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(%s), client=" - << client->GetClientId() << " generated WifiLanServiceInfo " + NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " generated WifiLanServiceInfo " << nsd_service_info.GetServiceName() << " with service_id=" << service_id; @@ -1357,6 +1381,109 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( }; } +proto::connections::Medium P2pClusterPcpHandler::StartWifiLanV2Advertising( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, + WebRtcState web_rtc_state) { + // Start listening for connections before advertising in case a connection + // request comes in very quickly. + NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartWifiLanAdvertising: service=" + << service_id << ": start"; + if (!wifi_lan_medium_v2_.IsAcceptingConnections(service_id)) { + if (!wifi_lan_medium_v2_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + WifiLanSocketV2 socket) { + if (!socket.IsValid()) { + NEARBY_LOGS(WARNING) + << "Invalid socket in accept callback(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId(); + return; + } + RunOnPcpHandlerThread( + "p2p-wifi-on-incoming-connection", + [this, client, local_endpoint_info, + socket = std::move( + socket)]() RUN_ON_PCP_HANDLER_THREAD() mutable { + std::string remote_service_info_name; + auto channel = absl::make_unique( + remote_service_info_name, socket); + ByteArray remote_service_info{remote_service_info_name}; + + OnIncomingConnection(client, remote_service_info, + std::move(channel), + proto::connections::Medium::WIFI_LAN); + }); + }})) { + NEARBY_LOGS(WARNING) + << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " failed to start listening for incoming WifiLan connections " + "to service_id=" + << service_id; + return proto::connections::UNKNOWN_MEDIUM; + } + NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " started listening for incoming WifiLan connections " + "to service_id = " + << service_id; + } + + // Generate a WifiLanServiceInfo with which to become WifiLan discoverable. + // TODO(b/169550050): Implement UWBAddress. + const ByteArray service_id_hash = + GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); + WifiLanServiceInfo service_info{kWifiLanServiceInfoVersion, + GetPcp(), + local_endpoint_id, + service_id_hash, + local_endpoint_info, + ByteArray{}, + web_rtc_state}; + NsdServiceInfo nsd_service_info(service_info); + if (!nsd_service_info.IsValid()) { + NEARBY_LOGS(WARNING) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " failed to generate WifiLanServiceInfo {version=" + << static_cast(kWifiLanServiceInfoVersion) + << ", pcp=" << PcpToStrategy(GetPcp()).GetName() + << ", endpoint_id=" << local_endpoint_id + << ", service_id_hash=" + << absl::BytesToHexString(service_id_hash.data()) + << ", endpoint_info=" + << absl::BytesToHexString(local_endpoint_info.data()) + << "}."; + wifi_lan_medium_v2_.StopAcceptingConnections(service_id); + return proto::connections::UNKNOWN_MEDIUM; + } + NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " generated WifiLanServiceInfo " + << nsd_service_info.GetServiceName() + << " with service_id=" << service_id; + + if (!wifi_lan_medium_v2_.StartAdvertising(service_id, nsd_service_info)) { + NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " couldn't advertise with WifiLanServiceInfo " + << nsd_service_info.GetServiceName(); + wifi_lan_medium_v2_.StopAcceptingConnections(service_id); + return proto::connections::UNKNOWN_MEDIUM; + } + NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising(" + << absl::BytesToHexString(local_endpoint_info.data()) + << "), client=" << client->GetClientId() + << " advertised with WifiLanServiceInfo " + << nsd_service_info.GetServiceName(); + return proto::connections::WIFI_LAN; +} + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.h b/cpp/core/internal/p2p_cluster_pcp_handler.h index efbb13ae..7a4b7bcf 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core/internal/p2p_cluster_pcp_handler.h @@ -180,7 +180,7 @@ class P2pClusterPcpHandler : public BasePcpHandler { const std::string& service_id); proto::connections::Medium StartWifiLanAdvertising( ClientProxy* client, const std::string& service_id, - const ByteArray& service_id_hash, const std::string& local_endpoint_id, + const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); proto::connections::Medium StartWifiLanDiscovery( WifiLanDiscoveredServiceCallback callback, ClientProxy* client, @@ -188,10 +188,17 @@ class P2pClusterPcpHandler : public BasePcpHandler { BasePcpHandler::ConnectImplResult WifiLanConnectImpl( ClientProxy* client, WifiLanEndpoint* endpoint); + // WifiLanV2 + proto::connections::Medium StartWifiLanV2Advertising( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const ByteArray& local_endpoint_info, WebRtcState web_rtc_state); + BluetoothRadio& bluetooth_radio_; BluetoothClassic& bluetooth_medium_; Ble& ble_medium_; WifiLan& wifi_lan_medium_; + WifiLanV2& wifi_lan_medium_v2_; mediums::WebRtc& webrtc_medium_; InjectedBluetoothDeviceStore& injected_bluetooth_device_store_; std::int64_t bluetooth_classic_discoverer_client_id_{0}; diff --git a/cpp/platform/base/medium_environment.cc b/cpp/platform/base/medium_environment.cc index 5b78d97f..b5e5757d 100644 --- a/cpp/platform/base/medium_environment.cc +++ b/cpp/platform/base/medium_environment.cc @@ -26,8 +26,10 @@ #include "platform/api/bluetooth_adapter.h" #include "platform/api/bluetooth_classic.h" #include "platform/api/wifi_lan.h" +#include "platform/api/wifi_lan_v2.h" #include "platform/base/feature_flags.h" #include "platform/base/logging.h" +#include "platform/base/nsd_service_info.h" #include "platform/public/count_down_latch.h" namespace location { @@ -65,6 +67,7 @@ void MediumEnvironment::Reset() { webrtc_signaling_message_callback_.clear(); webrtc_signaling_complete_callback_.clear(); wifi_lan_mediums_.clear(); + wifi_lan_mediums_v2_.clear(); use_valid_peer_connection_ = true; peer_connection_latency_ = absl::ZeroDuration(); }); @@ -705,6 +708,53 @@ api::WifiLanService* MediumEnvironment::GetWifiLanService( return remote_wifi_lan_service; } +void MediumEnvironment::RegisterWifiLanMediumV2(api::WifiLanMediumV2& medium) { + if (!enabled_) return; + RunOnMediumEnvironmentThread([this, &medium]() { + wifi_lan_mediums_v2_.insert({&medium, WifiLanMediumV2Context{}}); + NEARBY_LOG(INFO, "Registered: medium=%p", &medium); + }); +} + +void MediumEnvironment::UpdateWifiLanMediumV2ForAdvertising( + api::WifiLanMediumV2& medium, const NsdServiceInfo& service_info, + bool enabled) { + if (!enabled_) return; + RunOnMediumEnvironmentThread([this, &medium, service_info = service_info, + enabled]() { + std::string service_type = service_info.GetServiceType(); + NEARBY_LOGS(INFO) << "Update WifiLan medium for advertising: this=" << this + << "; medium=" << &medium + << "; service_name=" << service_info.GetServiceName() + << "; service_type=" << service_type + << ", enabled=" << enabled; + for (auto& medium_info : wifi_lan_mediums_v2_) { + auto& local_medium = medium_info.first; + auto& info = medium_info.second; + // Do not send notification to the same medium but update + // service info map. + if (local_medium == &medium) { + if (enabled) { + info.advertising_services.insert({service_type, service_info}); + } else { + info.advertising_services.erase(service_type); + } + continue; + } + } + }); +} + +void MediumEnvironment::UnregisterWifiLanMediumV2( + api::WifiLanMediumV2& medium) { + if (!enabled_) return; + RunOnMediumEnvironmentThread([this, &medium]() { + auto item = wifi_lan_mediums_v2_.extract(&medium); + if (item.empty()) return; + NEARBY_LOG(INFO, "Unregistered WifiLan medium"); + }); +} + void MediumEnvironment::SetFeatureFlags(const FeatureFlags::Flags& flags) { const_cast(FeatureFlags::GetInstance()).SetFlags(flags); } diff --git a/cpp/platform/base/medium_environment.h b/cpp/platform/base/medium_environment.h index 0b47eada..aab9841c 100644 --- a/cpp/platform/base/medium_environment.h +++ b/cpp/platform/base/medium_environment.h @@ -16,6 +16,7 @@ #define PLATFORM_BASE_MEDIUM_ENVIRONMENT_H_ #include +#include #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" @@ -243,6 +244,20 @@ class MediumEnvironment { api::WifiLanService* GetWifiLanService(const std::string& ip_address, int port); + // Adds medium-related info to allow for discovery/advertising to work. + // This provides acccess to this medium from other mediums, when protocol + // expects they should communicate. + void RegisterWifiLanMediumV2(api::WifiLanMediumV2& medium); + + // Updates advertising info to indicate the current medium is exposing + // advertising event. + void UpdateWifiLanMediumV2ForAdvertising( + api::WifiLanMediumV2& medium, const NsdServiceInfo& nsd_service_info, + bool enabled); + + // Removes medium-related info. This should correspond to device power off. + void UnregisterWifiLanMediumV2(api::WifiLanMediumV2& medium); + void SetFeatureFlags(const FeatureFlags::Flags& flags); private: @@ -272,6 +287,11 @@ class MediumEnvironment { absl::flat_hash_map services; }; + struct WifiLanMediumV2Context { + // advertising service type vs NsdServiceInfo map. + absl::flat_hash_map advertising_services; + }; + // This is a singleton object, for which destructor will never be called. // Constructor will be invoked once from Instance() static method. // Object is create in-place (with a placement new) to guarantee that @@ -323,6 +343,9 @@ class MediumEnvironment { absl::flat_hash_map wifi_lan_mediums_; + absl::flat_hash_map + wifi_lan_mediums_v2_; + bool use_valid_peer_connection_ = true; absl::Duration peer_connection_latency_ = absl::ZeroDuration(); }; diff --git a/cpp/platform/impl/g3/wifi_lan_v2.cc b/cpp/platform/impl/g3/wifi_lan_v2.cc index f6d5233f..7fa64be9 100644 --- a/cpp/platform/impl/g3/wifi_lan_v2.cc +++ b/cpp/platform/impl/g3/wifi_lan_v2.cc @@ -134,15 +134,62 @@ Exception WifiLanServerSocketV2::Close() { Exception WifiLanServerSocketV2::DoClose() { return {Exception::kSuccess}; } -WifiLanMediumV2::WifiLanMediumV2() {} +WifiLanMediumV2::WifiLanMediumV2() { + auto& env = MediumEnvironment::Instance(); + env.RegisterWifiLanMediumV2(*this); +} -WifiLanMediumV2::~WifiLanMediumV2() {} +WifiLanMediumV2::~WifiLanMediumV2() { + auto& env = MediumEnvironment::Instance(); + env.UnregisterWifiLanMediumV2(*this); +} bool WifiLanMediumV2::StartAdvertising(const NsdServiceInfo& nsd_service_info) { + std::string service_type = nsd_service_info.GetServiceType(); + NEARBY_LOGS(INFO) << "G3 WifiLan StartAdvertising: nsd_service_info=" + << &nsd_service_info + << ", service_name=" << nsd_service_info.GetServiceName() + << ", service_type=" << service_type; + { + absl::MutexLock lock(&mutex_); + if (advertising_info_.Existed(service_type)) { + NEARBY_LOGS(INFO) + << "G3 WifiLan StartAdvertising: Can't start advertising because " + "service_type=" + << service_type << ", has started already."; + return false; + } + } + auto& env = MediumEnvironment::Instance(); + env.UpdateWifiLanMediumV2ForAdvertising(*this, nsd_service_info, + /*enabled=*/true); + { + absl::MutexLock lock(&mutex_); + advertising_info_.Add(service_type); + } return true; } bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { + std::string service_type = nsd_service_info.GetServiceType(); + NEARBY_LOGS(INFO) << "G3 WifiLan StopAdvertising: nsd_service_info=" + << &nsd_service_info + << ", service_name=" << nsd_service_info.GetServiceName() + << ", service_type=" << service_type; + { + absl::MutexLock lock(&mutex_); + if (!advertising_info_.Existed(service_type)) { + NEARBY_LOGS(INFO) + << "G3 WifiLan StopAdvertising: Can't stop advertising because " + "we never started advertising for service_type=" + << service_type; + return false; + } + advertising_info_.Remove(service_type); + } + auto& env = MediumEnvironment::Instance(); + env.UpdateWifiLanMediumV2ForAdvertising(*this, nsd_service_info, + /*enabled=*/false); return true; } @@ -171,6 +218,19 @@ std::unique_ptr WifiLanMediumV2::ListenForService( return {}; } +std::pair WifiLanMediumV2::GetFakeCredentials() const { + std::string ip_address; + ip_address.resize(4); + uint32_t raw_ip_addr = Prng().NextUint32(); + uint16_t port = Prng().NextUint32(); + ip_address[0] = static_cast(raw_ip_addr >> 24); + ip_address[1] = static_cast(raw_ip_addr >> 16); + ip_address[2] = static_cast(raw_ip_addr >> 8); + ip_address[3] = static_cast(raw_ip_addr >> 0); + + return std::make_pair(ip_address, port); +} + } // namespace g3 } // namespace nearby } // namespace location diff --git a/cpp/platform/impl/g3/wifi_lan_v2.h b/cpp/platform/impl/g3/wifi_lan_v2.h index f852689b..eea97f2a 100644 --- a/cpp/platform/impl/g3/wifi_lan_v2.h +++ b/cpp/platform/impl/g3/wifi_lan_v2.h @@ -208,26 +208,26 @@ class WifiLanMediumV2 : public api::WifiLanMediumV2 { int port = 0) override; private: - static constexpr int kMaxConcurrentAcceptLoops = 5; - struct AdvertisingInfo { - bool Empty() const { return service_id.empty(); } - void Clear() { service_id.clear(); } + bool Empty() const { return service_types.empty(); } + void Clear() { service_types.clear(); } + void Add(const std::string& service_type) { + service_types.insert(service_type); + } + void Remove(const std::string& service_type) { + service_types.erase(service_type); + } + bool Existed(const std::string& service_type) const { + return service_types.contains(service_type); + } - std::string service_id; + absl::flat_hash_set service_types; }; - struct DiscoveringInfo { - bool Empty() const { return service_id.empty(); } - void Clear() { service_id.clear(); } - - std::string service_id; - }; - - void SetWifiLanService(const NsdServiceInfo& nsd_service_info); std::pair GetFakeCredentials() const; absl::Mutex mutex_; + AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); }; } // namespace g3 diff --git a/cpp/platform/public/BUILD b/cpp/platform/public/BUILD index 57b1eaba..79e0d389 100644 --- a/cpp/platform/public/BUILD +++ b/cpp/platform/public/BUILD @@ -150,6 +150,7 @@ cc_test( "scheduled_executor_test.cc", "single_thread_executor_test.cc", "wifi_lan_test.cc", + "wifi_lan_test_v2.cc", ], copts = ["-DCORE_ADAPTER_DLL"], shard_count = 16, diff --git a/cpp/platform/public/wifi_lan_test_v2.cc b/cpp/platform/public/wifi_lan_test_v2.cc new file mode 100644 index 00000000..dda38b74 --- /dev/null +++ b/cpp/platform/public/wifi_lan_test_v2.cc @@ -0,0 +1,110 @@ +// Copyright 2020 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 + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "platform/base/medium_environment.h" +#include "platform/public/count_down_latch.h" +#include "platform/public/logging.h" +#include "platform/public/wifi_lan_v2.h" + +namespace location { +namespace nearby { +namespace { + +using FeatureFlags = FeatureFlags::Flags; + +constexpr FeatureFlags kTestCases[] = { + FeatureFlags{ + .enable_cancellation_flag = true, + }, + FeatureFlags{ + .enable_cancellation_flag = false, + }, +}; + +constexpr absl::string_view kServiceType{"_service.tcp_"}; +constexpr absl::string_view kServiceInfoName{"Simulated service info name"}; +constexpr absl::string_view kEndpointName{"Simulated endpoint name"}; +constexpr absl::string_view kEndpointInfoKey{"n"}; + +class WifiLanMediumV2Test : public ::testing::TestWithParam { + protected: + WifiLanMediumV2Test() { env_.Stop(); } + + MediumEnvironment& env_{MediumEnvironment::Instance()}; +}; + +TEST_F(WifiLanMediumV2Test, ConstructorDestructorWorks) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + WifiLanMediumV2 wifi_lan_b; + + // Make sure we can create functional mediums. + ASSERT_TRUE(wifi_lan_a.IsValid()); + ASSERT_TRUE(wifi_lan_b.IsValid()); + + // Make sure we can create 2 distinct mediums. + EXPECT_NE(&wifi_lan_a.GetImpl(), &wifi_lan_b.GetImpl()); + env_.Stop(); +} + +TEST_F(WifiLanMediumV2Test, CanStartAdvertising) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + std::string service_type(kServiceType); + std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; + + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(service_info_name); + nsd_service_info.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + nsd_service_info.SetServiceType(service_type); + wifi_lan_a.StartAdvertising(nsd_service_info); + + EXPECT_TRUE(wifi_lan_a.StopAdvertising(nsd_service_info)); + env_.Stop(); +} + +TEST_F(WifiLanMediumV2Test, CanStartMultipleAdvertising) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + std::string service_type(kServiceType); + std::string service_tye_1("_service_1.tcp_"); + std::string service_info_name{kServiceInfoName}; + std::string endpoint_info_name{kEndpointName}; + + NsdServiceInfo nsd_service_info_1; + nsd_service_info_1.SetServiceName(service_info_name); + nsd_service_info_1.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + nsd_service_info_1.SetServiceType(service_type); + + NsdServiceInfo nsd_service_info_2 = nsd_service_info_1; + nsd_service_info_2.SetServiceType(service_tye_1); + + EXPECT_TRUE(wifi_lan_a.StartAdvertising(nsd_service_info_1)); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(nsd_service_info_2)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(nsd_service_info_1)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(nsd_service_info_2)); + env_.Stop(); +} + +} // namespace +} // namespace nearby +} // namespace location diff --git a/cpp/platform/public/wifi_lan_v2.cc b/cpp/platform/public/wifi_lan_v2.cc index e2388068..cd5410dc 100644 --- a/cpp/platform/public/wifi_lan_v2.cc +++ b/cpp/platform/public/wifi_lan_v2.cc @@ -20,11 +20,11 @@ namespace location { namespace nearby { bool WifiLanMediumV2::StartAdvertising(const NsdServiceInfo& nsd_service_info) { - return false; + return impl_->StartAdvertising(nsd_service_info); } bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { - return false; + return impl_->StopAdvertising(nsd_service_info); } bool WifiLanMediumV2::StartDiscovery(const std::string& service_type,