mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Fixed WI-FI hotspot stuck issue during close
PiperOrigin-RevId: 551703821
This commit is contained in:
committed by
Copybara-Service
parent
0a13ce51f4
commit
eb5f8aed10
@@ -16,8 +16,8 @@
|
||||
#define PLATFORM_IMPL_WINDOWS_WIFI_HOTSPOT_H_
|
||||
|
||||
// Windows headers
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <wlanapi.h>
|
||||
|
||||
// Standard C/C++ headers
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <string>
|
||||
|
||||
// Nearby connections headers
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/implementation/wifi_hotspot.h"
|
||||
#include "internal/platform/implementation/windows/scheduled_executor.h"
|
||||
#include "internal/platform/implementation/windows/submittable_executor.h"
|
||||
@@ -123,7 +124,7 @@ class WifiHotspotSocket : public api::WifiHotspotSocket {
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
enum class SocketType {kWinRTSocket = 0, kWin32Socket};
|
||||
enum class SocketType { kWinRTSocket = 0, kWin32Socket };
|
||||
// A simple wrapper to handle input stream of socket
|
||||
class SocketInputStream : public InputStream {
|
||||
public:
|
||||
@@ -204,6 +205,10 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
|
||||
bool listen();
|
||||
|
||||
private:
|
||||
static constexpr int kSocketEventsCount = 2;
|
||||
static constexpr int kSocketEventListen = 0;
|
||||
static constexpr int kSocketEventClose = 1;
|
||||
|
||||
// The listener is accepting incoming connections
|
||||
fire_and_forget Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
@@ -214,6 +219,8 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
|
||||
// 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_;
|
||||
@@ -225,6 +232,13 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket {
|
||||
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;
|
||||
|
||||
|
||||
@@ -36,7 +36,11 @@ namespace {
|
||||
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
} // namespace
|
||||
|
||||
WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {}
|
||||
WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {
|
||||
for (auto &it : socket_events_) {
|
||||
it = WSA_INVALID_EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
WifiHotspotServerSocket::~WifiHotspotServerSocket() { Close(); }
|
||||
|
||||
@@ -55,7 +59,7 @@ std::string WifiHotspotServerSocket::GetIPAddress() const {
|
||||
|
||||
std::string hotspot_ip_address = GetHotspotIpAddress();
|
||||
NEARBY_LOGS(INFO) << __func__
|
||||
<< ": Return hotspot IP address: " << hotspot_ip_address;
|
||||
<< ": Return hotspot IP address: " << hotspot_ip_address;
|
||||
|
||||
return hotspot_ip_address;
|
||||
}
|
||||
@@ -126,18 +130,26 @@ Exception WifiHotspotServerSocket::Close() {
|
||||
kEnableHotspotWin32Socket)) {
|
||||
if (listen_socket_ != INVALID_SOCKET) {
|
||||
NEARBY_LOGS(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_);
|
||||
listen_socket_ = INVALID_SOCKET;
|
||||
client_socket_ = INVALID_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_ = {};
|
||||
}
|
||||
submittable_executor_.Shutdown();
|
||||
} else {
|
||||
if (stream_socket_listener_ != nullptr) {
|
||||
stream_socket_listener_.ConnectionReceived(listener_event_token_);
|
||||
@@ -254,14 +266,16 @@ bool WifiHotspotServerSocket::SetupServerSocketWinRT() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks for SOCKET_ERROR, this error can come up when trying to bind, listen,
|
||||
// Getsockname, WSACreateEvent, WSAEventSelect etc.
|
||||
void SocketErrorNotice(SOCKET socket_to_close, const char *action) {
|
||||
// const char *actionAttempted = action;
|
||||
NEARBY_LOGS(WARNING) << "socket error. " << action
|
||||
void WifiHotspotServerSocket::SocketErrorNotice(absl::string_view reason) {
|
||||
NEARBY_LOGS(WARNING) << "socket error. " << reason
|
||||
<< " failed with error: " << WSAGetLastError();
|
||||
|
||||
closesocket(socket_to_close);
|
||||
for (auto &it : socket_events_) {
|
||||
if (it != WSA_INVALID_EVENT) {
|
||||
WSACloseEvent(it);
|
||||
it = WSA_INVALID_EVENT;
|
||||
}
|
||||
}
|
||||
closesocket(listen_socket_);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
@@ -293,7 +307,7 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() {
|
||||
sizeof(flag));
|
||||
if (bind(listen_socket_, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ==
|
||||
SOCKET_ERROR) {
|
||||
SocketErrorNotice(listen_socket_, "Bind");
|
||||
SocketErrorNotice("Bind");
|
||||
return false;
|
||||
}
|
||||
NEARBY_LOGS(INFO) << "Bind socket successful";
|
||||
@@ -302,50 +316,63 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() {
|
||||
memset(&serv_addr, 0, size);
|
||||
if (getsockname(listen_socket_, (struct sockaddr *)&serv_addr, &size) ==
|
||||
SOCKET_ERROR) {
|
||||
SocketErrorNotice(listen_socket_, "Getsockname");
|
||||
SocketErrorNotice("Getsockname");
|
||||
return false;
|
||||
}
|
||||
port_ = ntohs(serv_addr.sin_port);
|
||||
NEARBY_LOGS(INFO) << "Hotspot Server bound to port: " << port_;
|
||||
|
||||
socket_event = WSACreateEvent();
|
||||
if (socket_event == nullptr) {
|
||||
SocketErrorNotice(listen_socket_, "WSACreateEvent");
|
||||
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_event, FD_ACCEPT | FD_CLOSE) ==
|
||||
SOCKET_ERROR) {
|
||||
SocketErrorNotice(listen_socket_, "WSAEventSelect");
|
||||
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_socket_, "Listen");
|
||||
SocketErrorNotice("Listen");
|
||||
return false;
|
||||
}
|
||||
NEARBY_LOGS(INFO) << "Hotspot Server Socket " << listen_socket_
|
||||
<< " started to listen with socket event: " << socket_event;
|
||||
|
||||
submittable_executor_.Execute([this, socket_event]() {
|
||||
submittable_executor_.Execute([this]() {
|
||||
DWORD index;
|
||||
WSANETWORKEVENTS network_events;
|
||||
// Wait for network events on all sockets
|
||||
index =
|
||||
WSAWaitForMultipleEvents(1, &socket_event, FALSE, WSA_INFINITE, FALSE);
|
||||
index = WSAWaitForMultipleEvents(kSocketEventsCount, socket_events_, FALSE,
|
||||
WSA_INFINITE, FALSE);
|
||||
|
||||
NEARBY_LOGS(INFO) << "Hotspot Server Socket " << listen_socket_
|
||||
<< " received event: " << socket_event;
|
||||
<< " received event index: " << index;
|
||||
if (index == WSA_WAIT_TIMEOUT || index == WSA_WAIT_FAILED) {
|
||||
NEARBY_LOGS(INFO) << "Hotspot Server Socket timout or failed ";
|
||||
return false;
|
||||
}
|
||||
|
||||
index = index - WSA_WAIT_EVENT_0;
|
||||
if (index == kSocketEventClose) {
|
||||
// the socket is closed by SDK
|
||||
NEARBY_LOGS(INFO) << "listner socket is closed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate through all events and enumerate
|
||||
if (WSAEnumNetworkEvents(listen_socket_, socket_event, &network_events) ==
|
||||
SOCKET_ERROR) {
|
||||
if (WSAEnumNetworkEvents(listen_socket_, socket_events_[index],
|
||||
&network_events) == SOCKET_ERROR) {
|
||||
NEARBY_LOGS(INFO) << "Iterate through all events failed";
|
||||
return false;
|
||||
}
|
||||
@@ -361,7 +388,8 @@ bool WifiHotspotServerSocket::SetupServerSocketWinSock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WSAEventSelect(listen_socket_, socket_event, 0) == SOCKET_ERROR) {
|
||||
if (WSAEventSelect(listen_socket_, socket_events_[kSocketEventListen],
|
||||
0) == SOCKET_ERROR) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "Remove association between listen_socket_ and event failed: "
|
||||
<< WSAGetLastError();
|
||||
|
||||
Reference in New Issue
Block a user