diff --git a/Core/HLE/SocketManager.cpp b/Core/HLE/SocketManager.cpp index 241b6fca53..458d50cd0b 100644 --- a/Core/HLE/SocketManager.cpp +++ b/Core/HLE/SocketManager.cpp @@ -46,6 +46,29 @@ InetSocket *SocketManager::CreateSocket(int *index, int *returned_errno, SocketS 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) { diff --git a/Core/HLE/SocketManager.h b/Core/HLE/SocketManager.h index 13f8e5630d..c277ff526a 100644 --- a/Core/HLE/SocketManager.h +++ b/Core/HLE/SocketManager.h @@ -32,6 +32,9 @@ public: }; 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); diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index ee37325b1b..d926daa091 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -691,14 +691,23 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { SockAddrIN4 saddr{}; if (srclen) *srclen = std::min((*srclen) > 0 ? *srclen : 0, static_cast(sizeof(saddr))); - int retval = accept(inetSock->sock, (struct sockaddr*)&saddr.addr, srclen); - if (retval < 0) { + + int newHostSocket = accept(inetSock->sock, (struct sockaddr*)&saddr.addr, srclen); + if (newHostSocket < 0) { inetLastErrno = socket_errno; if (inetLastErrno == EAGAIN) - hleLogDebug(Log::sceNet, retval, "errno = %d", inetLastErrno); + hleLogDebug(Log::sceNet, newHostSocket, "errno = %d", inetLastErrno); else - hleLogError(Log::sceNet, retval, "errno = %d", inetLastErrno); - return retval; + hleLogError(Log::sceNet, newHostSocket, "errno = %d", inetLastErrno); + return -1; + } + + int newSocketId; + InetSocket *newInetSocket = g_socketManager.AdoptSocket(&newSocketId, newHostSocket, inetSock); + if (!newInetSocket) { + // Ran out of space. Shouldn't really happen. + inetLastErrno = ENOMEM; + return -1; } if (src) { @@ -708,7 +717,7 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { } DEBUG_LOG(Log::sceNet, "Accept: Address = %s, Port = %d", ip2str(saddr.in.sin_addr).c_str(), ntohs(saddr.in.sin_port)); - return hleLogSuccessI(Log::sceNet, retval); + return hleLogSuccessI(Log::sceNet, newSocketId); } static int sceNetInetShutdown(int socket, int how) {