Skip to content

Commit

Permalink
Support blocking socket in Wi-Fi hotspot medium
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 718006644
  • Loading branch information
ggli-google authored and copybara-github committed Jan 21, 2025
1 parent d73d1d0 commit b0be56b
Show file tree
Hide file tree
Showing 4 changed files with 545 additions and 334 deletions.
22 changes: 22 additions & 0 deletions internal/platform/implementation/windows/wifi_hotspot.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/implementation/wifi_hotspot.h"
#include "internal/platform/implementation/windows/nearby_client_socket.h"
#include "internal/platform/implementation/windows/nearby_server_socket.h"
#include "internal/platform/implementation/windows/scheduled_executor.h"
#include "internal/platform/implementation/windows/submittable_executor.h"
#include "internal/platform/implementation/windows/wifi_hotspot_native.h"
Expand All @@ -55,6 +58,8 @@
#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"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/wifi_credential.h"

namespace nearby {
Expand Down Expand Up @@ -109,6 +114,8 @@ using ::winrt::Windows::Networking::Sockets::
// remote WiFi Hotspot service, also will return a WifiHotspotSocket to caller.
class WifiHotspotSocket : public api::WifiHotspotSocket {
public:
WifiHotspotSocket();
explicit WifiHotspotSocket(std::unique_ptr<NearbyClientSocket> socket);
explicit WifiHotspotSocket(StreamSocket socket);
explicit WifiHotspotSocket(SOCKET socket);
WifiHotspotSocket(const WifiHotspotSocket&) = default;
Expand All @@ -134,48 +141,59 @@ class WifiHotspotSocket : public api::WifiHotspotSocket {
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override;

bool Connect(const std::string& ip_address, int port);

private:
enum class SocketType { kWinRTSocket = 0, kWin32Socket };
// A simple wrapper to handle input stream of socket
class SocketInputStream : public InputStream {
public:
explicit SocketInputStream(IInputStream input_stream);
explicit SocketInputStream(SOCKET socket);
explicit SocketInputStream(NearbyClientSocket* client_socket);
~SocketInputStream() override = default;

ExceptionOr<ByteArray> Read(std::int64_t size) override;
ExceptionOr<size_t> Skip(size_t offset) override;
Exception Close() override;

private:
bool enable_blocking_socket_ = false;
IInputStream input_stream_{nullptr};
SOCKET socket_ = INVALID_SOCKET;
SocketType socket_type_ = SocketType::kWinRTSocket;
ByteArray read_buffer_;
NearbyClientSocket* client_socket_{nullptr};
};

// A simple wrapper to handle output stream of socket
class SocketOutputStream : public OutputStream {
public:
explicit SocketOutputStream(IOutputStream output_stream);
explicit SocketOutputStream(SOCKET socket);
explicit SocketOutputStream(NearbyClientSocket* client_socket);
~SocketOutputStream() override = default;

Exception Write(const ByteArray& data) override;
Exception Flush() override;
Exception Close() override;

private:
bool enable_blocking_socket_ = false;
IOutputStream output_stream_{nullptr};
SOCKET socket_ = INVALID_SOCKET;
SocketType socket_type_ = SocketType::kWinRTSocket;
NearbyClientSocket* client_socket_{nullptr};
};

// Internal properties
SOCKET stream_soket_winsock_ = INVALID_SOCKET;
StreamSocket stream_soket_{nullptr};
SocketInputStream input_stream_{nullptr};
SocketOutputStream output_stream_{nullptr};

bool enable_blocking_socket_ = false;
std::unique_ptr<NearbyClientSocket> client_socket_;
};

// WifiHotspotServerSocket provides the support to server socket, this server
Expand Down Expand Up @@ -216,6 +234,10 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
// Binds to local port
bool listen();

// Flag to enable blocking socket.
bool enable_blocking_socket_ = false;
NearbyServerSocket server_socket_;

private:
static constexpr int kSocketEventsCount = 2;
static constexpr int kSocketEventListen = 0;
Expand Down
143 changes: 93 additions & 50 deletions internal/platform/implementation/windows/wifi_hotspot_medium.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "absl/strings/str_format.h"
#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/byte_array.h"
#include "internal/platform/cancellation_flag.h"
Expand Down Expand Up @@ -97,9 +98,6 @@ std::unique_ptr<api::WifiHotspotSocket> WifiHotspotMedium::ConnectToService(
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 wifi_hotspot_max_connection_retries,
// because it may fail first time if DHCP procedure is not finished yet.
int64_t wifi_hotspot_max_connection_retries =
Expand All @@ -120,14 +118,17 @@ std::unique_ptr<api::WifiHotspotSocket> WifiHotspotMedium::ConnectToService(
<< ", connection interval=" << wifi_hotspot_retry_interval_millis
<< "ms, connection timeout="
<< wifi_hotspot_client_socket_connect_timeout_millis << "ms";
for (int i = 0; i < wifi_hotspot_max_connection_retries; i++) {
try {
StreamSocket socket{};
// Listener to connect cancellation.
std::unique_ptr<CancellationFlagListener>
connection_cancellation_listener = nullptr;

if (NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket)) {
LOG(INFO) << "Connect to service " << ipv4_address << ":" << port;
for (int i = 0; i < wifi_hotspot_max_connection_retries; ++i) {
auto wifi_hotspot_socket = std::make_unique<WifiHotspotSocket>();

// 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 " << ipv4_address
Expand All @@ -137,57 +138,100 @@ std::unique_ptr<api::WifiHotspotSocket> WifiHotspotMedium::ConnectToService(

connection_cancellation_listener =
std::make_unique<nearby::CancellationFlagListener>(
cancellation_flag, [socket]() {
cancellation_flag, [socket = wifi_hotspot_socket.get()]() {
LOG(WARNING) << "connect is closed due to it is cancelled.";
socket.Close();
socket->Close();
});
}

if (FeatureFlags::GetInstance().GetFlags().enable_connection_timeout) {
connection_timeout_ = scheduled_executor_.Schedule(
[socket]() {
LOG(WARNING) << "connect is closed due to timeout.";
socket.Close();
},
absl::Milliseconds(
wifi_hotspot_client_socket_connect_timeout_millis));
bool result = wifi_hotspot_socket->Connect(ipv4_address, port);
if (!result) {
LOG(WARNING) << "reconnect to service at " << (i + 1) << "th times";
Sleep(wifi_hotspot_retry_interval_millis);
continue;
}

socket.ConnectAsync(host_name, service_name).get();
LOG(INFO) << "connected to remote service " << ipv4_address << ":"
<< port;
return wifi_hotspot_socket;
}

LOG(ERROR) << "Failed to connect to service " << ipv4_address << ":"
<< port;
return nullptr;
} else {
HostName host_name{winrt::to_hstring(ipv4_address)};
winrt::hstring service_name{winrt::to_hstring(port)};

for (int i = 0; i < wifi_hotspot_max_connection_retries; i++) {
try {
StreamSocket socket{};
// Listener to connect cancellation.
std::unique_ptr<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();
});
}

if (FeatureFlags::GetInstance().GetFlags().enable_connection_timeout) {
connection_timeout_ = scheduled_executor_.Schedule(
[socket]() {
LOG(WARNING) << "connect is closed due to timeout.";
socket.Close();
},
absl::Milliseconds(
wifi_hotspot_client_socket_connect_timeout_millis));
}

socket.ConnectAsync(host_name, service_name).get();

if (connection_timeout_ != nullptr) {
connection_timeout_->Cancel();
connection_timeout_ = nullptr;
}

auto wifi_hotspot_socket = std::make_unique<WifiHotspotSocket>(socket);

LOG(INFO) << "connected to remote service " << ipv4_address << ":"
<< port;
return wifi_hotspot_socket;
} catch (std::exception exception) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time. Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time. WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time due to unknown reason.";
}

if (connection_timeout_ != nullptr) {
connection_timeout_->Cancel();
connection_timeout_ = nullptr;
}

auto wifi_hotspot_socket = std::make_unique<WifiHotspotSocket>(socket);

LOG(INFO) << "connected to remote service " << ipv4_address << ":"
<< port;
return wifi_hotspot_socket;
} catch (std::exception exception) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time. Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time. WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port << " for the " << i + 1
<< " time due to unknown reason.";
}

if (connection_timeout_ != nullptr) {
connection_timeout_->Cancel();
connection_timeout_ = nullptr;
Sleep(wifi_hotspot_retry_interval_millis);
}

Sleep(wifi_hotspot_retry_interval_millis);
return nullptr;
}
return nullptr;
}

std::unique_ptr<api::WifiHotspotServerSocket>
Expand Down Expand Up @@ -401,10 +445,9 @@ fire_and_forget WifiHotspotMedium::OnConnectionRequested(
// We found new connection request comes in during hotspot transfer. In this
// case, we should create a new WiFiDirectDevice for it. It will cause
// transfer failure if replace the old WiFiDirectDevice with it.
auto wifi_direct_device =
WiFiDirectDevice::FromIdAsync(
connection_request.DeviceInformation().Id())
.get();
auto wifi_direct_device = WiFiDirectDevice::FromIdAsync(
connection_request.DeviceInformation().Id())
.get();
wifi_direct_devices_.push_back(wifi_direct_device);
LOG(INFO) << "Registered the device " << winrt::to_string(device_name)
<< " in WLAN-AutoConfig";
Expand Down
Loading

0 comments on commit b0be56b

Please sign in to comment.