Files
ppsspp/Core/HLE/SocketManager.h
T
Henrik RydgårdandClaude Opus 5.5 22e0a1a536 sceNetInet: Wait for blocking socket calls in emulated time
Host sockets are always non-blocking, so a game's blocking recv(), accept()
and so on came back with EAGAIN at once, and connect() and poll() blocked the
whole emulator in the host call instead. Now recv, recvfrom, send, sendto,
accept, connect, poll and select try once, and if the call would block on a
blocking socket (no SO_NBIO or MSG_DONTWAIT), the thread waits and a
CoreTiming event retries it every millisecond. It ends when the call completes
or fails, or when SO_RCVTIMEO/SO_SNDTIMEO runs out in emulated time.

Sockets accepted on Linux are made non-blocking too: unlike BSD and Windows,
Linux doesn't pass that on from the listening socket. select() rejects a
tv_usec of a second or more with EINVAL.

Hardware behaviour from pspautotests net/inet/blocking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:03:59 +01:00

61 lines
1.6 KiB
C++

#pragma once
#include "Common/CommonTypes.h"
#include "Common/Net/SocketCompat.h"
// Keep track of who's using a socket.
enum class SocketState {
Unused = 0,
UsedNetInet,
UsedProAdhoc,
};
const char *SocketStateToString(SocketState state);
// Internal socket state tracking
struct InetSocket {
SOCKET sock; // native socket
SocketState state;
// NOTE: These are the PSP types. Can be converted to the host types if needed.
int domain;
int type;
int protocol;
bool nonblocking;
// SO_RCVTIMEO and SO_SNDTIMEO, for the blocking calls we wait for in emulated time. 0 is forever.
u32 recvTimeoutUs;
u32 sendTimeoutUs;
// Metadata for debug use only.
std::string addr;
int port;
};
// Only use this for sockets whose ID are exposed to the game.
// Don't really need to bother with the others, as the game doesn't know about them.
class SocketManager {
public:
enum {
VALID_INET_SOCKET_COUNT = 256,
MIN_VALID_INET_SOCKET = 1,
};
InetSocket *CreateSocket(int *index, int *returned_errno, SocketState state, int domain, int type, int protocol);
// for accept()
InetSocket *AdoptSocket(int *index, SOCKET hostSocket, const InetSocket *derive);
bool GetInetSocket(int sock, InetSocket **inetSocket);
SOCKET GetHostSocketFromInetSocket(int sock);
bool Close(InetSocket *inetSocket);
void CloseAll();
// For debugger
const InetSocket *Sockets() {
return inetSockets_;
}
private:
// We use this array from MIN_VALID_INET_SOCKET and forward. It's probably not a good idea to return 0 as a socket.
InetSocket inetSockets_[VALID_INET_SOCKET_COUNT];
};
extern SocketManager g_socketManager;