diff --git a/internal/platform/implementation/windows/wifi_hotspot.h b/internal/platform/implementation/windows/wifi_hotspot.h index 5202d4adbb..c02fc59ba7 100644 --- a/internal/platform/implementation/windows/wifi_hotspot.h +++ b/internal/platform/implementation/windows/wifi_hotspot.h @@ -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" @@ -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 { @@ -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 socket); explicit WifiHotspotSocket(StreamSocket socket); explicit WifiHotspotSocket(SOCKET socket); WifiHotspotSocket(const WifiHotspotSocket&) = default; @@ -134,6 +141,8 @@ 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 @@ -141,6 +150,7 @@ class WifiHotspotSocket : public api::WifiHotspotSocket { public: explicit SocketInputStream(IInputStream input_stream); explicit SocketInputStream(SOCKET socket); + explicit SocketInputStream(NearbyClientSocket* client_socket); ~SocketInputStream() override = default; ExceptionOr Read(std::int64_t size) override; @@ -148,10 +158,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 @@ -159,6 +171,7 @@ class WifiHotspotSocket : public api::WifiHotspotSocket { public: explicit SocketOutputStream(IOutputStream output_stream); explicit SocketOutputStream(SOCKET socket); + explicit SocketOutputStream(NearbyClientSocket* client_socket); ~SocketOutputStream() override = default; Exception Write(const ByteArray& data) override; @@ -166,9 +179,11 @@ 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 @@ -176,6 +191,9 @@ class WifiHotspotSocket : public api::WifiHotspotSocket { StreamSocket stream_soket_{nullptr}; SocketInputStream input_stream_{nullptr}; SocketOutputStream output_stream_{nullptr}; + + bool enable_blocking_socket_ = false; + std::unique_ptr client_socket_; }; // WifiHotspotServerSocket provides the support to server socket, this server @@ -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; diff --git a/internal/platform/implementation/windows/wifi_hotspot_medium.cc b/internal/platform/implementation/windows/wifi_hotspot_medium.cc index 847411299b..408acdcf6f 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_medium.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_medium.cc @@ -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" @@ -97,9 +98,6 @@ std::unique_ptr 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 = @@ -120,14 +118,17 @@ std::unique_ptr 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 - 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(); // setup cancel listener + std::unique_ptr + connection_cancellation_listener = nullptr; if (cancellation_flag != nullptr) { if (cancellation_flag->Cancelled()) { LOG(INFO) << "connect has been cancelled to service " << ipv4_address @@ -137,57 +138,100 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( connection_cancellation_listener = std::make_unique( - 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 + 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( + 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(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(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 @@ -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"; diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc index 08b8a0c512..e286f8c0d4 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc @@ -14,17 +14,23 @@ #include +#include #include #include #include +#include #include // ABSL headers +#include "absl/functional/any_invocable.h" #include "absl/strings/match.h" // Nearby connections headers +#include "absl/synchronization/mutex.h" #include "internal/flags/nearby_flags.h" +#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.Networking.Sockets.h" #include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi_hotspot.h" @@ -37,78 +43,102 @@ using ::winrt::Windows::Networking::Sockets::SocketQualityOfService; } // namespace WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) { - for (auto &it : socket_events_) { - it = WSA_INVALID_EVENT; + 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() { Close(); } std::string WifiHotspotServerSocket::GetIPAddress() const { - if (NearbyFlags::GetInstance().GetBoolFlag( - platform::config_package_nearby::nearby_platform_feature:: - kEnableHotspotWin32Socket)) { - if (listen_socket_ == INVALID_SOCKET) { - return {}; - } + if (enable_blocking_socket_) { + return server_socket_.GetIPAddress(); } else { - if (stream_socket_listener_ == nullptr) { - return {}; + 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 {}; + } } - } - std::string hotspot_ip_address = GetHotspotIpAddress(); - LOG(INFO) << __func__ - << ": Return hotspot IP address: " << hotspot_ip_address; + std::string hotspot_ip_address = GetHotspotIpAddress(); + LOG(INFO) << __func__ + << ": Return hotspot IP address: " << hotspot_ip_address; - return hotspot_ip_address; + return hotspot_ip_address; + } } int WifiHotspotServerSocket::GetPort() const { - 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_; + if (enable_blocking_socket_) { + return server_socket_.GetPort(); } else { - if (stream_socket_listener_ == nullptr) { - return 0; + 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 std::stoi(stream_socket_listener_.Information().LocalPort().c_str()); } } std::unique_ptr WifiHotspotServerSocket::Accept() { - absl::MutexLock lock(&mutex_); - LOG(INFO) << __func__ << ": Accept is called."; + if (enable_blocking_socket_) { + auto client_socket = server_socket_.Accept(); + if (client_socket == nullptr) { + return nullptr; + } - if (NearbyFlags::GetInstance().GetBoolFlag( - platform::config_package_nearby::nearby_platform_feature:: - kEnableHotspotWin32Socket)) { - while (!closed_ && pending_client_sockets_.empty()) { + LOG(INFO) << __func__ << ": Accepted a remote connection."; + return std::make_unique(std::move(client_socket)); + } else { + absl::MutexLock lock(&mutex_); + LOG(INFO) << __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(wifi_hotspot_socket); + } + + // Code when using WinRT API + while (!closed_ && pending_sockets_.empty()) { cond_.Wait(&mutex_); } if (closed_) return {}; - SOCKET wifi_hotspot_socket = pending_client_sockets_.front(); - pending_client_sockets_.pop_front(); + StreamSocket wifi_hotspot_socket = pending_sockets_.front(); + pending_sockets_.pop_front(); LOG(INFO) << __func__ << ": Accepted a remote connection."; return std::make_unique(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(wifi_hotspot_socket); } void WifiHotspotServerSocket::SetCloseNotifier( @@ -119,55 +149,70 @@ void WifiHotspotServerSocket::SetCloseNotifier( Exception WifiHotspotServerSocket::Close() { try { absl::MutexLock lock(&mutex_); - LOG(INFO) << __func__ << ": Close is called."; - - if (closed_) { - return {Exception::kSuccess}; - } + if (enable_blocking_socket_) { + 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(); + server_socket_.Close(); + closed_ = true; - pending_client_sockets_ = {}; + if (close_notifier_ != nullptr) { + close_notifier_(); } + + LOG(INFO) << __func__ << ": Close completed successfully."; } else { - if (stream_socket_listener_ != nullptr) { - stream_socket_listener_.ConnectionReceived(listener_event_token_); - stream_socket_listener_.Close(); - stream_socket_listener_ = nullptr; + LOG(INFO) << __func__ << ": Close is called."; - for (const auto &pending_socket : pending_sockets_) { - pending_socket.Close(); + 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_ = {}; + pending_sockets_ = {}; + } } - } - closed_ = true; - cond_.SignalAll(); - if (close_notifier_ != nullptr) { - close_notifier_(); + closed_ = true; + cond_.SignalAll(); + if (close_notifier_ != nullptr) { + close_notifier_(); + } } LOG(INFO) << __func__ << ": Close completed succesfully."; @@ -186,7 +231,7 @@ Exception WifiHotspotServerSocket::Close() { } catch (...) { closed_ = true; cond_.SignalAll(); - LOG(ERROR) << __func__ << ": Unknown exeption."; + LOG(ERROR) << __func__ << ": Unknown exception."; return {Exception::kIo}; } } @@ -240,7 +285,7 @@ bool WifiHotspotServerSocket::SetupServerSocketWinRT() { << ":Cannot accept connection on preferred port. WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; + LOG(ERROR) << __func__ << ": Unknown exception."; } try { @@ -258,7 +303,7 @@ bool WifiHotspotServerSocket::SetupServerSocketWinRT() { << ": Cannot bind to any port. WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; + LOG(ERROR) << __func__ << ": Unknown exception."; } return false; @@ -436,12 +481,21 @@ bool WifiHotspotServerSocket::listen() { return false; } - if (NearbyFlags::GetInstance().GetBoolFlag( - platform::config_package_nearby::nearby_platform_feature:: - kEnableHotspotWin32Socket)) { - return SetupServerSocketWinSock(); + if (enable_blocking_socket_) { + if (!server_socket_.Listen(hotspot_ipaddr_, port_)) { + LOG(ERROR) << "Failed to listen socket."; + return false; + } + + return true; } else { - return SetupServerSocketWinRT(); + if (NearbyFlags::GetInstance().GetBoolFlag( + platform::config_package_nearby::nearby_platform_feature:: + kEnableHotspotWin32Socket)) { + return SetupServerSocketWinSock(); + } else { + return SetupServerSocketWinRT(); + } } } @@ -489,7 +543,7 @@ std::string WifiHotspotServerSocket::GetHotspotIpAddress() const { << winrt::to_string(error.message()); return {}; } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; + LOG(ERROR) << __func__ << ": Unknown exception."; return {}; } } diff --git a/internal/platform/implementation/windows/wifi_hotspot_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_socket.cc index 2a84e5295e..7d460980d5 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_socket.cc @@ -15,9 +15,15 @@ #include #include #include +#include +#include +#include +#include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/flags/nearby_platform_feature_flags.h" +#include "internal/platform/implementation/windows/nearby_client_socket.h" #include "internal/platform/implementation/windows/wifi_hotspot.h" #include "internal/platform/input_stream.h" #include "internal/platform/logging.h" @@ -79,6 +85,15 @@ 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(); + input_stream_ = SocketInputStream(client_socket_.get()); + output_stream_ = SocketOutputStream(client_socket_.get()); +} + WifiHotspotSocket::WifiHotspotSocket(StreamSocket socket) { stream_soket_ = socket; input_stream_ = SocketInputStream(socket.InputStream()); @@ -91,48 +106,57 @@ WifiHotspotSocket::WifiHotspotSocket(SOCKET socket) { output_stream_ = SocketOutputStream(socket); } -WifiHotspotSocket::~WifiHotspotSocket() { - try { - if (stream_soket_ != nullptr || stream_soket_winsock_ != INVALID_SOCKET) { - Close(); - } - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - } +WifiHotspotSocket::WifiHotspotSocket( + std::unique_ptr 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()); } +WifiHotspotSocket::~WifiHotspotSocket() { Close(); } + InputStream& WifiHotspotSocket::GetInputStream() { return input_stream_; } OutputStream& WifiHotspotSocket::GetOutputStream() { return output_stream_; } Exception WifiHotspotSocket::Close() { - try { - if (stream_soket_ != nullptr) { - stream_soket_.Close(); - } - if (stream_soket_winsock_ != INVALID_SOCKET) { - closesocket(stream_soket_winsock_); - stream_soket_winsock_ = INVALID_SOCKET; + if (enable_blocking_socket_) { + if (client_socket_ != nullptr) { + return client_socket_->Close(); } + return {Exception::kSuccess}; - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {Exception::kIo}; - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return {Exception::kIo}; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - return {Exception::kIo}; + } 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}; + } } } +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; @@ -144,125 +168,160 @@ WifiHotspotSocket::SocketInputStream::SocketInputStream(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 WifiHotspotSocket::SocketInputStream::Read( std::int64_t size) { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - Buffer buffer = Buffer(size); + if (enable_blocking_socket_) { + if (client_socket_ == nullptr) { + LOG(ERROR) << "Failed to read data due to no client socket."; + return {Exception::kIo}; + } - auto ibuffer = - input_stream_.ReadAsync(buffer, size, InputStreamOptions::None).get(); + return client_socket_->Read(size); + } else { + try { + if (socket_type_ == SocketType::kWinRTSocket) { + Buffer buffer = Buffer(size); - if (ibuffer.Length() != size) { - LOG(WARNING) << "Only got part of data of needed."; - } + auto ibuffer = + input_stream_.ReadAsync(buffer, size, InputStreamOptions::None) + .get(); - ByteArray data((char*)ibuffer.data(), ibuffer.Length()); - return ExceptionOr(data); - } + if (ibuffer.Length() != size) { + LOG(WARNING) << "Only got part of data of needed."; + } - int result; - int count = 0; + ByteArray data((char*)ibuffer.data(), ibuffer.Length()); + return ExceptionOr(data); + } - // When socket_type_ == SocketType::kWin32Socket - if (size > read_buffer_.size()) { - read_buffer_.resize(size); - } + int result; + int count = 0; - 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; + // 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(data); - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {Exception::kIo}; - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return {Exception::kIo}; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - return {Exception::kIo}; + ByteArray data(read_buffer_.data(), size); + return ExceptionOr(data); + } catch (std::exception exception) { + LOG(ERROR) << __func__ << ": Exception: " << exception.what(); + return {Exception::kIo}; + } catch (const winrt::hresult_error& error) { + LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " + << winrt::to_string(error.message()); + return {Exception::kIo}; + } catch (...) { + LOG(ERROR) << __func__ << ": Unknown exception."; + return {Exception::kIo}; + } } } ExceptionOr WifiHotspotSocket::SocketInputStream::Skip(size_t offset) { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - Buffer buffer = Buffer(offset); - - auto ibuffer = - input_stream_.ReadAsync(buffer, offset, InputStreamOptions::None) - .get(); - return ExceptionOr((size_t)ibuffer.Length()); + if (enable_blocking_socket_) { + if (client_socket_ == nullptr) { + return {Exception::kIo}; } - // When socket_type_ == SocketType::kWin32Socket - int result; - int count = 0; - // When socket_type_ == SocketType::kWin32Socket - if (offset > read_buffer_.size()) { - read_buffer_.resize(offset); - } + return client_socket_->Skip(offset); + } else { + try { + if (socket_type_ == SocketType::kWinRTSocket) { + Buffer buffer = Buffer(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; + auto ibuffer = + input_stream_.ReadAsync(buffer, offset, InputStreamOptions::None) + .get(); + return ExceptionOr((size_t)ibuffer.Length()); } - } + // When socket_type_ == SocketType::kWin32Socket + int result; + int count = 0; - return ExceptionOr(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 exeption."; - return {Exception::kIo}; + // 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(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}; + } } } Exception WifiHotspotSocket::SocketInputStream::Close() { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - input_stream_.Close(); - } else { - // When socket_type_ == SocketType::kWin32Socket - shutdown(socket_, SD_RECEIVE); + 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}; } - return {Exception::kSuccess}; - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {Exception::kIo}; - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return {Exception::kIo}; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - return {Exception::kIo}; } } @@ -278,87 +337,120 @@ WifiHotspotSocket::SocketOutputStream::SocketOutputStream(SOCKET socket) { socket_type_ = SocketType::kWin32Socket; } -Exception WifiHotspotSocket::SocketOutputStream::Write(const ByteArray& data) { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - Buffer buffer = Buffer(data.size()); - std::memcpy(buffer.data(), data.data(), data.size()); - buffer.Length(data.size()); +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; +} - output_stream_.WriteAsync(buffer).get(); - return {Exception::kSuccess}; +Exception WifiHotspotSocket::SocketOutputStream::Write(const ByteArray& data) { + if (enable_blocking_socket_) { + if (client_socket_ == nullptr) { + return {Exception::kIo}; } - 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 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}; } - } - 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 exeption."; - return {Exception::kIo}; + 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}; + } } } Exception WifiHotspotSocket::SocketOutputStream::Flush() { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - output_stream_.FlushAsync().get(); + 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}; } - return {Exception::kSuccess}; - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {Exception::kIo}; - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return {Exception::kIo}; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - return {Exception::kIo}; } } Exception WifiHotspotSocket::SocketOutputStream::Close() { - try { - if (socket_type_ == SocketType::kWinRTSocket) { - output_stream_.Close(); - } else { - // When socket_type_ == SocketType::kWin32Socket - shutdown(socket_, SD_SEND); + 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}; } - return {Exception::kSuccess}; - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {Exception::kIo}; - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return {Exception::kIo}; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exeption."; - return {Exception::kIo}; } }