From 83480d6473e22017ddba71dbef41f535f624271d Mon Sep 17 00:00:00 2001 From: edwinwu Date: Tue, 26 Oct 2021 18:26:52 -0700 Subject: [PATCH] nearbyconnections : Implement WifiLanV2 Discovery functions for /medium, /public(wrapper), /g3. PiperOrigin-RevId: 405782006 --- cpp/core/internal/base_pcp_handler.h | 8 + cpp/core/internal/mediums/wifi_lan_test_v2.cc | 130 +++++++++++-- cpp/core/internal/mediums/wifi_lan_v2.cc | 50 ++++- cpp/core/internal/mediums/wifi_lan_v2.h | 10 +- .../offline_service_controller_test.cc | 4 +- cpp/core/internal/p2p_cluster_pcp_handler.cc | 179 +++++++++++++++++- cpp/core/internal/p2p_cluster_pcp_handler.h | 14 ++ cpp/platform/api/wifi_lan_v2.h | 11 +- cpp/platform/base/medium_environment.cc | 121 +++++++++++- cpp/platform/base/medium_environment.h | 30 +++ cpp/platform/impl/g3/wifi_lan_v2.cc | 51 +++-- cpp/platform/impl/g3/wifi_lan_v2.h | 16 +- cpp/platform/public/wifi_lan_test_v2.cc | 138 ++++++++++++-- cpp/platform/public/wifi_lan_v2.cc | 94 ++++++++- cpp/platform/public/wifi_lan_v2.h | 15 +- 15 files changed, 786 insertions(+), 85 deletions(-) diff --git a/cpp/core/internal/base_pcp_handler.h b/cpp/core/internal/base_pcp_handler.h index 8d3da9c5..ed18a5bf 100644 --- a/cpp/core/internal/base_pcp_handler.h +++ b/cpp/core/internal/base_pcp_handler.h @@ -206,6 +206,14 @@ class BasePcpHandler : public PcpHandler, WifiLanService wifi_lan_service; }; + struct WifiLanV2Endpoint : public DiscoveredEndpoint { + WifiLanV2Endpoint(DiscoveredEndpoint endpoint, + const NsdServiceInfo& service_info) + : DiscoveredEndpoint(std::move(endpoint)), service_info(service_info) {} + + NsdServiceInfo service_info; + }; + struct WebRtcEndpoint : public DiscoveredEndpoint { WebRtcEndpoint(DiscoveredEndpoint endpoint, mediums::PeerId peer_id) : DiscoveredEndpoint(std::move(endpoint)), diff --git a/cpp/core/internal/mediums/wifi_lan_test_v2.cc b/cpp/core/internal/mediums/wifi_lan_test_v2.cc index 587fbfc0..86a2b120 100644 --- a/cpp/core/internal/mediums/wifi_lan_test_v2.cc +++ b/cpp/core/internal/mediums/wifi_lan_test_v2.cc @@ -19,6 +19,7 @@ #include "absl/strings/string_view.h" #include "core/internal/mediums/wifi_lan_v2.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" @@ -38,14 +39,16 @@ constexpr FeatureFlags kTestCases[] = { }, }; +constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); 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 kServiceInfoName{"ServiceInfoName"}; +constexpr absl::string_view kEndpointName{"EndpointName"}; constexpr absl::string_view kEndpointInfoKey{"n"}; class WifiLanV2Test : public ::testing::TestWithParam { protected: + using DiscoveredServiceCallback = WifiLanMediumV2::DiscoveredServiceCallback; + WifiLanV2Test() { env_.Stop(); } MediumEnvironment& env_{MediumEnvironment::Instance()}; @@ -66,8 +69,8 @@ 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}; + std::string service_info_name(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); NsdServiceInfo nsd_service_info; nsd_service_info.SetServiceName(service_info_name); @@ -81,20 +84,123 @@ TEST_F(WifiLanV2Test, CanStartAdvertising) { 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}; + std::string service_info_name_1(kServiceInfoName); + std::string service_info_name_2("ServiceInfoName_1"); + std::string endpoint_info_name(kEndpointName); + + NsdServiceInfo nsd_service_info_1; + nsd_service_info_1.SetServiceName(service_info_name_1); + nsd_service_info_1.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + NsdServiceInfo nsd_service_info_2; + nsd_service_info_2.SetServiceName(service_info_name_2); + nsd_service_info_2.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id_1, nsd_service_info_1)); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id_2, nsd_service_info_2)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id_1)); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id_2)); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanStartDiscovery) { + env_.Start(); + WifiLanV2 wifi_lan_a; + std::string service_id(kServiceID); + + EXPECT_TRUE( + wifi_lan_a.StartDiscovery(service_id, DiscoveredServiceCallback{})); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_id)); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanStartMultipleDiscovery) { + env_.Start(); + WifiLanV2 wifi_lan_a; + std::string service_id_1(kServiceID); + std::string service_id_2("com.google.location.nearby.apps.test_1"); + + EXPECT_TRUE( + wifi_lan_a.StartDiscovery(service_id_1, DiscoveredServiceCallback{})); + + EXPECT_TRUE( + wifi_lan_a.StartDiscovery(service_id_2, DiscoveredServiceCallback{})); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_id_1)); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_id_2)); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanAdvertiseThatOtherMediumDiscover) { + env_.Start(); + WifiLanV2 wifi_lan_a; + WifiLanV2 wifi_lan_b; + std::string service_id(kServiceID); + std::string service_info_name(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); + CountDownLatch discovered_latch(1); + CountDownLatch lost_latch(1); + + wifi_lan_b.StartDiscovery( + service_id, DiscoveredServiceCallback{ + .service_discovered_cb = + [&discovered_latch](NsdServiceInfo service_info, + const std::string& service_id) { + discovered_latch.CountDown(); + }, + .service_lost_cb = + [&lost_latch](NsdServiceInfo service_info, + const std::string& service_id) { + lost_latch.CountDown(); + }, + }); 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)); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, nsd_service_info)); + EXPECT_TRUE(discovered_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id)); + EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_b.StopDiscovery(service_id)); + env_.Stop(); +} + +TEST_F(WifiLanV2Test, CanDiscoverThatOtherMediumAdvertise) { + env_.Start(); + WifiLanV2 wifi_lan_a; + WifiLanV2 wifi_lan_b; + std::string service_id(kServiceID); + std::string service_info_name(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); + CountDownLatch discovered_latch(1); + CountDownLatch lost_latch(1); + + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(service_info_name); + nsd_service_info.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + wifi_lan_b.StartAdvertising(service_id, nsd_service_info); + + EXPECT_TRUE(wifi_lan_a.StartDiscovery( + service_id, DiscoveredServiceCallback{ + .service_discovered_cb = + [&discovered_latch](NsdServiceInfo service_info, + const std::string& service_id) { + discovered_latch.CountDown(); + }, + .service_lost_cb = + [&lost_latch](NsdServiceInfo service_info, + const std::string& service_id) { + lost_latch.CountDown(); + }, + })); + EXPECT_TRUE(discovered_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_b.StopAdvertising(service_id)); + EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_id)); env_.Stop(); } diff --git a/cpp/core/internal/mediums/wifi_lan_v2.cc b/cpp/core/internal/mediums/wifi_lan_v2.cc index 22f501c1..3903a899 100644 --- a/cpp/core/internal/mediums/wifi_lan_v2.cc +++ b/cpp/core/internal/mediums/wifi_lan_v2.cc @@ -115,12 +115,56 @@ bool WifiLanV2::IsAdvertisingLocked(const std::string& service_id) { bool WifiLanV2::StartDiscovery(const std::string& service_id, DiscoveredServiceCallback callback) { MutexLock lock(&mutex_); - return false; + + if (service_id.empty()) { + NEARBY_LOGS(INFO) + << "Refusing to start WifiLan discovering with empty service_id."; + return false; + } + + if (!IsAvailableLocked()) { + NEARBY_LOGS(INFO) + << "Can't discover WifiLan services because WifiLan isn't available."; + return false; + } + + if (IsDiscoveringLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Refusing to start discovery of WifiLan services because another " + "discovery is already in-progress."; + return false; + } + + std::string service_type = GenerateServiceType(service_id); + bool ret = medium_.StartDiscovery(service_id, service_type, callback); + if (!ret) { + NEARBY_LOGS(INFO) << "Failed to start discovery of WifiLan services."; + return false; + } + + NEARBY_LOGS(INFO) << "Turned on WifiLan discovering with service_id=" + << service_id; + // Mark the fact that we're currently performing a WifiLan discovering. + discovering_info_.Add(service_id); + return true; } bool WifiLanV2::StopDiscovery(const std::string& service_id) { MutexLock lock(&mutex_); - return false; + + if (!IsDiscoveringLocked(service_id)) { + NEARBY_LOGS(INFO) + << "Can't turn off WifiLan discovering because we never started " + "discovering."; + return false; + } + + std::string service_type = GenerateServiceType(service_id); + NEARBY_LOGS(INFO) << "Turned off WifiLan discovering with service_id=" + << service_id << ", service_type=" << service_type; + bool ret = medium_.StopDiscovery(service_type); + discovering_info_.Remove(service_id); + return ret; } bool WifiLanV2::IsDiscovering(const std::string& service_id) { @@ -153,7 +197,7 @@ bool WifiLanV2::IsAcceptingConnectionsLocked(const std::string& service_id) { } WifiLanSocketV2 WifiLanV2::Connect(const std::string& service_id, - NsdServiceInfo& service_info, + const NsdServiceInfo& service_info, CancellationFlag* cancellation_flag) { MutexLock lock(&mutex_); diff --git a/cpp/core/internal/mediums/wifi_lan_v2.h b/cpp/core/internal/mediums/wifi_lan_v2.h index d1587ab9..119ce152 100644 --- a/cpp/core/internal/mediums/wifi_lan_v2.h +++ b/cpp/core/internal/mediums/wifi_lan_v2.h @@ -92,7 +92,7 @@ class WifiLanV2 { // Blocks until connection is established, or server-side is terminated. // Returns socket instance. On success, WifiLanSocket.IsValid() return true. WifiLanSocketV2 Connect(const std::string& service_id, - NsdServiceInfo& service_info, + const NsdServiceInfo& service_info, CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_); @@ -104,6 +104,10 @@ class WifiLanV2 { CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_); + // Gets ip address + port for remote services on the network to identify and + // connect to this service. + // + // Credential is for the currently-hosted Wifi ServerSocket (if any). std::pair GetCredentials(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); @@ -135,7 +139,7 @@ class WifiLanV2 { struct DiscoveringInfo { bool Empty() const { return service_ids.empty(); } void Clear() { service_ids.clear(); } - void Add(const std::string& service_id) { service_ids.emplace(service_id); } + void Add(const std::string& service_id) { service_ids.insert(service_id); } void Remove(const std::string& service_id) { service_ids.erase(service_id); } @@ -187,4 +191,4 @@ class WifiLanV2 { } // namespace nearby } // namespace location -#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_V2_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_ diff --git a/cpp/core/internal/offline_service_controller_test.cc b/cpp/core/internal/offline_service_controller_test.cc index 8649fd71..35f04845 100644 --- a/cpp/core/internal/offline_service_controller_test.cc +++ b/cpp/core/internal/offline_service_controller_test.cc @@ -38,8 +38,8 @@ constexpr absl::string_view kServiceId = "service-id"; constexpr absl::string_view kDeviceA = "device-a"; constexpr absl::string_view kDeviceB = "device-b"; constexpr absl::string_view kMessage = "message"; -constexpr absl::Duration kProgressTimeout = absl::Milliseconds(1000); -constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1000); +constexpr absl::Duration kProgressTimeout = absl::Milliseconds(1500); +constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1500); constexpr absl::Duration kDisconnectTimeout = absl::Milliseconds(15000); constexpr BooleanMediumSelector kTestCases[] = { diff --git a/cpp/core/internal/p2p_cluster_pcp_handler.cc b/cpp/core/internal/p2p_cluster_pcp_handler.cc index 4ec6f496..78e9d6cf 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core/internal/p2p_cluster_pcp_handler.cc @@ -674,6 +674,128 @@ void P2pClusterPcpHandler::WifiLanServiceLostHandler( }); } +bool P2pClusterPcpHandler::IsRecognizedWifiLanV2Endpoint( + const std::string& service_id, + const WifiLanServiceInfo& wifi_lan_service_info) const { + if (!wifi_lan_service_info.IsValid()) { + NEARBY_LOGS(INFO) + << "WifiLanServiceInfo doesn't conform to the format, discarding."; + return false; + } + + if (wifi_lan_service_info.GetPcp() != GetPcp()) { + NEARBY_LOGS(INFO) + << "WifiLanServiceInfo doesn't match on Pcp; expected " + << PcpToStrategy(GetPcp()).GetName() << ", found " + << PcpToStrategy(wifi_lan_service_info.GetPcp()).GetName(); + return false; + } + + ByteArray expected_service_id_hash = + GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); + + if (wifi_lan_service_info.GetServiceIdHash() != expected_service_id_hash) { + NEARBY_LOGS(INFO) + << "WifiLanServiceInfo doesn't match on expected service_id_hash; " + "expected " + << absl::BytesToHexString(expected_service_id_hash.data()) << ", found " + << absl::BytesToHexString( + wifi_lan_service_info.GetServiceIdHash().data()); + return false; + } + + return true; +} + +void P2pClusterPcpHandler::WifiLanV2ServiceDiscoveredHandler( + ClientProxy* client, NsdServiceInfo service_info, + const std::string& service_id) { + RunOnPcpHandlerThread( + "p2p-wifi-service-discovered", + [this, client, service_id, service_info]() RUN_ON_PCP_HANDLER_THREAD() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOGS(WARNING) << "Skipping discovery of NsdServiceInfo " + << service_info.GetServiceName() + << " because we are no longer discovering."; + return; + } + + // Parse the WifiLanServiceInfo. + WifiLanServiceInfo wifi_lan_service_info(service_info); + // Make sure the WifiLan service name points to a valid + // endpoint we're discovering. + if (!IsRecognizedWifiLanV2Endpoint(service_id, wifi_lan_service_info)) { + return; + } + + // Report the discovered endpoint to the client. + NEARBY_LOGS(INFO) << "Found NsdServiceInfo " + << service_info.GetServiceName() + << " (with endpoint_id=" + << wifi_lan_service_info.GetEndpointId() + << "and endpoint_info=" + << absl::BytesToHexString( + wifi_lan_service_info.GetEndpointInfo().data()) + << ")."; + OnEndpointFound(client, + std::make_shared(WifiLanV2Endpoint{ + { + wifi_lan_service_info.GetEndpointId(), + wifi_lan_service_info.GetEndpointInfo(), + service_id, + proto::connections::Medium::WIFI_LAN, + wifi_lan_service_info.GetWebRtcState(), + }, + service_info, + })); + }); +} + +void P2pClusterPcpHandler::WifiLanV2ServiceLostHandler( + ClientProxy* client, NsdServiceInfo service_info, + const std::string& service_id) { + NEARBY_LOGS(INFO) << "WifiLan: [LOST, SCHED] service_info=" << &service_info + << ", service_name=" << service_info.GetServiceName(); + RunOnPcpHandlerThread( + "p2p-wifi-service-lost", + [this, client, service_id, service_info]() RUN_ON_PCP_HANDLER_THREAD() { + // Make sure we are still discovering before proceeding. + if (!client->IsDiscovering()) { + NEARBY_LOGS(WARNING) << "Ignoring lost NsdServiceInfo " + << service_info.GetServiceName() + << " because we are no longer " + "discovering."; + return; + } + + // Parse the WifiLanServiceInfo. + WifiLanServiceInfo wifi_lan_service_info(service_info); + + // Make sure the WifiLan service name points to a valid + // endpoint we're discovering. + if (!IsRecognizedWifiLanV2Endpoint(service_id, wifi_lan_service_info)) + return; + + // Report the lost endpoint to the client. + NEARBY_LOGS(INFO) << "Lost NsdServiceInfo " + << service_info.GetServiceName() + << " (with endpoint_id=" + << wifi_lan_service_info.GetEndpointId() + << " and endpoint_info=" + << absl::BytesToHexString( + wifi_lan_service_info.GetEndpointInfo().data()) + << ")."; + OnEndpointLost(client, DiscoveredEndpoint{ + wifi_lan_service_info.GetEndpointId(), + wifi_lan_service_info.GetEndpointInfo(), + service_id, + proto::connections::Medium::WIFI_LAN, + WebRtcState::kUndefined, + }); + }); +} + BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( ClientProxy* client, const std::string& service_id, const ConnectionOptions& options) { @@ -686,6 +808,24 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( std::vector mediums_started_successfully; + if (options.allowed.wifi_lan) { + proto::connections::Medium wifi_lan_medium = StartWifiLanV2Discovery( + { + .service_discovered_cb = absl::bind_front( + &P2pClusterPcpHandler::WifiLanV2ServiceDiscoveredHandler, this, + client), + .service_lost_cb = absl::bind_front( + &P2pClusterPcpHandler::WifiLanV2ServiceLostHandler, this, + client), + }, + client, service_id); + if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOGS(INFO) + << "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added"; + mediums_started_successfully.push_back(wifi_lan_medium); + } + } + if (options.allowed.wifi_lan) { proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery( { @@ -1403,17 +1543,18 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanV2Advertising( 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}; + 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); - }); + OnIncomingConnection( + client, remote_service_info, std::move(channel), + proto::connections::Medium::WIFI_LAN); + }); }})) { NEARBY_LOGS(WARNING) << "In StartWifiLanAdvertising(" @@ -1484,6 +1625,24 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanV2Advertising( return proto::connections::WIFI_LAN; } +proto::connections::Medium P2pClusterPcpHandler::StartWifiLanV2Discovery( + WifiLanV2DiscoveredServiceCallback callback, ClientProxy* client, + const std::string& service_id) { + if (wifi_lan_medium_v2_.StartDiscovery(service_id, std::move(callback))) { + NEARBY_LOGS(INFO) << "In StartWifiLanDiscovery(), client=" + << client->GetClientId() + << " started scanning for Wifi devices for service_id=" + << service_id; + return proto::connections::WIFI_LAN; + } else { + NEARBY_LOGS(INFO) << "In StartWifiLanDiscovery(), client=" + << client->GetClientId() + << " couldn't start scanning on Wifi for service_id=" + << service_id; + return proto::connections::UNKNOWN_MEDIUM; + } +} + } // 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 7a4b7bcf..d4ecc40e 100644 --- a/cpp/core/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core/internal/p2p_cluster_pcp_handler.h @@ -109,6 +109,8 @@ class P2pClusterPcpHandler : public BasePcpHandler { BluetoothClassic::DiscoveredDeviceCallback; using BleDiscoveredPeripheralCallback = Ble::DiscoveredPeripheralCallback; using WifiLanDiscoveredServiceCallback = WifiLan::DiscoveredServiceCallback; + using WifiLanV2DiscoveredServiceCallback = + WifiLanV2::DiscoveredServiceCallback; static constexpr BluetoothDeviceName::Version kBluetoothDeviceNameVersion = BluetoothDeviceName::Version::kV1; @@ -189,10 +191,22 @@ class P2pClusterPcpHandler : public BasePcpHandler { ClientProxy* client, WifiLanEndpoint* endpoint); // WifiLanV2 + bool IsRecognizedWifiLanV2Endpoint( + const std::string& service_id, + const WifiLanServiceInfo& wifi_lan_service_info) const; + void WifiLanV2ServiceDiscoveredHandler(ClientProxy* client, + NsdServiceInfo service_info, + const std::string& service_id); + void WifiLanV2ServiceLostHandler(ClientProxy* client, + NsdServiceInfo service_info, + const std::string& service_id); 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); + proto::connections::Medium StartWifiLanV2Discovery( + WifiLanV2DiscoveredServiceCallback callback, ClientProxy* client, + const std::string& service_id); BluetoothRadio& bluetooth_radio_; BluetoothClassic& bluetooth_medium_; diff --git a/cpp/platform/api/wifi_lan_v2.h b/cpp/platform/api/wifi_lan_v2.h index 12c1106c..2d7aad89 100644 --- a/cpp/platform/api/wifi_lan_v2.h +++ b/cpp/platform/api/wifi_lan_v2.h @@ -97,13 +97,10 @@ class WifiLanMediumV2 { // Callback that is invoked when a discovered service is found or lost. struct DiscoveredServiceCallback { - std::function - service_discovered_cb = - DefaultCallback(); - std::function - service_lost_cb = DefaultCallback(); + std::function service_discovered_cb = + DefaultCallback(); + std::function service_lost_cb = + DefaultCallback(); }; // Starts the discovery of nearby WifiLan services. diff --git a/cpp/platform/base/medium_environment.cc b/cpp/platform/base/medium_environment.cc index b5e5757d..3dfbced8 100644 --- a/cpp/platform/base/medium_environment.cc +++ b/cpp/platform/base/medium_environment.cc @@ -22,14 +22,9 @@ #include #include -#include "platform/api/ble.h" -#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/base/prng.h" #include "platform/public/count_down_latch.h" namespace location { @@ -260,6 +255,66 @@ void MediumEnvironment::OnWifiLanServiceStateChanged( }); } +void MediumEnvironment::OnWifiLanServiceV2StateChanged( + WifiLanMediumV2Context& info, const NsdServiceInfo& service_info, + bool enabled) { + if (!enabled_) return; + std::string service_type = service_info.GetServiceType(); + auto item = info.discovered_services.find(service_type); + if (item == info.discovered_services.end()) { + NEARBY_LOGS(INFO) << "G3 OnWifiLanServiceStateChanged; context=" << &info + << "; service_type=" << service_type + << "; enabled=" << enabled + << "; notify=" << enable_notifications_.load(); + if (enabled) { + // Find advertising service with matched service_type. Report it as + // discovered by assigning the fake ip address and port. + NsdServiceInfo discovered_service_info(service_info); + discovered_service_info.SetIPAddress(GetFakeIPAddress()); + discovered_service_info.SetPort(GetFakePort()); + info.discovered_services.insert({service_type, discovered_service_info}); + if (enable_notifications_) { + RunOnMediumEnvironmentThread( + [&info, discovered_service_info, service_type]() { + auto item = info.discovered_callbacks.find(service_type); + if (item != info.discovered_callbacks.end()) { + item->second.service_discovered_cb(discovered_service_info); + } + }); + } + } + } else { + NEARBY_LOGS(INFO) + << "G3 OnWifiLanServiceStateChanged: exisitng service; context=" + << &info << "; service_type=" << service_type << "; enabled=" << enabled + << "; notify=" << enable_notifications_.load(); + if (enabled) { + if (enable_notifications_) { + RunOnMediumEnvironmentThread( + [&info, service_info = service_info, service_type]() { + auto item = info.discovered_callbacks.find(service_type); + if (item != info.discovered_callbacks.end()) { + item->second.service_discovered_cb(service_info); + } + }); + } + } else { + // Known service is off. + // Erase it from the map, and report as lost. + if (enable_notifications_) { + RunOnMediumEnvironmentThread( + [&info, service_info = service_info, service_type]() { + auto item = info.discovered_callbacks.find(service_type); + if (item != info.discovered_callbacks.end()) { + item->second.service_lost_cb(service_info); + } + }); + } + info.discovered_services.erase(item); + } + } +} + void MediumEnvironment::RunOnMediumEnvironmentThread( std::function runnable) { job_count_++; @@ -625,6 +680,24 @@ void MediumEnvironment::UpdateWifiLanMediumForDiscovery( }); } +std::string MediumEnvironment::GetFakeIPAddress() const { + std::string ip_address; + ip_address.resize(4); + uint32_t raw_ip_addr = 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 ip_address; +} + +int MediumEnvironment::GetFakePort() const { + uint16_t port = Prng().NextUint32(); + + return port; +} + void MediumEnvironment::UpdateWifiLanMediumForAcceptedConnection( api::WifiLanMedium& medium, const std::string& service_id, WifiLanAcceptedConnectionCallback callback) { @@ -741,6 +814,40 @@ void MediumEnvironment::UpdateWifiLanMediumV2ForAdvertising( } continue; } + OnWifiLanServiceV2StateChanged(info, service_info, enabled); + } + }); +} + +void MediumEnvironment::UpdateWifiLanMediumV2ForDiscovery( + api::WifiLanMediumV2& medium, WifiLanDiscoveredServiceV2Callback callback, + const std::string& service_type, bool enabled) { + if (!enabled_) return; + RunOnMediumEnvironmentThread([this, &medium, callback = std::move(callback), + service_type, enabled]() { + auto item = wifi_lan_mediums_v2_.find(&medium); + if (item == wifi_lan_mediums_v2_.end()) { + NEARBY_LOGS(INFO) + << "UpdateWifiLanMediumForDiscovery failed. There is no medium " + "registered."; + return; + } + auto& context = item->second; + context.discovered_callbacks.insert({service_type, std::move(callback)}); + NEARBY_LOGS(INFO) << "Update WifiLan medium for discovery: this=" << this + << "; medium=" << &medium + << "; 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. + if (local_medium == &medium) continue; + // Search advertising services and send notification. + for (auto& advertising_service : info.advertising_services) { + auto& service_info = advertising_service.second; + OnWifiLanServiceV2StateChanged(context, service_info, /*enabled=*/true); + } } }); } @@ -751,7 +858,7 @@ void MediumEnvironment::UnregisterWifiLanMediumV2( RunOnMediumEnvironmentThread([this, &medium]() { auto item = wifi_lan_mediums_v2_.extract(&medium); if (item.empty()) return; - NEARBY_LOG(INFO, "Unregistered WifiLan medium"); + NEARBY_LOGS(INFO) << "Unregistered WifiLan medium"; }); } diff --git a/cpp/platform/base/medium_environment.h b/cpp/platform/base/medium_environment.h index aab9841c..665d87f6 100644 --- a/cpp/platform/base/medium_environment.h +++ b/cpp/platform/base/medium_environment.h @@ -20,8 +20,11 @@ #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" +#include "platform/api/ble.h" #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/api/webrtc.h" #include "platform/base/byte_array.h" #include "platform/base/feature_flags.h" @@ -62,6 +65,8 @@ class MediumEnvironment { api::WifiLanMedium::DiscoveredServiceCallback; using WifiLanAcceptedConnectionCallback = api::WifiLanMedium::AcceptedConnectionCallback; + using WifiLanDiscoveredServiceV2Callback = + api::WifiLanMediumV2::DiscoveredServiceCallback; MediumEnvironment(const MediumEnvironment&) = delete; MediumEnvironment& operator=(const MediumEnvironment&) = delete; @@ -255,6 +260,21 @@ class MediumEnvironment { api::WifiLanMediumV2& medium, const NsdServiceInfo& nsd_service_info, bool enabled); + // Updates discovery callback info to allow for dispatch of discovery events. + // + // This should be called when discoverable state changes. + // with user-specified callback when discovery is enabled, and with default + // (empty) callback otherwise. + void UpdateWifiLanMediumV2ForDiscovery( + api::WifiLanMediumV2& medium, WifiLanDiscoveredServiceV2Callback callback, + const std::string& service_type, bool enabled); + + // Gets Fake IP address for WifiLan medium. + std::string GetFakeIPAddress() const; + + // Gets Fake port number for WifiLan medium. + int GetFakePort() const; + // Removes medium-related info. This should correspond to device power off. void UnregisterWifiLanMediumV2(api::WifiLanMediumV2& medium); @@ -290,6 +310,12 @@ class MediumEnvironment { struct WifiLanMediumV2Context { // advertising service type vs NsdServiceInfo map. absl::flat_hash_map advertising_services; + // discovered service type vs callback map. + absl::flat_hash_map + discovered_callbacks; + // discovered service vs service type map. + absl::flat_hash_map + discovered_services; }; // This is a singleton object, for which destructor will never be called. @@ -315,6 +341,10 @@ class MediumEnvironment { const std::string& service_id, bool enabled); + void OnWifiLanServiceV2StateChanged(WifiLanMediumV2Context& info, + const NsdServiceInfo& service_info, + bool enabled); + void RunOnMediumEnvironmentThread(std::function runnable); std::atomic_bool enabled_ = true; diff --git a/cpp/platform/impl/g3/wifi_lan_v2.cc b/cpp/platform/impl/g3/wifi_lan_v2.cc index 7fa64be9..5e983d57 100644 --- a/cpp/platform/impl/g3/wifi_lan_v2.cc +++ b/cpp/platform/impl/g3/wifi_lan_v2.cc @@ -25,7 +25,6 @@ #include "platform/base/logging.h" #include "platform/base/medium_environment.h" #include "platform/base/nsd_service_info.h" -#include "platform/base/prng.h" namespace location { namespace nearby { @@ -195,11 +194,44 @@ bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { bool WifiLanMediumV2::StartDiscovery(const std::string& service_type, DiscoveredServiceCallback callback) { - return false; + NEARBY_LOGS(INFO) << "G3 WifiLan StartDiscovery: service_type=" + << service_type; + { + absl::MutexLock lock(&mutex_); + if (discovering_info_.Existed(service_type)) { + NEARBY_LOGS(INFO) + << "G3 WifiLan StartDiscovery: Can't start discovery because " + "service_type=" + << service_type << " has started already."; + return false; + } + } + auto& env = MediumEnvironment::Instance(); + env.UpdateWifiLanMediumV2ForDiscovery(*this, std::move(callback), + service_type, true); + { + absl::MutexLock lock(&mutex_); + discovering_info_.Add(service_type); + } + return true; } bool WifiLanMediumV2::StopDiscovery(const std::string& service_type) { - return false; + NEARBY_LOGS(INFO) << "G3 WifiLan StopDiscovery: service_type=" + << service_type; + { + absl::MutexLock lock(&mutex_); + if (!discovering_info_.Existed(service_type)) { + NEARBY_LOGS(INFO) + << "G3 WifiLan StopDiscovery: Can't stop discovering because we " + "never started discovering."; + return false; + } + discovering_info_.Remove(service_type); + } + auto& env = MediumEnvironment::Instance(); + env.UpdateWifiLanMediumV2ForDiscovery(*this, {}, service_type, false); + return true; } std::unique_ptr WifiLanMediumV2::ConnectToService( @@ -218,19 +250,6 @@ 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 eea97f2a..e6b642b8 100644 --- a/cpp/platform/impl/g3/wifi_lan_v2.h +++ b/cpp/platform/impl/g3/wifi_lan_v2.h @@ -223,11 +223,25 @@ class WifiLanMediumV2 : public api::WifiLanMediumV2 { absl::flat_hash_set service_types; }; + struct DiscoveringInfo { + 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::pair GetFakeCredentials() const; + absl::flat_hash_set service_types; + }; absl::Mutex mutex_; AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); + DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_); }; } // namespace g3 diff --git a/cpp/platform/public/wifi_lan_test_v2.cc b/cpp/platform/public/wifi_lan_test_v2.cc index dda38b74..33a21fc0 100644 --- a/cpp/platform/public/wifi_lan_test_v2.cc +++ b/cpp/platform/public/wifi_lan_test_v2.cc @@ -37,6 +37,8 @@ constexpr FeatureFlags kTestCases[] = { }, }; +constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); +constexpr absl::string_view kServiceId{"service_id"}; constexpr absl::string_view kServiceType{"_service.tcp_"}; constexpr absl::string_view kServiceInfoName{"Simulated service info name"}; constexpr absl::string_view kEndpointName{"Simulated endpoint name"}; @@ -44,6 +46,8 @@ constexpr absl::string_view kEndpointInfoKey{"n"}; class WifiLanMediumV2Test : public ::testing::TestWithParam { protected: + using DiscoveredServiceCallback = WifiLanMediumV2::DiscoveredServiceCallback; + WifiLanMediumV2Test() { env_.Stop(); } MediumEnvironment& env_{MediumEnvironment::Instance()}; @@ -67,16 +71,15 @@ 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}; + 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.StartAdvertising(nsd_service_info)); EXPECT_TRUE(wifi_lan_a.StopAdvertising(nsd_service_info)); env_.Stop(); } @@ -84,19 +87,23 @@ TEST_F(WifiLanMediumV2Test, CanStartAdvertising) { 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}; + std::string service_type_1(kServiceType); + std::string service_type_2("_service_1.tcp_"); + std::string service_info_name_1(kServiceInfoName); + std::string service_info_name_2(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); NsdServiceInfo nsd_service_info_1; - nsd_service_info_1.SetServiceName(service_info_name); + nsd_service_info_1.SetServiceName(service_info_name_1); nsd_service_info_1.SetTxtRecord(std::string(kEndpointInfoKey), endpoint_info_name); - nsd_service_info_1.SetServiceType(service_type); + nsd_service_info_1.SetServiceType(service_type_1); - NsdServiceInfo nsd_service_info_2 = nsd_service_info_1; - nsd_service_info_2.SetServiceType(service_tye_1); + NsdServiceInfo nsd_service_info_2; + nsd_service_info_2.SetServiceName(service_info_name_2); + nsd_service_info_2.SetTxtRecord(std::string(kEndpointInfoKey), + endpoint_info_name); + nsd_service_info_2.SetServiceType(service_type_2); EXPECT_TRUE(wifi_lan_a.StartAdvertising(nsd_service_info_1)); EXPECT_TRUE(wifi_lan_a.StartAdvertising(nsd_service_info_2)); @@ -105,6 +112,113 @@ TEST_F(WifiLanMediumV2Test, CanStartMultipleAdvertising) { env_.Stop(); } +TEST_F(WifiLanMediumV2Test, CanStartDiscovery) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + std::string service_id(kServiceId); + std::string service_type(kServiceType); + + EXPECT_TRUE(wifi_lan_a.StartDiscovery(service_id, service_type, + DiscoveredServiceCallback{})); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_type)); + env_.Stop(); +} + +TEST_F(WifiLanMediumV2Test, CanStartMultipleDiscovery) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + std::string service_id_1(kServiceId); + std::string service_id_2("service_id_2"); + std::string service_type_1(kServiceType); + std::string service_type_2("_service_1.tcp_"); + + EXPECT_TRUE(wifi_lan_a.StartDiscovery(service_id_1, service_type_1, + DiscoveredServiceCallback{})); + EXPECT_TRUE(wifi_lan_a.StartDiscovery(service_id_2, service_type_2, + DiscoveredServiceCallback{})); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_type_1)); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_type_2)); + env_.Stop(); +} + +TEST_F(WifiLanMediumV2Test, CanAdvertiseThatOtherMediumDiscover) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + WifiLanMediumV2 wifi_lan_b; + std::string service_id(kServiceId); + std::string service_type(kServiceType); + std::string service_info_name(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); + CountDownLatch discovered_latch(1); + CountDownLatch lost_latch(1); + + wifi_lan_b.StartDiscovery( + service_id, service_type, + DiscoveredServiceCallback{ + .service_discovered_cb = + [&discovered_latch](NsdServiceInfo service_info, + const std::string& service_type) { + discovered_latch.CountDown(); + }, + .service_lost_cb = + [&lost_latch](NsdServiceInfo service_info, + const std::string& service_id) { + lost_latch.CountDown(); + }, + }); + + 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); + EXPECT_TRUE(wifi_lan_a.StartAdvertising(nsd_service_info)); + EXPECT_TRUE(discovered_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_a.StopAdvertising(nsd_service_info)); + EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_b.StopDiscovery(service_type)); + env_.Stop(); +} + +TEST_F(WifiLanMediumV2Test, CanDiscoverThatOtherMediumAdvertise) { + env_.Start(); + WifiLanMediumV2 wifi_lan_a; + WifiLanMediumV2 wifi_lan_b; + std::string service_id(kServiceId); + std::string service_type(kServiceType); + std::string service_info_name(kServiceInfoName); + std::string endpoint_info_name(kEndpointName); + CountDownLatch discovered_latch(1); + CountDownLatch lost_latch(1); + + wifi_lan_a.StartDiscovery( + service_id, service_type, + DiscoveredServiceCallback{ + .service_discovered_cb = + [&discovered_latch](NsdServiceInfo service_info, + const std::string& service_type) { + discovered_latch.CountDown(); + }, + .service_lost_cb = + [&lost_latch](NsdServiceInfo service_info, + const std::string& service_type) { + lost_latch.CountDown(); + }, + }); + + 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); + EXPECT_TRUE(wifi_lan_b.StartAdvertising(nsd_service_info)); + EXPECT_TRUE(discovered_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_b.StopAdvertising(nsd_service_info)); + EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(wifi_lan_a.StopDiscovery(service_type)); + 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 cd5410dc..32f97198 100644 --- a/cpp/platform/public/wifi_lan_v2.cc +++ b/cpp/platform/public/wifi_lan_v2.cc @@ -27,13 +27,101 @@ bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { return impl_->StopAdvertising(nsd_service_info); } -bool WifiLanMediumV2::StartDiscovery(const std::string& service_type, +bool WifiLanMediumV2::StartDiscovery(const std::string& service_id, + const std::string& service_type, DiscoveredServiceCallback callback) { - return false; + { + MutexLock lock(&mutex_); + if (discovery_callbacks_.contains(service_type)) { + NEARBY_LOGS(INFO) << "WifiLan Discovery already start with service_type=" + << service_type << "; impl=" << &GetImpl(); + return false; + } + } + api::WifiLanMediumV2::DiscoveredServiceCallback api_callback = { + .service_discovered_cb = + [this](NsdServiceInfo service_info) { + MutexLock lock(&mutex_); + std::string service_type = service_info.GetServiceType(); + auto pair = discovery_services_.insert(service_type); + if (!pair.second) { + NEARBY_LOGS(INFO) + << "Discovering (again) service_info=" << &service_info + << ", service_type=" << service_type + << ", service_name=" << service_info.GetServiceName(); + return; + } + NEARBY_LOGS(INFO) + << "Adding service_info=" << &service_info + << ", service_type=" << service_type + << ", service_name=" << service_info.GetServiceName(); + // Callback service found. + const auto& it = discovery_callbacks_.find(service_type); + if (it != discovery_callbacks_.end()) { + std::string service_id = it->second->service_id; + DiscoveredServiceCallback medium_callback = + it->second->medium_callback; + medium_callback.service_discovered_cb(service_info, service_id); + } else { + NEARBY_LOGS(ERROR) + << "There is no callback found for service_type=" + << service_type; + } + }, + .service_lost_cb = + [this](NsdServiceInfo service_info) { + MutexLock lock(&mutex_); + std::string service_type = service_info.GetServiceType(); + auto item = discovery_services_.extract(service_type); + if (item.empty()) return; + NEARBY_LOGS(INFO) + << "Removing service_info=" << &service_info + << ", service_type=" << service_type + << ", service_info_name=" << service_info.GetServiceName(); + // Callback service lost. + const auto& it = discovery_callbacks_.find(service_type); + if (it != discovery_callbacks_.end()) { + std::string service_id = it->second->service_id; + DiscoveredServiceCallback medium_callback = + it->second->medium_callback; + medium_callback.service_lost_cb(service_info, service_id); + } + }, + }; + { + // Insert callback to the map first no matter it succeeds or not. + MutexLock lock(&mutex_); + auto pair = discovery_callbacks_.insert( + {service_type, absl::make_unique()}); + auto& context = *pair.first->second; + context.medium_callback = std::move(callback); + context.service_id = service_id; + } + + bool success = impl_->StartDiscovery(service_type, std::move(api_callback)); + if (!success) { + // If failed, then revert back the insertion. + MutexLock lock(&mutex_); + discovery_callbacks_.erase(service_type); + } + NEARBY_LOGS(INFO) << "WifiLan Discovery started for service_type=" + << service_type << ", impl=" << &GetImpl() + << ", success=" << success; + return success; } bool WifiLanMediumV2::StopDiscovery(const std::string& service_type) { - return false; + MutexLock lock(&mutex_); + if (!discovery_callbacks_.contains(service_type)) { + return false; + } + discovery_callbacks_.erase(service_type); + if (discovery_services_.contains(service_type)) { + discovery_services_.erase(service_type); + } + NEARBY_LOGS(INFO) << "WifiLan Discovery disabled for service_type=" + << service_type << ", impl=" << &GetImpl(); + return impl_->StopDiscovery(service_type); } WifiLanSocketV2 WifiLanMediumV2::ConnectToService( diff --git a/cpp/platform/public/wifi_lan_v2.h b/cpp/platform/public/wifi_lan_v2.h index 3c5d1385..57276327 100644 --- a/cpp/platform/public/wifi_lan_v2.h +++ b/cpp/platform/public/wifi_lan_v2.h @@ -126,15 +126,9 @@ class WifiLanMediumV2 { public: using Platform = api::ImplementationPlatform; - // WifiLanService is a proxy object created as a result of WifiLan discovery. - // Its lifetime spans between calls to service_discovered_cb and - // service_lost_cb. - // It is safe to use WifiLanService in service_discovered_cb() callback - // and at any time afterwards, until service_lost_cb() is called. - // It is not safe to use WifiLanService after returning from - // service_lost_cb() callback. struct DiscoveredServiceCallback { - std::function + std::function service_discovered_cb = DefaultCallback(); std::function impl_; absl::flat_hash_map> discovery_callbacks_ ABSL_GUARDED_BY(mutex_); + absl::flat_hash_set discovery_services_ ABSL_GUARDED_BY(mutex_); }; } // namespace nearby