diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index cbc2cd17f59d..043ffd27738d 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -176,28 +176,6 @@ enum { #ifdef _MSC_VER #pragma pack(push,1) #endif -// Sockaddr -typedef struct SceNetInetSockaddr { - uint8_t sa_len; - uint8_t sa_family; - uint8_t sa_data[14]; -} PACK SceNetInetSockaddr; - -// Sockaddr_in -typedef struct SceNetInetSockaddrIn { - uint8_t sin_len; - uint8_t sin_family; - u16_le sin_port; //uint16_t - u32_le sin_addr; //uint32_t - uint8_t sin_zero[8]; -} PACK SceNetInetSockaddrIn; - -// Polling Event Field -typedef struct SceNetInetPollfd { //similar format to pollfd in 32bit (pollfd in 64bit have different size) - s32_le fd; - s16_le events; - s16_le revents; -} PACK SceNetInetPollfd; typedef struct ProductStruct { // Similar to SceNetAdhocctlAdhocId ? s32_le unknown; // Unknown, set to 0 // Product Type ? diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index da4bec756869..7b6dfb225da4 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -44,7 +44,7 @@ #include "Core/Reporting.h" // TODO: move Core/Net #include "Core/Net/InetCommon.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #include "Core/Util/PortManager.h" #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) @@ -68,12 +68,43 @@ using netBufferType = void; // TODO: ignore SO_NOSIGPIPE // TODO: timeouts (PSP_NET_INET_SO_SNDTIMEO) -struct SceTimeval { +/** + * @file sceNetInet.cpp + * + * @brief A shim for SceNetInet functions to operate over native POSIX sockets. These POSIX socket implementations are + * largely standarized and consistent between platforms with the exception of Windows which uses Winsock2 which itself + * is similar enough. + * + * Glossary: + * - Inet: Anything with is prefaced with Inet, regardless of case, is the PSP variant of the function / structure / etc. + * + * Standards: + * - C++-style implementations are preferred over C-style implementations when applicable (see SceFdSetOperations) for + * an example which implements fd_set and FD_* functions using C++-style code. + * - The last error is implemented within SceNetInet itself and is not a direct passthrough from the platforms errno + * implementation. + * - Invalid arguments (unmapped sockets, invalid options / flags etc) are mapped to EINVAL. + * - Invalid memory regions are mapped to EFAULT. + * - hleLogError should be used to return errors. + * - hleLogSuccess* should be used to return success, with optional messages. These message formattings have > 0 + * overhead so be mindful of their usage. + * - SceNetInet must have SetLastError called in all error cases except when SceNetInet itself is not initialized. + * - DEBUG_LOG should be used where it makes sense. + * - Comments must be left to indicate the intent of each section of each function. The comments should be short and + * concise while not mentioning any specific games or similar in particular. Mention the constraints that came from + * the game. + * - Explicit mappings should be used over implicit passthrough. Cases which are not known to work for PSP should be + * mapped to an EINVAL error unless it is demonstrated to work as expected. + * - It should not be possible for a game to crash the application via any shim; think what would happen if every + * parameter is randomized. + */ + +struct PspInetTimeval { u32 tv_sec; /* Seconds. */ u32 tv_usec; /* Microseconds. */ }; -class SceFdSetOperations { +class PspInetFdSetOperations { public: typedef long int fdMask; static constexpr int gFdsBitsCount = 8 * static_cast(sizeof(fdMask)); @@ -82,20 +113,20 @@ class SceFdSetOperations { fdMask mFdsBits[256 / gFdsBitsCount]; }; - static void Set(FdSet *sceFdSetBits, int socket) { - sceFdSetBits->mFdsBits[Position(socket)] |= ConvertToMask(socket); + static void Set(FdSet &sceFdSetBits, int socket) { + sceFdSetBits.mFdsBits[Position(socket)] |= ConvertToMask(socket); } - static bool IsSet(const FdSet *sceFdSetBits, int socket) { - return (sceFdSetBits->mFdsBits[Position(socket)] & ConvertToMask(socket)) != 0; + static bool IsSet(const FdSet &sceFdSetBits, int socket) { + return (sceFdSetBits.mFdsBits[Position(socket)] & ConvertToMask(socket)) != 0; } - static void Clear(FdSet *sceFdSetBits, int socket) { - sceFdSetBits->mFdsBits[Position(socket)] &= ~ConvertToMask(socket); + static void Clear(FdSet &sceFdSetBits, int socket) { + sceFdSetBits.mFdsBits[Position(socket)] &= ~ConvertToMask(socket); } - static void Zero(FdSet *sceFdSetBits) { - memset(sceFdSetBits->mFdsBits, 0, sizeof(FdSet)); + static void Zero(FdSet &sceFdSetBits) { + memset(sceFdSetBits.mFdsBits, 0, sizeof(FdSet)); } private: @@ -108,29 +139,22 @@ class SceFdSetOperations { } }; -// static int getLastPlatformError() { -// #if PPSSPP_PLATFORM(WINDOWS) -// return WSAGetLastError(); -// #else -// return errno; -// #endif -// } - -static bool sceSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { - const auto sceNetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); - if (sceNetSockaddrIn == nullptr || addressLength == 0) { +static bool inetSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { + const auto inetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); + if (inetSockaddrIn == nullptr || addressLength == 0) { return false; } + // Clear dest of any existing data and copy relevant fields from inet sockaddr_in memset(&dest, 0, sizeof(dest)); - dest.sin_family = sceNetSockaddrIn->sin_family; - dest.sin_port = sceNetSockaddrIn->sin_port; - dest.sin_addr.s_addr = sceNetSockaddrIn->sin_addr; - DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), sceNetSockaddrIn->sin_len); + dest.sin_family = inetSockaddrIn->sin_family; + dest.sin_port = inetSockaddrIn->sin_port; + dest.sin_addr.s_addr = inetSockaddrIn->sin_addr; + DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), inetSockaddrIn->sin_len); return true; } -static bool writeSockAddrInToSceSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, sockaddr_in src) { +static bool writeSockAddrInToInetSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, sockaddr_in src) { const auto sceNetSocklenPtr = reinterpret_cast(Memory::GetPointerWrite(destAddrLenPtr)); u32 sceNetSocklen = 0; if (sceNetSocklenPtr != nullptr) { @@ -140,7 +164,7 @@ static bool writeSockAddrInToSceSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, so if (sceNetSockaddrIn == nullptr) { return false; } - INFO_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); + DEBUG_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); if (sceNetSocklenPtr) { *sceNetSocklenPtr = std::min(sceNetSocklen, sizeof(SceNetInetSockaddr)); } @@ -194,16 +218,25 @@ static int sceNetInetSocket(int domain, int type, int protocol) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } + // TODO: translate domain, type and protocol if applicable + + // Attempt to open socket const int nativeSocketId = socket(domain, type, protocol); - const auto sceSocket = sceNetInet->CreateAndAssociateSceSocket(nativeSocketId); + if (nativeSocketId < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, domain, type, protocol, error, strerror(error)); + } - if (!sceSocket) { + // Map opened socket to an inet socket which is 1-indexed + const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId); + + // Close opened socket if such a socket exists + if (!inetSocket) { close(nativeSocketId); sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new SceSocket for native socket id %i, closing", __func__, nativeSocketId); + return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new InetSocket for native socket id %i, closing", __func__, nativeSocketId); } - - return sceSocket->GetSceSocketId(); + return inetSocket->GetInetSocketId(); } static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, u32 optlenPtr) { @@ -214,23 +247,23 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { - sceNetInet->SetLastError(EFAULT); + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { + sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } - const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); if (optname != inetOptname) { DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } - const auto nativeSocketId = sceSocket->GetNativeSocketId(); + const auto nativeSocketId = inetSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(WINDOWS) auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); @@ -248,7 +281,8 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } - // TODO: implement non-blocking sockopt + // TODO: implement non-blocking getsockopt + // TODO: implement SOL const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -265,18 +299,20 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + const auto nativeSocketId = inetSocket->GetNativeSocketId(); + + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); + return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); } - const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); if (optname != inetOptname) { DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } @@ -284,29 +320,38 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability if (optlen != sizeof(u32)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "[%i]: %s: Unhandled optlen %i for optname %04x", sceSocket->GetNativeSocketId(), __func__, optlen, inetOptname); + return hleLogError(SCENET, -1, "[%i]: %s: Unhandled optlen %i for optname %04x", nativeSocketId, __func__, optlen, inetOptname); + } + + if (!Memory::IsValidAddress(optvalPtr)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i]: %s: Invalid address %08x for optval", nativeSocketId, __func__, optvalPtr); } auto optval = Memory::Read_U32(optvalPtr); - const auto nativeSocketId = sceSocket->GetNativeSocketId(); - INFO_LOG(SCENET, "[%i] setsockopt_u32(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); + DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); switch (optname) { // Unmatched PSP functions - no direct equivalent case INET_SO_NONBLOCK: { const bool nonblocking = optval != 0; - sceSocket->SetNonBlocking(nonblocking); + inetSocket->SetNonBlocking(nonblocking); INFO_LOG(SCENET, "[%i] setsockopt_u32: Set non-blocking=%i", nativeSocketId, nonblocking); if (setBlockingMode(nativeSocketId, nonblocking) != 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i] Failed to set to non-blocking: %i: %s", nativeSocketId, error, strerror(error)); + ERROR_LOG(SCENET, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return 0; } + // Functions with identical structs to native functions default: { INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); - int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + const int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, optname, optval, error, strerror(error)); + } return ret; } } @@ -320,19 +365,21 @@ static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLen } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + // Translate inet sockaddr to native sockaddr sockaddr_in convertedSockaddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { + if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Error translating sceSockaddr to native sockaddr", nativeSocketId, __func__); } DEBUG_LOG(SCENET, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); + // Attempt to connect using translated sockaddr int ret = connect(nativeSocketId, reinterpret_cast(&convertedSockaddr), sizeof(convertedSockaddr)); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -349,16 +396,17 @@ static int sceNetInetListen(int socket, int backlog) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - // TODO: here + // Map PSP_NET_INET_SOMAXCONN (128) to platform SOMAXCONN if (backlog == PSP_NET_INET_SOMAXCONN) { backlog = SOMAXCONN; } + // Attempt to listen using either backlog, or SOMAXCONN as per above const int ret = listen(socket, backlog); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -376,23 +424,26 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + // Attempt to accept a connection which will provide us with a sockaddrIn containing remote connection details sockaddr_in sockaddrIn{}; socklen_t socklen; - int ret = accept(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); + const int ret = accept(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); if (ret < 0) { - const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - if (error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + // Ensure that ERROR_WHEN_NONBLOCKING_CALL_OCCURS is not mapped to an hleLogError + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return ret; } - if (addrPtr != 0 && !writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Don't call writeSockAddrInToInetSockAddr when addrPtr is 0, otherwise do and send false to EFAULT + if (addrPtr != 0 && !writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range", nativeSocketId, __func__); } @@ -470,23 +521,25 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } + // Translate all input fd_sets to native fd_sets. None of these will be nullptr and so this needs to be checked later. int recomputedMaxFd = 1; fd_set readFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, readFds, readFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, readFds, readFdsPtr); fd_set writeFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, writeFds, writeFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, writeFds, writeFdsPtr); fd_set exceptFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, exceptFds, exceptFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, exceptFds, exceptFdsPtr); + // Convert timeval when applicable timeval tv{}; if (timeoutPtr != 0) { - const auto sceTimeval = Memory::GetTypedPointerRange(timeoutPtr, sizeof(SceTimeval)); - if (sceTimeval != nullptr) { - tv.tv_sec = sceTimeval->tv_sec; - tv.tv_usec = sceTimeval->tv_usec; - DEBUG_LOG(SCENET, "sceNetInetSelect: Timeout seconds=%lu, useconds=%lu", tv.tv_sec, tv.tv_usec); + const auto inetTimeval = Memory::GetTypedPointerRange(timeoutPtr, sizeof(PspInetTimeval)); + if (inetTimeval != nullptr) { + tv.tv_sec = inetTimeval->tv_sec; + tv.tv_usec = inetTimeval->tv_usec; + DEBUG_LOG(SCENET, "%s: Timeout seconds=%lu, useconds=%lu", __func__, tv.tv_sec, tv.tv_usec); } else { - WARN_LOG(SCENET, "sceNetInetSelect: Encountered invalid timeout value, continuing anyway"); + WARN_LOG(SCENET, "%s: Encountered invalid timeout value, continuing anyway", __func__); } } @@ -494,11 +547,11 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce const int ret = select(recomputedMaxFd, readFdsPtr != 0 ? &readFds : nullptr, writeFdsPtr != 0 ? &writeFds : nullptr, exceptFdsPtr != 0 ? &exceptFds : nullptr, timeoutPtr != 0 ? &tv : nullptr); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "sceNetInetSelect: Received error from select() %i: %s", error, strerror(error)); + ERROR_LOG(SCENET, "%s: Received error from select() %i: %s", __func__, error, strerror(error)); } - INFO_LOG(SCENET, "sceNetInetSelect: select() returned %i", ret); - return hleDelayResult(ret, "TODO: unhack", 300); + INFO_LOG(SCENET, "%s: select() returned %i", __func__, ret); + return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetClose(int socket) { @@ -507,16 +560,16 @@ static int sceNetInetClose(int socket) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EINVAL); return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } - const int ret = close(sceSocket->GetNativeSocketId()); + const int ret = close(inetSocket->GetNativeSocketId()); if (!sceNetInet->EraseNativeSocket(socket)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Unable to clear mapping of sceSocketId->nativeSocketId, was there contention?", __func__); + return hleLogError(SCENET, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); } return ret; } @@ -551,20 +604,32 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } + if (hostname == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Invalid hostname: %08x", __func__, hostname); + } + if (!Memory::IsValidAddress(addrPtr)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Invalid addrPtr: %08x", __func__, addrPtr); } + // Convert the input hostname into an inaddr in_addr inAddr{}; #if PPSSPP_PLATFORM(WINDOWS) + // Use inet_pton to accomplish the same behavior on Winsock2 which is missing inet_aton const int ret = inet_pton(AF_INET, hostname, &inAddr); #else const int ret = inet_aton(hostname, &inAddr); #endif - if (ret != 0) { - Memory::Write_U32(inAddr.s_addr, addrPtr); + + if (ret == 0) { + // inet_aton does not set errno when an error occurs, so neither should we + return hleLogError(SCENET, ret, "%s: Invalid hostname %s", __func__, hostname); } + + // Write back to addrPtr if ret is != 0 + Memory::Write_U32(inAddr.s_addr, addrPtr); return ret; } @@ -600,28 +665,29 @@ static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 return hleLogSuccessX(SCENET, dstBufPtr); } -static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstBufPtr) { - WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstBufPtr); +static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstPtr) { + WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); - if (srcSockaddrIn == nullptr) { - return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); + if (hostname == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, 0, "%s: Invalid memory range for hostname %08x", __func__, hostname); } // IPv4, the only supported address family on PSP, will always be 32 bits - const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, sizeof(u32)); - if (dstBuf == nullptr) { - return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); + const auto dst = Memory::GetTypedPointerWriteRange(dstPtr, sizeof(u32)); + if (dst == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, 0, "%s: Invalid memory range for dstPtr %08x, size %i", __func__, dstPtr, sizeof(u32)); } // TODO: convert address family // TODO: If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT. - const int ret = inet_pton(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf); + const int ret = inet_pton(addressFamily, hostname, dst); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); @@ -637,7 +703,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); return -1; } @@ -645,7 +711,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { // Write PSP sockaddr to native sockaddr in preparation of getpeername sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); - if (!sceSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { + if (!inetSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i]: %s: Encountered invalid addrPtr %08x and/or invalid addrLenPtr %08x", nativeSocketId, addrPtr, addrLenPtr); } @@ -656,7 +722,8 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getpeername %i: %s", nativeSocketId, __func__, error, strerror(error)); } - if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Write output of getpeername to the input addrPtr + if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); } @@ -671,11 +738,12 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); - return -1; + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "%s: Requested socket %i which does not exist", __func__, socket); } + // Set sockaddrIn to the result of getsockname sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); const int ret = getsockname(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); @@ -684,7 +752,9 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getsockname %i: %s", nativeSocketId, __func__, error, strerror(error)); } - if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Write output of getsockname to the input addrPtr + if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } return ret; @@ -697,23 +767,24 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { - WARN_LOG(SCENET, "sceNetInetClose: Attempting to close socket %i which does not exist", socket); + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { + WARN_LOG(SCENET, "%s: Attempting to close socket %i which does not exist", __func__, socket); return -1; } + const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "sceNetInetRecv: Invalid pointer %08x (size %i)", bufPtr, bufLen); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } - // TODO: debug log the API calls - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); - - const int ret = recv(sceSocket->GetNativeSocketId(), dstBuf, bufLen, nativeFlags); + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int ret = recv(nativeSocketId, dstBuf, bufLen, nativeFlags); + DEBUG_LOG(SCENET, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret); if (ret < 0) { - if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); } } @@ -727,65 +798,66 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const auto nativeSocketId = sceSocket->GetNativeSocketId(); + const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + // Translate PSP flags to native flags and prepare sockaddrIn to receive peer address + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); Memory::Memset(bufPtr, 0, bufLen, __func__); const int ret = recvfrom(nativeSocketId, dstBuf, bufLen, nativeFlags, reinterpret_cast(&sockaddrIn), &socklen); - if (ret < 0) { if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != 0 && error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { - WARN_LOG(SCENET, "[%i] sceNetInetRecvfrom: Received error %i: %s", nativeSocketId, error, strerror(error)); + WARN_LOG(SCENET, "[%i] %s: Received error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return hleDelayResult(ret, "TODO: unhack", 500); } + // If ret was successful, write peer sockaddr to input fromAddr if (ret > 0) { - if (!writeSockAddrInToSceSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { - ERROR_LOG(SCENET, "[%i] sceNetInetRecvfrom: Error writing native sockaddr to sceSockaddr", nativeSocketId); + if (!writeSockAddrInToInetSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { + ERROR_LOG(SCENET, "[%i] %s: Error writing native sockaddr to sceSockaddr", nativeSocketId, __func__); } - INFO_LOG(SCENET, "[%i] sceNetInetRecvfrom: Got %i bytes from recvfrom", nativeSocketId, ret); + INFO_LOG(SCENET, "[%i] %s: Got %i bytes from recvfrom", nativeSocketId, __func__, ret); } return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { - WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED %s(%i, %08x, %i, %08x)", __func__, socket, bufPtr, bufLen, flags); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const auto resolvedPtr = Memory::GetTypedPointerRange(bufPtr, bufLen); - if (resolvedPtr == nullptr) { + const auto buf = Memory::GetTypedPointerRange(bufPtr, bufLen); + if (buf == nullptr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); - - const int ret = send(sceSocket->GetNativeSocketId(), resolvedPtr, bufLen, nativeFlags); + // Translate PSP flags to native flags and send + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int ret = send(inetSocket->GetNativeSocketId(), buf, bufLen, nativeFlags); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); @@ -800,35 +872,35 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const int nativeSocketId = sceSocket->GetNativeSocketId(); + const int nativeSocketId = inetSocket->GetNativeSocketId(); const auto srcBuf = Memory::GetTypedPointerRange(bufPtr, bufLen); if (srcBuf == nullptr) { - ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Invalid pointer range: %08x (size %i)", socket, bufPtr, bufLen); + ERROR_LOG(SCENET, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); return -1; } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + // Translate PSP flags to native flags and convert toAddr to native addr + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); sockaddr_in convertedSockAddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { - ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Unable to translate sceSockAddr to native sockaddr", nativeSocketId); + if (!inetSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { + ERROR_LOG(SCENET, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__); return -1; } - // TODO: improve debug log - DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: Writing %i bytes to %s on port %i", nativeSocketId, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); + DEBUG_LOG(SCENET, "[%i] %s: Writing %i bytes to %s on port %i", nativeSocketId, __func__, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); const int ret = sendto(nativeSocketId, srcBuf, bufLen, nativeFlags, reinterpret_cast(&convertedSockAddr), sizeof(sockaddr_in)); - DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: sendto returned %i", nativeSocketId, ret); + DEBUG_LOG(SCENET, "[%i] %s: sendto returned %i", nativeSocketId, __func__, ret); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - WARN_LOG(SCENET, "[%i] sceNetInetSendto: Got error %i=%s", nativeSocketId, error, strerror(error)); + WARN_LOG(SCENET, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); } return ret; @@ -843,11 +915,10 @@ static int sceNetInetGetErrno() { const auto nativeError = sceNetInet->GetLastError(); if (nativeError != ERROR_WHEN_NONBLOCKING_CALL_OCCURS && nativeError != 0) { - INFO_LOG(SCENET, "Requested sceNetInetGetErrno %i=%s", nativeError, strerror(nativeError)); + INFO_LOG(SCENET, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError)); } - // TODO: consider moving below function to SceNetInet - return SceSocket::TranslateNativeErrorToInetError(nativeError); + return InetSocket::TranslateNativeErrorToInetError(nativeError); } static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { @@ -857,17 +928,17 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const int nativeSocketId = sceSocket->GetNativeSocketId(); + const int nativeSocketId = inetSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(LINUX) // Set broadcast - // TODO: move broadcast SceSocket + // TODO: move broadcast InetSocket int broadcastEnabled = 1; int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, &broadcastEnabled, sizeof(broadcastEnabled)); @@ -880,15 +951,16 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #elif PPSSPP_PLATFORM(WINDOWS) // Set broadcast - // TODO: move broadcast SceSocket + // TODO: move broadcast InetSocket int broadcastEnabled = 1; int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnabled), sizeof(broadcastEnabled)); int opt = 1; setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)); #endif + // Convert PSP bind addr to native bind addr sockaddr_in convertedSockaddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { + if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { ERROR_LOG(SCENET, "[%i] Error translating sceSockaddr to native sockaddr", nativeSocketId); return -1; } @@ -907,11 +979,11 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s sockoptRet %i", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str(), sockoptRet); const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); - setBlockingMode(nativeSocketId, sceSocket->IsNonBlocking()); + setBlockingMode(nativeSocketId, inetSocket->IsNonBlocking()); // Set UPnP const auto port = ntohs(convertedSockaddr.sin_port); - switch (sceSocket->GetProtocol()) { + switch (inetSocket->GetProtocol()) { case INET_PROTOCOL_TCP: { UPnP_Add(IP_PROTOCOL_TCP, port, port); break; @@ -920,8 +992,9 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { UPnP_Add(IP_PROTOCOL_UDP, port, port); break; } + // TODO: Unknown IP protocol 000f when attempting to set up UPnP port forwarding default: { - WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, sceSocket->GetProtocol()); + WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, inetSocket->GetProtocol()); break; } } @@ -956,12 +1029,12 @@ const HLEFunction sceNetInet[] = { {0XD0792666, &WrapU_IUUU, "sceNetInetInetNtop", '?', "" }, {0XE30B8C19, &WrapI_ICU, "sceNetInetInetPton", '?', "" }, {0X8CA3A97E, nullptr, "sceNetInetGetPspError", '?', "" }, - {0XE247B6D6, &WrapI_IUU,"sceNetInetGetpeername", '?', "" }, + {0XE247B6D6, &WrapI_IUU, "sceNetInetGetpeername", '?', "" }, {0X162E6FD5, &WrapI_IUU, "sceNetInetGetsockname", '?', "" }, {0X80A21ABD, nullptr, "sceNetInetSocketAbort", '?', "" }, {0X39B0C7D3, nullptr, "sceNetInetGetUdpcbstat", '?', "" }, {0XB3888AD4, nullptr, "sceNetInetGetTcpcbstat", '?', "" }, -}; +};; std::shared_ptr SceNetInet::gInstance; std::shared_mutex SceNetInet::gLock; @@ -995,7 +1068,6 @@ void SceNetInet::SetLastError(const int error) { mLastError = error; } -// TODO: ensure this is applied to every function int SceNetInet::SetLastErrorToMatchPlatform() { int error; #if PPSSPP_PLATFORM(WINDOWS) @@ -1007,77 +1079,75 @@ int SceNetInet::SetLastErrorToMatchPlatform() { return error; } -std::shared_ptr SceNetInet::CreateAndAssociateSceSocket(int nativeSocketId) { +std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId) { auto lock = std::unique_lock(mLock); - int sceSocketId = ++mCurrentSceSocketId; - if (const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); it != mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated sceSocketId: %i", __func__, sceSocketId); + int inetSocketId = ++mCurrentInetSocketId; + if (const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); it != mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId); return nullptr; } - auto sceSocket = std::make_shared(sceSocketId, nativeSocketId); - mSceSocketIdToNativeSocket.emplace(sceSocketId, sceSocket); - return sceSocket; + auto inetSocket = std::make_shared(inetSocketId, nativeSocketId); + mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket); + return inetSocket; } -std::shared_ptr SceNetInet::GetSceSocket(int sceSocketId) { +std::shared_ptr SceNetInet::GetInetSocket(int inetSocketId) { auto lock = std::shared_lock(mLock); - const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); - if (it == mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from sceSocketId: %i", __func__, sceSocketId); + const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); + if (it == mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); return nullptr; } return it->second; } -bool SceNetInet::GetNativeSocketIdForSceSocketId(int& nativeSocketId, int sceSocketId) { - const auto sceSocket = GetSceSocket(sceSocketId); - if (!sceSocket) +bool SceNetInet::GetNativeSocketIdForInetSocketId(int& nativeSocketId, int inetSocketId) { + const auto inetSocket = GetInetSocket(inetSocketId); + if (!inetSocket) return false; - nativeSocketId = sceSocket->GetNativeSocketId(); + nativeSocketId = inetSocket->GetNativeSocketId(); return true; } -bool SceNetInet::EraseNativeSocket(int sceSocketId) { +bool SceNetInet::EraseNativeSocket(int inetSocketId) { auto lock = std::unique_lock(mLock); - const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); - if (it == mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from sceSocketId: %i", __func__, sceSocketId); + const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); + if (it == mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from inetSocketId: %i", __func__, inetSocketId); return false; } - mSceSocketIdToNativeSocket.erase(it); + mInetSocketIdToNativeSocket.erase(it); return true; } -bool SceNetInet::TranslateSceFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u32 fdsPtr) const { +bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u32 fdsPtr) const { if (fdsPtr == 0) { // Allow nullptr to be used without failing return true; } FD_ZERO(&destFdSet); - const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(SceFdSetOperations::FdSet)); + const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(PspInetFdSetOperations::FdSet)); if (sceFdSet == nullptr) { ERROR_LOG(SCENET, "%s: Invalid fdsPtr %08x", __func__, fdsPtr); return false; } int setSize = 0; - for (auto& it : mSceSocketIdToNativeSocket) { - const auto sceSocket = it.first; + for (auto& it : mInetSocketIdToNativeSocket) { + const auto inetSocket = it.first; const auto nativeSocketId = it.second->GetNativeSocketId(); - if (nativeSocketId + 1 > maxFd) { - maxFd = nativeSocketId + 1; - } - if (SceFdSetOperations::IsSet(sceFdSet, sceSocket)) { + maxFd = std::max(nativeSocketId + 1, maxFd); + if (PspInetFdSetOperations::IsSet(*sceFdSet, inetSocket)) { if (++setSize > FD_SETSIZE) { ERROR_LOG(SCENET, "%s: Encountered input FD_SET which is greater than max supported size %i", __func__, setSize); return false; } - DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, sceSocket, nativeSocketId); + DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, inetSocket, nativeSocketId); FD_SET(nativeSocketId, &destFdSet); } } @@ -1087,14 +1157,13 @@ bool SceNetInet::TranslateSceFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u } void SceNetInet::CloseAllRemainingSockets() const { - for (auto& it : mSceSocketIdToNativeSocket) { - if (!it.second) { - continue; + for (const auto &[first, second] : mInetSocketIdToNativeSocket) { + if (second) { + close(second->GetNativeSocketId()); } - close(it.second->GetNativeSocketId()); } } void Register_sceNetInet() { - RegisterModule("sceNetInet", ARRAY_SIZE(sceNetInet), sceNetInet); + RegisterModule("sceNetInet", std::size(sceNetInet), sceNetInet); } diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h index db2301e3031f..584ec7710937 100644 --- a/Core/HLE/sceNetInet.h +++ b/Core/HLE/sceNetInet.h @@ -1,7 +1,7 @@ #pragma once #include "Core/HLE/HLE.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #if PPSSPP_PLATFORM(WINDOWS) #include @@ -11,6 +11,28 @@ #include #include +// Sockaddr +typedef struct SceNetInetSockaddr { + uint8_t sa_len; + uint8_t sa_family; + uint8_t sa_data[14]; +} PACK SceNetInetSockaddr; + +// Sockaddr_in +typedef struct SceNetInetSockaddrIn { + uint8_t sin_len; + uint8_t sin_family; + u16_le sin_port; //uint16_t + u32_le sin_addr; //uint32_t + uint8_t sin_zero[8]; +} PACK SceNetInetSockaddrIn; + +// Polling Event Field +typedef struct SceNetInetPollfd { //similar format to pollfd in 32bit (pollfd in 64bit have different size) + s32_le fd; + s16_le events; + s16_le revents; +} PACK SceNetInetPollfd; enum { // pspnet_inet @@ -40,11 +62,11 @@ class SceNetInet { int GetLastError(); void SetLastError(int error); int SetLastErrorToMatchPlatform(); - std::shared_ptr CreateAndAssociateSceSocket(int nativeSocketId); - std::shared_ptr GetSceSocket(int sceSocketId); - bool GetNativeSocketIdForSceSocketId(int &nativeSocketId, int sceSocketId); - bool EraseNativeSocket(int sceSocketId); - bool TranslateSceFdSetToNativeFdSet(int& maxFd, fd_set &destFdSet, u32 fdsPtr) const; + std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId); + std::shared_ptr GetInetSocket(int inetSocketId); + bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId); + bool EraseNativeSocket(int inetSocketId); + bool TranslateInetFdSetToNativeFdSet(int& maxFd, fd_set &destFdSet, u32 fdsPtr) const; private: void CloseAllRemainingSockets() const; @@ -53,8 +75,8 @@ class SceNetInet { static std::shared_mutex gLock; int mLastError = 0; - std::unordered_map> mSceSocketIdToNativeSocket; - int mCurrentSceSocketId = 0; + std::unordered_map> mInetSocketIdToNativeSocket; + int mCurrentInetSocketId = 0; std::shared_mutex mLock; }; diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index df2bc483f199..1fd104e3ff0f 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -54,7 +54,7 @@ #include "Core/HLE/sceNp.h" #include "Core/Reporting.h" #include "Core/Instance.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) // Missing toolchain define diff --git a/Core/Net/SceSocket.cpp b/Core/Net/InetSocket.cpp similarity index 68% rename from Core/Net/SceSocket.cpp rename to Core/Net/InetSocket.cpp index c155401f3b8f..945ecd077ea2 100644 --- a/Core/Net/SceSocket.cpp +++ b/Core/Net/InetSocket.cpp @@ -1,3 +1,3 @@ // TODO: remove me if the functions remain inlined -#include "SceSocket.h" +#include "InetSocket.h" diff --git a/Core/Net/SceSocket.h b/Core/Net/InetSocket.h similarity index 96% rename from Core/Net/SceSocket.h rename to Core/Net/InetSocket.h index bf0a4a3b5a8a..4bb06784e258 100644 --- a/Core/Net/SceSocket.h +++ b/Core/Net/InetSocket.h @@ -108,12 +108,12 @@ static std::unordered_map gNativeErrorCodeToInetErrorCode = }; // TODO: document -class SceSocket { +class InetSocket { public: - SceSocket(int sceSocketId, int nativeSocketId) : mSceSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} + InetSocket(int sceSocketId, int nativeSocketId) : mInetSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} - int GetSceSocketId() const { - return mSceSocketId; + int GetInetSocketId() const { + return mInetSocketId; } int GetNativeSocketId() const { @@ -180,6 +180,7 @@ class SceSocket { return nativeFlags; } + // TODO: consider moving to SceNetInet static int TranslateNativeErrorToInetError(const int nativeError) { if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError); it != gNativeErrorCodeToInetErrorCode.end()) { @@ -189,7 +190,7 @@ class SceSocket { } private: - int mSceSocketId; + int mInetSocketId; int mNativeSocketId; Protocol mProtocol; bool mNonBlocking = false;