From b6b692b0eac9c6af15bb57ada3ce05e32361be04 Mon Sep 17 00:00:00 2001 From: Suet-Fei Li Date: Mon, 31 Oct 2022 09:11:40 -0700 Subject: [PATCH] WIFI Direct implementation (1) Part 1: Implement internal common code Add implementation/g3 skeleton code for testing coverage. PiperOrigin-RevId: 485067018 --- Package.swift | 1 + internal/platform/BUILD | 3 + internal/platform/implementation/BUILD | 1 + internal/platform/implementation/g3/BUILD | 2 + .../platform/implementation/g3/platform.cc | 6 ++ .../platform/implementation/g3/wifi_direct.cc | 64 +++++++++++++ .../platform/implementation/g3/wifi_direct.h | 88 ++++++++++++++++++ .../platform/implementation/ios/platform.mm | 4 + internal/platform/implementation/platform.h | 2 + .../platform/implementation/wifi_direct.h | 76 +++++++++++++++ .../implementation/windows/platform.cc | 6 ++ internal/platform/wifi_direct.cc | 32 +++++++ internal/platform/wifi_direct.h | 92 +++++++++++++++++++ internal/platform/wifi_direct_test.cc | 71 ++++++++++++++ 14 files changed, 448 insertions(+) create mode 100644 internal/platform/implementation/g3/wifi_direct.cc create mode 100644 internal/platform/implementation/g3/wifi_direct.h create mode 100644 internal/platform/implementation/wifi_direct.h create mode 100644 internal/platform/wifi_direct.cc create mode 100644 internal/platform/wifi_direct.h create mode 100644 internal/platform/wifi_direct_test.cc diff --git a/Package.swift b/Package.swift index d23c8661..ae16f6fe 100644 --- a/Package.swift +++ b/Package.swift @@ -479,6 +479,7 @@ let package = Package( "internal/platform/count_down_latch_test.cc", "internal/platform/pipe_test.cc", "internal/platform/uuid_test.cc", + "internal/platform/wifi_direct_test.cc", "internal/platform/wifi_hotspot_test.cc", "internal/platform/wifi_lan_test.cc", "internal/platform/wifi_test.cc", diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 75f15f35..30c400fa 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -365,6 +365,7 @@ cc_library( "bluetooth_classic.cc", "credential_storage_impl.cc", "file.cc", + "wifi_direct.cc", "wifi_hotspot.cc", "wifi_lan.cc", "wifi_utils.cc", @@ -376,6 +377,7 @@ cc_library( "bluetooth_classic.h", "credential_storage_impl.h", "wifi.h", + "wifi_direct.h", "wifi_hotspot.h", "wifi_lan.h", "wifi_utils.h", @@ -431,6 +433,7 @@ cc_test( "scheduled_executor_test.cc", "single_thread_executor_test.cc", "uuid_test.cc", + "wifi_direct_test.cc", "wifi_hotspot_test.cc", "wifi_lan_test.cc", "wifi_test.cc", diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index f28f9005..5a91f916 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -61,6 +61,7 @@ cc_library( "credential_storage.h", "server_sync.h", "wifi.h", + "wifi_direct.h", "wifi_hotspot.h", "wifi_lan.h", ], diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index cdd33e18..242a0e47 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -57,6 +57,7 @@ cc_library( "bluetooth_adapter.cc", "bluetooth_classic.cc", "credential_storage_impl.cc", + "wifi_direct.cc", "wifi_hotspot.cc", "wifi_lan.cc", ], @@ -66,6 +67,7 @@ cc_library( "bluetooth_adapter.h", "bluetooth_classic.h", "credential_storage_impl.h", + "wifi_direct.h", "wifi_hotspot.h", "wifi_lan.h", ], diff --git a/internal/platform/implementation/g3/platform.cc b/internal/platform/implementation/g3/platform.cc index a95385ca..3871947d 100644 --- a/internal/platform/implementation/g3/platform.cc +++ b/internal/platform/implementation/g3/platform.cc @@ -51,6 +51,7 @@ #include "internal/platform/implementation/g3/mutex.h" #include "internal/platform/implementation/g3/scheduled_executor.h" #include "internal/platform/implementation/g3/single_thread_executor.h" +#include "internal/platform/implementation/g3/wifi_direct.h" #include "internal/platform/implementation/g3/wifi_hotspot.h" #include "internal/platform/implementation/g3/wifi_lan.h" #include "internal/platform/implementation/shared/file.h" @@ -183,6 +184,11 @@ ImplementationPlatform::CreateWifiHotspotMedium() { return std::make_unique(); } +std::unique_ptr +ImplementationPlatform::CreateWifiDirectMedium() { + return std::make_unique(); +} + #ifndef NO_WEBRTC std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { diff --git a/internal/platform/implementation/g3/wifi_direct.cc b/internal/platform/implementation/g3/wifi_direct.cc new file mode 100644 index 00000000..a0e8b4e6 --- /dev/null +++ b/internal/platform/implementation/g3/wifi_direct.cc @@ -0,0 +1,64 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/g3/wifi_direct.h" + +#include +#include +#include +#include +#include +#include + +#include "absl/strings/str_format.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/cancellation_flag_listener.h" +#include "internal/platform/implementation/g3/wifi_hotspot.h" +#include "internal/platform/implementation/wifi_direct.h" +#include "internal/platform/implementation/wifi_hotspot.h" +#include "internal/platform/logging.h" + +namespace location { +namespace nearby { +namespace g3 { +bool WifiDirectMedium::StartWifiDirect( + HotspotCredentials* wifi_direct_credentials) { + return true; +} + +bool WifiDirectMedium::StopWifiDirect() { + absl::MutexLock lock(&mutex_); + return true; +} + +bool WifiDirectMedium::ConnectWifiDirect( + HotspotCredentials* wifi_direct_credentials) { + return true; +} + +bool WifiDirectMedium::DisconnectWifiDirect() { return true; } + +std::unique_ptr WifiDirectMedium::ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag* cancellation_flag) { + return nullptr; +} + +std::unique_ptr +WifiDirectMedium::ListenForService(int port) { + return nullptr; +} +} // namespace g3 +} // namespace nearby +} // namespace location diff --git a/internal/platform/implementation/g3/wifi_direct.h b/internal/platform/implementation/g3/wifi_direct.h new file mode 100644 index 00000000..7733326d --- /dev/null +++ b/internal/platform/implementation/g3/wifi_direct.h @@ -0,0 +1,88 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_G3_WIFI_DIRECT_H_ +#define PLATFORM_IMPL_G3_WIFI_DIRECT_H_ + +#include +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/g3/multi_thread_executor.h" +#include "internal/platform/implementation/g3/pipe.h" +#include "internal/platform/implementation/g3/wifi_hotspot.h" +#include "internal/platform/implementation/wifi_direct.h" +#include "internal/platform/implementation/wifi_hotspot.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" + +namespace location { +namespace nearby { +namespace g3 { + +class WifiDirectMedium; + +// Container of operations that can be performed over the WifiDirect medium. +class WifiDirectMedium : public api::WifiDirectMedium { + public: + WifiDirectMedium() = default; + ~WifiDirectMedium() override = default; + + WifiDirectMedium(const WifiDirectMedium&) = delete; + WifiDirectMedium(WifiDirectMedium&&) = delete; + WifiDirectMedium& operator=(const WifiDirectMedium&) = delete; + WifiDirectMedium& operator=(WifiDirectMedium&&) = delete; + + // If the WiFi Adaptor supports to start a WifiDirect interface. + bool IsInterfaceValid() const override { return true; } + + // Discoverer connects to server socket + std::unique_ptr ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag* cancellation_flag) override; + + // Advertiser starts to listen on server socket + std::unique_ptr ListenForService( + int port) override; + + // Advertiser start WiFiDirect GO with specific Crendentials + bool StartWifiDirect(HotspotCredentials* wifi_direct_credentials) override; + // Advertiser stop the current WiFiDirect GO + bool StopWifiDirect() override; + // Discoverer connects to the WiFiDirect GO + bool ConnectWifiDirect(HotspotCredentials* wifi_direct_credentials) override; + // Discoverer disconnects from the WiFiDirect GO + bool DisconnectWifiDirect() override; + + std::optional> GetDynamicPortRange() + override { + return std::nullopt; + } + + private: + absl::Mutex mutex_; + + absl::flat_hash_map server_sockets_ + ABSL_GUARDED_BY(mutex_); +}; + +} // namespace g3 +} // namespace nearby +} // namespace location + +#endif // PLATFORM_IMPL_G3_WIFI_DIRECT_H_ diff --git a/internal/platform/implementation/ios/platform.mm b/internal/platform/implementation/ios/platform.mm index f0519111..1423302c 100644 --- a/internal/platform/implementation/ios/platform.mm +++ b/internal/platform/implementation/ios/platform.mm @@ -150,6 +150,10 @@ std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedi return nullptr; } +std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { + return nullptr; +} + #ifndef NO_WEBRTC std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { return nullptr; } #endif diff --git a/internal/platform/implementation/platform.h b/internal/platform/implementation/platform.h index df4ac219..f4b826bd 100644 --- a/internal/platform/implementation/platform.h +++ b/internal/platform/implementation/platform.h @@ -43,6 +43,7 @@ #include "internal/platform/implementation/webrtc.h" #endif #include "internal/platform/implementation/wifi.h" +#include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/os_name.h" @@ -122,6 +123,7 @@ class ImplementationPlatform { static std::unique_ptr CreateWifiMedium(); static std::unique_ptr CreateWifiLanMedium(); static std::unique_ptr CreateWifiHotspotMedium(); + static std::unique_ptr CreateWifiDirectMedium(); #ifndef NO_WEBRTC static std::unique_ptr CreateWebRtcMedium(); #endif diff --git a/internal/platform/implementation/wifi_direct.h b/internal/platform/implementation/wifi_direct.h new file mode 100644 index 00000000..03dd94cb --- /dev/null +++ b/internal/platform/implementation/wifi_direct.h @@ -0,0 +1,76 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_API_WIFI_DIRECT_H_ +#define PLATFORM_API_WIFI_DIRECT_H_ + +#include +#include +#include + +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/implementation/wifi_hotspot.h" +#include "internal/platform/wifi_hotspot_credential.h" + +namespace location { +namespace nearby { +namespace api { + +// Container of operations that can be performed over the WifiLan medium. +class WifiDirectMedium { + public: + virtual ~WifiDirectMedium() = default; + + // If the WiFi Adaptor supports to start a WifiDirect interface. + virtual bool IsInterfaceValid() const = 0; + + // Connects to a WifiDirect service by port. + // On success, returns a new WifiDirectSocket. + // On error, returns nullptr. + virtual std::unique_ptr ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag* cancellation_flag) = 0; + + // 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 WifiDirectServerSocket. + // On error, returns nullptr. + virtual std::unique_ptr ListenForService( + int port) = 0; + + // Start a WifiDirect GO with platform dependent APIs and set the + // SSID/password pair back to the credentials. BWU module will retrieve these + // credentials and send to the client device through established channel and + // then client may connect to this WifiDirect GO with these credentials. + virtual bool StartWifiDirect(HotspotCredentials* wifi_direct_credentials) = 0; + virtual bool StopWifiDirect() = 0; + + // Client device connect to a softAP with specified credential. + virtual bool ConnectWifiDirect( + HotspotCredentials* wifi_direct_credentials) = 0; + virtual bool DisconnectWifiDirect() = 0; + + // Returns the port range as a pair of min and max port. + virtual absl::optional> + GetDynamicPortRange() = 0; +}; + +} // namespace api +} // namespace nearby +} // namespace location + +#endif // PLATFORM_API_WIFI_DIRECT_H_ diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index 4b5a3a58..306a49ba 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -406,6 +407,11 @@ ImplementationPlatform::CreateWifiHotspotMedium() { return std::make_unique(); } +std::unique_ptr +ImplementationPlatform::CreateWifiDirectMedium() { + return nullptr; +} + // TODO(b/184975123): replace with real implementation. std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { return absl::make_unique(); diff --git a/internal/platform/wifi_direct.cc b/internal/platform/wifi_direct.cc new file mode 100644 index 00000000..9beb0943 --- /dev/null +++ b/internal/platform/wifi_direct.cc @@ -0,0 +1,32 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/wifi_direct.h" + +#include "internal/platform/wifi_hotspot.h" + +namespace location { +namespace nearby { + +WifiHotspotSocket WifiDirectMedium::ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag* cancellation_flag) { + NEARBY_LOGS(INFO) << "WifiDirectMedium::ConnectToService: ip address=" + << ip_address << ", port=" << port; + return WifiHotspotSocket( + impl_->ConnectToService(ip_address, port, cancellation_flag)); +} + +} // namespace nearby +} // namespace location diff --git a/internal/platform/wifi_direct.h b/internal/platform/wifi_direct.h new file mode 100644 index 00000000..f5d120bb --- /dev/null +++ b/internal/platform/wifi_direct.h @@ -0,0 +1,92 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_PUBLIC_WIFI_DIRECT_H_ +#define PLATFORM_PUBLIC_WIFI_DIRECT_H_ + +#include +#include +#include + +#include "internal/platform/implementation/platform.h" +#include "internal/platform/implementation/wifi_direct.h" +#include "internal/platform/implementation/wifi_hotspot.h" +#include "internal/platform/mutex_lock.h" +#include "internal/platform/wifi_hotspot.h" +#include "internal/platform/wifi_hotspot_credential.h" + +namespace location { +namespace nearby { + +// Container of operations that can be performed over the WifiLan medium. +class WifiDirectMedium { + public: + using Platform = api::ImplementationPlatform; + + WifiDirectMedium() : impl_(Platform::CreateWifiDirectMedium()) {} + ~WifiDirectMedium() = default; + + // Returns a new WifiDirectSocket by ip address and port. + // On Success, WifiDirectSocket::IsValid() returns true. + WifiHotspotSocket ConnectToService(absl::string_view ip_address, int port, + CancellationFlag* cancellation_flag); + + // Returns a new WifiDirectServerSocket. + // On Success, WifiDirectServerSocket::IsValid() returns true. + WifiHotspotServerSocket ListenForService(int port = 0) { + return WifiHotspotServerSocket(impl_->ListenForService(port)); + } + + // Returns the port range as a pair of min and max port. + absl::optional> GetDynamicPortRange() { + return impl_->GetDynamicPortRange(); + } + + bool StartWifiDirect() { + MutexLock lock(&mutex_); + return impl_->StartWifiDirect(&wifi_direct_credentials_); + } + bool StopWifiDirect() { return impl_->StopWifiDirect(); } + + bool ConnectWifiDirect(absl::string_view ssid, absl::string_view password) { + MutexLock lock(&mutex_); + wifi_direct_credentials_.SetSSID(std::string(ssid)); + wifi_direct_credentials_.SetPassword(std::string(password)); + return impl_->ConnectWifiDirect(&wifi_direct_credentials_); + } + bool DisconnectWifiDirect() { return impl_->DisconnectWifiDirect(); } + + HotspotCredentials* GetCredential() { return &wifi_direct_credentials_; } + + bool IsInterfaceValid() const { + CHECK(impl_); + return impl_->IsInterfaceValid(); + } + + bool IsValid() const { return impl_ != nullptr; } + api::WifiDirectMedium& GetImpl() { + CHECK(impl_); + return *impl_; + } + + private: + Mutex mutex_; + std::unique_ptr impl_; + HotspotCredentials wifi_direct_credentials_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace nearby +} // namespace location + +#endif // PLATFORM_PUBLIC_WIFI_DIRECT_H_ diff --git a/internal/platform/wifi_direct_test.cc b/internal/platform/wifi_direct_test.cc new file mode 100644 index 00000000..32274b17 --- /dev/null +++ b/internal/platform/wifi_direct_test.cc @@ -0,0 +1,71 @@ +// 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 "internal/platform/wifi_direct.h" + +#include +#include + +#include "gtest/gtest.h" +#include "internal/platform/wifi_hotspot.h" +#include "internal/platform/wifi_hotspot_credential.h" + +namespace location { +namespace nearby { +namespace { +constexpr absl::string_view kSsid = "Direct-357a2d8c"; +constexpr absl::string_view kPassword = "b592f7d3"; +constexpr absl::string_view kIp = "123.234.23.1"; +constexpr const size_t kPort = 20; + +class WifiDirectMediumTest : public ::testing::Test {}; + +TEST_F(WifiDirectMediumTest, ConstructorDestructorWorks) { + auto wifi_direct_a = WifiDirectMedium(); + auto wifi_direct_b = WifiDirectMedium(); + + ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); + ASSERT_TRUE(wifi_direct_b.IsInterfaceValid()); + + // Make sure we can create 2 distinct mediums. + EXPECT_NE(&wifi_direct_a.GetImpl(), &wifi_direct_b.GetImpl()); +} + +TEST_F(WifiDirectMediumTest, CanStartStopDirect) { + auto wifi_direct_a = WifiDirectMedium(); + ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); + EXPECT_TRUE(wifi_direct_a.StartWifiDirect()); + EXPECT_EQ(wifi_direct_a.GetDynamicPortRange(), std::nullopt); + + WifiHotspotServerSocket server_socket = wifi_direct_a.ListenForService(); + EXPECT_FALSE(server_socket.IsValid()); + EXPECT_TRUE(wifi_direct_a.StopWifiDirect()); +} + +TEST_F(WifiDirectMediumTest, CanConnectDisconnectDirect) { + auto wifi_direct_a = WifiDirectMedium(); + + ASSERT_TRUE(wifi_direct_a.IsInterfaceValid()); + EXPECT_TRUE(wifi_direct_a.ConnectWifiDirect(kSsid, kPassword)); + EXPECT_TRUE(wifi_direct_a.DisconnectWifiDirect()); +} + +TEST_F(WifiDirectMediumTest, CanConnectToService) { + auto wifi_direct = WifiDirectMedium(); + CancellationFlag flag; + EXPECT_FALSE(wifi_direct.ConnectToService(kIp, kPort, &flag).IsValid()); +} +} // namespace +} // namespace nearby +} // namespace location