diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp index c4f7d8497c..64e486b8d1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -79,6 +79,35 @@ void fmt_class_string::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 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 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 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 fds, s32 n { std::lock_guard lock(sock->mutex); +#ifdef _WIN32 + sock->is_connecting = connecting[i]; +#endif + bs_t 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::ptris_connecting; +#endif } else { @@ -1774,7 +1832,7 @@ error_code sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptrmutex); +#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 events) { diff --git a/rpcs3/Emu/Cell/lv2/sys_net.h b/rpcs3/Emu/Cell/lv2/sys_net.h index eff1e2f19a..a3c922e50b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net.h +++ b/rpcs3/Emu/Cell/lv2/sys_net.h @@ -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)