diff --git a/cpp/core/internal/BUILD b/cpp/core/internal/BUILD index 9247f02e..40e734a8 100644 --- a/cpp/core/internal/BUILD +++ b/cpp/core/internal/BUILD @@ -44,6 +44,7 @@ cc_library( "webrtc_endpoint_channel.cc", "wifi_lan_bwu_handler.cc", "wifi_lan_endpoint_channel.cc", + "wifi_lan_endpoint_channel_v2.cc", "wifi_lan_service_info.cc", ], hdrs = [ @@ -81,6 +82,7 @@ cc_library( "webrtc_endpoint_channel.h", "wifi_lan_bwu_handler.h", "wifi_lan_endpoint_channel.h", + "wifi_lan_endpoint_channel_v2.h", "wifi_lan_service_info.h", ], compatible_with = ["//buildenv/target:non_prod"], diff --git a/cpp/core/internal/mediums/BUILD b/cpp/core/internal/mediums/BUILD index 8aa64dcf..c9bfcd5a 100644 --- a/cpp/core/internal/mediums/BUILD +++ b/cpp/core/internal/mediums/BUILD @@ -24,6 +24,7 @@ cc_library( "uuid.cc", "webrtc.cc", "wifi_lan.cc", + "wifi_lan_v2.cc", ], hdrs = [ "ble.h", @@ -35,6 +36,7 @@ cc_library( "uuid.h", "webrtc.h", "wifi_lan.h", + "wifi_lan_v2.h", ], compatible_with = ["//buildenv/target:non_prod"], visibility = [ diff --git a/cpp/core/internal/mediums/mediums.cc b/cpp/core/internal/mediums/mediums.cc index 8b0b3100..25135de0 100644 --- a/cpp/core/internal/mediums/mediums.cc +++ b/cpp/core/internal/mediums/mediums.cc @@ -26,6 +26,8 @@ Ble& Mediums::GetBle() { return ble_; } WifiLan& Mediums::GetWifiLan() { return wifi_lan_; } +WifiLanV2& Mediums::GetWifiLanV2() { return wifi_lan_v2_; } + mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; } } // namespace connections diff --git a/cpp/core/internal/mediums/mediums.h b/cpp/core/internal/mediums/mediums.h index 4c6127eb..d47b9b42 100644 --- a/cpp/core/internal/mediums/mediums.h +++ b/cpp/core/internal/mediums/mediums.h @@ -20,6 +20,7 @@ #include "core/internal/mediums/bluetooth_radio.h" #include "core/internal/mediums/webrtc.h" #include "core/internal/mediums/wifi_lan.h" +#include "core/internal/mediums/wifi_lan_v2.h" namespace location { namespace nearby { @@ -43,6 +44,9 @@ class Mediums { // Returns a handle to the Wifi-Lan medium. WifiLan& GetWifiLan(); + // Returns a handle to the Wifi-Lan medium. + WifiLanV2& GetWifiLanV2(); + // Returns a handle to the WebRtc medium. mediums::WebRtc& GetWebRtc(); @@ -59,6 +63,7 @@ class Mediums { BluetoothClassic bluetooth_classic_{bluetooth_radio_}; Ble ble_{bluetooth_radio_}; WifiLan wifi_lan_; + WifiLanV2 wifi_lan_v2_; mediums::WebRtc webrtc_; }; diff --git a/cpp/core/internal/mediums/wifi_lan_v2.cc b/cpp/core/internal/mediums/wifi_lan_v2.cc new file mode 100644 index 00000000..edfe44a9 --- /dev/null +++ b/cpp/core/internal/mediums/wifi_lan_v2.cc @@ -0,0 +1,142 @@ +// 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 "core/internal/mediums/wifi_lan_v2.h" + +#include +#include +#include + +#include "absl/strings/str_format.h" +#include "core/internal/mediums/utils.h" +#include "platform/public/logging.h" +#include "platform/public/mutex_lock.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiLanV2::~WifiLanV2() { + // All the AcceptLoopRunnable objects in here should already have gotten an + // opportunity to shut themselves down cleanly in the calls to + // StopAcceptingConnections() above. + accept_loops_runner_.Shutdown(); +} + +bool WifiLanV2::IsAvailable() const { + MutexLock lock(&mutex_); + return IsAvailableLocked(); +} + +bool WifiLanV2::IsAvailableLocked() const { return medium_.IsValid(); } + +bool WifiLanV2::StartAdvertising(const std::string& service_id, + NsdServiceInfo& nsd_service_info) { + return false; +} + +bool WifiLanV2::StopAdvertising(const std::string& service_id) { return false; } + +bool WifiLanV2::IsAdvertising(const std::string& service_id) { + MutexLock lock(&mutex_); + return IsAdvertisingLocked(service_id); +} + +bool WifiLanV2::IsAdvertisingLocked(const std::string& service_id) { + return advertising_info_.Existed(service_id); +} + +bool WifiLanV2::StartDiscovery(const std::string& service_id, + DiscoveredServiceCallback callback) { + MutexLock lock(&mutex_); + return false; +} + +bool WifiLanV2::StopDiscovery(const std::string& service_id) { + MutexLock lock(&mutex_); + return false; +} + +bool WifiLanV2::IsDiscovering(const std::string& service_id) { + MutexLock lock(&mutex_); + return IsDiscoveringLocked(service_id); +} + +bool WifiLanV2::IsDiscoveringLocked(const std::string& service_id) { + return discovering_info_.Existed(service_id); +} + +bool WifiLanV2::StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) { + MutexLock lock(&mutex_); + return false; +} + +bool WifiLanV2::StopAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); + return false; +} + +bool WifiLanV2::IsAcceptingConnections(const std::string& service_id) { + MutexLock lock(&mutex_); + return IsAcceptingConnectionsLocked(service_id); +} + +bool WifiLanV2::IsAcceptingConnectionsLocked(const std::string& service_id) { + return server_sockets_.find(service_id) != server_sockets_.end(); +} + +WifiLanSocketV2 WifiLanV2::Connect(const std::string& service_id, + NsdServiceInfo& service_info, + CancellationFlag* cancellation_flag) { + MutexLock lock(&mutex_); + + return {}; +} + +WifiLanSocketV2 WifiLanV2::Connect(const std::string& service_id, + const std::string& ip_address, int port, + CancellationFlag* cancellation_flag) { + MutexLock lock(&mutex_); + + return {}; +} + +std::pair WifiLanV2::GetCredentials( + const std::string& service_id) { + MutexLock lock(&mutex_); + const auto& it = server_sockets_.find(service_id); + if (it == server_sockets_.end()) { + return std::pair(); + } + return std::pair(it->second.GetIpAddress(), + it->second.GetPort()); +} + +std::string WifiLanV2::GenerateServiceType(const std::string& service_id) { + std::string service_id_hash_string; + + const ByteArray service_id_hash = Utils::Sha256Hash( + service_id, NsdServiceInfo::kTypeFromServiceIdHashLength); + for (auto byte : std::string(service_id_hash)) { + absl::StrAppend(&service_id_hash_string, absl::StrFormat("%02X", byte)); + } + + return absl::StrFormat(NsdServiceInfo::kNsdTypeFormat, + service_id_hash_string); +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/mediums/wifi_lan_v2.h b/cpp/core/internal/mediums/wifi_lan_v2.h new file mode 100644 index 00000000..d1587ab9 --- /dev/null +++ b/cpp/core/internal/mediums/wifi_lan_v2.h @@ -0,0 +1,190 @@ +// 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. + +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_LAN_V2_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_LAN_V2_H_ + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "platform/base/byte_array.h" +#include "platform/base/cancellation_flag.h" +#include "platform/base/nsd_service_info.h" +#include "platform/public/multi_thread_executor.h" +#include "platform/public/mutex.h" +#include "platform/public/wifi_lan_v2.h" + +namespace location { +namespace nearby { +namespace connections { + +class WifiLanV2 { + public: + using DiscoveredServiceCallback = WifiLanMediumV2::DiscoveredServiceCallback; + + // Callback that is invoked when a new connection is accepted. + struct AcceptedConnectionCallback { + std::function accepted_cb = + DefaultCallback(); + }; + + WifiLanV2() = default; + ~WifiLanV2(); + + // Returns true, if WifiLan communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Sets custom service info name, endpoint info name in NsdServiceInfo and + // then enables WifiLan advertising. + // Returns true, if NsdServiceInfo is successfully set, and false otherwise. + bool StartAdvertising(const std::string& service_id, + NsdServiceInfo& nsd_service_info) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Disables WifiLan advertising. + // Returns false if no successful call StartAdvertising() was previously + // made, otherwise returns true. + bool StopAdvertising(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + + // Enables WifiLan discovery. Will report any discoverable services + // through a callback. + // Returns true, if discovery was enabled, false otherwise. + bool StartDiscovery(const std::string& service_id, + DiscoveredServiceCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Disables WifiLan discovery. + bool StopDiscovery(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + + bool IsDiscovering(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + + // Starts a worker thread, creates a WifiLan socket, associates it with a + // service id. + bool StartAcceptingConnections(const std::string& service_id, + AcceptedConnectionCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Closes socket corresponding to a service id. + bool StopAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + bool IsAcceptingConnections(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Establishes connection to WifiLan service that was might be started on + // another service with StartAcceptingConnections() using the same service_id. + // 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, + CancellationFlag* cancellation_flag) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Establishes connection to WifiLan service by ip address and port for + // bandwidth upgradation. + // Returns socket instance. On success, WifiLanSocket.IsValid() return true. + WifiLanSocketV2 Connect(const std::string& service_id, + const std::string& ip_address, int port, + CancellationFlag* cancellation_flag) + ABSL_LOCKS_EXCLUDED(mutex_); + + std::pair GetCredentials(const std::string& service_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + struct AdvertisingInfo { + bool Empty() const { return nsd_service_infos.empty(); } + void Clear() { nsd_service_infos.clear(); } + void Add(const std::string& service_id, + const NsdServiceInfo& nsd_service_info) { + nsd_service_infos.insert({service_id, nsd_service_info}); + } + void Remove(const std::string& service_id) { + nsd_service_infos.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return nsd_service_infos.contains(service_id); + } + NsdServiceInfo* GetServiceInfo(const std::string& service_id) { + const auto& it = nsd_service_infos.find(service_id); + if (it == nsd_service_infos.end()) { + return nullptr; + } + return &it->second; + } + + absl::flat_hash_map nsd_service_infos; + }; + + 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 Remove(const std::string& service_id) { + service_ids.erase(service_id); + } + bool Existed(const std::string& service_id) const { + return service_ids.contains(service_id); + } + + absl::flat_hash_set service_ids; + }; + + static constexpr int kMaxConcurrentAcceptLoops = 5; + + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Same as IsAdvertising(), but must be called with mutex_ held. + bool IsAdvertisingLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Same as IsDiscovering(), but must be called with mutex_ held. + bool IsDiscoveringLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Same as IsAcceptingConnections(), but must be called with mutex_ held. + bool IsAcceptingConnectionsLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Generates mDNS type. + std::string GenerateServiceType(const std::string& service_id); + + mutable Mutex mutex_; + WifiLanMediumV2 medium_ ABSL_GUARDED_BY(mutex_); + AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_); + DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_); + + // A thread pool dedicated to running all the accept loops from + // StartAcceptingConnections(). + MultiThreadExecutor accept_loops_runner_{kMaxConcurrentAcceptLoops}; + + // A map of service_id -> ServerSocket. If map is non-empty, we + // are currently listening for incoming connections. + // WifiLanServerSocket instances are used from accept_loops_runner_, + // and thus require pointer stability. + absl::flat_hash_map server_sockets_ + ABSL_GUARDED_BY(mutex_); +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_V2_H_ diff --git a/cpp/core/internal/wifi_lan_endpoint_channel_v2.cc b/cpp/core/internal/wifi_lan_endpoint_channel_v2.cc new file mode 100644 index 00000000..837d3233 --- /dev/null +++ b/cpp/core/internal/wifi_lan_endpoint_channel_v2.cc @@ -0,0 +1,47 @@ +// 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 "core/internal/wifi_lan_endpoint_channel_v2.h" + +#include + +#include "platform/public/logging.h" +#include "platform/public/wifi_lan_v2.h" + +namespace location { +namespace nearby { +namespace connections { + +WifiLanEndpointChannelV2::WifiLanEndpointChannelV2( + const std::string& channel_name, WifiLanSocketV2 socket) + : BaseEndpointChannel(channel_name, &socket.GetInputStream(), + &socket.GetOutputStream()), + socket_(std::move(socket)) {} + +proto::connections::Medium WifiLanEndpointChannelV2::GetMedium() const { + return proto::connections::Medium::WIFI_LAN; +} + +void WifiLanEndpointChannelV2::CloseImpl() { + auto status = socket_.Close(); + if (!status.Ok()) { + NEARBY_LOGS(INFO) + << "Failed to close underlying socket for WifiLanEndpointChannel " + << GetName() << " : exception = " << status.value; + } +} + +} // namespace connections +} // namespace nearby +} // namespace location diff --git a/cpp/core/internal/wifi_lan_endpoint_channel_v2.h b/cpp/core/internal/wifi_lan_endpoint_channel_v2.h new file mode 100644 index 00000000..cd389e04 --- /dev/null +++ b/cpp/core/internal/wifi_lan_endpoint_channel_v2.h @@ -0,0 +1,43 @@ +// 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. + +#ifndef CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_V2_H_ +#define CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_V2_H_ + +#include "core/internal/base_endpoint_channel.h" +#include "platform/public/wifi_lan_v2.h" + +namespace location { +namespace nearby { +namespace connections { + +class WifiLanEndpointChannelV2 final : public BaseEndpointChannel { + public: + // Creates both outgoing and incoming WifiLan channels. + WifiLanEndpointChannelV2(const std::string& channel_name, + WifiLanSocketV2 socket); + + proto::connections::Medium GetMedium() const override; + + private: + void CloseImpl() override; + + WifiLanSocketV2 socket_; +}; + +} // namespace connections +} // namespace nearby +} // namespace location + +#endif // CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_V2_H_ diff --git a/cpp/platform/api/platform.h b/cpp/platform/api/platform.h index 6cf54cae..5224d0d4 100644 --- a/cpp/platform/api/platform.h +++ b/cpp/platform/api/platform.h @@ -41,6 +41,7 @@ #include "platform/api/webrtc.h" #include "platform/api/wifi.h" #include "platform/api/wifi_lan.h" +#include "platform/api/wifi_lan_v2.h" #include "platform/base/payload_id.h" namespace location { @@ -101,6 +102,7 @@ class ImplementationPlatform { static std::unique_ptr CreateServerSyncMedium(); static std::unique_ptr CreateWifiMedium(); static std::unique_ptr CreateWifiLanMedium(); + static std::unique_ptr CreateWifiLanMediumV2(); static std::unique_ptr CreateWebRtcMedium(); }; diff --git a/cpp/platform/api/wifi_lan_v2.h b/cpp/platform/api/wifi_lan_v2.h index 56c1076e..12c1106c 100644 --- a/cpp/platform/api/wifi_lan_v2.h +++ b/cpp/platform/api/wifi_lan_v2.h @@ -27,19 +27,6 @@ namespace location { namespace nearby { namespace api { -// Opaque wrapper over a WifiLan service which contains |NsdServiceInfo|. -class WifiLanServiceV2 { - public: - virtual ~WifiLanServiceV2() = default; - - // Returns the |NsdServiceInfo| which contains the packed string of - // |WifiLanServiceInfo| and the endpoint info with named key in a TXTRecord - // map. - // The details refer to - // https://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html. - virtual NsdServiceInfo GetServiceInfo() const = 0; -}; - class WifiLanSocketV2 { public: virtual ~WifiLanSocketV2() = default; @@ -60,15 +47,11 @@ class WifiLanSocketV2 { // Returns Exception::kIo on error, Exception::kSuccess otherwise. virtual Exception Close() = 0; - - // Returns valid WifiLanService pointer if there is a connection, and - // nullptr otherwise. - virtual WifiLanServiceV2* GetRemoteService() = 0; }; -class WifiLanServerSocket { +class WifiLanServerSocketV2 { public: - virtual ~WifiLanServerSocket() = default; + virtual ~WifiLanServerSocketV2() = default; // Returns ip address. virtual std::string GetIpAddress() = 0; @@ -114,35 +97,45 @@ 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. // - // Returns uuid once the WifiLan discovery has been initiated. The uuid - // returned is corresponding to callback, if pass the same callback without - // StopDiscovery in advance, then there will be two different uuids correspond - // to the same callback instance, which might cause unexpected behavior. - // Returns uuid if discovery started successfully. - // Returns 0 if discovery started unsuccessfully. - virtual int StartDiscovery(DiscoveredServiceCallback callback) = 0; + // service_type - mDNS service type. + // callback - the instance of DiscoveredServiceCallback. + // Returns true once the WifiLan discovery has been initiated. The + // service_type is associated with callback. + virtual bool StartDiscovery(const std::string& service_type, + DiscoveredServiceCallback callback) = 0; // Stops the discovery of nearby WifiLan services. // - // uuid - The one returned from StartDiscovery. - // On success if uuid is matched to the callback and will be removed from the - // list. If list is empty then stops the WifiLan discovery service. - // On error if the uuid is not existed, then return immediately. - virtual bool StopDiscovery(int uuid) = 0; + // service_type - The one assigned in StartDiscovery. + // On success if the service_type is matched to the callback and will be + // removed from the list. If list is empty then stops the WifiLan + // discovery service. + // On error if the service_type is not existed, then return immediately. + virtual bool StopDiscovery(const std::string& service_type) = 0; // Connects to a WifiLan service. // On success, returns a new WifiLanSocket. // On error, returns nullptr. virtual std::unique_ptr ConnectToService( - WifiLanServiceV2& remote_service, + NsdServiceInfo& remote_service_info, + CancellationFlag* cancellation_flag) = 0; + + // Connects to a WifiLan service by ip address and port. + // On success, returns a new WifiLanSocket. + // On error, returns nullptr. + virtual std::unique_ptr ConnectToService( + const std::string& ip_address, int port, CancellationFlag* cancellation_flag) = 0; // Listens for incoming connection. @@ -152,11 +145,8 @@ class WifiLanMediumV2 { // 1~65536 : open a server socket on that exact port. // On success, returns a new WifiLanServerSocket. // On error, returns nullptr. - virtual std::unique_ptr ListenForService( + virtual std::unique_ptr ListenForService( int port = 0) = 0; - - virtual WifiLanServiceV2* GetRemoteService(const std::string& ip_address, - int port) = 0; }; } // namespace api diff --git a/cpp/platform/impl/g3/BUILD b/cpp/platform/impl/g3/BUILD index d2588be3..462c3da1 100644 --- a/cpp/platform/impl/g3/BUILD +++ b/cpp/platform/impl/g3/BUILD @@ -57,6 +57,7 @@ cc_library( "bluetooth_classic.cc", "webrtc.cc", "wifi_lan.cc", + "wifi_lan_v2.cc", ], hdrs = [ "ble.h", @@ -64,6 +65,7 @@ cc_library( "bluetooth_classic.h", "webrtc.h", "wifi_lan.h", + "wifi_lan_v2.h", ], visibility = ["//visibility:private"], deps = [ diff --git a/cpp/platform/impl/g3/platform.cc b/cpp/platform/impl/g3/platform.cc index 470af01d..143e20c6 100644 --- a/cpp/platform/impl/g3/platform.cc +++ b/cpp/platform/impl/g3/platform.cc @@ -49,6 +49,7 @@ #include "platform/impl/g3/single_thread_executor.h" #include "platform/impl/g3/webrtc.h" #include "platform/impl/g3/wifi_lan.h" +#include "platform/impl/g3/wifi_lan_v2.h" #include "platform/impl/shared/file.h" namespace location { @@ -146,6 +147,11 @@ std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { return absl::make_unique(); } +std::unique_ptr +ImplementationPlatform::CreateWifiLanMediumV2() { + return absl::make_unique(); +} + std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { return absl::make_unique(); diff --git a/cpp/platform/impl/g3/wifi_lan_v2.cc b/cpp/platform/impl/g3/wifi_lan_v2.cc new file mode 100644 index 00000000..f6d5233f --- /dev/null +++ b/cpp/platform/impl/g3/wifi_lan_v2.cc @@ -0,0 +1,176 @@ +// 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 "platform/impl/g3/wifi_lan_v2.h" + +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "platform/api/wifi_lan_v2.h" +#include "platform/base/cancellation_flag_listener.h" +#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 { +namespace g3 { + +WifiLanSocketV2::~WifiLanSocketV2() { + absl::MutexLock lock(&mutex_); + DoClose(); +} + +void WifiLanSocketV2::Connect(WifiLanSocketV2& other) { + absl::MutexLock lock(&mutex_); + remote_socket_ = &other; + input_ = other.output_; +} + +InputStream& WifiLanSocketV2::GetInputStream() { + auto* remote_socket = GetRemoteSocket(); + CHECK(remote_socket != nullptr); + return remote_socket->GetLocalInputStream(); +} + +OutputStream& WifiLanSocketV2::GetOutputStream() { + return GetLocalOutputStream(); +} + +WifiLanSocketV2* WifiLanSocketV2::GetRemoteSocket() { + absl::MutexLock lock(&mutex_); + return remote_socket_; +} + +bool WifiLanSocketV2::IsConnected() const { + absl::MutexLock lock(&mutex_); + return IsConnectedLocked(); +} + +bool WifiLanSocketV2::IsClosed() const { + absl::MutexLock lock(&mutex_); + return closed_; +} + +Exception WifiLanSocketV2::Close() { + absl::MutexLock lock(&mutex_); + DoClose(); + return {Exception::kSuccess}; +} + +void WifiLanSocketV2::DoClose() { + if (!closed_) { + remote_socket_ = nullptr; + output_->GetOutputStream().Close(); + output_->GetInputStream().Close(); + if (IsConnectedLocked()) { + input_->GetOutputStream().Close(); + input_->GetInputStream().Close(); + } + closed_ = true; + } +} + +bool WifiLanSocketV2::IsConnectedLocked() const { return input_ != nullptr; } + +InputStream& WifiLanSocketV2::GetLocalInputStream() { + absl::MutexLock lock(&mutex_); + return output_->GetInputStream(); +} + +OutputStream& WifiLanSocketV2::GetLocalOutputStream() { + absl::MutexLock lock(&mutex_); + return output_->GetOutputStream(); +} + +std::string WifiLanServerSocketV2::GetIpAddress() { + absl::MutexLock lock(&mutex_); + return {}; +} + +int WifiLanServerSocketV2::GetPort() { + absl::MutexLock lock(&mutex_); + return 0; +} + +std::unique_ptr WifiLanServerSocketV2::Accept() { + absl::MutexLock lock(&mutex_); + return nullptr; +} + +bool WifiLanServerSocketV2::Connect(WifiLanSocketV2& socket) { + absl::MutexLock lock(&mutex_); + return true; +} + +void WifiLanServerSocketV2::SetCloseNotifier(std::function notifier) { + absl::MutexLock lock(&mutex_); +} + +WifiLanServerSocketV2::~WifiLanServerSocketV2() { + absl::MutexLock lock(&mutex_); + DoClose(); +} + +Exception WifiLanServerSocketV2::Close() { + absl::MutexLock lock(&mutex_); + return DoClose(); +} + +Exception WifiLanServerSocketV2::DoClose() { return {Exception::kSuccess}; } + +WifiLanMediumV2::WifiLanMediumV2() {} + +WifiLanMediumV2::~WifiLanMediumV2() {} + +bool WifiLanMediumV2::StartAdvertising(const NsdServiceInfo& nsd_service_info) { + return true; +} + +bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { + return true; +} + +bool WifiLanMediumV2::StartDiscovery(const std::string& service_type, + DiscoveredServiceCallback callback) { + return false; +} + +bool WifiLanMediumV2::StopDiscovery(const std::string& service_type) { + return false; +} + +std::unique_ptr WifiLanMediumV2::ConnectToService( + NsdServiceInfo& remote_service_info, CancellationFlag* cancellation_flag) { + return nullptr; +} + +std::unique_ptr WifiLanMediumV2::ConnectToService( + const std::string& ip_address, int port, + CancellationFlag* cancellation_flag) { + return nullptr; +} + +std::unique_ptr WifiLanMediumV2::ListenForService( + int port) { + return {}; +} + +} // 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 new file mode 100644 index 00000000..f852689b --- /dev/null +++ b/cpp/platform/impl/g3/wifi_lan_v2.h @@ -0,0 +1,237 @@ +// 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. + +#ifndef PLATFORM_IMPL_G3_WIFI_LAN_V2_H_ +#define PLATFORM_IMPL_G3_WIFI_LAN_V2_H_ + +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/synchronization/mutex.h" +#include "platform/api/wifi_lan_v2.h" +#include "platform/base/byte_array.h" +#include "platform/base/input_stream.h" +#include "platform/base/nsd_service_info.h" +#include "platform/base/output_stream.h" +#include "platform/impl/g3/multi_thread_executor.h" +#include "platform/impl/g3/pipe.h" + +namespace location { +namespace nearby { +namespace g3 { + +class WifiLanMediumV2; + +class WifiLanSocketV2 : public api::WifiLanSocketV2 { + public: + WifiLanSocketV2() = default; + ~WifiLanSocketV2() override; + + // Connect to another WifiLanSocket, to form a functional low-level channel. + // from this point on, and until Close is called, connection exists. + void Connect(WifiLanSocketV2& other) ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns the InputStream of this connected WifiLanSocket. + InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns the OutputStream of this connected WifiLanSocket. + // This stream is for local side to write. + OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns address of a remote WifiLanSocket or nullptr. + WifiLanSocketV2* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns true if connection exists to the (possibly closed) remote socket. + bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns true if socket is closed. + bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + private: + void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Returns true if connection exists to the (possibly closed) remote socket. + bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Returns InputStream of our side of a connection. + // This is what the remote side is supposed to read from. + // This is a helper for GetInputStream() method. + InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns OutputStream of our side of a connection. + // This is what the local size is supposed to write to. + // This is a helper for GetOutputStream() method. + OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_); + + // Output pipe is initialized by constructor, it remains always valid, until + // it is closed. it represents output part of a local socket. Input part of a + // local socket comes from the peer socket, after connection. + std::shared_ptr output_{new Pipe}; + std::shared_ptr input_; + mutable absl::Mutex mutex_; + WifiLanSocketV2* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; +}; + +class WifiLanServerSocketV2 : public api::WifiLanServerSocketV2 { + public: + ~WifiLanServerSocketV2() override; + + // Returns ip address. + std::string GetIpAddress() override ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns port. + int GetPort() override ABSL_LOCKS_EXCLUDED(mutex_); + + // Blocks until either: + // - at least one incoming connection request is available, or + // - ServerSocket is closed. + // On success, returns connected socket, ready to exchange data. + // Returns nullptr on error. + // Once error is reported, it is permanent, and ServerSocket has to be closed. + // + // Called by the server side of a connection. + // Returns WifiLanSocket to the server side. + // If not null, returned socket is connected to its remote (client-side) peer. + std::unique_ptr Accept() override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Blocks until either: + // - connection is available, or + // - server socket is closed, or + // - error happens. + // + // Called by the client side of a connection. + // Returns true, if socket is successfully connected. + bool Connect(WifiLanSocketV2& socket) ABSL_LOCKS_EXCLUDED(mutex_); + + // Called by the server side of a connection before passing ownership of + // WifiLanServerSocker to user, to track validity of a pointer to this + // server socket. + void SetCloseNotifier(std::function notifier) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + // Calls close_notifier if it was previously set, and marks socket as closed. + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + private: + Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + absl::Mutex mutex_; +}; + +// Container of operations that can be performed over the WifiLan medium. +class WifiLanMediumV2 : public api::WifiLanMediumV2 { + public: + WifiLanMediumV2(); + ~WifiLanMediumV2() override; + + // Starts WifiLan advertising. + // + // nsd_service_info - NsdServiceInfo data that's advertised through mDNS + // service. + // On success if the service is now advertising. + // On error if the service cannot start to advertise or the service type in + // NsdServiceInfo has been passed previously which StopAdvertising is not + // been called. + bool StartAdvertising(const NsdServiceInfo& nsd_service_info) override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Stops WifiLan advertising. + // + // nsd_service_info - NsdServiceInfo data that's advertised through mDNS + // service. + // On success if the service stops advertising. + // On error if the service cannot stop advertising or the service type in + // NsdServiceInfo cannot be found. + bool StopAdvertising(const NsdServiceInfo& nsd_service_info) override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Starts the discovery of nearby WifiLan services. + // + // Returns true once the WifiLan discovery has been initiated. The + // service_type is associated with callback. + bool StartDiscovery(const std::string& service_type, + DiscoveredServiceCallback callback) override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Stops the discovery of nearby WifiLan services. + // + // service_type - The one assigend in StartDiscovery. + // On success if service_type is matched to the callback and will be removed + // from the list. If list is empty then stops the WifiLan discovery + // service. + // On error if the service_type is not existed, then return immediately. + bool StopDiscovery(const std::string& service_type) override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Connects to a WifiLan service. + // On success, returns a new WifiLanSocket. + // On error, returns nullptr. + std::unique_ptr ConnectToService( + NsdServiceInfo& remote_service_info, + CancellationFlag* cancellation_flag) override; + + // Connects to a WifiLan service by ip address and port. + // On success, returns a new WifiLanSocket. + // On error, returns nullptr. + std::unique_ptr ConnectToService( + const std::string& ip_address, int port, + CancellationFlag* cancellation_flag) override; + + // Listens for incoming connection. + // + // port - A port number. + // 0 : use a random port. + // 1~65536 : open a server socket on that exact port. + // On success, returns a new WifiLanServerSocket. + // On error, returns nullptr. + std::unique_ptr ListenForService( + int port = 0) override; + + private: + static constexpr int kMaxConcurrentAcceptLoops = 5; + + struct AdvertisingInfo { + bool Empty() const { return service_id.empty(); } + void Clear() { service_id.clear(); } + + std::string service_id; + }; + + 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_; +}; + +} // namespace g3 +} // namespace nearby +} // namespace location + +#endif // PLATFORM_IMPL_G3_WIFI_LAN_V2_H_ diff --git a/cpp/platform/impl/windows/platform.cc b/cpp/platform/impl/windows/platform.cc index 4a1eca8f..01bf64f1 100644 --- a/cpp/platform/impl/windows/platform.cc +++ b/cpp/platform/impl/windows/platform.cc @@ -144,6 +144,12 @@ std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { return absl::make_unique(); } +// TODO(b/184975123): replace with real implementation. +std::unique_ptr +ImplementationPlatform::CreateWifiLanMediumV2() { + return std::unique_ptr(); +} + // TODO(b/184975123): replace with real implementation. std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { return absl::make_unique(); diff --git a/cpp/platform/public/BUILD b/cpp/platform/public/BUILD index d1e122de..57b1eaba 100644 --- a/cpp/platform/public/BUILD +++ b/cpp/platform/public/BUILD @@ -78,6 +78,7 @@ cc_library( "bluetooth_classic.cc", "file.cc", "wifi_lan.cc", + "wifi_lan_v2.cc", ], hdrs = [ "ble.h", @@ -85,6 +86,7 @@ cc_library( "bluetooth_classic.h", "webrtc.h", "wifi_lan.h", + "wifi_lan_v2.h", ], compatible_with = ["//buildenv/target:non_prod"], copts = ["-DCORE_ADAPTER_DLL"], diff --git a/cpp/platform/public/wifi_lan_v2.cc b/cpp/platform/public/wifi_lan_v2.cc new file mode 100644 index 00000000..e2388068 --- /dev/null +++ b/cpp/platform/public/wifi_lan_v2.cc @@ -0,0 +1,51 @@ +// 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 "platform/public/wifi_lan_v2.h" + +#include "platform/public/mutex_lock.h" + +namespace location { +namespace nearby { + +bool WifiLanMediumV2::StartAdvertising(const NsdServiceInfo& nsd_service_info) { + return false; +} + +bool WifiLanMediumV2::StopAdvertising(const NsdServiceInfo& nsd_service_info) { + return false; +} + +bool WifiLanMediumV2::StartDiscovery(const std::string& service_type, + DiscoveredServiceCallback callback) { + return false; +} + +bool WifiLanMediumV2::StopDiscovery(const std::string& service_type) { + return false; +} + +WifiLanSocketV2 WifiLanMediumV2::ConnectToService( + NsdServiceInfo remote_service_info, CancellationFlag* cancellation_flag) { + return {}; +} + +WifiLanSocketV2 WifiLanMediumV2::ConnectToService( + const std::string& ip_address, int port, + CancellationFlag* cancellation_flag) { + return {}; +} + +} // namespace nearby +} // namespace location diff --git a/cpp/platform/public/wifi_lan_v2.h b/cpp/platform/public/wifi_lan_v2.h new file mode 100644 index 00000000..3c5d1385 --- /dev/null +++ b/cpp/platform/public/wifi_lan_v2.h @@ -0,0 +1,209 @@ +// 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. + +#ifndef PLATFORM_PUBLIC_WIFI_LAN_V2_H_ +#define PLATFORM_PUBLIC_WIFI_LAN_V2_H_ + +#include "absl/container/flat_hash_map.h" +#include "platform/api/platform.h" +#include "platform/api/wifi_lan_v2.h" +#include "platform/base/byte_array.h" +#include "platform/base/cancellation_flag.h" +#include "platform/base/input_stream.h" +#include "platform/base/nsd_service_info.h" +#include "platform/base/output_stream.h" +#include "platform/public/logging.h" +#include "platform/public/mutex.h" + +namespace location { +namespace nearby { + +class WifiLanSocketV2 final { + public: + WifiLanSocketV2() = default; + WifiLanSocketV2(const WifiLanSocketV2&) = default; + WifiLanSocketV2& operator=(const WifiLanSocketV2&) = default; + ~WifiLanSocketV2() = default; + explicit WifiLanSocketV2(std::unique_ptr socket) + : impl_(std::move(socket)) {} + + // Returns the InputStream of the WifiLanSocket. + // On error, returned stream will report Exception::kIo on any operation. + // + // The returned object is not owned by the caller, and can be invalidated once + // the WifiLanSocket object is destroyed. + InputStream& GetInputStream() { return impl_->GetInputStream(); } + + // Returns the OutputStream of the WifiLanSocket. + // On error, returned stream will report Exception::kIo on any operation. + // + // The returned object is not owned by the caller, and can be invalidated once + // the WifiLanSocket object is destroyed. + OutputStream& GetOutputStream() { return impl_->GetOutputStream(); } + + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() { return impl_->Close(); } + + // Returns true if a socket is usable. If this method returns false, + // it is not safe to call any other method. + // NOTE(socket validity): + // Socket created by a default public constructor is not valid, because + // it is missing platform implementation. + // The only way to obtain a valid socket is through connection, such as + // an object returned by WifiLanMedium::Connect + // These methods may also return an invalid socket if connection failed for + // any reason. + bool IsValid() const { return impl_ != nullptr; } + + // Returns reference to platform implementation. + // This is used to communicate with platform code, and for debugging purposes. + // Returned reference will remain valid for while WifiLanSocket object is + // itself valid. Typically WifiLanSocket lifetime matches duration of the + // connection, and is controlled by end user, since they hold the instance. + api::WifiLanSocketV2& GetImpl() { return *impl_; } + + private: + std::shared_ptr impl_; +}; + +class WifiLanServerSocketV2 final { + public: + WifiLanServerSocketV2() = default; + WifiLanServerSocketV2(const WifiLanServerSocketV2&) = default; + WifiLanServerSocketV2& operator=(const WifiLanServerSocketV2&) = default; + ~WifiLanServerSocketV2() = default; + explicit WifiLanServerSocketV2( + std::unique_ptr socket) + : impl_(std::move(socket)) {} + + // Returns ip address. + std::string GetIpAddress() { return impl_->GetIpAddress(); } + + // Returns port. + int GetPort() { return impl_->GetPort(); } + + // Blocks until either: + // - at least one incoming connection request is available, or + // - ServerSocket is closed. + // On success, returns connected socket, ready to exchange data. + // Returns nullptr on error. + // Once error is reported, it is permanent, and ServerSocket has to be closed. + WifiLanSocketV2 Accept() { + std::unique_ptr socket = impl_->Accept(); + if (!socket) { + NEARBY_LOGS(INFO) + << "WifiLanServerSocket Accept() failed on server socket: " << this; + } + return WifiLanSocketV2(std::move(socket)); + } + + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() { + NEARBY_LOGS(INFO) << "WifiLanServerSocket Closing:: " << this; + return impl_->Close(); + } + + bool IsValid() const { return impl_ != nullptr; } + api::WifiLanServerSocketV2& GetImpl() { return *impl_; } + + private: + std::shared_ptr impl_; +}; + +// Container of operations that can be performed over the WifiLan medium. +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 + service_discovered_cb = + DefaultCallback(); + std::function + service_lost_cb = DefaultCallback(); + }; + + struct DiscoveryCallbackInfo { + DiscoveredServiceCallback medium_callback; + }; + + WifiLanMediumV2() : impl_(Platform::CreateWifiLanMediumV2()) {} + ~WifiLanMediumV2() = default; + + // Starts WifiLan advertising. + // + // nsd_service_info - NsdServiceInfo data that's advertised through mDNS + // service. + // On success if the service is now advertising. + // On error if the service cannot start to advertise or the nsd_type in + // NsdServiceInfo has been passed previously which StopAdvertising is not + // been called. + bool StartAdvertising(const NsdServiceInfo& nsd_service_info); + + // Stops WifiLan advertising. + // + // nsd_service_info - NsdServiceInfo data that's advertised through mDNS + // service. + // On success if the service stops advertising. + // On error if the service cannot stop advertising or the nsd_type in + // NsdServiceInfo cannot be found. + bool StopAdvertising(const NsdServiceInfo& nsd_service_info); + + // Returns true once the WifiLan discovery has been initiated. + bool StartDiscovery(const std::string& service_type, + DiscoveredServiceCallback callback); + + // Returns true once service_type is associated to existing callback. If the + // callback is the last found then WifiLan discovery will be stopped. + bool StopDiscovery(const std::string& service_type); + + // Returns a new WifiLanSocket. + // On Success, WifiLanSocket::IsValid() returns true. + WifiLanSocketV2 ConnectToService(NsdServiceInfo remote_service_info, + CancellationFlag* cancellation_flag); + + // Returns a new WifiLanSocket by ip address and port. + // On Success, WifiLanSocket::IsValid()returns true. + WifiLanSocketV2 ConnectToService(const std::string& ip_address, int port, + CancellationFlag* cancellation_flag); + + // Returns a new WifiLanServerSocket. + // On Success, WifiLanServerSocket::IsValid() returns true. + WifiLanServerSocketV2 ListenForService(int port) { + return WifiLanServerSocketV2(impl_->ListenForService(port)); + } + + bool IsValid() const { return impl_ != nullptr; } + + api::WifiLanMediumV2& GetImpl() { return *impl_; } + + private: + Mutex mutex_; + std::unique_ptr impl_; + absl::flat_hash_map> + discovery_callbacks_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_PUBLIC_WIFI_LAN_V2_H_