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:
parent
bc1fbe8158
commit
513479380c
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue