From 44798085bd26fd27078671789f5e8426aeb21521 Mon Sep 17 00:00:00 2001 From: Aryan Sharma <81407258+Aryansh1520@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:24:21 +0530 Subject: [PATCH] network: handle SO_NBIO on non-Windows hosts (#954) * network: handle SO_NBIO on non-Windows hosts Setsockopt only translated the guest SOL_SOCKET/SO_NBIO (0x1200) option under _WIN32; other hosts rejected it with ENOPROTOOPT. FMOD Studio's Live Update listener sets SO_NBIO, so on Linux its socket setup failed and the Studio async manager latched FMOD_ERR_NET_CONNECT. Every blocking Studio call then failed: loadBankFile returned FMOD_ERR_NOTREADY for all banks, leaving the game silent and stuck on the splash screen waiting for RuntimeManager.HaveAllBanksLoaded (PPSA28997). Toggle O_NONBLOCK with fcntl on non-Windows hosts. * network: map connection errors from POSIX socket calls ConvertHostSocketError only covered a handful of errno values on non-Windows hosts, so anything else reached the guest as EIO. With SO_NBIO now honoured there, a nonblocking connect() that is still in progress returned EIO instead of EINPROGRESS (and EALREADY on retry). Map the same connection and network errors the Windows branch already translates. * network: share nonblocking socket error handling --------- Co-authored-by: nmzik --- src/libs/network.cpp | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libs/network.cpp b/src/libs/network.cpp index fae5a91b5..627a8057c 100644 --- a/src/libs/network.cpp +++ b/src/libs/network.cpp @@ -997,14 +997,31 @@ static int ConvertHostSocketError(int error) { case EAGAIN: posix_error = Posix::POSIX_EWOULDBLOCK; break; case EBADF: posix_error = Posix::POSIX_EBADF; break; case EFAULT: posix_error = Posix::POSIX_EFAULT; break; + case EINTR: posix_error = Posix::POSIX_EINTR; break; case EINVAL: posix_error = Posix::POSIX_EINVAL; break; + case EISCONN: posix_error = Posix::POSIX_EISCONN; break; case EMFILE: posix_error = Posix::POSIX_EMFILE; break; + case EMSGSIZE: posix_error = Posix::POSIX_EMSGSIZE; break; case ENFILE: posix_error = Posix::POSIX_ENFILE; break; case ENOBUFS: posix_error = Posix::POSIX_ENOBUFS; break; case ENOMEM: posix_error = Posix::POSIX_ENOMEM; break; + case ENETDOWN: posix_error = Posix::POSIX_ENETDOWN; break; + case ENETRESET: posix_error = Posix::POSIX_ENETRESET; break; + case ENETUNREACH: posix_error = Posix::POSIX_ENETUNREACH; break; + case ENOTCONN: posix_error = Posix::POSIX_ENOTCONN; break; case ENOTSOCK: posix_error = Posix::POSIX_ENOTSOCK; break; + case EOPNOTSUPP: posix_error = Posix::POSIX_EOPNOTSUPP; break; case EPIPE: posix_error = Posix::POSIX_EPIPE; break; case EPROTONOSUPPORT: posix_error = Posix::POSIX_EPROTONOSUPPORT; break; + case ESHUTDOWN: posix_error = Posix::POSIX_ESHUTDOWN; break; + case ETIMEDOUT: posix_error = Posix::POSIX_ETIMEDOUT; break; + case ECONNABORTED: posix_error = Posix::POSIX_ECONNABORTED; break; + case ECONNREFUSED: posix_error = Posix::POSIX_ECONNREFUSED; break; + case ECONNRESET: posix_error = Posix::POSIX_ECONNRESET; break; + case EDESTADDRREQ: posix_error = Posix::POSIX_EDESTADDRREQ; break; + case EHOSTUNREACH: posix_error = Posix::POSIX_EHOSTUNREACH; break; + case EINPROGRESS: posix_error = Posix::POSIX_EINPROGRESS; break; + case EALREADY: posix_error = Posix::POSIX_EALREADY; break; default: break; } #endif @@ -2098,17 +2115,22 @@ int KYTY_SYSV_ABI Setsockopt(int s, int level, int optname, const void* optval, return 0; } -#if defined(_WIN32) constexpr int ORBIS_SO_NBIO = 0x1200; if (ConvertSocketOptionLevel(level) == SOL_SOCKET && optname == ORBIS_SO_NBIO && optlen >= sizeof(int)) { - u_long enabled = (*static_cast(optval) != 0 ? 1 : 0); - if (ioctlsocket(socket, FIONBIO, &enabled) == SOCKET_ERROR) { - return SetHostSocketError(); - } - return 0; - } + const bool enabled = *static_cast(optval) != 0; +#if defined(_WIN32) + u_long mode = enabled ? 1 : 0; + const bool failed = ioctlsocket(socket, FIONBIO, &mode) == SOCKET_ERROR; #else + const int flags = ::fcntl(socket, F_GETFL, 0); + const bool failed = + flags < 0 || + ::fcntl(socket, F_SETFL, enabled ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK)) != 0; +#endif + return failed ? SetHostSocketError() : 0; + } +#if !defined(_WIN32) // Guest TCP options: IPPROTO_TCP=6, TCP_NODELAY=1. if (level != 6 || optname != 1) { return SetGuestSocketError(Posix::POSIX_ENOPROTOOPT);