// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "internal/platform/implementation/windows/wifi_hotspot.h" #include "internal/platform/logging.h" namespace nearby { namespace windows { namespace { // Recorded the maximum bytes received in one read is 65586 in the test, but add // a little more for const kMaxByteRecieved for safty reason. constexpr int kMaxByteRecieved = 66000; } // namespace 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() { try { if (stream_soket_ != nullptr || stream_soket_winsock_ != INVALID_SOCKET) { Close(); } } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; } } 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; } return {Exception::kSuccess}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; return {Exception::kIo}; } } 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; } ExceptionOr WifiHotspotSocket::SocketInputStream::Read( std::int64_t size) { try { if (socket_type_ == SocketType::kWinRTSocket) { Buffer buffer = Buffer(size); auto ibuffer = input_stream_.ReadAsync(buffer, size, InputStreamOptions::None).get(); if (ibuffer.Length() != size) { NEARBY_LOGS(WARNING) << "Only got part of data of needed."; } ByteArray data((char*)ibuffer.data(), ibuffer.Length()); return ExceptionOr(data); } // When socket_type_ == SocketType::kWin32Socket char recv_buf[kMaxByteRecieved]; int result; struct fd_set readfds; result = recv(socket_, recv_buf, size, 0); if (result > 0) { ByteArray data(recv_buf, result); return ExceptionOr(data); } if (result == 0) { NEARBY_LOGS(INFO) << "Connection closed."; return {Exception::kIo}; } // When WSAEWOULDBLOCK happens, it means the packet for receive is not // ready at the moment. The API select() will block till the packet is // ready for recieving. if (WSAEWOULDBLOCK == WSAGetLastError()) { FD_ZERO(&readfds); FD_SET(socket_, &readfds); if ((select(/*nfds ignored*/ 0, &readfds, nullptr, nullptr, nullptr) > 0) && FD_ISSET(socket_, &readfds)) { result = recv(socket_, recv_buf, size, 0); if (result > 0) { ByteArray data(recv_buf, result); return ExceptionOr(data); } } } return {Exception::kIo}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; 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()); } // When socket_type_ == SocketType::kWin32Socket char recv_buf[kMaxByteRecieved]; int result; struct fd_set readfds; result = recv(socket_, recv_buf, offset, 0); if (result > 0) { return ExceptionOr((size_t)result); } if (result == 0) { NEARBY_LOGS(INFO) << "Connection closed."; } else { // When WSAEWOULDBLOCK happens, it means the packet for receive is not // ready at the moment. The API select() will block till the packet is // ready for recieving. if (WSAEWOULDBLOCK == WSAGetLastError()) { FD_ZERO(&readfds); FD_SET(socket_, &readfds); if ((select(/*nfds ignored*/ 0, &readfds, nullptr, nullptr, nullptr) > 0) && FD_ISSET(socket_, &readfds)) { result = recv(socket_, recv_buf, offset, 0); if (result > 0) { return ExceptionOr((size_t)result); } } } } return {Exception::kIo}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; 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); } return {Exception::kSuccess}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; return {Exception::kIo}; } } // 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; } 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()); output_stream_.WriteAsync(buffer).get(); return {Exception::kSuccess}; } // When socket_type_ == SocketType::kWin32Socket char sendbuf[kMaxByteRecieved]; int result; std::memcpy(sendbuf, data.data(), data.size()); result = send(socket_, sendbuf, data.size(), 0); if (result > 0) { return {Exception::kSuccess}; } NEARBY_LOGS(INFO) << "recv failed: " << WSAGetLastError(); return {Exception::kIo}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; return {Exception::kIo}; } } Exception WifiHotspotSocket::SocketOutputStream::Flush() { try { if (socket_type_ == SocketType::kWinRTSocket) { output_stream_.FlushAsync().get(); } return {Exception::kSuccess}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(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); } return {Exception::kSuccess}; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what(); return {Exception::kIo}; } catch (const winrt::hresult_error& error) { NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " << winrt::to_string(error.message()); return {Exception::kIo}; } catch (...) { NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption."; return {Exception::kIo}; } } } // namespace windows } // namespace nearby