mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-11 08:39:28 +01:00
sceNetInet: Fix the blocking socket waits on Windows
Headless only started Winsock (net::Init) for the debugger, so on Windows every socket call failed with WSANOTINITIALISED. Start it always. Winsock's select() fails on empty sets, where POSIX waits out the timeout, so a select() used as a sleep (the VSH's Skype) returned an error at once. With no host sockets to check, select and poll now just report nothing ready. Look up host sockets without GetHostSocketFromInetSocket, which asserts on a socket closed while a call waits for it, and whose -1 can't be caught with < 0 on Windows, where SOCKET is unsigned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
be9383c08f
commit
bd56e07bb0
1 file changed
+32
-14
+32
-14
@@ -278,6 +278,18 @@ static InetTry TrySendTo(SceUID threadID, const u32 *args);
|
||||
static InetTry TryAccept(SceUID threadID, const u32 *args);
|
||||
static InetTry TryConnectDone(SceUID threadID, const u32 *args);
|
||||
|
||||
// The host socket behind a guest one, or false if there's none. Unlike GetHostSocketFromInetSocket,
|
||||
// doesn't assert, since a socket can be closed while a call waits for it, and works on Windows,
|
||||
// where SOCKET is unsigned and can't be checked for -1 with < 0.
|
||||
static bool GetHostSocket(int socket, SOCKET *hostSocket) {
|
||||
InetSocket *inetSock;
|
||||
if (!g_socketManager.GetInetSocket(socket, &inetSock)) {
|
||||
return false;
|
||||
}
|
||||
*hostSocket = inetSock->sock;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsWouldBlock(int hostErrno) {
|
||||
return hostErrno == EAGAIN || hostErrno == EWOULDBLOCK;
|
||||
}
|
||||
@@ -337,17 +349,16 @@ static InetTry TrySelect(SceUID threadID, const u32 *args, bool firstTry) {
|
||||
if (!set.set || !NetInetFD_ISSET(i, set.set)) {
|
||||
continue;
|
||||
}
|
||||
SOCKET sock = g_socketManager.GetHostSocketFromInetSocket(i);
|
||||
_dbg_assert_(sock != 0);
|
||||
if (sock < 0) {
|
||||
SOCKET sock;
|
||||
if (!GetHostSocket(i, &sock)) {
|
||||
if (firstTry) {
|
||||
ERROR_LOG(Log::sceNet, "Bad socket #%d in %s fds", i, set.name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
hostSockets[i] = sock;
|
||||
if (sock > maxHostSocket)
|
||||
maxHostSocket = sock;
|
||||
if ((int)sock > maxHostSocket)
|
||||
maxHostSocket = (int)sock;
|
||||
if (*set.count < FD_SETSIZE) {
|
||||
FD_SET(sock, set.hostSet); // This might pointed to a non-existing socket or sockets belonged to other programs on Windows, because most of the time Windows socket have an id above 1k instead of 0-255
|
||||
(*set.count)++;
|
||||
@@ -362,6 +373,11 @@ static InetTry TrySelect(SceUID threadID, const u32 *args, bool firstTry) {
|
||||
_dbg_assert_(wrcnt < FD_SETSIZE);
|
||||
_dbg_assert_(excnt < FD_SETSIZE);
|
||||
|
||||
if (rdcnt + wrcnt + excnt == 0) {
|
||||
// Nothing to check: a select() used as a sleep. Winsock's select() fails on empty sets.
|
||||
return { 0, true, EAGAIN };
|
||||
}
|
||||
|
||||
timeval tmout = { 0, 0 };
|
||||
int retval = select(maxHostSocket + 1, readfds ? &rdfds : nullptr, writefds ? &wrfds : nullptr, exceptfds ? &exfds : nullptr, &tmout);
|
||||
if (retval == 0) {
|
||||
@@ -402,24 +418,27 @@ static InetTry TryPoll(SceUID threadID, const u32 *args) {
|
||||
fd_set readfds{}, writefds{}, exceptfds{};
|
||||
FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
SOCKET hostSocket;
|
||||
fdarray[i].revents = 0;
|
||||
InetSocket *inetSock;
|
||||
if (!g_socketManager.GetInetSocket(fdarray[i].fd, &inetSock)) {
|
||||
if (!GetHostSocket(fdarray[i].fd, &hostSocket)) {
|
||||
// Not open, reported as POLLNVAL below.
|
||||
closedCount++;
|
||||
continue;
|
||||
}
|
||||
SOCKET hostSocket = inetSock->sock;
|
||||
hostCount++;
|
||||
if (hostSocket > maxHostFd) {
|
||||
maxHostFd = hostSocket;
|
||||
if ((int)hostSocket > maxHostFd) {
|
||||
maxHostFd = (int)hostSocket;
|
||||
}
|
||||
_dbg_assert_(hostSocket != 0);
|
||||
FD_SET(hostSocket, &readfds);
|
||||
FD_SET(hostSocket, &writefds);
|
||||
FD_SET(hostSocket, &exceptfds);
|
||||
}
|
||||
|
||||
if (hostCount == 0 && closedCount == 0) {
|
||||
// Winsock's select() fails on empty sets.
|
||||
return { 0, true, EAGAIN };
|
||||
}
|
||||
|
||||
if (hostCount > 0) {
|
||||
timeval tmout = { 0, 0 };
|
||||
if (select(maxHostFd + 1, &readfds, &writefds, &exceptfds, &tmout) < 0) {
|
||||
@@ -430,14 +449,13 @@ static InetTry TryPoll(SceUID threadID, const u32 *args) {
|
||||
|
||||
int retval = 0;
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
InetSocket *inetSock;
|
||||
if (!g_socketManager.GetInetSocket(fdarray[i].fd, &inetSock)) {
|
||||
SOCKET hostSocket;
|
||||
if (!GetHostSocket(fdarray[i].fd, &hostSocket)) {
|
||||
// As on hardware (pspautotests net/inet/poll).
|
||||
fdarray[i].revents = INET_POLLNVAL;
|
||||
retval++;
|
||||
continue;
|
||||
}
|
||||
SOCKET hostSocket = inetSock->sock;
|
||||
if ((fdarray[i].events & (INET_POLLRDNORM | INET_POLLIN)) && FD_ISSET(hostSocket, &readfds))
|
||||
fdarray[i].revents |= (INET_POLLRDNORM | INET_POLLIN); //POLLIN_SET
|
||||
if ((fdarray[i].events & (INET_POLLWRNORM | INET_POLLOUT)) && FD_ISSET(hostSocket, &writefds))
|
||||
|
||||
Reference in new issue
Block a user