mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Wi-Fi Direct Service Implementation(4)
PiperOrigin-RevId: 824914003
This commit is contained in:
@@ -189,6 +189,8 @@ cc_library(
|
||||
"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",
|
||||
|
||||
@@ -20,12 +20,27 @@
|
||||
#include <wlanapi.h>
|
||||
|
||||
// Standard C/C++ headers
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// Nearby connections headers
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
#include "internal/platform/output_stream.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/wifi_direct_service.h"
|
||||
#include "internal/platform/implementation/windows/nearby_client_socket.h"
|
||||
#include "internal/platform/implementation/windows/nearby_server_socket.h"
|
||||
#include "internal/platform/implementation/windows/submittable_executor.h"
|
||||
|
||||
// WinRT headers
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
|
||||
@@ -39,18 +54,18 @@
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.System.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/base.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace nearby::windows {
|
||||
|
||||
using ::winrt::event_token;
|
||||
using ::winrt::fire_and_forget;
|
||||
using ::winrt::Windows::Devices::Enumeration::DeviceInformation;
|
||||
using ::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
|
||||
using ::winrt::Windows::Devices::Enumeration::DeviceWatcher;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::WiFiDirectService;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::
|
||||
WiFiDirectServiceAdvertiser;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::
|
||||
WiFiDirectServiceAdvertisementStatus;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::
|
||||
WiFiDirectServiceAdvertiser;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::
|
||||
WiFiDirectServiceAutoAcceptSessionConnectedEventArgs;
|
||||
using ::winrt::Windows::Devices::WiFiDirect::Services::
|
||||
@@ -62,6 +77,136 @@ using ::winrt::Windows::Devices::WiFiDirect::Services::WiFiDirectServiceStatus;
|
||||
using ::winrt::Windows::Foundation::AsyncStatus;
|
||||
using ::winrt::Windows::Foundation::IInspectable;
|
||||
|
||||
// WifiDirectServiceSocket wraps the socket functions to read and write stream.
|
||||
// In WiFi HOTSPOT, A WifiDirectServiceSocket will be passed to
|
||||
// StartAcceptingConnections's callback when Winsock Server Socket receives a
|
||||
// new connection. When call API to connect to remote WiFi Hotspot service, also
|
||||
// will return a WifiDirectServiceSocket to caller.
|
||||
class WifiDirectServiceSocket : public api::WifiDirectServiceSocket {
|
||||
public:
|
||||
WifiDirectServiceSocket();
|
||||
explicit WifiDirectServiceSocket(
|
||||
absl_nonnull std::unique_ptr<NearbyClientSocket> socket);
|
||||
WifiDirectServiceSocket(WifiDirectServiceSocket&&) = default;
|
||||
~WifiDirectServiceSocket() override;
|
||||
WifiDirectServiceSocket& operator=(WifiDirectServiceSocket&&) = default;
|
||||
|
||||
// Returns the InputStream of the WifiDirectServiceSocket.
|
||||
// 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 WifiDirectServiceSocket object is destroyed.
|
||||
InputStream& GetInputStream() override { return input_stream_; }
|
||||
|
||||
// Returns the OutputStream of the WifiDirectServiceSocket.
|
||||
// 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 WifiDirectServiceSocket object is destroyed.
|
||||
OutputStream& GetOutputStream() override { return output_stream_; }
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() override { return client_socket_->Close(); }
|
||||
|
||||
bool Connect(const SocketAddress& server_address) {
|
||||
return client_socket_->Connect(server_address);
|
||||
}
|
||||
|
||||
private:
|
||||
// A simple wrapper to handle input stream of socket
|
||||
class SocketInputStream : public InputStream {
|
||||
public:
|
||||
explicit SocketInputStream(NearbyClientSocket* absl_nonnull client_socket)
|
||||
: client_socket_(client_socket) {}
|
||||
~SocketInputStream() override = default;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override {
|
||||
return client_socket_->Read(size);
|
||||
}
|
||||
ExceptionOr<size_t> Skip(size_t offset) override {
|
||||
return client_socket_->Skip(offset);
|
||||
}
|
||||
Exception Close() override { return client_socket_->Close(); }
|
||||
|
||||
private:
|
||||
NearbyClientSocket* absl_nonnull const client_socket_;
|
||||
};
|
||||
|
||||
// A simple wrapper to handle output stream of socket
|
||||
class SocketOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit SocketOutputStream(NearbyClientSocket* absl_nonnull client_socket)
|
||||
: client_socket_(client_socket) {}
|
||||
~SocketOutputStream() override = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override {
|
||||
return client_socket_->Write(data);
|
||||
}
|
||||
Exception Flush() override { return client_socket_->Flush(); }
|
||||
Exception Close() override { return client_socket_->Close(); }
|
||||
|
||||
private:
|
||||
NearbyClientSocket* absl_nonnull const client_socket_;
|
||||
};
|
||||
|
||||
absl_nonnull std::unique_ptr<NearbyClientSocket> client_socket_;
|
||||
SocketInputStream input_stream_;
|
||||
SocketOutputStream output_stream_;
|
||||
};
|
||||
|
||||
// WifiDirectServiceServerSocket provides the support to server socket, this
|
||||
// server socket accepts connection from clients.
|
||||
class WifiDirectServiceServerSocket
|
||||
: public api::WifiDirectServiceServerSocket {
|
||||
public:
|
||||
explicit WifiDirectServiceServerSocket(int port = 0);
|
||||
WifiDirectServiceServerSocket(const WifiDirectServiceServerSocket&) = default;
|
||||
WifiDirectServiceServerSocket(WifiDirectServiceServerSocket&&) = default;
|
||||
~WifiDirectServiceServerSocket() override;
|
||||
WifiDirectServiceServerSocket& operator=(
|
||||
const WifiDirectServiceServerSocket&) = default;
|
||||
WifiDirectServiceServerSocket& operator=(WifiDirectServiceServerSocket&&) =
|
||||
default;
|
||||
|
||||
std::string GetIPAddress() const override;
|
||||
int GetPort() const override;
|
||||
|
||||
// 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::WifiDirectServiceSocket> Accept() override;
|
||||
|
||||
// Called by the server side of a connection before passing ownership of
|
||||
// WifiDirectServiceServerSocker 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(bool dual_stack, std::string& ip_address);
|
||||
|
||||
NearbyServerSocket server_socket_;
|
||||
|
||||
private:
|
||||
// Retrieves hotspot IP address from local machine
|
||||
std::string GetWifiDirectServiceIpAddress() const;
|
||||
|
||||
const int port_;
|
||||
mutable absl::Mutex mutex_;
|
||||
|
||||
// Close notifier
|
||||
absl::AnyInvocable<void()> close_notifier_ = nullptr;
|
||||
|
||||
// IP addresses of the server socket.
|
||||
std::string wifi_direct_service_ipaddr_ = {};
|
||||
bool closed_ = false;
|
||||
};
|
||||
|
||||
class WifiDirectServiceDiscovered {
|
||||
public:
|
||||
explicit WifiDirectServiceDiscovered(const DeviceInformation& device_info);
|
||||
@@ -86,22 +231,39 @@ class WifiDirectServiceDiscovered {
|
||||
// std::string name_;
|
||||
};
|
||||
|
||||
class WifiDirectServiceMedium {
|
||||
class WifiDirectServiceMedium : public api::WifiDirectServiceMedium {
|
||||
public:
|
||||
WifiDirectServiceMedium();
|
||||
~WifiDirectServiceMedium();
|
||||
~WifiDirectServiceMedium() override;
|
||||
// WifiDirectServiceMedium is neither copyable nor movable.
|
||||
WifiDirectServiceMedium(const WifiDirectServiceMedium&) = delete;
|
||||
WifiDirectServiceMedium& operator=(const WifiDirectServiceMedium&) = delete;
|
||||
|
||||
// If the WiFi Adaptor supports to start WifiDirect Service GO.
|
||||
bool IsInterfaceValid() const override;
|
||||
|
||||
// Discoverer connects to server socket
|
||||
std::unique_ptr<api::WifiDirectServiceSocket> ConnectToService(
|
||||
absl::string_view ip_address, int port,
|
||||
CancellationFlag* cancellation_flag) override;
|
||||
|
||||
// Advertiser starts to listen on server socket
|
||||
std::unique_ptr<api::WifiDirectServiceServerSocket> ListenForService(
|
||||
int port) override;
|
||||
|
||||
// Starts to advertising
|
||||
bool StartWifiDirectService();
|
||||
bool StartWifiDirectService() override;
|
||||
// Stops to advertising
|
||||
bool StopWifiDirectService();
|
||||
bool StopWifiDirectService() override;
|
||||
// Connects to a WifiDirectService
|
||||
bool ConnectWifiDirectService();
|
||||
bool ConnectWifiDirectService() override;
|
||||
// Disconnects from a WifiDirectService
|
||||
bool DisconnectWifiDirectService();
|
||||
bool DisconnectWifiDirectService() override;
|
||||
|
||||
absl::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
|
||||
override {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Value : char {
|
||||
@@ -109,6 +271,7 @@ class WifiDirectServiceMedium {
|
||||
kMediumStatusAccepting = (1 << 0),
|
||||
kMediumStatusServiceStarted = (1 << 1),
|
||||
kMediumStatusConnecting = (1 << 2),
|
||||
kMediumStatusConnected = (1 << 3),
|
||||
};
|
||||
// Medium Status
|
||||
int medium_status_ = kMediumStatusIdle;
|
||||
@@ -116,14 +279,18 @@ class WifiDirectServiceMedium {
|
||||
bool IsIdle() { return medium_status_ == kMediumStatusIdle; }
|
||||
// Advertiser is accepting connection on server socket
|
||||
bool IsAccepting() { return (medium_status_ & kMediumStatusAccepting) != 0; }
|
||||
// Advertiser started Hotspot and sending beacon
|
||||
// Advertiser started WifiDirectService
|
||||
bool IsServiceStarted() {
|
||||
return (medium_status_ & kMediumStatusServiceStarted) != 0;
|
||||
}
|
||||
// Discoverer is connected with the Hotspot
|
||||
// Discoverer is connecting with the WifiDirectService
|
||||
bool IsConnecting() {
|
||||
return (medium_status_ & kMediumStatusConnecting) != 0;
|
||||
}
|
||||
// Discoverer is connected with the WifiDirectService
|
||||
bool IsConnected() {
|
||||
return (medium_status_ & kMediumStatusConnected) != 0;
|
||||
}
|
||||
|
||||
// Converts WiFiDirectServiceConfigurationMethod enum to a string.
|
||||
static std::string ConfigMethodToString(
|
||||
@@ -171,6 +338,12 @@ class WifiDirectServiceMedium {
|
||||
std::string ip_address_remote_;
|
||||
|
||||
absl::Mutex mutex_;
|
||||
absl::CondVar is_ip_address_ready_;
|
||||
// Keep the server socket listener pointer
|
||||
WifiDirectServiceServerSocket* server_socket_ptr_ ABSL_GUARDED_BY(mutex_) =
|
||||
nullptr;
|
||||
SubmittableExecutor listener_executor_;
|
||||
|
||||
absl::flat_hash_map<winrt::hstring,
|
||||
std::unique_ptr<WifiDirectServiceDiscovered>>
|
||||
discovered_devices_by_id_;
|
||||
@@ -180,7 +353,6 @@ class WifiDirectServiceMedium {
|
||||
connection_requested_devices_by_id_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace nearby::windows
|
||||
|
||||
#endif // PLATFORM_IMPL_WINDOWS_WIFI_DIRECT_SERVICE_H_
|
||||
|
||||
@@ -12,12 +12,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/flags/nearby_flags.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
#include "internal/platform/cancellation_flag_listener.h"
|
||||
#include "internal/platform/flags/nearby_platform_feature_flags.h"
|
||||
#include "internal/platform/implementation/wifi_direct_service.h"
|
||||
#include "internal/platform/implementation/windows/socket_address.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct_service.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
@@ -26,6 +37,7 @@ namespace windows {
|
||||
namespace {
|
||||
constexpr std::wstring_view kServiceName = L"QuickShare";
|
||||
constexpr std::wstring_view kPin = L"1234";
|
||||
constexpr int kWaitingForConnectionTimeoutSeconds = 90; // seconds
|
||||
} // namespace
|
||||
|
||||
WifiDirectServiceMedium::WifiDirectServiceMedium() {
|
||||
@@ -41,6 +53,7 @@ WifiDirectServiceMedium::WifiDirectServiceMedium() {
|
||||
}
|
||||
|
||||
WifiDirectServiceMedium::~WifiDirectServiceMedium() {
|
||||
listener_executor_.Shutdown();
|
||||
StopWifiDirectService();
|
||||
DisconnectWifiDirectService();
|
||||
if (controller_) {
|
||||
@@ -55,6 +68,206 @@ WifiDirectServiceMedium::~WifiDirectServiceMedium() {
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiDirectServiceMedium::IsInterfaceValid() const {
|
||||
HANDLE wifi_direct_handle = nullptr;
|
||||
DWORD negotiated_version = 0;
|
||||
DWORD result = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Discoverer connects to server socket
|
||||
std::unique_ptr<api::WifiDirectServiceSocket>
|
||||
WifiDirectServiceMedium::ConnectToService(absl::string_view ip_address,
|
||||
int port,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
LOG(INFO) << "WifiDirectServiceMedium::ConnectToService Server Socket";
|
||||
// check current status
|
||||
if (!IsConnecting()) {
|
||||
LOG(WARNING) << "GC is not connecting to GO, skip.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string remote_ip_address;
|
||||
if (ip_address.empty()) {
|
||||
remote_ip_address = ip_address_remote_;
|
||||
} else {
|
||||
remote_ip_address = std::string(ip_address);
|
||||
}
|
||||
// when this API is called, GC may not finish connecting to GO, so we need to
|
||||
// wait the connection is finished and IP address is ready.
|
||||
if (remote_ip_address.empty()) {
|
||||
LOG(INFO) << "Waiting for IP address to be ready.";
|
||||
absl::MutexLock lock(mutex_);
|
||||
is_ip_address_ready_.WaitWithTimeout(
|
||||
&mutex_, absl::Seconds(kWaitingForConnectionTimeoutSeconds));
|
||||
if (ip_address_remote_.empty()) {
|
||||
LOG(WARNING)
|
||||
<< "IP address is still empty, probably GC connecting to GO failed.";
|
||||
return nullptr;
|
||||
}
|
||||
LOG(INFO) << "IP address is ready.";
|
||||
remote_ip_address = ip_address_remote_;
|
||||
}
|
||||
|
||||
if (remote_ip_address.empty() || port == 0) {
|
||||
LOG(ERROR) << "no valid service address and port to connect: "
|
||||
<< "ip_address = " << remote_ip_address << ", port = " << port;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool dual_stack = NearbyFlags::GetInstance().GetBoolFlag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kEnableIpv6DualStack);
|
||||
SocketAddress server_address(dual_stack);
|
||||
if (!server_address.FromString(server_address, remote_ip_address, port)) {
|
||||
LOG(ERROR) << "no valid service address and port to connect.";
|
||||
return nullptr;
|
||||
}
|
||||
VLOG(1) << "ConnectToService server address: " << server_address.ToString();
|
||||
|
||||
// Try connecting to the service up to wifi_direct_max_connection_retries,
|
||||
// because it may fail first time if DHCP procedure is not finished yet.
|
||||
int64_t wifi_direct_max_connection_retries =
|
||||
NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionMaxRetries);
|
||||
int64_t wifi_direct_retry_interval_millis =
|
||||
NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionIntervalMillis);
|
||||
int64_t wifi_direct_client_socket_connect_timeout_millis =
|
||||
NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionTimeoutMillis);
|
||||
|
||||
VLOG(1) << "maximum connection retries=" << wifi_direct_max_connection_retries
|
||||
<< ", connection interval=" << wifi_direct_retry_interval_millis
|
||||
<< "ms, connection timeout="
|
||||
<< wifi_direct_client_socket_connect_timeout_millis << "ms";
|
||||
|
||||
LOG(INFO) << "Connect to service ";
|
||||
for (int i = 0; i < wifi_direct_max_connection_retries; ++i) {
|
||||
auto wifi_direct_socket = std::make_unique<WifiDirectServiceSocket>();
|
||||
|
||||
// setup cancel listener
|
||||
std::unique_ptr<CancellationFlagListener> connection_cancellation_listener =
|
||||
nullptr;
|
||||
if (cancellation_flag != nullptr) {
|
||||
if (cancellation_flag->Cancelled()) {
|
||||
LOG(INFO) << "connect has been cancelled to service ";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
connection_cancellation_listener =
|
||||
std::make_unique<nearby::CancellationFlagListener>(
|
||||
cancellation_flag, [socket = wifi_direct_socket.get()]() {
|
||||
LOG(WARNING) << "connect is closed due to it is cancelled.";
|
||||
socket->Close();
|
||||
});
|
||||
}
|
||||
|
||||
bool result = wifi_direct_socket->Connect(server_address);
|
||||
if (!result) {
|
||||
LOG(WARNING) << "reconnect to service at " << (i + 1) << "th times";
|
||||
Sleep(wifi_direct_retry_interval_millis);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(INFO) << "connected to remote service ";
|
||||
return wifi_direct_socket;
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Failed to connect to service ";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Advertiser starts to listen on server socket
|
||||
std::unique_ptr<api::WifiDirectServiceServerSocket>
|
||||
WifiDirectServiceMedium::ListenForService(int port) {
|
||||
LOG(INFO) << "WifiDirectServiceMedium::ListenForService";
|
||||
|
||||
absl::MutexLock lock(mutex_);
|
||||
if (!IsServiceStarted()) {
|
||||
LOG(WARNING) << "WifiDirect service is not started, skip.";
|
||||
return nullptr;
|
||||
}
|
||||
// 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<WifiDirectServiceServerSocket>(port);
|
||||
server_socket_ptr_ = server_socket.get();
|
||||
|
||||
// Start to listen on server socket in a separate thread. Before GC
|
||||
// connects to GO, GO doesn't have IP address. BWU calls this API right away
|
||||
// after it starts GO, we need to spin out the following logic to another
|
||||
// thread to avoid blocking BWU sending out of band upgrade frame to GC.
|
||||
listener_executor_.Execute([this]() mutable {
|
||||
absl::MutexLock lock(mutex_);
|
||||
bool dual_stack = NearbyFlags::GetInstance().GetBoolFlag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kEnableIpv6DualStack);
|
||||
if (ip_address_local_.empty()) {
|
||||
if (server_socket_ptr_) {
|
||||
LOG(INFO) << "Waiting for IP address is ready.";
|
||||
is_ip_address_ready_.WaitWithTimeout(
|
||||
&mutex_, absl::Seconds(kWaitingForConnectionTimeoutSeconds));
|
||||
if (!server_socket_ptr_) {
|
||||
LOG(WARNING)
|
||||
<< "Server socket was closed before IP address is ready.";
|
||||
return;
|
||||
}
|
||||
if (ip_address_local_.empty()) {
|
||||
LOG(WARNING) << "IP address is still empty, probably the GO doesn't "
|
||||
"receive GC's connection request.";
|
||||
server_socket_ptr_->Close();
|
||||
server_socket_ptr_ = nullptr;
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "IP address is ready.";
|
||||
}
|
||||
}
|
||||
|
||||
if (server_socket_ptr_ &&
|
||||
server_socket_ptr_->Listen(dual_stack, ip_address_local_)) {
|
||||
medium_status_ |= kMediumStatusAccepting;
|
||||
|
||||
// Setup close notifier after listen started.
|
||||
server_socket_ptr_->SetCloseNotifier([this]() {
|
||||
absl::MutexLock lock(mutex_);
|
||||
LOG(INFO) << "Server socket was closed.";
|
||||
medium_status_ &= (~kMediumStatusAccepting);
|
||||
server_socket_ptr_ = nullptr;
|
||||
});
|
||||
LOG(INFO) << "Started to listen serive on port "
|
||||
<< server_socket_ptr_->GetPort();
|
||||
} else {
|
||||
LOG(WARNING) << "server_socket_ptr_ is null or Listen failed.";
|
||||
if (server_socket_ptr_) {
|
||||
server_socket_ptr_->Close();
|
||||
server_socket_ptr_ = nullptr;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
LOG(INFO) << "Started to listen service on port " << port;
|
||||
|
||||
return server_socket;
|
||||
}
|
||||
|
||||
bool WifiDirectServiceMedium::StartWifiDirectService() {
|
||||
LOG(INFO) << "WifiDirectServiceMedium::StartWifiDirectService";
|
||||
|
||||
@@ -137,6 +350,9 @@ bool WifiDirectServiceMedium::StopWifiDirectService() {
|
||||
session_ = nullptr;
|
||||
}
|
||||
medium_status_ &= (~kMediumStatusServiceStarted);
|
||||
medium_status_ &= (~kMediumStatusConnected);
|
||||
server_socket_ptr_ = nullptr;
|
||||
listener_executor_.Shutdown();
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
LOG(ERROR) << __func__ << ": Stop WifiDirect GO failed. Exception: "
|
||||
@@ -272,9 +488,11 @@ fire_and_forget WifiDirectServiceMedium::OnSessionRequested(
|
||||
winrt::to_string(pair.RemoteHostName().DisplayName());
|
||||
LOG(INFO) << "GO: Local IP: " << ip_address_local_
|
||||
<< ", Remote IP: " << ip_address_remote_;
|
||||
is_ip_address_ready_.SignalAll();
|
||||
} else {
|
||||
LOG(WARNING) << "GO: No connection endpoint pairs found.";
|
||||
}
|
||||
medium_status_ |= kMediumStatusConnected;
|
||||
|
||||
LOG(INFO) << "Service Address: "
|
||||
<< winrt::to_string(session_.ServiceAddress())
|
||||
@@ -417,6 +635,11 @@ fire_and_forget WifiDirectServiceMedium::Watcher_DeviceAdded(
|
||||
<< ", Session Address: "
|
||||
<< winrt::to_string(session_.SessionAddress())
|
||||
<< ", Session ID: " << session_.SessionId();
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
is_ip_address_ready_.SignalAll();
|
||||
}
|
||||
medium_status_ |= kMediumStatusConnected;
|
||||
|
||||
// Subscribe to events to prevent early teardown
|
||||
session_.SessionStatusChanged([](auto const& s, auto const& e) {
|
||||
@@ -456,7 +679,7 @@ fire_and_forget WifiDirectServiceMedium::Watcher_DeviceEnumerationCompleted(
|
||||
|
||||
fire_and_forget WifiDirectServiceMedium::Watcher_DeviceStopped(
|
||||
DeviceWatcher sender, IInspectable inspectable) {
|
||||
LOG(INFO) << "WifiDirectServiceMedium::Watcher_DeviceStopped";
|
||||
medium_status_ &= (~kMediumStatusConnecting);
|
||||
return fire_and_forget();
|
||||
}
|
||||
|
||||
@@ -476,6 +699,7 @@ bool WifiDirectServiceMedium::DisconnectWifiDirectService() {
|
||||
device_watcher_.Removed(device_watcher_removed_event_token_);
|
||||
device_watcher_.Stopped(device_watcher_stopped_event_token_);
|
||||
medium_status_ &= (~kMediumStatusConnecting);
|
||||
medium_status_ &= (~kMediumStatusConnected);
|
||||
device_watcher_ = nullptr;
|
||||
service_ = nullptr;
|
||||
session_ = nullptr;
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
// 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 <cstdint>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// Nearby connections headers
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/wifi_direct_service.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.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/socket_address.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct_service.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby::windows {
|
||||
|
||||
namespace {
|
||||
using ::winrt::Windows::Networking::Connectivity::NetworkInformation;
|
||||
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
} // namespace
|
||||
|
||||
WifiDirectServiceServerSocket::WifiDirectServiceServerSocket(int port)
|
||||
: port_(port) {}
|
||||
|
||||
WifiDirectServiceServerSocket::~WifiDirectServiceServerSocket() { Close(); }
|
||||
|
||||
std::string WifiDirectServiceServerSocket::GetIPAddress() const {
|
||||
return wifi_direct_service_ipaddr_;
|
||||
}
|
||||
|
||||
int WifiDirectServiceServerSocket::GetPort() const {
|
||||
return server_socket_.GetPort();
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectServiceSocket>
|
||||
WifiDirectServiceServerSocket::Accept() {
|
||||
auto client_socket = server_socket_.Accept();
|
||||
if (client_socket == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG(INFO) << __func__ << ": Accepted a remote connection.";
|
||||
return std::make_unique<WifiDirectServiceSocket>(std::move(client_socket));
|
||||
}
|
||||
|
||||
void WifiDirectServiceServerSocket::SetCloseNotifier(
|
||||
absl::AnyInvocable<void()> notifier) {
|
||||
close_notifier_ = std::move(notifier);
|
||||
}
|
||||
|
||||
Exception WifiDirectServiceServerSocket::Close() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (closed_) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
server_socket_.Close();
|
||||
closed_ = true;
|
||||
|
||||
if (close_notifier_ != nullptr) {
|
||||
close_notifier_();
|
||||
}
|
||||
|
||||
LOG(INFO) << __func__ << ": Close completed succesfully.";
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
bool WifiDirectServiceServerSocket::Listen(bool dual_stack,
|
||||
std::string& ip_address) {
|
||||
// Get current IP addresses of the device.
|
||||
if (ip_address.empty()) {
|
||||
return false;
|
||||
}
|
||||
wifi_direct_service_ipaddr_ = ip_address;
|
||||
LOG(INFO) << "Listen wifi_direct_service on IP:port " << ip_address << ":"
|
||||
<< port_;
|
||||
SocketAddress address(dual_stack);
|
||||
if (!SocketAddress::FromString(address, ip_address, port_)) {
|
||||
LOG(ERROR) << "Failed to parse wifi_direct_service IP address: "
|
||||
<< ip_address << " and port: " << port_;
|
||||
return false;
|
||||
}
|
||||
if (!server_socket_.Listen(address)) {
|
||||
LOG(ERROR) << "Failed to listen socket.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WifiDirectServiceServerSocket::GetWifiDirectServiceIpAddress()
|
||||
const {
|
||||
return wifi_direct_service_ipaddr_;
|
||||
}
|
||||
|
||||
} // namespace nearby::windows
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/nullability.h"
|
||||
#include "internal/platform/implementation/windows/nearby_client_socket.h"
|
||||
#include "internal/platform/implementation/windows/wifi_direct_service.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
WifiDirectServiceSocket::WifiDirectServiceSocket()
|
||||
: client_socket_(std::make_unique<NearbyClientSocket>()),
|
||||
input_stream_(client_socket_.get()),
|
||||
output_stream_(client_socket_.get()) {}
|
||||
|
||||
WifiDirectServiceSocket::WifiDirectServiceSocket(
|
||||
absl_nonnull std::unique_ptr<NearbyClientSocket> socket)
|
||||
: client_socket_(std::move(socket)),
|
||||
input_stream_(client_socket_.get()),
|
||||
output_stream_(client_socket_.get()) {}
|
||||
|
||||
WifiDirectServiceSocket::~WifiDirectServiceSocket() { Close(); }
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
Reference in New Issue
Block a user