fix(libSceNet): report EINPROGRESS for a non-blocking connect

A non-blocking sceNetConnect that cannot complete at once must fail with
EINPROGRESS (36, 0x80410124), as FreeBSD's connect does, and a repeated call
while it is pending with EALREADY (37). On Windows, Winsock reports the
first case as WSAEWOULDBLOCK, which was translated to EAGAIN (0x80410123); on
Linux, EINPROGRESS and EALREADY had no translation and became EIO
(0x80410105). Code that waits for the connection only when connect reports
EINPROGRESS treated both as a failed connection.

guest_sce_net connects a non-blocking socket to the loopback listener and
accepts 0 or EINPROGRESS; before this change it received EAGAIN on Windows.
This commit is contained in:
Raj 2026-10-08 12:22:49 +05:30
parent bc1fbe8158
commit 513479380c
2 changed files with 17 additions and 2 deletions

View File

@ -42,6 +42,8 @@ constexpr int NET_EFAULT = 14;
constexpr int NET_EINVAL = 22;
constexpr int NET_ENOSPC = 28;
constexpr int NET_EAGAIN = 35;
constexpr int NET_EINPROGRESS = 36;
constexpr int NET_EALREADY = 37;
constexpr int NET_ENOTSOCK = 38;
constexpr int NET_EOPNOTSUPP = 45;
constexpr int NET_EPROTONOSUPPORT = 43;
@ -84,6 +86,8 @@ void close_socket(NativeSocket socket) { closesocket(socket); }
int native_error() {
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK: return NET_EAGAIN;
case WSAEINPROGRESS: return NET_EINPROGRESS;
case WSAEALREADY: return NET_EALREADY;
case WSAEADDRINUSE: return NET_EADDRINUSE;
case WSAEAFNOSUPPORT: return NET_EAFNOSUPPORT;
case WSAENETUNREACH: return NET_ENETUNREACH;
@ -112,6 +116,8 @@ int native_error() {
#if EWOULDBLOCK != EAGAIN
case EWOULDBLOCK: return NET_EAGAIN;
#endif
case EINPROGRESS: return NET_EINPROGRESS;
case EALREADY: return NET_EALREADY;
case EADDRINUSE: return NET_EADDRINUSE;
case EAFNOSUPPORT: return NET_EAFNOSUPPORT;
case ENETUNREACH: return NET_ENETUNREACH;
@ -480,8 +486,11 @@ int APS5_VABI sceNetConnect(int s, const void* addr, uint32_t addrlen) {
NativeLength native_length = 0;
if (!guest_to_native_address(addr, addrlen, native, native_length)) return fail(NET_EINVAL);
if (native.ss_family != (socket.family == NET_AF_INET ? AF_INET : AF_INET6)) return fail(NET_EAFNOSUPPORT);
return ::connect(socket.native->value, reinterpret_cast<const sockaddr*>(&native), native_length) == 0
? 0 : fail(native_error());
if (::connect(socket.native->value, reinterpret_cast<const sockaddr*>(&native), native_length) == 0) return 0;
#ifdef _WIN32
if (WSAGetLastError() == WSAEWOULDBLOCK) return fail(NET_EINPROGRESS);
#endif
return fail(native_error());
}
int64_t APS5_VABI sceNetRecv(int s, void* buf, size_t len, int flags) {

View File

@ -211,6 +211,12 @@ int main() {
Require(sceNetSetsockopt(accepted, 0xffff, 0x1200, &nonblocking, sizeof(nonblocking)) == 0);
char pending = 0;
Require(sceNetRecv(accepted, &pending, sizeof(pending), 0) == static_cast<int>(0x80410123) && *sceNetErrnoLoc() == 35);
const int connecting = sceNetSocket(nullptr, 2, 1, 6);
Require(connecting >= 0);
Require(sceNetSetsockopt(connecting, 0xffff, 0x1200, &nonblocking, sizeof(nonblocking)) == 0);
const int started = sceNetConnect(connecting, address.data(), address.size());
Require(started == 0 || (started == static_cast<int>(0x80410124) && *sceNetErrnoLoc() == 36));
Require(sceNetSocketClose(connecting) == 0);
const int epoll = sceNetEpollCreate("guest-sce-net", 0);
Require(epoll >= 0);