mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 20:18:15 +01:00
sceNetInet: errno per thread as on hardware, and the socket table
errno: - A thread that hasn't made a call yet reads 0x80410001 from GetErrno, as the PSP has no errno record for it until then. errno is saved in savestates now, in a new sceNet section version. - socket(), close() and setsockopt() clear it when they succeed. - Running out of descriptors is EMFILE, at 255 like the PSP, and an unconnected UDP socket sending without an address EDESTADDRREQ, which Winsock calls ENOTCONN. - On Windows, ENOBUFS, EPROTOTYPE, ENOPROTOOPT, EMSGSIZE, ENETRESET and EDESTADDRREQ now map to the PSP's errnos. They only did elsewhere. All from pspautotests net/inet/errors, options and errnothread. The socket table: - Descriptor numbers are handed out round-robin up to 255, as on the PSP (net/inet/states), rather than the lowest free one. - Closing frees the slot even if the host's close fails, and Close and CloseAll take the lock the rest of SocketManager does. - accept no longer leaks the host socket when it runs out of numbers. - bind no longer asks UPnP to forward port 0, and closing the socket removes its forward, unless another socket still uses the port. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
be9c244938
commit
79537d18bd
8 files changed
+208
-77
No files matched your search
+59
-41
@@ -23,64 +23,80 @@ InetSocket *SocketManager::CreateSocket(int *index, int *returned_errno, SocketS
|
||||
|
||||
std::lock_guard<std::mutex> guard(g_socketMutex);
|
||||
|
||||
for (int i = MIN_VALID_INET_SOCKET; i < ARRAY_SIZE(inetSockets_); i++) {
|
||||
const int i = FindFreeSlot();
|
||||
if (i == 0) {
|
||||
// The PSP runs out at 255 too, with EMFILE (pspautotests net/inet/errors).
|
||||
ERROR_LOG(Log::sceNet, "Ran out of socket handles!");
|
||||
closesocket(hostSock);
|
||||
*index = 0;
|
||||
*returned_errno = EMFILE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*index = i;
|
||||
InetSocket *inetSock = inetSockets_ + i;
|
||||
*inetSock = {}; // Reset to default.
|
||||
inetSock->sock = hostSock;
|
||||
inetSock->state = state;
|
||||
inetSock->domain = domain;
|
||||
inetSock->type = type;
|
||||
inetSock->protocol = protocol;
|
||||
inetSock->nonblocking = false;
|
||||
*returned_errno = 0;
|
||||
return inetSock;
|
||||
}
|
||||
|
||||
// Numbers are handed out round-robin, the next free one after the last, wrapping from 255 to 1
|
||||
// (pspautotests net/inet/states). Returns 0 if they're all in use.
|
||||
int SocketManager::FindFreeSlot() {
|
||||
for (int n = 0; n < VALID_INET_SOCKET_COUNT - MIN_VALID_INET_SOCKET; n++) {
|
||||
int i = lastSlot_ + 1 + n;
|
||||
if (i >= VALID_INET_SOCKET_COUNT) {
|
||||
i -= VALID_INET_SOCKET_COUNT - MIN_VALID_INET_SOCKET;
|
||||
}
|
||||
if (inetSockets_[i].state == SocketState::Unused) {
|
||||
*index = i;
|
||||
InetSocket *inetSock = inetSockets_ + i;
|
||||
*inetSock = {}; // Reset to default.
|
||||
inetSock->sock = hostSock;
|
||||
inetSock->state = state;
|
||||
inetSock->domain = domain;
|
||||
inetSock->type = type;
|
||||
inetSock->protocol = protocol;
|
||||
inetSock->nonblocking = false;
|
||||
*returned_errno = 0;
|
||||
return inetSock;
|
||||
lastSlot_ = i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
_dbg_assert_(false);
|
||||
|
||||
ERROR_LOG(Log::sceNet, "Ran out of socket handles! This is BAD.");
|
||||
closesocket(hostSock);
|
||||
*index = 0;
|
||||
*returned_errno = ENOMEM; // or something..
|
||||
return nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
InetSocket *SocketManager::AdoptSocket(int *index, SOCKET hostSocket, const InetSocket *derive) {
|
||||
std::lock_guard<std::mutex> guard(g_socketMutex);
|
||||
|
||||
for (int i = MIN_VALID_INET_SOCKET; i < ARRAY_SIZE(inetSockets_); i++) {
|
||||
if (inetSockets_[i].state == SocketState::Unused) {
|
||||
*index = i;
|
||||
|
||||
InetSocket *inetSock = inetSockets_ + i;
|
||||
inetSock->sock = hostSocket;
|
||||
inetSock->state = derive->state;
|
||||
inetSock->domain = derive->domain;
|
||||
inetSock->type = derive->type;
|
||||
inetSock->protocol = derive->protocol;
|
||||
inetSock->nonblocking = derive->nonblocking; // should we inherit blocking state?
|
||||
inetSock->recvTimeoutUs = derive->recvTimeoutUs;
|
||||
inetSock->sendTimeoutUs = derive->sendTimeoutUs;
|
||||
return inetSock;
|
||||
}
|
||||
const int i = FindFreeSlot();
|
||||
if (i == 0) {
|
||||
// No space. Shouldn't ever happen.
|
||||
*index = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// No space? Return nullptr and let the caller handle it. Shouldn't ever happen.
|
||||
*index = 0;
|
||||
return nullptr;
|
||||
*index = i;
|
||||
InetSocket *inetSock = inetSockets_ + i;
|
||||
*inetSock = {};
|
||||
inetSock->sock = hostSocket;
|
||||
inetSock->state = derive->state;
|
||||
inetSock->domain = derive->domain;
|
||||
inetSock->type = derive->type;
|
||||
inetSock->protocol = derive->protocol;
|
||||
inetSock->nonblocking = derive->nonblocking; // should we inherit blocking state?
|
||||
inetSock->recvTimeoutUs = derive->recvTimeoutUs;
|
||||
inetSock->sendTimeoutUs = derive->sendTimeoutUs;
|
||||
return inetSock;
|
||||
}
|
||||
|
||||
// The slot is freed even if the host's close fails, since the host socket is no use either way.
|
||||
bool SocketManager::Close(InetSocket *inetSocket) {
|
||||
std::lock_guard<std::mutex> guard(g_socketMutex);
|
||||
_dbg_assert_(inetSocket->state != SocketState::Unused);
|
||||
if (closesocket(inetSocket->sock) != 0) {
|
||||
ERROR_LOG(Log::sceNet, "closesocket(%d) failed", inetSocket->sock);
|
||||
return false;
|
||||
const bool closed = closesocket(inetSocket->sock) == 0;
|
||||
if (!closed) {
|
||||
ERROR_LOG(Log::sceNet, "closesocket(%d) failed: %d", (int)inetSocket->sock, socket_errno);
|
||||
}
|
||||
inetSocket->state = SocketState::Unused;
|
||||
inetSocket->sock = 0;
|
||||
return true;
|
||||
return closed;
|
||||
}
|
||||
|
||||
bool SocketManager::GetInetSocket(int sock, InetSocket **inetSocket) {
|
||||
@@ -108,6 +124,7 @@ SOCKET SocketManager::GetHostSocketFromInetSocket(int sock) {
|
||||
}
|
||||
|
||||
void SocketManager::CloseAll() {
|
||||
std::lock_guard<std::mutex> guard(g_socketMutex);
|
||||
for (auto &sock : inetSockets_) {
|
||||
if (sock.state != SocketState::Unused) {
|
||||
closesocket(sock.sock);
|
||||
@@ -115,6 +132,7 @@ void SocketManager::CloseAll() {
|
||||
sock.state = SocketState::Unused;
|
||||
sock.sock = 0;
|
||||
}
|
||||
lastSlot_ = 0;
|
||||
}
|
||||
|
||||
const char *SocketStateToString(SocketState state) {
|
||||
|
||||
Reference in new issue
Block a user