WSAPoll workaround

This commit is contained in:
RipleyTom 2019-12-17 04:00:29 +01:00 committed by Ivan
parent 9b77febd10
commit 90e4fe23c5
2 changed files with 67 additions and 3 deletions

View File

@ -79,6 +79,35 @@ void fmt_class_string<sys_net_error>::format(std::string& out, u64 arg)
});
}
#ifdef _WIN32
// Workaround function for WSAPoll not reporting failed connections
void windows_poll(pollfd* fds, unsigned long nfds, int timeout, bool *connecting)
{
int r = ::WSAPoll(fds, nfds, timeout);
for (unsigned long i = 0; i < nfds; i++)
{
if (connecting[i])
{
if (!fds[i].revents)
{
int error = 0;
socklen_t intlen = sizeof(error);
if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, (char*)&error, &intlen) == -1 || error != 0)
{
// Connection silently failed
connecting[i] = false;
fds[i].revents = POLLERR | POLLHUP | (fds[i].events & (POLLIN | POLLOUT));
}
}
else
{
connecting[i] = false;
}
}
}
}
#endif
// Error helper functions
static sys_net_error get_last_error(bool is_blocking, int native_error = 0)
{
@ -186,12 +215,15 @@ struct network_thread
s_to_awake.clear();
::pollfd fds[lv2_socket::id_count]{};
#ifdef _WIN32
bool connecting[lv2_socket::id_count]{};
#endif
while (thread_ctrl::state() != thread_state::aborting)
{
// Wait with 1ms timeout
#ifdef _WIN32
::WSAPoll(fds, socklist.size(), 1);
windows_poll(fds, socklist.size(), 1, connecting);
#else
::poll(fds, socklist.size(), 1);
#endif
@ -204,6 +236,10 @@ struct network_thread
lv2_socket& sock = *socklist[i];
#ifdef _WIN32
sock.is_connecting = connecting[i];
#endif
if (fds[i].revents & (POLLIN | POLLHUP) && socklist[i]->events.test_and_reset(lv2_socket::poll::read))
events += lv2_socket::poll::read;
if (fds[i].revents & POLLOUT && socklist[i]->events.test_and_reset(lv2_socket::poll::write))
@ -265,6 +301,9 @@ struct network_thread
(events & lv2_socket::poll::write ? POLLOUT : 0) |
0;
fds[i].revents = 0;
#ifdef _WIN32
connecting[i] = socklist[i]->is_connecting;
#endif
}
}
}
@ -522,6 +561,9 @@ error_code sys_net_bnet_connect(ppu_thread& ppu, s32 s, vm::ptr<sys_net_sockaddr
{
if (result == SYS_NET_EWOULDBLOCK)
{
#ifdef _WIN32
sock.is_connecting = true;
#endif
result = SYS_NET_EINPROGRESS;
}
@ -1577,6 +1619,9 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
reader_lock lock(id_manager::g_mutex);
::pollfd _fds[1024]{};
#ifdef _WIN32
bool connecting[1024]{};
#endif
for (s32 i = 0; i < nfds; i++)
{
@ -1597,6 +1642,9 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
_fds[i].events |= POLLIN;
if (fds[i].events & SYS_NET_POLLOUT)
_fds[i].events |= POLLOUT;
#ifdef _WIN32
connecting[i] = sock->is_connecting;
#endif
}
else
{
@ -1606,7 +1654,7 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
}
#ifdef _WIN32
::WSAPoll(_fds, nfds, 0);
windows_poll(_fds, nfds, 0, connecting);
#else
::poll(_fds, nfds, 0);
#endif
@ -1641,6 +1689,10 @@ error_code sys_net_bnet_poll(ppu_thread& ppu, vm::ptr<sys_net_pollfd> fds, s32 n
{
std::lock_guard lock(sock->mutex);
#ifdef _WIN32
sock->is_connecting = connecting[i];
#endif
bs_t<lv2_socket::poll> selected = +lv2_socket::poll::error;
if (fds[i].events & SYS_NET_POLLIN)
@ -1737,6 +1789,9 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set
reader_lock lock(id_manager::g_mutex);
::pollfd _fds[1024]{};
#ifdef _WIN32
bool connecting[1024]{};
#endif
for (s32 i = 0; i < nfds; i++)
{
@ -1766,6 +1821,9 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set
_fds[i].events |= POLLIN;
if (selected & lv2_socket::poll::write)
_fds[i].events |= POLLOUT;
#ifdef _WIN32
connecting[i] = sock->is_connecting;
#endif
}
else
{
@ -1774,7 +1832,7 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set
}
#ifdef _WIN32
::WSAPoll(_fds, nfds, 0);
windows_poll(_fds, nfds, 0, connecting);
#else
::poll(_fds, nfds, 0);
#endif
@ -1827,6 +1885,10 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr<sys_net_fd_set
{
std::lock_guard lock(sock->mutex);
#ifdef _WIN32
sock->is_connecting = connecting[i];
#endif
sock->events += selected;
sock->queue.emplace_back(ppu.id, [sock, selected, i, &rread, &rwrite, &rexcept, &signaled, &ppu](bs_t<lv2_socket::poll> events)
{

View File

@ -336,6 +336,8 @@ struct lv2_socket final
#ifdef _WIN32
// Remember events (WSAEnumNetworkEvents)
u32 ev_set = 0;
// Tracks connect for WSAPoll workaround
bool is_connecting = false;
#endif
// Native socket (must be non-blocking)