mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Remove the fake Windows WifiDirect implementation files.
PiperOrigin-RevId: 828009506
This commit is contained in:
@@ -220,12 +220,9 @@ cc_library(
|
||||
"preferences_repository.cc",
|
||||
"system_clock.cc",
|
||||
"webrtc.cc",
|
||||
"wifi_direct_medium.cc",
|
||||
"wifi_direct_server_socket.cc",
|
||||
"wifi_direct_service_medium.cc",
|
||||
"wifi_direct_service_server_socket.cc",
|
||||
"wifi_direct_service_socket.cc",
|
||||
"wifi_direct_socket.cc",
|
||||
"wifi_hotspot_medium.cc",
|
||||
"wifi_hotspot_native.cc",
|
||||
"wifi_hotspot_server_socket.cc",
|
||||
@@ -258,7 +255,6 @@ cc_library(
|
||||
"preferences_repository.h",
|
||||
"webrtc.h",
|
||||
"wifi.h",
|
||||
"wifi_direct.h",
|
||||
"wifi_direct_service.h",
|
||||
"wifi_hotspot.h",
|
||||
"wifi_hotspot_native.h",
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
// 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_WINDOWS_WIFI_DIRECT_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_WIFI_DIRECT_H_
|
||||
|
||||
// Windows headers
|
||||
#include <windows.h>
|
||||
#include <wlanapi.h>
|
||||
|
||||
// Standard C/C++ headers
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Nearby connections headers
|
||||
#include "internal/platform/implementation/wifi_direct.h"
|
||||
#include "internal/platform/implementation/windows/scheduled_executor.h"
|
||||
|
||||
// ABSL header
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
// WinRT headers
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.WiFi.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.WiFiDirect.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Connectivity.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Security.Credentials.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Security.Cryptography.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Storage.Streams.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/base.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
using ::winrt::fire_and_forget;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::
|
||||
WiFiDirectAdvertisementListenStateDiscoverability;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectAdvertisementPublisher;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::
|
||||
WiFiDirectAdvertisementPublisherStatus;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::
|
||||
WiFiDirectAdvertisementPublisherStatusChangedEventArgs;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionListener;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionRequest;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::
|
||||
WiFiDirectConnectionRequestedEventArgs;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionStatus;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectDevice;
|
||||
|
||||
using ::winrt::Windows::Devices::WiFi::WiFiAccessStatus;
|
||||
using ::winrt::Windows::Devices::WiFi::WiFiAdapter;
|
||||
using ::winrt::Windows::Devices::WiFi::WiFiAvailableNetwork;
|
||||
using ::winrt::Windows::Devices::WiFi::WiFiConnectionStatus;
|
||||
using ::winrt::Windows::Devices::WiFi::WiFiReconnectionKind;
|
||||
|
||||
using ::winrt::Windows::Devices::Enumeration::DeviceInformation;
|
||||
using ::winrt::Windows::Devices::Enumeration::DeviceInformationPairing;
|
||||
|
||||
using ::winrt::Windows::Storage::Streams::Buffer;
|
||||
using ::winrt::Windows::Storage::Streams::IInputStream;
|
||||
using ::winrt::Windows::Storage::Streams::InputStreamOptions;
|
||||
using ::winrt::Windows::Storage::Streams::IOutputStream;
|
||||
|
||||
using ::winrt::Windows::Security::Credentials::PasswordCredential;
|
||||
using ::winrt::Windows::Security::Cryptography::CryptographicBuffer;
|
||||
|
||||
using ::winrt::Windows::Networking::HostName;
|
||||
using ::winrt::Windows::Networking::HostNameType;
|
||||
using ::winrt::Windows::Networking::Connectivity::ConnectionProfile;
|
||||
using ::winrt::Windows::Networking::Connectivity::ConnectionProfileDeleteStatus;
|
||||
using ::winrt::Windows::Networking::Connectivity::NetworkInformation;
|
||||
using ::winrt::Windows::Networking::Sockets::StreamSocket;
|
||||
using ::winrt::Windows::Networking::Sockets::StreamSocketListener;
|
||||
using ::winrt::Windows::Networking::Sockets::
|
||||
StreamSocketListenerConnectionReceivedEventArgs;
|
||||
|
||||
// WifiDirectSocket wraps the socket functions to read and write stream.
|
||||
// In WifiDirect GO, A WifiDirectSocket will be passed to
|
||||
// StartAcceptingConnections's call back when StreamSocketListener got connect.
|
||||
// When call API to connect to remote WiFi Direct service, also will return a
|
||||
// WifiDirectSocket to caller.
|
||||
class WifiDirectSocket : public api::WifiDirectSocket {
|
||||
public:
|
||||
explicit WifiDirectSocket(StreamSocket socket);
|
||||
WifiDirectSocket(const WifiDirectSocket&) = default;
|
||||
WifiDirectSocket(WifiDirectSocket&&) = default;
|
||||
~WifiDirectSocket() override;
|
||||
WifiDirectSocket& operator=(const WifiDirectSocket&) = default;
|
||||
WifiDirectSocket& operator=(WifiDirectSocket&&) = default;
|
||||
|
||||
// Returns the InputStream of the WifiDirectSocket.
|
||||
// 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 WifiDirectSocket object is destroyed.
|
||||
InputStream& GetInputStream() override;
|
||||
|
||||
// Returns the OutputStream of the WifiDirectSocket.
|
||||
// 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 WifiDirectSocket object is destroyed.
|
||||
OutputStream& GetOutputStream() override;
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
// A simple wrapper to handle input stream of socket
|
||||
class SocketInputStream : public InputStream {
|
||||
public:
|
||||
explicit SocketInputStream(IInputStream input_stream);
|
||||
~SocketInputStream() override = default;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
ExceptionOr<size_t> Skip(size_t offset) override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
IInputStream input_stream_{nullptr};
|
||||
};
|
||||
|
||||
// A simple wrapper to handle output stream of socket
|
||||
class SocketOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit SocketOutputStream(IOutputStream output_stream);
|
||||
~SocketOutputStream() override = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
IOutputStream output_stream_{nullptr};
|
||||
};
|
||||
|
||||
// Internal properties
|
||||
StreamSocket stream_soket_{nullptr};
|
||||
SocketInputStream input_stream_{nullptr};
|
||||
SocketOutputStream output_stream_{nullptr};
|
||||
};
|
||||
|
||||
// WifiDirectServerSocket provides the support to server socket, this server
|
||||
// socket accepts connection from clients.
|
||||
class WifiDirectServerSocket : public api::WifiDirectServerSocket {
|
||||
public:
|
||||
explicit WifiDirectServerSocket(int port = 0);
|
||||
WifiDirectServerSocket(const WifiDirectServerSocket&) = default;
|
||||
WifiDirectServerSocket(WifiDirectServerSocket&&) = default;
|
||||
~WifiDirectServerSocket() override;
|
||||
WifiDirectServerSocket& operator=(const WifiDirectServerSocket&) = default;
|
||||
WifiDirectServerSocket& operator=(WifiDirectServerSocket&&) = default;
|
||||
|
||||
std::string GetIPAddress() const override;
|
||||
int GetPort() const override;
|
||||
void SetPort(int port) { port_ = port; }
|
||||
|
||||
StreamSocketListener GetSocketListener() const {
|
||||
return stream_socket_listener_;
|
||||
}
|
||||
|
||||
// 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.
|
||||
std::unique_ptr<api::WifiDirectSocket> Accept() override;
|
||||
|
||||
// Called by the server side of a connection before passing ownership of
|
||||
// WifiDirectServerSocker to user, to track validity of a pointer to this
|
||||
// server socket.
|
||||
void SetCloseNotifier(absl::AnyInvocable<void()> notifier);
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() override;
|
||||
|
||||
// Binds to local port
|
||||
bool listen();
|
||||
|
||||
private:
|
||||
// The listener is accepting incoming connections
|
||||
fire_and_forget Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args);
|
||||
|
||||
// Retrieves IP addresses from local machine
|
||||
std::vector<std::string> GetIpAddresses() const;
|
||||
std::string GetDirectGOIpAddresses() const;
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
absl::CondVar cond_;
|
||||
|
||||
std::deque<StreamSocket> pending_sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
StreamSocketListener stream_socket_listener_{nullptr};
|
||||
winrt::event_token listener_event_token_{};
|
||||
|
||||
// Close notifier
|
||||
absl::AnyInvocable<void()> close_notifier_ = nullptr;
|
||||
|
||||
// IP addresses of the computer. mDNS uses them to advertise.
|
||||
std::vector<std::string> ip_addresses_{};
|
||||
|
||||
// Cache socket not be picked by upper layer
|
||||
std::string wifi_direct_go_ipaddr_ = {};
|
||||
int port_ = 0;
|
||||
bool closed_ = false;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiDirect medium.
|
||||
class WifiDirectMedium : public api::WifiDirectMedium {
|
||||
public:
|
||||
WifiDirectMedium() = default;
|
||||
~WifiDirectMedium() override;
|
||||
|
||||
// If the WiFi Adaptor supports to start a WifiDirect interface.
|
||||
bool IsInterfaceValid() const override;
|
||||
|
||||
// WifiDirect GC connects to server socket
|
||||
std::unique_ptr<api::WifiDirectSocket> ConnectToService(
|
||||
absl::string_view ip_address, int port,
|
||||
CancellationFlag* cancellation_flag) override;
|
||||
|
||||
// WifiDirect GO starts to listen on server socket
|
||||
std::unique_ptr<api::WifiDirectServerSocket> ListenForService(
|
||||
int port) override;
|
||||
|
||||
// Start WifiDirect GO with specific Credentials.
|
||||
bool StartWifiDirect(WifiDirectCredentials* wifi_direct_credentials) override;
|
||||
// Stop the current WifiDirect GO
|
||||
bool StopWifiDirect() override;
|
||||
|
||||
// WifiDirect GC connects to the GO
|
||||
bool ConnectWifiDirect(
|
||||
WifiDirectCredentials* wifi_direct_credentials) override;
|
||||
// WifiDirect GC disconnects to the GO
|
||||
bool DisconnectWifiDirect() override;
|
||||
|
||||
absl::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
|
||||
override {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Value : char {
|
||||
kMediumStatusIdle = 0,
|
||||
kMediumStatusAccepting = (1 << 0),
|
||||
kMediumStatusBeaconing = (1 << 1),
|
||||
kMediumStatusConnected = (1 << 2),
|
||||
};
|
||||
|
||||
// Implemented the internal disconnection to WifiDirect GO, and used to avoid
|
||||
// deadlock.
|
||||
bool InternalDisconnectWifiDirect();
|
||||
bool IsIdle() { return medium_status_ == kMediumStatusIdle; }
|
||||
// WifiDirect GO is accepting connection on server socket
|
||||
bool IsAccepting() { return (medium_status_ & kMediumStatusAccepting) != 0; }
|
||||
// WifiDirect GO is started and sending beacon
|
||||
bool IsBeaconing() { return (medium_status_ & kMediumStatusBeaconing) != 0; }
|
||||
// WifiDirect GC is connected with the GO
|
||||
bool IsConnected() { return (medium_status_ & kMediumStatusConnected) != 0; }
|
||||
void RestoreWifiConnection();
|
||||
// Gets error message from exception pointer
|
||||
std::string GetErrorMessage(std::exception_ptr eptr);
|
||||
|
||||
fire_and_forget OnStatusChanged(
|
||||
WiFiDirectAdvertisementPublisher sender,
|
||||
WiFiDirectAdvertisementPublisherStatusChangedEventArgs event);
|
||||
|
||||
fire_and_forget OnConnectionRequested(
|
||||
WiFiDirectConnectionListener const& sender,
|
||||
WiFiDirectConnectionRequestedEventArgs const& event);
|
||||
|
||||
// WINRT related data member
|
||||
WiFiAdapter wifi_adapter_{nullptr};
|
||||
WiFiAvailableNetwork wifi_connected_network_{nullptr};
|
||||
WiFiDirectAdvertisementPublisher publisher_{nullptr};
|
||||
WiFiDirectConnectionListener listener_{nullptr};
|
||||
WiFiDirectDevice wifi_direct_device_{nullptr};
|
||||
winrt::event_token publisher_status_changed_token_;
|
||||
winrt::event_token connection_requested_token_;
|
||||
|
||||
// Protects to access some members
|
||||
absl::Mutex mutex_;
|
||||
|
||||
// Medium Status
|
||||
int medium_status_ = kMediumStatusIdle;
|
||||
|
||||
// Keep the server socket listener pointer
|
||||
WifiDirectServerSocket* server_socket_ptr_ ABSL_GUARDED_BY(mutex_) = nullptr;
|
||||
|
||||
// Scheduler for timeout.
|
||||
ScheduledExecutor scheduled_executor_;
|
||||
|
||||
// Scheduled task for connection timeout.
|
||||
std::shared_ptr<api::Cancelable> connection_timeout_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_WINDOWS_WIFI_DIRECT_H_
|
||||
@@ -1,622 +0,0 @@
|
||||
// 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 <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/base/masker.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
#include "internal/platform/implementation/wifi_direct.h"
|
||||
#include "internal/platform/implementation/wifi_utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct.h"
|
||||
|
||||
// Nearby connections headers
|
||||
#include "internal/platform/cancellation_flag_listener.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace {
|
||||
|
||||
// The maximum scanning times for GC to find WifiDirect GO.
|
||||
constexpr int kWifiDirectMaxScans = 2;
|
||||
|
||||
// The maximum connection times to remote WifiDirect GO server socket.
|
||||
constexpr int kWifiDirectMaxConnectionRetries = 3;
|
||||
|
||||
// The interval between 2 connectin attempts.
|
||||
constexpr absl::Duration kWifiDirectRetryIntervalMillis =
|
||||
absl::Milliseconds(300);
|
||||
|
||||
// The connection timeout to remote WifiDirect GO server socket.
|
||||
constexpr absl::Duration kWifiDirectClientSocketConnectTimeoutMillis =
|
||||
absl::Milliseconds(10000);
|
||||
|
||||
// The maximum times to check IP address.
|
||||
constexpr int kIpAddressMaxRetries = 3;
|
||||
|
||||
// The time interval to check IP address.
|
||||
constexpr absl::Duration kIpAddressRetryIntervalMillis =
|
||||
absl::Milliseconds(2000);
|
||||
|
||||
} // namespace
|
||||
|
||||
WifiDirectMedium::~WifiDirectMedium() {
|
||||
StopWifiDirect();
|
||||
DisconnectWifiDirect();
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::IsInterfaceValid() const {
|
||||
HANDLE wifi_direct_handle = nullptr;
|
||||
DWORD negotiated_version = 0;
|
||||
DWORD result =
|
||||
WFDOpenHandle(WFD_API_VERSION, &negotiated_version, &wifi_direct_handle);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
LOG(INFO) << "WiFi can support WifiDirect";
|
||||
WFDCloseHandle(wifi_direct_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG(ERROR) << "WiFi can't support WifiDirect";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectSocket> WifiDirectMedium::ConnectToService(
|
||||
absl::string_view ip_address, int port,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
LOG(WARNING) << __func__ << " : Connect to remote service.";
|
||||
|
||||
if (ip_address.empty() || port == 0) {
|
||||
LOG(ERROR) << "no valid service address and port to connect: "
|
||||
<< "ip_address = " << ip_address << ", port = " << port;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string ipv4_address;
|
||||
if (ip_address.length() == 4) {
|
||||
ipv4_address = ipaddr_4bytes_to_dotdecimal_string(ip_address);
|
||||
} else {
|
||||
ipv4_address = std::string(ip_address);
|
||||
}
|
||||
|
||||
if (!WifiUtils::ValidateIPV4(ipv4_address)) {
|
||||
LOG(ERROR) << "Invalid IP address parameter.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HostName host_name{winrt::to_hstring(ipv4_address)};
|
||||
winrt::hstring service_name{winrt::to_hstring(port)};
|
||||
|
||||
// Try connecting to the service up to kWifiDirectMaxConnectionRetries,
|
||||
// because it may fail first time if DHCP procedure is not finished yet.
|
||||
for (int i = 0; i < kWifiDirectMaxConnectionRetries; i++) {
|
||||
try {
|
||||
StreamSocket socket{};
|
||||
|
||||
std::unique_ptr<nearby::CancellationFlagListener>
|
||||
connection_cancellation_listener = nullptr;
|
||||
|
||||
// setup cancel listener
|
||||
if (cancellation_flag != nullptr) {
|
||||
if (cancellation_flag->Cancelled()) {
|
||||
LOG(INFO) << "connect has been cancelled to service " << ipv4_address
|
||||
<< ":" << port;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
connection_cancellation_listener =
|
||||
std::make_unique<nearby::CancellationFlagListener>(
|
||||
cancellation_flag, [socket]() {
|
||||
LOG(WARNING) << "connect is closed due to it is cancelled.";
|
||||
socket.Close();
|
||||
});
|
||||
}
|
||||
|
||||
connection_timeout_ = scheduled_executor_.Schedule(
|
||||
[socket]() {
|
||||
LOG(WARNING) << "connect is closed due to timeout.";
|
||||
socket.Close();
|
||||
},
|
||||
kWifiDirectClientSocketConnectTimeoutMillis);
|
||||
|
||||
socket.ConnectAsync(host_name, service_name).get();
|
||||
|
||||
if (connection_timeout_ != nullptr) {
|
||||
connection_timeout_->Cancel();
|
||||
connection_timeout_ = nullptr;
|
||||
}
|
||||
|
||||
auto client_socket = std::make_unique<WifiDirectSocket>(socket);
|
||||
|
||||
LOG(INFO) << "connected to remote service " << ipv4_address << ":"
|
||||
<< port;
|
||||
return client_socket;
|
||||
} catch (...) {
|
||||
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
|
||||
<< port << " for the " << i + 1 << " time";
|
||||
}
|
||||
|
||||
if (connection_timeout_ != nullptr) {
|
||||
connection_timeout_->Cancel();
|
||||
connection_timeout_ = nullptr;
|
||||
}
|
||||
|
||||
Sleep(kWifiDirectRetryIntervalMillis / absl::Milliseconds(1));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectServerSocket> WifiDirectMedium::ListenForService(
|
||||
int port) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
// check current status
|
||||
if (IsAccepting()) {
|
||||
LOG(WARNING) << "accepting connections already started on port "
|
||||
<< server_socket_ptr_->GetPort();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto server_socket = std::make_unique<WifiDirectServerSocket>(port);
|
||||
server_socket_ptr_ = server_socket.get();
|
||||
|
||||
if (server_socket->listen()) {
|
||||
medium_status_ |= kMediumStatusAccepting;
|
||||
server_socket->SetCloseNotifier([this]() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << "server socket was closed on port "
|
||||
<< server_socket_ptr_->GetPort();
|
||||
medium_status_ &= (~kMediumStatusAccepting);
|
||||
server_socket_ptr_ = nullptr;
|
||||
});
|
||||
|
||||
LOG(INFO) << "started to listen serive on port "
|
||||
<< server_socket_ptr_->GetPort();
|
||||
return server_socket;
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Failed to listen service on port " << port;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::StartWifiDirect(
|
||||
WifiDirectCredentials* wifi_direct_credentials) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
if (IsBeaconing()) {
|
||||
LOG(WARNING) << "cannot create SoftAP again when it is running.";
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
publisher_ = WiFiDirectAdvertisementPublisher();
|
||||
publisher_status_changed_token_ =
|
||||
publisher_.StatusChanged({this, &WifiDirectMedium::OnStatusChanged});
|
||||
listener_ = WiFiDirectConnectionListener();
|
||||
connection_requested_token_ = listener_.ConnectionRequested(
|
||||
{this, &WifiDirectMedium::OnConnectionRequested});
|
||||
|
||||
// Normal mode: The device is highly discoverable so long as the app is in
|
||||
// the foreground.
|
||||
publisher_.Advertisement().ListenStateDiscoverability(
|
||||
WiFiDirectAdvertisementListenStateDiscoverability::Normal);
|
||||
// Enable Autonomous GO mode
|
||||
publisher_.Advertisement().IsAutonomousGroupOwnerEnabled(true);
|
||||
|
||||
// Using WIFIDirect legacy mode to create a softAP. AP means "access point".
|
||||
// Windows WinRT WifiDirect class follows a full P2P protocol to establish a
|
||||
// P2P connection. However the current Phone Nearby Connection uses a
|
||||
// simplified protocol for P2P connection, which is just like a legacy
|
||||
// AP/STA SSID/password mode. To accommodate with this, Windows side give up
|
||||
// the formal P2P connection code suite, instead it uses Hotspot and legacy
|
||||
// STA to fake a P2P connection. By this way, when Phone act as Group
|
||||
// Client(GC), it can keep the connection with Router(AP) at the same time.
|
||||
// But if phone act as Group Owner(GO), Windows side still can't keep its AP
|
||||
// connection when connecting to phone as a GC because it is in normal STA
|
||||
// mode.
|
||||
Prng prng;
|
||||
publisher_.Advertisement().LegacySettings().IsEnabled(true);
|
||||
std::string password = absl::StrFormat("%08x", prng.NextUint32());
|
||||
wifi_direct_credentials->SetPassword(password);
|
||||
PasswordCredential creds;
|
||||
creds.Password(winrt::to_hstring(password));
|
||||
publisher_.Advertisement().LegacySettings().Passphrase(creds);
|
||||
|
||||
std::string ssid = "DIRECT-" + std::to_string(prng.NextUint32());
|
||||
wifi_direct_credentials->SetSSID(ssid);
|
||||
publisher_.Advertisement().LegacySettings().Ssid(winrt::to_hstring(ssid));
|
||||
|
||||
publisher_.Start();
|
||||
if (publisher_.Status() ==
|
||||
WiFiDirectAdvertisementPublisherStatus::Started) {
|
||||
LOG(INFO) << "Windows WiFiDirect GO(SoftAP) started";
|
||||
medium_status_ |= kMediumStatusBeaconing;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clean up when fail
|
||||
LOG(ERROR) << "Windows WiFiDirect GO(SoftAP) fails to start";
|
||||
publisher_.StatusChanged(publisher_status_changed_token_);
|
||||
listener_.ConnectionRequested(connection_requested_token_);
|
||||
listener_ = nullptr;
|
||||
publisher_ = nullptr;
|
||||
return false;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Cannot start WiFiDirect GO. Exception: "
|
||||
<< exception.what();
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": Cannot start WiFiDirect GO. WinRT exception: "
|
||||
<< error.code() << ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exception.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::StopWifiDirect() {
|
||||
// Need to use Win32 API to deregister the Dnssd instance
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
if (!IsBeaconing()) {
|
||||
LOG(WARNING)
|
||||
<< "Cannot stop WiFiDirect GO(SoftAP) because no GO was started.";
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (publisher_) {
|
||||
publisher_.Stop();
|
||||
listener_.ConnectionRequested(connection_requested_token_);
|
||||
publisher_.StatusChanged(publisher_status_changed_token_);
|
||||
wifi_direct_device_ = nullptr;
|
||||
listener_ = nullptr;
|
||||
publisher_ = nullptr;
|
||||
LOG(INFO) << "succeeded to stop WiFiDirect GO(SoftAP)";
|
||||
}
|
||||
|
||||
medium_status_ &= (~kMediumStatusBeaconing);
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Stop WiFiDirect GO failed. Exception: "
|
||||
<< exception.what();
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": Stop WiFiDirect GO failed. WinRT exception: "
|
||||
<< error.code() << ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exception.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fire_and_forget WifiDirectMedium::OnStatusChanged(
|
||||
WiFiDirectAdvertisementPublisher sender,
|
||||
WiFiDirectAdvertisementPublisherStatusChangedEventArgs event) {
|
||||
if (event.Status() == WiFiDirectAdvertisementPublisherStatus::Started) {
|
||||
if (sender.Advertisement().LegacySettings().IsEnabled()) {
|
||||
LOG(INFO) << "WiFiDirect GO SSID: "
|
||||
<< winrt::to_string(
|
||||
publisher_.Advertisement().LegacySettings().Ssid());
|
||||
LOG(INFO) << "WiFiDirect GO password: "
|
||||
<< masker::Mask(winrt::to_string(publisher_.Advertisement()
|
||||
.LegacySettings()
|
||||
.Passphrase()
|
||||
.Password()));
|
||||
}
|
||||
return winrt::fire_and_forget();
|
||||
} else if (event.Status() ==
|
||||
WiFiDirectAdvertisementPublisherStatus::Created) {
|
||||
LOG(INFO) << "Receive WiFiDirect/SoftAP Created event.";
|
||||
return winrt::fire_and_forget();
|
||||
} else if (event.Status() ==
|
||||
WiFiDirectAdvertisementPublisherStatus::Stopped) {
|
||||
LOG(INFO) << "Receive WiFiDirect/SoftAP Stopped event.";
|
||||
} else if (event.Status() ==
|
||||
WiFiDirectAdvertisementPublisherStatus::Aborted) {
|
||||
LOG(INFO) << "Receive WiFiDirect/SoftAP Aborted event.";
|
||||
}
|
||||
|
||||
// Publisher is stopped. Need to clean up the publisher.
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (publisher_ != nullptr) {
|
||||
LOG(ERROR) << "Windows WiFiDirect GO(SoftAP) cleanup.";
|
||||
listener_.ConnectionRequested(connection_requested_token_);
|
||||
publisher_.StatusChanged(publisher_status_changed_token_);
|
||||
wifi_direct_device_ = nullptr;
|
||||
listener_ = nullptr;
|
||||
publisher_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
fire_and_forget WifiDirectMedium::OnConnectionRequested(
|
||||
WiFiDirectConnectionListener const& sender,
|
||||
WiFiDirectConnectionRequestedEventArgs const& event) {
|
||||
WiFiDirectConnectionRequest connection_request = event.GetConnectionRequest();
|
||||
winrt::hstring device_name = connection_request.DeviceInformation().Name();
|
||||
LOG(INFO) << "Receive connection request from: "
|
||||
<< winrt::to_string(device_name);
|
||||
|
||||
try {
|
||||
// This is to solve b/236805122.
|
||||
// Problem: [Microsoft-Windows-WLAN-AutoConfig] issues a disconnection to
|
||||
// WifiDirect Client every 2 minutes and stopped WifiDirect GO eventually.
|
||||
// Solution: Creating a WiFiDirectDevice for Client’s connection request can
|
||||
// solve the problem. Guess when this object is created,
|
||||
// [Microsoft-Windows-WLAN-AutoConfig] will recognise it as a valid device
|
||||
// and won't kick it away.
|
||||
wifi_direct_device_ = WiFiDirectDevice::FromIdAsync(
|
||||
connection_request.DeviceInformation().Id())
|
||||
.get();
|
||||
LOG(INFO) << "Registered the device in WLAN-AutoConfig";
|
||||
} catch (...) {
|
||||
LOG(ERROR) << "Failed to registered the device in WLAN-AutoConfig";
|
||||
wifi_direct_device_ = nullptr;
|
||||
connection_request.Close();
|
||||
}
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::ConnectWifiDirect(
|
||||
WifiDirectCredentials* wifi_direct_credentials) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
try {
|
||||
if (IsConnected()) {
|
||||
LOG(WARNING) << "Already connected to AP, disconnect first.";
|
||||
InternalDisconnectWifiDirect();
|
||||
}
|
||||
|
||||
auto access = WiFiAdapter::RequestAccessAsync().get();
|
||||
if (access != WiFiAccessStatus::Allowed) {
|
||||
LOG(WARNING) << "Access Denied with reason: " << static_cast<int>(access);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto adapters = WiFiAdapter::FindAllAdaptersAsync().get();
|
||||
if (adapters.Size() < 1) {
|
||||
LOG(WARNING) << "No WiFi Adapter found.";
|
||||
return false;
|
||||
}
|
||||
wifi_adapter_ = adapters.GetAt(0);
|
||||
|
||||
// Retrieve the current connected network's profile
|
||||
ConnectionProfile profile =
|
||||
wifi_adapter_.NetworkAdapter().GetConnectedProfileAsync().get();
|
||||
std::string ssid;
|
||||
|
||||
if (profile != nullptr && profile.IsWlanConnectionProfile()) {
|
||||
ssid = winrt::to_string(
|
||||
profile.WlanConnectionProfileDetails().GetConnectedSsid());
|
||||
}
|
||||
|
||||
// SoftAP is an abbreviation for "software enabled access point".
|
||||
WiFiAvailableNetwork nearby_softap{nullptr};
|
||||
LOG(INFO) << "Scanning for Nearby WifiDirect GO's SSID: "
|
||||
<< wifi_direct_credentials->GetSSID();
|
||||
|
||||
// First time scan may not find our target GO, try 2 more times can
|
||||
// almost guarantee to find the GO
|
||||
wifi_adapter_.ScanAsync().get();
|
||||
|
||||
wifi_connected_network_ = nullptr;
|
||||
for (int i = 0; i < kWifiDirectMaxScans; i++) {
|
||||
for (const auto& network :
|
||||
wifi_adapter_.NetworkReport().AvailableNetworks()) {
|
||||
if (!wifi_connected_network_ && !ssid.empty() &&
|
||||
(winrt::to_string(network.Ssid()) == ssid)) {
|
||||
wifi_connected_network_ = network;
|
||||
LOG(INFO) << "Save the current connected network: " << ssid;
|
||||
} else if (!nearby_softap && winrt::to_string(network.Ssid()) ==
|
||||
wifi_direct_credentials->GetSSID()) {
|
||||
LOG(INFO) << "Found Nearby SSID: "
|
||||
<< winrt::to_string(network.Ssid());
|
||||
nearby_softap = network;
|
||||
}
|
||||
if (nearby_softap && wifi_connected_network_) break;
|
||||
}
|
||||
if (nearby_softap) break;
|
||||
LOG(INFO) << "Scan ... ";
|
||||
wifi_adapter_.ScanAsync().get();
|
||||
}
|
||||
|
||||
if (!nearby_softap) {
|
||||
LOG(INFO) << "WifiDirect GO is not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
PasswordCredential creds;
|
||||
creds.Password(winrt::to_hstring(wifi_direct_credentials->GetPassword()));
|
||||
|
||||
auto connect_result =
|
||||
wifi_adapter_
|
||||
.ConnectAsync(nearby_softap, WiFiReconnectionKind::Manual, creds)
|
||||
.get();
|
||||
|
||||
if (connect_result == nullptr ||
|
||||
connect_result.ConnectionStatus() != WiFiConnectionStatus::Success) {
|
||||
LOG(INFO) << "Connecting failed with reason: "
|
||||
<< static_cast<int>(connect_result.ConnectionStatus());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure IP address is ready.
|
||||
std::string ip_address;
|
||||
for (int i = 0; i < kIpAddressMaxRetries; i++) {
|
||||
LOG(INFO) << "Check IP address at attempt " << i;
|
||||
std::vector<std::string> ip_addresses = GetIpv4Addresses();
|
||||
if (ip_addresses.empty()) {
|
||||
Sleep(kIpAddressRetryIntervalMillis / absl::Milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
ip_address = ip_addresses[0];
|
||||
break;
|
||||
}
|
||||
|
||||
if (ip_address.empty()) {
|
||||
LOG(INFO) << "Failed to get IP address from WifiDirect GO.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Got IP: " << ip_address << " from WifiDirect GO.";
|
||||
|
||||
std::string last_ssid = wifi_direct_credentials->GetSSID();
|
||||
medium_status_ |= kMediumStatusConnected;
|
||||
LOG(INFO) << "Connected to WifiDirect GO: " << last_ssid;
|
||||
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Cannot connet to WifiDirect GO. Exception: "
|
||||
<< exception.what();
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Cannot connet to WifiDirect GO. WinRT exception: "
|
||||
<< error.code() << ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exception.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WifiDirectMedium::RestoreWifiConnection() {
|
||||
if (!wifi_connected_network_ && wifi_adapter_) {
|
||||
wifi_adapter_.Disconnect();
|
||||
return;
|
||||
}
|
||||
if (wifi_adapter_) {
|
||||
ConnectionProfile profile =
|
||||
wifi_adapter_.NetworkAdapter().GetConnectedProfileAsync().get();
|
||||
std::string ssid;
|
||||
|
||||
if (profile != nullptr && profile.IsWlanConnectionProfile()) {
|
||||
ssid = winrt::to_string(
|
||||
profile.WlanConnectionProfileDetails().GetConnectedSsid());
|
||||
if (!ssid.empty() &&
|
||||
(winrt::to_string(wifi_connected_network_.Ssid()) == ssid)) {
|
||||
LOG(INFO) << "Already conneted to the previous WIFI network " << ssid
|
||||
<< "! Skip restoration.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect to the WiFi connection through the WiFi adapter.
|
||||
wifi_adapter_.Disconnect();
|
||||
LOG(INFO) << "Disconnected to current network.";
|
||||
|
||||
auto connect_result = wifi_adapter_
|
||||
.ConnectAsync(wifi_connected_network_,
|
||||
WiFiReconnectionKind::Automatic)
|
||||
.get();
|
||||
|
||||
if (connect_result == nullptr ||
|
||||
connect_result.ConnectionStatus() != WiFiConnectionStatus::Success) {
|
||||
LOG(INFO) << "Connecting to previous network failed with reason: "
|
||||
<< static_cast<int>(connect_result.ConnectionStatus());
|
||||
} else {
|
||||
LOG(INFO) << "Restored the previous WIFI connection: "
|
||||
<< winrt::to_string(wifi_connected_network_.Ssid());
|
||||
}
|
||||
wifi_connected_network_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::DisconnectWifiDirect() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
try {
|
||||
return InternalDisconnectWifiDirect();
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Disconnect WifiDirect GO failed. Exception: "
|
||||
<< exception.what();
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Disconnect WifiDirect GO failed. WinRT exception: "
|
||||
<< error.code() << ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exception.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WifiDirectMedium::InternalDisconnectWifiDirect() {
|
||||
if (!IsConnected()) {
|
||||
LOG(WARNING)
|
||||
<< "Cannot disconnect WifiDirect GO because it is not connected.";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wifi_adapter_) {
|
||||
// Gets connected WiFi profile.
|
||||
auto profile =
|
||||
wifi_adapter_.NetworkAdapter().GetConnectedProfileAsync().get();
|
||||
|
||||
// Disconnect to the WiFi connection through the WiFi adapter.
|
||||
RestoreWifiConnection();
|
||||
wifi_adapter_ = nullptr;
|
||||
|
||||
// Try to remove the WiFi profile
|
||||
if (profile != nullptr && profile.CanDelete() &&
|
||||
profile.IsWlanConnectionProfile()) {
|
||||
std::string ssid = winrt::to_string(
|
||||
profile.WlanConnectionProfileDetails().GetConnectedSsid());
|
||||
|
||||
auto profile_delete_status = profile.TryDeleteAsync().get();
|
||||
switch (profile_delete_status) {
|
||||
case ConnectionProfileDeleteStatus::Success:
|
||||
LOG(INFO) << "WiFi profile with SSID:" << ssid << " is deleted.";
|
||||
break;
|
||||
case ConnectionProfileDeleteStatus::DeniedBySystem:
|
||||
LOG(ERROR) << "Failed to delete WiFi profile with SSID:" << ssid
|
||||
<< " due to denied by system.";
|
||||
break;
|
||||
case ConnectionProfileDeleteStatus::DeniedByUser:
|
||||
LOG(ERROR) << "Failed to delete WiFi profile with SSID:" << ssid
|
||||
<< " due to denied by user.";
|
||||
break;
|
||||
case ConnectionProfileDeleteStatus::UnknownError:
|
||||
LOG(ERROR) << "Failed to delete WiFi profile with SSID:" << ssid
|
||||
<< " due to unknonw error.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
medium_status_ &= (~kMediumStatusConnected);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WifiDirectMedium::GetErrorMessage(std::exception_ptr eptr) {
|
||||
try {
|
||||
if (eptr) {
|
||||
std::rethrow_exception(eptr);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
return e.what();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
@@ -1,282 +0,0 @@
|
||||
// Copyright 2021 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 <windows.h>
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ABSL headers
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/match.h"
|
||||
|
||||
// Nearby connections headers
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/wifi_direct.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace {
|
||||
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
|
||||
constexpr int kMaxRetries = 3;
|
||||
constexpr int kRetryIntervalMilliSeconds = 300;
|
||||
|
||||
} // namespace
|
||||
|
||||
WifiDirectServerSocket::WifiDirectServerSocket(int port) : port_(port) {}
|
||||
|
||||
WifiDirectServerSocket::~WifiDirectServerSocket() { Close(); }
|
||||
|
||||
std::string WifiDirectServerSocket::GetIPAddress() const {
|
||||
if (stream_socket_listener_ == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (ip_addresses_.empty()) {
|
||||
auto ip_addr = GetIpAddresses();
|
||||
if (ip_addr.empty()) {
|
||||
return {};
|
||||
}
|
||||
return ip_addr.front();
|
||||
}
|
||||
return ip_addresses_.front();
|
||||
}
|
||||
|
||||
int WifiDirectServerSocket::GetPort() const {
|
||||
if (stream_socket_listener_ == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectSocket> WifiDirectServerSocket::Accept() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << __func__ << ": Accept is called.";
|
||||
|
||||
while (!closed_ && pending_sockets_.empty()) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
if (closed_) return {};
|
||||
|
||||
StreamSocket wifi_direct_socket = pending_sockets_.front();
|
||||
pending_sockets_.pop_front();
|
||||
|
||||
LOG(INFO) << __func__ << ": Accepted a remote connection.";
|
||||
return std::make_unique<WifiDirectSocket>(wifi_direct_socket);
|
||||
}
|
||||
|
||||
void WifiDirectServerSocket::SetCloseNotifier(
|
||||
absl::AnyInvocable<void()> notifier) {
|
||||
close_notifier_ = std::move(notifier);
|
||||
}
|
||||
|
||||
Exception WifiDirectServerSocket::Close() {
|
||||
try {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << __func__ << ": Close is called.";
|
||||
|
||||
if (closed_) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
if (stream_socket_listener_ != nullptr) {
|
||||
stream_socket_listener_.ConnectionReceived(listener_event_token_);
|
||||
stream_socket_listener_.Close();
|
||||
stream_socket_listener_ = nullptr;
|
||||
|
||||
for (const auto &pending_socket : pending_sockets_) {
|
||||
pending_socket.Close();
|
||||
}
|
||||
|
||||
pending_sockets_ = {};
|
||||
}
|
||||
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
if (close_notifier_ != nullptr) {
|
||||
close_notifier_();
|
||||
}
|
||||
|
||||
LOG(INFO) << __func__ << ": Close completed succesfully.";
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error &error) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiDirectServerSocket::listen() {
|
||||
// Get current IP addresses of the device.
|
||||
for (int i = 0; i < kMaxRetries; i++) {
|
||||
wifi_direct_go_ipaddr_ = GetDirectGOIpAddresses();
|
||||
if (wifi_direct_go_ipaddr_.empty()) {
|
||||
LOG(WARNING) << "Failed to find WifiDirect GO's IP addr for the try: "
|
||||
<< i + 1 << ". Wait " << kRetryIntervalMilliSeconds
|
||||
<< "ms snd try again";
|
||||
Sleep(kRetryIntervalMilliSeconds);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wifi_direct_go_ipaddr_.empty()) {
|
||||
LOG(WARNING) << "Failed to start accepting connection without IP "
|
||||
"addresses configured on computer.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup stream socket listener.
|
||||
stream_socket_listener_ = StreamSocketListener();
|
||||
|
||||
stream_socket_listener_.Control().QualityOfService(
|
||||
SocketQualityOfService::LowLatency);
|
||||
|
||||
stream_socket_listener_.Control().KeepAlive(true);
|
||||
|
||||
// Setup socket event of ConnectionReceived.
|
||||
listener_event_token_ = stream_socket_listener_.ConnectionReceived(
|
||||
{this, &WifiDirectServerSocket::Listener_ConnectionReceived});
|
||||
|
||||
try {
|
||||
HostName host_name{winrt::to_hstring(wifi_direct_go_ipaddr_)};
|
||||
stream_socket_listener_
|
||||
.BindEndpointAsync(host_name, winrt::to_hstring(port_))
|
||||
.get();
|
||||
if (port_ == 0) {
|
||||
port_ =
|
||||
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Cannot accept connection on preferred port. Exception: "
|
||||
<< exception.what();
|
||||
} catch (const winrt::hresult_error &error) {
|
||||
LOG(ERROR)
|
||||
<< __func__
|
||||
<< ":Cannot accept connection on preferred port. WinRT exception: "
|
||||
<< error.code() << ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
}
|
||||
|
||||
try {
|
||||
stream_socket_listener_.BindServiceNameAsync({}).get();
|
||||
// need to save the port information.
|
||||
port_ =
|
||||
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
LOG(INFO) << "Server Socket port: " << port_;
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Cannot bind to any port. Exception: " << exception.what();
|
||||
} catch (const winrt::hresult_error &error) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Cannot bind to any port. WinRT exception: " << error.code()
|
||||
<< ": " << winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fire_and_forget WifiDirectServerSocket::Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const &args) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << __func__ << ": Received connection.";
|
||||
|
||||
if (closed_) {
|
||||
return fire_and_forget{};
|
||||
}
|
||||
|
||||
pending_sockets_.push_back(args.Socket());
|
||||
cond_.SignalAll();
|
||||
return fire_and_forget{};
|
||||
}
|
||||
|
||||
std::vector<std::string> WifiDirectServerSocket::GetIpAddresses() const {
|
||||
std::vector<std::string> result{};
|
||||
auto host_names = NetworkInformation::GetHostNames();
|
||||
for (auto host_name : host_names) {
|
||||
if (host_name.IPInformation() != nullptr &&
|
||||
host_name.IPInformation().NetworkAdapter() != nullptr &&
|
||||
host_name.Type() == HostNameType::Ipv4) {
|
||||
std::string ipv4_s = winrt::to_string(host_name.ToString());
|
||||
|
||||
if (absl::EndsWith(ipv4_s, ".1")) {
|
||||
LOG(INFO) << "Found WifiDirect GO IP: " << ipv4_s;
|
||||
result.push_back(ipv4_s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string WifiDirectServerSocket::GetDirectGOIpAddresses() const {
|
||||
try {
|
||||
for (int i = 0; i < kMaxRetries; i++) {
|
||||
auto host_names = NetworkInformation::GetHostNames();
|
||||
for (auto host_name : host_names) {
|
||||
if (host_name.IPInformation() != nullptr &&
|
||||
host_name.IPInformation().NetworkAdapter() != nullptr &&
|
||||
host_name.Type() == HostNameType::Ipv4) {
|
||||
std::string ipv4_s = winrt::to_string(host_name.ToString());
|
||||
if (absl::EndsWith(ipv4_s, ".1")) {
|
||||
// TODO(b/228541380): replace when we find a better way to
|
||||
// identifying the WifiDirect GO IP address
|
||||
LOG(INFO) << "Found WifiDirect GO IP: " << ipv4_s;
|
||||
return ipv4_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {};
|
||||
} catch (const winrt::hresult_error &error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
@@ -1,204 +0,0 @@
|
||||
// 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 <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/platform/output_stream.h"
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
WifiDirectSocket::WifiDirectSocket(StreamSocket socket) {
|
||||
stream_soket_ = socket;
|
||||
input_stream_ = SocketInputStream(socket.InputStream());
|
||||
output_stream_ = SocketOutputStream(socket.OutputStream());
|
||||
}
|
||||
|
||||
WifiDirectSocket::~WifiDirectSocket() {
|
||||
try {
|
||||
if (stream_soket_ != nullptr) {
|
||||
Close();
|
||||
}
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
}
|
||||
}
|
||||
|
||||
InputStream& WifiDirectSocket::GetInputStream() { return input_stream_; }
|
||||
|
||||
OutputStream& WifiDirectSocket::GetOutputStream() { return output_stream_; }
|
||||
|
||||
Exception WifiDirectSocket::Close() {
|
||||
try {
|
||||
if (stream_soket_ != nullptr) {
|
||||
stream_soket_.Close();
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
WifiDirectSocket::SocketInputStream::SocketInputStream(
|
||||
IInputStream input_stream) {
|
||||
input_stream_ = input_stream;
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> WifiDirectSocket::SocketInputStream::Read(
|
||||
std::int64_t size) {
|
||||
try {
|
||||
Buffer buffer = Buffer(size);
|
||||
|
||||
auto ibuffer =
|
||||
input_stream_.ReadAsync(buffer, size, InputStreamOptions::None).get();
|
||||
|
||||
if (ibuffer.Length() != size) {
|
||||
LOG(WARNING) << "Only got part of data of needed.";
|
||||
}
|
||||
|
||||
ByteArray data((char*)ibuffer.data(), ibuffer.Length());
|
||||
|
||||
return ExceptionOr(data);
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOr<size_t> WifiDirectSocket::SocketInputStream::Skip(size_t offset) {
|
||||
try {
|
||||
Buffer buffer = Buffer(offset);
|
||||
|
||||
auto ibuffer =
|
||||
input_stream_.ReadAsync(buffer, offset, InputStreamOptions::None).get();
|
||||
return ExceptionOr((size_t)ibuffer.Length());
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiDirectSocket::SocketInputStream::Close() {
|
||||
try {
|
||||
input_stream_.Close();
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
// SocketOutputStream
|
||||
WifiDirectSocket::SocketOutputStream::SocketOutputStream(
|
||||
IOutputStream output_stream) {
|
||||
output_stream_ = output_stream;
|
||||
}
|
||||
|
||||
Exception WifiDirectSocket::SocketOutputStream::Write(const ByteArray& data) {
|
||||
try {
|
||||
Buffer buffer = Buffer(data.size());
|
||||
std::memcpy(buffer.data(), data.data(), data.size());
|
||||
buffer.Length(data.size());
|
||||
|
||||
output_stream_.WriteAsync(buffer).get();
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiDirectSocket::SocketOutputStream::Flush() {
|
||||
try {
|
||||
output_stream_.FlushAsync().get();
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiDirectSocket::SocketOutputStream::Close() {
|
||||
try {
|
||||
output_stream_.Close();
|
||||
return {Exception::kSuccess};
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
|
||||
return {Exception::kIo};
|
||||
} catch (const winrt::hresult_error& error) {
|
||||
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
|
||||
<< winrt::to_string(error.message());
|
||||
return {Exception::kIo};
|
||||
} catch (...) {
|
||||
LOG(ERROR) << __func__ << ": Unknown exeption.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
Reference in New Issue
Block a user