Cleanup blocking socket flag.

PiperOrigin-RevId: 803211100
This commit is contained in:
Francis Tsui
2025-09-04 16:06:01 -07:00
committed by Copybara-Service
parent d25872b2e0
commit beaab63d4b
9 changed files with 180 additions and 1418 deletions
@@ -29,10 +29,6 @@ constexpr absl::string_view kConfigPackage = "nearby";
// The Nearby Platform features.
namespace nearby_platform_feature {
// Disable/Enable win32 socket implementation for Wi-Fi hotspot.
constexpr auto kEnableHotspotWin32Socket =
flags::Flag<bool>(kConfigPackage, "45401992", true);
// The maximum scanning times for available hotspots.
constexpr auto kWifiHotspotScanMaxRetries =
flags::Flag<int64_t>(kConfigPackage, "45415883", 3);
@@ -69,10 +65,6 @@ constexpr auto kEnableNewBluetoothRefactor =
constexpr auto kEnableWifiHotspotNativeScan =
flags::Flag<bool>(kConfigPackage, "45670001", false);
// Enable/Disable blocking socket
constexpr auto kEnableBlockingSocket =
flags::Flag<bool>(kConfigPackage, "45672381", false);
// The send buffer size of blocking socket
constexpr auto kSocketSendBufferSize =
flags::Flag<int64_t>(kConfigPackage, "45673785", 524288);
@@ -22,7 +22,6 @@
// Standard C/C++ headers
#include <cstdint>
#include <deque>
#include <exception>
#include <memory>
#include <optional>
@@ -37,26 +36,16 @@
#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"
// WinRT headers
#include "absl/types/optional.h"
#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"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
@@ -66,58 +55,23 @@ 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;
// WifiHotspotSocket wraps the socket functions to read and write stream.
// In WiFi HOTSPOT, A WifiHotspotSocket will be passed to
// StartAcceptingConnections's callback when Winsock Server Socket(or
// StreamSocketListener) receives a new connection. When call API to connect to
// remote WiFi Hotspot service, also will return a WifiHotspotSocket to caller.
// 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 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;
WifiHotspotSocket(WifiHotspotSocket&&) = default;
~WifiHotspotSocket() override;
@@ -144,12 +98,9 @@ class WifiHotspotSocket : public api::WifiHotspotSocket {
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;
@@ -158,19 +109,12 @@ class WifiHotspotSocket : public api::WifiHotspotSocket {
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;
@@ -179,20 +123,13 @@ class WifiHotspotSocket : public api::WifiHotspotSocket {
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_;
};
@@ -211,10 +148,6 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
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.
@@ -234,8 +167,6 @@ 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:
@@ -243,36 +174,11 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
static constexpr int kSocketEventListen = 0;
static constexpr int kSocketEventClose = 1;
// The listener is accepting incoming connections
fire_and_forget Listener_ConnectionReceived(
StreamSocketListener listener,
StreamSocketListenerConnectionReceivedEventArgs const& args);
bool SetupServerSocketWinRT();
bool SetupServerSocketWinSock();
// Retrieves hotspot IP address from local machine
std::string GetHotspotIpAddress() const;
void SocketErrorNotice(absl::string_view reason);
mutable absl::Mutex mutex_;
absl::CondVar cond_;
SubmittableExecutor submittable_executor_;
std::deque<StreamSocket> pending_sockets_ ABSL_GUARDED_BY(mutex_);
StreamSocketListener stream_socket_listener_{nullptr};
winrt::event_token listener_event_token_{};
std::deque<SOCKET> pending_client_sockets_ ABSL_GUARDED_BY(mutex_);
SOCKET listen_socket_ = INVALID_SOCKET;
SOCKET client_socket_ = INVALID_SOCKET;
// closesocket cannot trigger FD_CLOSE on listener socket. In order to avoid
// blocking in WSAWaitForMultipleEvents, we use a socket event to trigger
// WSAWaitForMultipleEvents safely.
// The socket_events_ has 2 events, the first one is to handle normal socket
// event, and the second one is to handle event to close the socket manually.
WSAEVENT socket_events_[kSocketEventsCount];
// Close notifier
absl::AnyInvocable<void()> close_notifier_ = nullptr;
@@ -369,9 +275,6 @@ class WifiHotspotMedium : public api::WifiHotspotMedium {
// Scheduler for timeout.
ScheduledExecutor scheduled_executor_;
// Scheduled task for connection timeout.
std::shared_ptr<api::Cancelable> connection_timeout_ = nullptr;
// connects Wi-Fi hotspot using native API.
WifiHotspotNative wifi_hotspot_native_;
std::optional<std::wstring> connected_hotspot_profile_name_;
@@ -19,7 +19,6 @@
#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"
@@ -32,6 +31,8 @@
#include "internal/platform/implementation/platform.h"
#include "internal/platform/implementation/wifi_hotspot.h"
#include "internal/platform/implementation/wifi_utils.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Security.Credentials.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/implementation/windows/wifi_hotspot.h"
@@ -42,8 +43,13 @@
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Devices::WiFiDirect::
WiFiDirectAdvertisementPublisherStatus;
using ::winrt::Windows::Devices::WiFiDirect::WiFiDirectConnectionRequest;
using ::winrt::Windows::Security::Credentials::PasswordCredential;
constexpr absl::string_view kHotspotSsidFileName = "ssid.txt";
}
} // namespace
WifiHotspotMedium::WifiHotspotMedium() {
std::string ssid = GetStoredHotspotSsid();
@@ -119,119 +125,41 @@ std::unique_ptr<api::WifiHotspotSocket> WifiHotspotMedium::ConnectToService(
<< "ms, connection timeout="
<< wifi_hotspot_client_socket_connect_timeout_millis << "ms";
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>();
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
<< ":" << port;
return nullptr;
}
connection_cancellation_listener =
std::make_unique<nearby::CancellationFlagListener>(
cancellation_flag, [socket = wifi_hotspot_socket.get()]() {
LOG(WARNING) << "connect is closed due to it is cancelled.";
socket->Close();
});
// 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
<< ":" << port;
return nullptr;
}
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;
}
LOG(INFO) << "connected to remote service " << ipv4_address << ":"
<< port;
return wifi_hotspot_socket;
connection_cancellation_listener =
std::make_unique<nearby::CancellationFlagListener>(
cancellation_flag, [socket = wifi_hotspot_socket.get()]() {
LOG(WARNING) << "connect is closed due to it is cancelled.";
socket->Close();
});
}
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;
}
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;
}
return nullptr;
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;
}
std::unique_ptr<api::WifiHotspotServerSocket>
@@ -31,6 +31,8 @@
#include "internal/platform/exception.h"
#include "internal/platform/flags/nearby_platform_feature_flags.h"
#include "internal/platform/implementation/wifi_hotspot.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/utils.h"
#include "internal/platform/implementation/windows/wifi_hotspot.h"
@@ -39,102 +41,31 @@
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Networking::Connectivity::NetworkInformation;
using ::winrt::Windows::Networking::HostNameType;
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
} // namespace
WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
if (!enable_blocking_socket_) {
for (auto &it : socket_events_) {
it = WSA_INVALID_EVENT;
}
}
}
WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {}
WifiHotspotServerSocket::~WifiHotspotServerSocket() { Close(); }
std::string WifiHotspotServerSocket::GetIPAddress() const {
if (enable_blocking_socket_) {
return server_socket_.GetIPAddress();
} else {
if (NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableHotspotWin32Socket)) {
if (listen_socket_ == INVALID_SOCKET) {
return {};
}
} else {
if (stream_socket_listener_ == nullptr) {
return {};
}
}
return GetHotspotIpAddress();
}
return server_socket_.GetIPAddress();
}
int WifiHotspotServerSocket::GetPort() const {
if (enable_blocking_socket_) {
return server_socket_.GetPort();
} else {
if (NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableHotspotWin32Socket)) {
if (listen_socket_ == INVALID_SOCKET) {
LOG(WARNING) << __func__ << ": listen_socket_ is invalid.";
return 0;
}
return port_;
} else {
if (stream_socket_listener_ == nullptr) {
return 0;
}
return std::stoi(
stream_socket_listener_.Information().LocalPort().c_str());
}
}
return server_socket_.GetPort();
}
std::unique_ptr<api::WifiHotspotSocket> WifiHotspotServerSocket::Accept() {
if (enable_blocking_socket_) {
auto client_socket = server_socket_.Accept();
if (client_socket == nullptr) {
return nullptr;
}
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiHotspotSocket>(std::move(client_socket));
} else {
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Accept is called.";
if (NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableHotspotWin32Socket)) {
while (!closed_ && pending_client_sockets_.empty()) {
cond_.Wait(&mutex_);
}
if (closed_) return {};
SOCKET wifi_hotspot_socket = pending_client_sockets_.front();
pending_client_sockets_.pop_front();
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiHotspotSocket>(wifi_hotspot_socket);
}
// Code when using WinRT API
while (!closed_ && pending_sockets_.empty()) {
cond_.Wait(&mutex_);
}
if (closed_) return {};
StreamSocket wifi_hotspot_socket = pending_sockets_.front();
pending_sockets_.pop_front();
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiHotspotSocket>(wifi_hotspot_socket);
auto client_socket = server_socket_.Accept();
if (client_socket == nullptr) {
return nullptr;
}
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiHotspotSocket>(std::move(client_socket));
}
void WifiHotspotServerSocket::SetCloseNotifier(
@@ -145,306 +76,35 @@ void WifiHotspotServerSocket::SetCloseNotifier(
Exception WifiHotspotServerSocket::Close() {
try {
absl::MutexLock lock(&mutex_);
if (enable_blocking_socket_) {
if (closed_) {
return {Exception::kSuccess};
}
if (closed_) {
return {Exception::kSuccess};
}
server_socket_.Close();
closed_ = true;
server_socket_.Close();
closed_ = true;
if (close_notifier_ != nullptr) {
close_notifier_();
}
} else {
VLOG(1) << __func__ << ": Close is called.";
if (closed_) {
return {Exception::kSuccess};
}
if (NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableHotspotWin32Socket)) {
if (listen_socket_ != INVALID_SOCKET) {
LOG(INFO) << ": Close listen_socket_: " << listen_socket_;
// Trigger close event manually
WSASetEvent(socket_events_[kSocketEventClose]);
shutdown(listen_socket_, 2);
shutdown(client_socket_, 2);
closesocket(listen_socket_);
closesocket(client_socket_);
for (const auto &pending_socket : pending_client_sockets_) {
if (pending_socket != INVALID_SOCKET) closesocket(pending_socket);
}
submittable_executor_.Shutdown();
listen_socket_ = INVALID_SOCKET;
client_socket_ = INVALID_SOCKET;
for (auto &it : socket_events_) {
WSACloseEvent(it);
it = WSA_INVALID_EVENT;
}
WSACleanup();
pending_client_sockets_ = {};
}
} else {
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_();
}
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 exception.";
return {Exception::kIo};
}
}
fire_and_forget WifiHotspotServerSocket::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{};
}
bool WifiHotspotServerSocket::SetupServerSocketWinRT() {
// 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, &WifiHotspotServerSocket::Listener_ConnectionReceived});
try {
HostName host_name{winrt::to_hstring(hotspot_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 exception.";
}
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 exception.";
}
return false;
}
void WifiHotspotServerSocket::SocketErrorNotice(absl::string_view reason) {
LOG(WARNING) << "socket error. " << reason
<< " failed with error: " << WSAGetLastError();
for (auto &it : socket_events_) {
if (it != WSA_INVALID_EVENT) {
WSACloseEvent(it);
it = WSA_INVALID_EVENT;
}
}
closesocket(listen_socket_);
WSACleanup();
}
bool WifiHotspotServerSocket::SetupServerSocketWinSock() {
WSADATA wsa_data;
int flag = 1;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
LOG(WARNING) << "WSAStartup failed with error:" << result;
return false;
}
listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_socket_ == INVALID_SOCKET) {
LOG(WARNING) << "Failed to get socket";
WSACleanup();
return false;
}
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_);
serv_addr.sin_addr.s_addr = inet_addr(hotspot_ipaddr_.c_str());
unsigned long qos = 1; // NOLINT
ioctlsocket(listen_socket_, SIO_SET_QOS, &qos);
setsockopt(listen_socket_, SOL_SOCKET, SO_KEEPALIVE, (const char *)&flag,
sizeof(flag));
if (bind(listen_socket_, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ==
SOCKET_ERROR) {
SocketErrorNotice("Bind");
return false;
}
VLOG(1) << "Bind socket successful";
int size = sizeof(serv_addr);
memset(&serv_addr, 0, size);
if (getsockname(listen_socket_, (struct sockaddr *)&serv_addr, &size) ==
SOCKET_ERROR) {
SocketErrorNotice("Getsockname");
return false;
}
port_ = ntohs(serv_addr.sin_port);
socket_events_[kSocketEventListen] = WSACreateEvent();
if (socket_events_[kSocketEventListen] == WSA_INVALID_EVENT) {
SocketErrorNotice("WSACreateEvent");
return false;
}
socket_events_[kSocketEventClose] = WSACreateEvent();
if (socket_events_[kSocketEventClose] == WSA_INVALID_EVENT) {
SocketErrorNotice("WSACreateEvent");
return false;
}
// Associate event types FD_ACCEPT and FD_CLOSE with the listen_socket_ and
// socket_event
if (WSAEventSelect(listen_socket_, socket_events_[kSocketEventListen],
FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR) {
SocketErrorNotice("WSAEventSelect");
return false;
}
if (::listen(listen_socket_, SOMAXCONN) == SOCKET_ERROR) {
SocketErrorNotice("Listen");
return false;
}
LOG(INFO) << "Hotspot Server Socket " << listen_socket_
<< " started to listen on port: " << port_;
submittable_executor_.Execute([this]() {
DWORD index;
WSANETWORKEVENTS network_events;
// Wait for network events on all sockets
index = WSAWaitForMultipleEvents(kSocketEventsCount, socket_events_, FALSE,
WSA_INFINITE, FALSE);
VLOG(1) << "Hotspot Server Socket " << listen_socket_
<< " received event index: " << index;
if (index == WSA_WAIT_TIMEOUT || index == WSA_WAIT_FAILED) {
LOG(INFO) << "Hotspot Server Socket timout or failed ";
return false;
}
index = index - WSA_WAIT_EVENT_0;
if (index == kSocketEventClose) {
// the socket is closed by SDK
LOG(INFO) << "listner socket is closed.";
return false;
}
// Iterate through all events and enumerate
if (WSAEnumNetworkEvents(listen_socket_, socket_events_[index],
&network_events) == SOCKET_ERROR) {
LOG(INFO) << "Iterate through all events failed";
return false;
}
if (network_events.lNetworkEvents & FD_CLOSE) {
LOG(INFO) << "Reveived FD_CLOSE event";
return false;
}
if (network_events.lNetworkEvents & FD_ACCEPT) {
client_socket_ = accept(listen_socket_, nullptr, nullptr);
VLOG(1) << "Reveived FD_ACCEPT event.";
if (client_socket_ == INVALID_SOCKET) {
return false;
}
if (WSAEventSelect(listen_socket_, socket_events_[kSocketEventListen],
0) == SOCKET_ERROR) {
LOG(WARNING)
<< "Remove association between listen_socket_ and event failed: "
<< WSAGetLastError();
}
LOG(INFO) << "Hotspot Server Client Socket created: " << client_socket_;
if (closed_) {
return false;
}
{
absl::MutexLock lock(&mutex_);
pending_client_sockets_.push_back(client_socket_);
cond_.SignalAll();
}
}
return true;
});
return true;
}
bool WifiHotspotServerSocket::listen() {
// Get current IP addresses of the device.
int64_t ip_address_max_retries = NearbyFlags::GetInstance().GetInt64Flag(
@@ -473,22 +133,12 @@ bool WifiHotspotServerSocket::listen() {
return false;
}
if (enable_blocking_socket_) {
if (!server_socket_.Listen(hotspot_ipaddr_, port_)) {
LOG(ERROR) << "Failed to listen socket.";
return false;
}
return true;
} else {
if (NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableHotspotWin32Socket)) {
return SetupServerSocketWinSock();
} else {
return SetupServerSocketWinRT();
}
if (!server_socket_.Listen(hotspot_ipaddr_, port_)) {
LOG(ERROR) << "Failed to listen socket.";
return false;
}
return true;
}
std::string WifiHotspotServerSocket::GetHotspotIpAddress() const {
@@ -86,31 +86,13 @@ int send_sync(SOCKET s, const char* buf, int len, int flags) {
} // namespace
WifiHotspotSocket::WifiHotspotSocket() {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = std::make_unique<NearbyClientSocket>();
input_stream_ = SocketInputStream(client_socket_.get());
output_stream_ = SocketOutputStream(client_socket_.get());
}
WifiHotspotSocket::WifiHotspotSocket(StreamSocket socket) {
stream_soket_ = socket;
input_stream_ = SocketInputStream(socket.InputStream());
output_stream_ = SocketOutputStream(socket.OutputStream());
}
WifiHotspotSocket::WifiHotspotSocket(SOCKET socket) {
stream_soket_winsock_ = socket;
input_stream_ = SocketInputStream(socket);
output_stream_ = SocketOutputStream(socket);
}
WifiHotspotSocket::WifiHotspotSocket(
std::unique_ptr<NearbyClientSocket> socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = std::move(socket);
input_stream_ = SocketInputStream(client_socket_.get());
output_stream_ = SocketOutputStream(client_socket_.get());
@@ -123,335 +105,76 @@ InputStream& WifiHotspotSocket::GetInputStream() { return input_stream_; }
OutputStream& WifiHotspotSocket::GetOutputStream() { return output_stream_; }
Exception WifiHotspotSocket::Close() {
if (enable_blocking_socket_) {
if (client_socket_ != nullptr) {
return client_socket_->Close();
}
return {Exception::kSuccess};
} else {
try {
if (stream_soket_ != nullptr) {
stream_soket_.Close();
}
if (stream_soket_winsock_ != INVALID_SOCKET) {
closesocket(stream_soket_winsock_);
stream_soket_winsock_ = INVALID_SOCKET;
}
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 exception.";
return {Exception::kIo};
}
if (client_socket_ != nullptr) {
return client_socket_->Close();
}
return {Exception::kSuccess};
}
bool WifiHotspotSocket::Connect(const std::string& ip_address, int port) {
return client_socket_->Connect(ip_address, port);
}
WifiHotspotSocket::SocketInputStream::SocketInputStream(
IInputStream input_stream) {
input_stream_ = input_stream;
socket_type_ = SocketType::kWinRTSocket;
}
WifiHotspotSocket::SocketInputStream::SocketInputStream(SOCKET socket) {
socket_ = socket;
socket_type_ = SocketType::kWin32Socket;
}
WifiHotspotSocket::SocketInputStream::SocketInputStream(
NearbyClientSocket* client_socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = client_socket;
}
ExceptionOr<ByteArray> WifiHotspotSocket::SocketInputStream::Read(
std::int64_t size) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
LOG(ERROR) << "Failed to read data due to no client socket.";
return {Exception::kIo};
}
return client_socket_->Read(size);
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
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<ByteArray>(data);
}
int result;
int count = 0;
// When socket_type_ == SocketType::kWin32Socket
if (size > read_buffer_.size()) {
read_buffer_.resize(size);
}
while (count < size) {
result =
recv_sync(socket_, read_buffer_.data() + count, size - count, 0);
if (result == 0) {
LOG(WARNING) << "Connection closed.";
return {Exception::kIo};
} else if (result < 0) {
LOG(ERROR) << "recv failed with error: " << WSAGetLastError();
return {Exception::kIo};
} else {
count += result;
}
}
ByteArray data(read_buffer_.data(), size);
return ExceptionOr<ByteArray>(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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
LOG(ERROR) << "Failed to read data due to no client socket.";
return {Exception::kIo};
}
return client_socket_->Read(size);
}
ExceptionOr<size_t> WifiHotspotSocket::SocketInputStream::Skip(size_t offset) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Skip(offset);
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
Buffer buffer = Buffer(offset);
auto ibuffer =
input_stream_.ReadAsync(buffer, offset, InputStreamOptions::None)
.get();
return ExceptionOr<size_t>((size_t)ibuffer.Length());
}
// When socket_type_ == SocketType::kWin32Socket
int result;
int count = 0;
// When socket_type_ == SocketType::kWin32Socket
if (offset > read_buffer_.size()) {
read_buffer_.resize(offset);
}
while (count < offset) {
result =
recv_sync(socket_, read_buffer_.data() + count, offset - count, 0);
if (result == 0) {
LOG(WARNING) << "Connection closed.";
return {Exception::kIo};
} else if (result < 0) {
LOG(ERROR) << "recv failed with error: " << WSAGetLastError();
return {Exception::kIo};
} else {
count += result;
}
}
return ExceptionOr<size_t>(offset);
} 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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Skip(offset);
}
Exception WifiHotspotSocket::SocketInputStream::Close() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
input_stream_.Close();
} else {
// When socket_type_ == SocketType::kWin32Socket
shutdown(socket_, SD_RECEIVE);
}
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
}
// SocketOutputStream
WifiHotspotSocket::SocketOutputStream::SocketOutputStream(
IOutputStream output_stream) {
output_stream_ = output_stream;
socket_type_ = SocketType::kWinRTSocket;
}
WifiHotspotSocket::SocketOutputStream::SocketOutputStream(SOCKET socket) {
socket_ = socket;
socket_type_ = SocketType::kWin32Socket;
}
WifiHotspotSocket::SocketOutputStream::SocketOutputStream(
NearbyClientSocket* client_socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = client_socket;
}
Exception WifiHotspotSocket::SocketOutputStream::Write(const ByteArray& data) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Write(data);
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
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};
}
int result;
int count = 0;
while (count < data.size()) {
result =
send_sync(socket_, data.data() + count, data.size() - count, 0);
if (result == 0) {
LOG(WARNING) << "Connection closed.";
return {Exception::kIo};
} else if (result < 0) {
LOG(ERROR) << "Failed to send data with error: " << WSAGetLastError();
return {Exception::kIo};
} else {
count += result;
}
}
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Write(data);
}
Exception WifiHotspotSocket::SocketOutputStream::Flush() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Flush();
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Flush();
}
Exception WifiHotspotSocket::SocketOutputStream::Close() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
} else {
try {
if (socket_type_ == SocketType::kWinRTSocket) {
output_stream_.Close();
} else {
// When socket_type_ == SocketType::kWin32Socket
shutdown(socket_, SD_SEND);
}
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
}
} // namespace windows
@@ -142,7 +142,6 @@ class WifiLanSocket : public api::WifiLanSocket {
Exception Close() override;
private:
bool enable_blocking_socket_ = false;
IInputStream input_stream_{nullptr};
Buffer read_buffer_{nullptr};
NearbyClientSocket* client_socket_{nullptr};
@@ -160,7 +159,6 @@ class WifiLanSocket : public api::WifiLanSocket {
Exception Close() override;
private:
bool enable_blocking_socket_ = false;
IOutputStream output_stream_{nullptr};
NearbyClientSocket* client_socket_{nullptr};
};
@@ -170,7 +168,6 @@ class WifiLanSocket : public api::WifiLanSocket {
SocketInputStream input_stream_{nullptr};
SocketOutputStream output_stream_{nullptr};
bool enable_blocking_socket_ = false;
std::unique_ptr<NearbyClientSocket> client_socket_;
};
@@ -239,8 +236,6 @@ class WifiLanServerSocket : public api::WifiLanServerSocket {
int port_ = 0;
bool closed_ = false;
// Flag to enable blocking socket.
bool enable_blocking_socket_ = false;
NearbyServerSocket server_socket_;
};
@@ -120,75 +120,18 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
absl::flat_hash_map<std::string, std::string> text_records =
nsd_service_info.GetTxtRecords();
if (NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket)) {
bool result = wifi_lan_mdns_.StartMdnsService(
service_name_, nsd_service_info.GetServiceType(),
nsd_service_info.GetPort(), text_records);
bool result = wifi_lan_mdns_.StartMdnsService(
service_name_, nsd_service_info.GetServiceType(),
nsd_service_info.GetPort(), text_records);
if (result) {
LOG(INFO) << "started to mDNS advertising.";
medium_status_ |= kMediumStatusAdvertising;
return true;
}
LOG(ERROR) << "failed to start mDNS advertising.";
return false;
} else {
std::string instance_name =
absl::StrFormat(kMdnsInstanceNameFormat, service_name_,
nsd_service_info.GetServiceType());
LOG(INFO) << "mDNS instance name is " << instance_name;
dnssd_service_instance_ = DnssdServiceInstance{
string_utils::StringToWideString(instance_name),
nullptr, // let windows use default computer's local name
(uint16_t)nsd_service_info.GetPort()};
// Add TextRecords from NsdServiceInfo
auto text_attributes = dnssd_service_instance_.TextAttributes();
auto it = text_records.begin();
while (it != text_records.end()) {
text_attributes.Insert(string_utils::StringToWideString(it->first),
string_utils::StringToWideString(it->second));
it++;
}
if (server_socket_ptr == nullptr) {
LOG(ERROR) << "server socket is null.";
return false;
}
dnssd_regirstraion_result_ = dnssd_service_instance_
.RegisterStreamSocketListenerAsync(
server_socket_ptr->GetSocketListener())
.get();
if (dnssd_regirstraion_result_.HasInstanceNameChanged()) {
LOG(WARNING) << "advertising instance name was changed due to have "
"same name instance was running.";
// stop the service and return false
StopAdvertising(nsd_service_info);
return false;
}
if (dnssd_regirstraion_result_.Status() ==
DnssdRegistrationStatus::Success) {
LOG(INFO) << "started to advertising.";
medium_status_ |= kMediumStatusAdvertising;
return true;
}
// Clean up
LOG(ERROR) << "failed to start advertising due to registration failure.";
dnssd_service_instance_ = nullptr;
dnssd_regirstraion_result_ = nullptr;
return false;
if (result) {
LOG(INFO) << "started to mDNS advertising.";
medium_status_ |= kMediumStatusAdvertising;
return true;
}
LOG(ERROR) << "failed to start mDNS advertising.";
return false;
}
bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
@@ -199,33 +142,19 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
return false;
}
if (NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket)) {
// The service may be running under WinRT when the flag is enabled.
dnssd_service_instance_ = nullptr;
// The service may be running under WinRT when the flag is enabled.
dnssd_service_instance_ = nullptr;
bool result = wifi_lan_mdns_.StopMdnsService();
bool result = wifi_lan_mdns_.StopMdnsService();
if (result) {
medium_status_ &= (~kMediumStatusAdvertising);
return true;
}
LOG(ERROR) << "failed to stop mDNS advertising.";
medium_status_ &= (~kMediumStatusAdvertising);
return false;
} else {
// The service may be running under Win32 when the flag is disabled.
wifi_lan_mdns_.StopMdnsService();
dnssd_service_instance_ = nullptr;
LOG(INFO) << "succeeded to stop mDNS advertising for service type ="
<< nsd_service_info.GetServiceType();
if (result) {
medium_status_ &= (~kMediumStatusAdvertising);
return true;
}
LOG(ERROR) << "failed to stop mDNS advertising.";
medium_status_ &= (~kMediumStatusAdvertising);
return false;
}
// Returns true once the WifiLan discovery has been initiated.
@@ -337,88 +266,28 @@ std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
std::unique_ptr<CancellationFlagListener> connection_cancellation_listener =
nullptr;
if (NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket)) {
auto wifi_lan_socket = std::make_unique<WifiLanSocket>();
auto wifi_lan_socket = std::make_unique<WifiLanSocket>();
// setup cancel listener
if (cancellation_flag != nullptr) {
connection_cancellation_listener =
std::make_unique<nearby::CancellationFlagListener>(
cancellation_flag, [socket = wifi_lan_socket.get()]() {
LOG(WARNING) << "connect is closed due to it is cancelled.";
socket->Close();
});
}
bool result = wifi_lan_socket->Connect(ipv4_address, port);
if (!result) {
LOG(ERROR) << "failed to connect to service " << ipv4_address << ":"
<< port;
return nullptr;
}
LOG(INFO) << "connected to remote service " << ipv4_address << ":" << port;
return wifi_lan_socket;
} else {
HostName host_name{
string_utils::StringToWideString(std::string(ipv4_address))};
winrt::hstring service_name{winrt::to_hstring(port)};
StreamSocket socket{};
// setup cancel listener
if (cancellation_flag != 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 to the service
try {
if (FeatureFlags::GetInstance().GetFlags().enable_connection_timeout) {
connection_timeout_ = scheduled_executor_.Schedule(
[socket]() {
LOG(WARNING) << "connect is closed due to timeout.";
socket.Close();
},
kConnectServiceTimeout);
}
socket.ConnectAsync(host_name, service_name).get();
if (connection_timeout_ != nullptr) {
connection_timeout_->Cancel();
connection_timeout_ = nullptr;
}
auto wifi_lan_socket = std::make_unique<WifiLanSocket>(socket);
std::string local_address =
winrt::to_string(socket.Information().LocalAddress().DisplayName());
std::string local_port =
winrt::to_string(socket.Information().LocalPort());
LOG(INFO) << "connected to remote service " << ipv4_address << ":" << port
<< " with local address " << local_address << ":" << local_port;
return wifi_lan_socket;
} catch (...) {
LOG(ERROR) << "failed to connect remote service " << ipv4_address << ":"
<< port;
}
if (connection_timeout_ != nullptr) {
connection_timeout_->Cancel();
connection_timeout_ = nullptr;
}
// setup cancel listener
if (cancellation_flag != nullptr) {
connection_cancellation_listener =
std::make_unique<nearby::CancellationFlagListener>(
cancellation_flag, [socket = wifi_lan_socket.get()]() {
LOG(WARNING) << "connect is closed due to it is cancelled.";
socket->Close();
});
}
bool result = wifi_lan_socket->Connect(ipv4_address, port);
if (!result) {
LOG(ERROR) << "failed to connect to service " << ipv4_address << ":"
<< port;
return nullptr;
}
LOG(INFO) << "connected to remote service " << ipv4_address << ":" << port;
return wifi_lan_socket;
}
std::unique_ptr<api::WifiLanServerSocket> WifiLanMedium::ListenForService(
@@ -40,44 +40,18 @@ using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
}
WifiLanServerSocket::WifiLanServerSocket(int port) : port_(port) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
}
WifiLanServerSocket::WifiLanServerSocket(int port) : port_(port) {}
WifiLanServerSocket::~WifiLanServerSocket() { Close(); }
// Returns the first IP address.
std::string WifiLanServerSocket::GetIPAddress() const {
if (enable_blocking_socket_) {
return ipaddr_dotdecimal_to_4bytes_string(server_socket_.GetIPAddress());
} else {
if (stream_socket_listener_ == nullptr) {
LOG(ERROR) << "Failed to get IP address due to no server socket.";
return "";
}
if (ip_addresses_.empty()) {
LOG(ERROR) << "Failed to get IP address due to no avaible IP addresses.";
return "";
}
return ip_addresses_.front();
}
return ipaddr_dotdecimal_to_4bytes_string(server_socket_.GetIPAddress());
}
// Returns socket port.
int WifiLanServerSocket::GetPort() const {
if (enable_blocking_socket_) {
return server_socket_.GetPort();
} else {
if (stream_socket_listener_ == nullptr) {
return 0;
}
return std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
}
return server_socket_.GetPort();
}
// Blocks until either:
@@ -87,29 +61,14 @@ int WifiLanServerSocket::GetPort() const {
// Returns nullptr on error.
// Once error is reported, it is permanent, and ServerSocket has to be closed.
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
if (enable_blocking_socket_) {
auto client_socket = server_socket_.Accept();
if (client_socket == nullptr) {
return nullptr;
}
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiLanSocket>(std::move(client_socket));
} else {
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Accept is called.";
while (!closed_ && pending_sockets_.empty()) {
cond_.Wait(&mutex_);
}
if (closed_) return {};
StreamSocket wifi_lan_socket = pending_sockets_.front();
pending_sockets_.pop_front();
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiLanSocket>(wifi_lan_socket);
auto client_socket = server_socket_.Accept();
if (client_socket == nullptr) {
return nullptr;
}
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<WifiLanSocket>(std::move(client_socket));
}
void WifiLanServerSocket::SetCloseNotifier(
@@ -122,41 +81,17 @@ Exception WifiLanServerSocket::Close() {
try {
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Close is called.";
if (enable_blocking_socket_) {
if (closed_) {
return {Exception::kSuccess};
}
if (closed_) {
return {Exception::kSuccess};
}
LOG(INFO) << __func__ << ": closing blocking socket.";
LOG(INFO) << __func__ << ": closing blocking socket.";
server_socket_.Close();
closed_ = true;
server_socket_.Close();
closed_ = true;
if (close_notifier_ != nullptr) {
close_notifier_();
}
} else {
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_();
}
if (close_notifier_ != nullptr) {
close_notifier_();
}
LOG(INFO) << __func__ << ": Close completed succesfully.";
@@ -181,14 +116,13 @@ Exception WifiLanServerSocket::Close() {
}
bool WifiLanServerSocket::listen() {
if (enable_blocking_socket_) {
ip_addresses_ = GetIpv4Addresses();
ip_addresses_ = GetIpv4Addresses();
if (ip_addresses_.empty()) {
LOG(ERROR) << "failed to start accepting connection without IP "
"addresses configured on computer.";
return false;
}
if (ip_addresses_.empty()) {
LOG(ERROR) << "failed to start accepting connection without IP "
"addresses configured on computer.";
return false;
}
// Listen on all interfaces.
if (!server_socket_.Listen("", port_)) {
@@ -196,69 +130,7 @@ bool WifiLanServerSocket::listen() {
return false;
}
return true;
} else {
// Get current IP addresses of the device.
ip_addresses_ = Get4BytesIpv4Addresses();
if (ip_addresses_.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, &WifiLanServerSocket::Listener_ConnectionReceived});
try {
stream_socket_listener_.BindServiceNameAsync(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 exception.";
}
try {
stream_socket_listener_.BindServiceNameAsync({}).get();
// Need to save the port information.
port_ =
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
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 exception.";
}
return false;
}
return true;
}
fire_and_forget WifiLanServerSocket::Listener_ConnectionReceived(
@@ -33,18 +33,12 @@ namespace nearby {
namespace windows {
WifiLanSocket::WifiLanSocket() {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = std::make_unique<NearbyClientSocket>();
input_stream_ = SocketInputStream(client_socket_.get());
output_stream_ = SocketOutputStream(client_socket_.get());
}
WifiLanSocket::WifiLanSocket(StreamSocket socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
stream_soket_ = socket;
VLOG(1) << "Socket send buffer size: "
<< socket.Control().OutboundBufferSizeInBytes();
@@ -56,9 +50,6 @@ WifiLanSocket::WifiLanSocket(StreamSocket socket) {
}
WifiLanSocket::WifiLanSocket(std::unique_ptr<NearbyClientSocket> socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = std::move(socket);
input_stream_ = SocketInputStream(client_socket_.get());
output_stream_ = SocketOutputStream(client_socket_.get());
@@ -71,28 +62,9 @@ InputStream& WifiLanSocket::GetInputStream() { return input_stream_; }
OutputStream& WifiLanSocket::GetOutputStream() { return output_stream_; }
Exception WifiLanSocket::Close() {
if (enable_blocking_socket_) {
if (client_socket_ != nullptr) {
return client_socket_->Close();
}
} else {
try {
if (stream_soket_ != nullptr) {
stream_soket_.Close();
}
} 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 exception.";
return {Exception::kIo};
}
if (client_socket_ != nullptr) {
return client_socket_->Close();
}
return {Exception::kSuccess};
}
@@ -102,215 +74,73 @@ bool WifiLanSocket::Connect(const std::string& ip_address, int port) {
// SocketInputStream
WifiLanSocket::SocketInputStream::SocketInputStream(IInputStream input_stream) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
input_stream_ = input_stream;
}
WifiLanSocket::SocketInputStream::SocketInputStream(
NearbyClientSocket* client_socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = client_socket;
}
ExceptionOr<ByteArray> WifiLanSocket::SocketInputStream::Read(
std::int64_t size) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
LOG(ERROR) << "Failed to read data due to no client socket.";
return {Exception::kIo};
}
return client_socket_->Read(size);
} else {
try {
if (read_buffer_ == nullptr || read_buffer_.Capacity() < size) {
read_buffer_ = Buffer(size);
}
// Reset the buffer length to 0.
read_buffer_.Length(0);
auto ibuffer =
input_stream_.ReadAsync(read_buffer_, size, InputStreamOptions::None)
.get();
if (ibuffer.Length() != size) {
LOG(WARNING) << "Only read partial of data: [" << ibuffer.Length()
<< "/" << size << "].";
}
ByteArray data((char*)ibuffer.data(), ibuffer.Length());
return ExceptionOr(std::move(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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
LOG(ERROR) << "Failed to read data due to no client socket.";
return {Exception::kIo};
}
return client_socket_->Read(size);
}
ExceptionOr<size_t> WifiLanSocket::SocketInputStream::Skip(size_t offset) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Skip(offset);
} else {
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Skip(offset);
}
Exception WifiLanSocket::SocketInputStream::Close() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
} else {
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
}
// SocketOutputStream
WifiLanSocket::SocketOutputStream::SocketOutputStream(
IOutputStream output_stream) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
output_stream_ = output_stream;
}
WifiLanSocket::SocketOutputStream::SocketOutputStream(
NearbyClientSocket* client_socket) {
enable_blocking_socket_ = NearbyFlags::GetInstance().GetBoolFlag(
nearby::platform::config_package_nearby::nearby_platform_feature::
kEnableBlockingSocket);
client_socket_ = client_socket;
}
Exception WifiLanSocket::SocketOutputStream::Write(const ByteArray& data) {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Write(data);
} else {
try {
Buffer buffer = Buffer(data.size());
std::memcpy(buffer.data(), data.data(), data.size());
buffer.Length(data.size());
uint32_t wrote_bytes = output_stream_.WriteAsync(buffer).get();
if (wrote_bytes != data.size()) {
LOG(WARNING) << "Only wrote partial of data:[" << wrote_bytes << "/"
<< data.size() << "].";
}
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Write(data);
}
Exception WifiLanSocket::SocketOutputStream::Flush() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Flush();
} else {
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Flush();
}
Exception WifiLanSocket::SocketOutputStream::Close() {
if (enable_blocking_socket_) {
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
} else {
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 exception.";
return {Exception::kIo};
}
if (client_socket_ == nullptr) {
return {Exception::kIo};
}
return client_socket_->Close();
}
} // namespace windows