#include "Common/Net/SocketCompat.h" #include "Core/HLE/NetInetConstants.h" #include "Core/HLE/SocketManager.h" #include "Common/Log.h" #include SocketManager g_socketManager; static std::mutex g_socketMutex; // TODO: Remove once the adhoc thread is gone InetSocket *SocketManager::CreateSocket(int *index, int *returned_errno, SocketState state, int domain, int type, int protocol) { _dbg_assert_(state != SocketState::Unused); int hostDomain = convertSocketDomainPSP2Host(domain); int hostType = convertSocketTypePSP2Host(type); int hostProtocol = convertSocketProtoPSP2Host(protocol); SOCKET hostSock = ::socket(hostDomain, hostType, hostProtocol); if (hostSock < 0) { *returned_errno = socket_errno; return nullptr; } std::lock_guard 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 = {}; // 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; } } _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; } InetSocket *SocketManager::AdoptSocket(int *index, SOCKET hostSocket, const InetSocket *derive) { std::lock_guard 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? return inetSock; } } // No space? Return nullptr and let the caller handle it. Shouldn't ever happen. *index = 0; return nullptr; } bool SocketManager::Close(InetSocket *inetSocket) { _dbg_assert_(inetSocket->state != SocketState::Unused); if (closesocket(inetSocket->sock) != 0) { ERROR_LOG(Log::sceNet, "closesocket(%d) failed", inetSocket->sock); return false; } inetSocket->state = SocketState::Unused; inetSocket->sock = 0; return true; } bool SocketManager::GetInetSocket(int sock, InetSocket **inetSocket) { std::lock_guard guard(g_socketMutex); if (sock < MIN_VALID_INET_SOCKET || sock >= ARRAY_SIZE(inetSockets_) || inetSockets_[sock].state == SocketState::Unused) { *inetSocket = nullptr; return false; } *inetSocket = inetSockets_ + sock; return true; } // Simplified mappers, only really useful in select/poll SOCKET SocketManager::GetHostSocketFromInetSocket(int sock) { std::lock_guard guard(g_socketMutex); if (sock < MIN_VALID_INET_SOCKET || sock >= ARRAY_SIZE(inetSockets_) || inetSockets_[sock].state == SocketState::Unused) { _dbg_assert_(false); return -1; } if (sock == 0) { // Map 0 to 0, special case. return 0; } return inetSockets_[sock].sock; } void SocketManager::CloseAll() { for (auto &sock : inetSockets_) { if (sock.state != SocketState::Unused) { closesocket(sock.sock); } sock.state = SocketState::Unused; sock.sock = 0; } } const char *SocketStateToString(SocketState state) { switch (state) { case SocketState::Unused: return "unused"; case SocketState::UsedNetInet: return "netInet"; case SocketState::UsedProAdhoc: return "proAdhoc"; default: return "N/A"; } }