From 4bc79481da69a015873be4ac178f5cb9e2d1abf8 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Wed, 27 Dec 2023 11:46:35 -0800 Subject: [PATCH] Translate all input parameters to socket(). --- Core/HLE/sceNetInet.cpp | 278 +++++++++++++++++++++++++++++----------- Core/HLE/sceNetInet.h | 56 +++++++- 2 files changed, 258 insertions(+), 76 deletions(-) diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index 3291c068d4..8e272f1d84 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -203,34 +203,59 @@ static int setBlockingMode(int nativeSocketId, bool nonblocking) { } static int sceNetInetInit() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); - return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; + ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); + return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; } int sceNetInetTerm() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); + ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); SceNetInet::Shutdown(); - return 0; + return hleLogSuccessI(SCENET, 0); } -static int sceNetInetSocket(int domain, int type, int protocol) { - WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", domain, type, protocol); +static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtocol) { + WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", inetAddressFamily, inetType, inetProtocol); auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - // TODO: translate domain, type and protocol if applicable + // Translate address family, type, and protocol. There is some complexity around the type in particular where + // flags are able to be encoded in the most significant bits. + + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, -1, "%s: Unable to translate inet address family %i", __func__, inetAddressFamily); + } + + int nativeType; + bool nonBlocking; + if (!SceNetInet::TranslateInetSocketTypeToNative(nativeType, nonBlocking, inetType)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "%s: Unable to translate inet type %08x", __func__, inetType); + } + + int nativeProtocol; + if (!SceNetInet::TranslateInetProtocolToNative(nativeProtocol, inetProtocol)) { + sceNetInet->SetLastError(EPROTONOSUPPORT); + return hleLogError(SCENET, -1, "%s: Unable to translate inet protocol %i", __func__, inetProtocol); + } // Attempt to open socket - const int nativeSocketId = socket(domain, type, protocol); + const int nativeSocketId = socket(nativeAddressFamily, nativeType, nativeProtocol); 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)); + return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, nativeAddressFamily, nativeType, nativeProtocol, error, strerror(error)); } // Map opened socket to an inet socket which is 1-indexed - const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId); + const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nonBlocking); + + // Set non-blocking mode since the translation function does not translate non-blocking mode due to platform incompatibilities + if (nonBlocking) { + setBlockingMode(nativeSocketId, true); + } // Close opened socket if such a socket exists if (!inetSocket) { @@ -241,8 +266,8 @@ static int sceNetInetSocket(int domain, int type, int protocol) { return inetSocket->GetInetSocketId(); } -static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, u32 optlenPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, level, inetOptname, optvalPtr, optlenPtr); +static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, u32 optlenPtr) { + WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, inetSocketLevel, inetOptname, optvalPtr, optlenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -255,6 +280,14 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + const auto nativeSocketId = inetSocket->GetNativeSocketId(); + + int nativeSocketLevel; + if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + } + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); @@ -265,8 +298,6 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } - const auto nativeSocketId = inetSocket->GetNativeSocketId(); - #if PPSSPP_PLATFORM(WINDOWS) auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); #else @@ -283,18 +314,31 @@ 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 getsockopt - // TODO: implement SOL - const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); - if (ret < 0) { - const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); + switch (optname) { + // No direct equivalents + case INET_SO_NONBLOCK: { + if (*optlen != sizeof(u32)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid optlen %i for INET_SO_NONBLOCK", nativeSocketId, __func__, *optlen); + } + Memory::Write_U32(optvalPtr, inetSocket->IsNonBlocking() ? 1 : 0); + return hleLogSuccessI(SCENET, 0); + } + // Direct 1:1 mappings + default: { + // TODO: implement non-blocking getsockopt + const int ret = getsockopt(nativeSocketId, nativeSocketLevel, optname, optval, optlen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + return hleLogSuccessI(SCENET, ret); + } } - return ret; } -static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, int optlen) { - WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, inetOptname, optvalPtr, optlen); +static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, int optlen) { + WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, inetSocketLevel, inetOptname, optvalPtr, optlen); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -309,6 +353,12 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv const auto nativeSocketId = inetSocket->GetNativeSocketId(); + int nativeSocketLevel; + if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + } + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); @@ -331,7 +381,7 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv } auto optval = Memory::Read_U32(optvalPtr); - DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); + DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, optname, optval); switch (optname) { // Unmatched PSP functions - no direct equivalent @@ -343,18 +393,18 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv const auto error = sceNetInet->SetLastErrorToMatchPlatform(); ERROR_LOG(SCENET, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return 0; + return hleLogSuccessI(SCENET, 0); } // Functions with identical structs to native functions default: { - INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); - const int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, optname, optval, 4); + const int ret = setsockopt(nativeSocketId, nativeSocketLevel, 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; + return hleLogSuccessI(SCENET, ret); } } } @@ -441,7 +491,7 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return ret; + return hleLogSuccessI(SCENET, ret); } // Don't call writeSockAddrInToInetSockAddr when addrPtr is 0, otherwise do and send false to EFAULT @@ -573,7 +623,7 @@ static int sceNetInetClose(int socket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static u32 sceNetInetInetAddr(const char *hostname) { @@ -585,7 +635,6 @@ static u32 sceNetInetInetAddr(const char *hostname) { } in_addr inAddr{}; - // TODO: de-dupe #if PPSSPP_PLATFORM(WINDOWS) const int ret = inet_pton(AF_INET, hostname, &inAddr); #else @@ -595,7 +644,7 @@ static u32 sceNetInetInetAddr(const char *hostname) { sceNetInet->SetLastErrorToMatchPlatform(); return inAddr.s_addr; } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { @@ -632,11 +681,11 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { // Write back to addrPtr if ret is != 0 Memory::Write_U32(inAddr.s_addr, addrPtr); - return ret; + return hleLogSuccessI(SCENET, ret); } -static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { - WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, addressFamily, srcPtr, dstBufPtr, dstBufSize); +static u32 sceNetInetInetNtop(int inetAddressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { + WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, inetAddressFamily, srcPtr, dstBufPtr, dstBufSize); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -660,15 +709,20 @@ static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 return hleLogError(SCENET, 0, "%s: dstBufSize must be > 0", __func__); } - // TODO: convert address family - if (inet_ntop(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + } + + if (inet_ntop(nativeAddressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { // Allow partial output in case it's desired for some reason } return hleLogSuccessX(SCENET, 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); +static int sceNetInetInetPton(int inetAddressFamily, const char *hostname, u32 dstPtr) { + WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, inetAddressFamily, hostname, dstPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -687,9 +741,14 @@ static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstPt 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, hostname, dst); + // Translate inet address family to native + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + } + + const int ret = inet_pton(inetAddressFamily, 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)); @@ -729,7 +788,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { @@ -759,7 +818,7 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { @@ -790,7 +849,7 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); } } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 fromAddr, u32 fromLenAddr) { @@ -905,7 +964,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t WARN_LOG(SCENET, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetGetErrno() { @@ -938,28 +997,6 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { const int nativeSocketId = inetSocket->GetNativeSocketId(); -#if PPSSPP_PLATFORM(LINUX) - // Set broadcast - // TODO: move broadcast InetSocket - int broadcastEnabled = 1; - int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, &broadcastEnabled, sizeof(broadcastEnabled)); - - // Set reuseport / reuseaddr by default - // TODO: evaluate - int opt = 1; -#if defined(SO_REUSEPORT) - setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); -#endif - setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); -#elif PPSSPP_PLATFORM(WINDOWS) - // Set broadcast - // 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 (!inetSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { @@ -978,7 +1015,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { // TODO: check whether setting to blocking and then non-blocking is valid setBlockingMode(nativeSocketId, false); - 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); + INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str()); const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); setBlockingMode(nativeSocketId, inetSocket->IsNonBlocking()); @@ -1000,7 +1037,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { break; } } - return ret; + return hleLogSuccessI(SCENET, ret); } // TODO: fix retmasks @@ -1040,6 +1077,32 @@ const HLEFunction sceNetInet[] = { std::shared_ptr SceNetInet::gInstance; std::shared_mutex SceNetInet::gLock; +std::unordered_map SceNetInet::gInetAddressFamilyToNativeAddressFamily = +{ + { PSP_NET_INET_AF_UNSPEC, AF_UNSPEC }, + { PSP_NET_INET_AF_LOCAL, AF_UNIX }, + { PSP_NET_INET_AF_INET, AF_INET }, +}; +std::unordered_map SceNetInet::gInetSocketTypeToNativeSocketType = +{ + { PSP_NET_INET_SOCK_STREAM, SOCK_STREAM }, + { PSP_NET_INET_SOCK_DGRAM, SOCK_DGRAM }, + { PSP_NET_INET_SOCK_RAW, SOCK_RAW }, + { PSP_NET_INET_SOCK_RDM, SOCK_RDM }, + { PSP_NET_INET_SOCK_SEQPACKET, SOCK_SEQPACKET }, +}; +std::unordered_map SceNetInet::gInetProtocolToNativeProtocol = +{ + { PSP_NET_INET_IPPROTO_IP, IPPROTO_IP }, + { PSP_NET_INET_IPPROTO_ICMP, IPPROTO_ICMP }, + { PSP_NET_INET_IPPROTO_IGMP, IPPROTO_IGMP }, + { PSP_NET_INET_IPPROTO_TCP, IPPROTO_TCP }, + { PSP_NET_INET_IPPROTO_EGP, IPPROTO_EGP }, + { PSP_NET_INET_IPPROTO_PUP, IPPROTO_PUP }, + { PSP_NET_INET_IPPROTO_UDP, IPPROTO_UDP }, + { PSP_NET_INET_IPPROTO_IDP, IPPROTO_IDP }, + { PSP_NET_INET_IPPROTO_RAW, IPPROTO_RAW }, +}; bool SceNetInet::Init() { auto lock = std::unique_lock(gLock); @@ -1060,6 +1123,69 @@ bool SceNetInet::Shutdown() { return true; } +bool SceNetInet::TranslateInetAddressFamilyToNative(int &destAddressFamily, int srcAddressFamily) { + const auto it = gInetAddressFamilyToNativeAddressFamily.find(static_cast(srcAddressFamily)); + if (it == gInetAddressFamilyToNativeAddressFamily.end()) { + return false; + } + destAddressFamily = it->second; + return true; +} + +bool SceNetInet::TranslateInetSocketLevelToNative(int &destSocketLevel, int srcSocketLevel) { + if (srcSocketLevel != PSP_NET_INET_SOL_SOCKET) { + return false; + } + destSocketLevel = SOL_SOCKET; + return true; +} + +bool SceNetInet::TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType) { + // First, take the base socket type + const int baseSocketType = static_cast(srcSocketType & PSP_NET_INET_SOCK_TYPE_MASK); + const auto it = gInetSocketTypeToNativeSocketType.find(static_cast(baseSocketType)); + if (it == gInetSocketTypeToNativeSocketType.end()) { + return false; + } + // Set base value for dest + destSocketType = it->second; + // Find any flags which are set, noting that this highly depends on the native platform and unknowns are ignored + const int srcFlags = srcSocketType & PSP_NET_INET_SOCK_FLAGS_MASK; +#if defined(SOCK_DCCP) + if ((srcFlags & PSP_NET_INET_SOCK_DCCP) != 0) { + destSocketType |= SOCK_DCCP; + } +#endif +#if defined(SOCK_PACKET) + if ((srcFlags & PSP_NET_INET_SOCK_PACKET) != 0) { + destSocketType |= SOCK_PACKET; + } +#endif +#if defined(SOCK_CLOEXEC) + if ((srcFlags & PSP_NET_INET_SOCK_CLOEXEC) != 0) { + destSocketType |= SOCK_CLOEXEC; + } +#endif + if ((srcFlags & PSP_NET_INET_SOCK_NONBLOCK) != 0) { + destNonBlocking = true; + } +#if defined(SOCK_NOSIGPIPE) + if ((srcFlags & PSP_NET_INET_SOCK_NOSIGPIPE) != 0) { + destSocketType |= SOCK_NOSIGPIPE; + } +#endif + return true; +} + +bool SceNetInet::TranslateInetProtocolToNative(int &destProtocol, int srcProtocol) { + const auto it = gInetProtocolToNativeProtocol.find(static_cast(srcProtocol)); + if (it == gInetProtocolToNativeProtocol.end()) { + return false; + } + destProtocol = it->second; + return true; +} + int SceNetInet::GetLastError() { auto lock = std::shared_lock(mLock); return mLastError; @@ -1081,7 +1207,7 @@ int SceNetInet::SetLastErrorToMatchPlatform() { return error; } -std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId) { +std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking) { auto lock = std::unique_lock(mLock); int inetSocketId = ++mCurrentInetSocketId; @@ -1090,6 +1216,7 @@ std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeS return nullptr; } auto inetSocket = std::make_shared(inetSocketId, nativeSocketId); + inetSocket->SetNonBlocking(nonBlocking); mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket); return inetSocket; } @@ -1102,14 +1229,14 @@ std::shared_ptr SceNetInet::GetInetSocket(int inetSocketId) { WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); return nullptr; } - return it->second; } bool SceNetInet::GetNativeSocketIdForInetSocketId(int& nativeSocketId, int inetSocketId) { const auto inetSocket = GetInetSocket(inetSocketId); - if (!inetSocket) + if (!inetSocket) { return false; + } nativeSocketId = inetSocket->GetNativeSocketId(); return true; } @@ -1160,9 +1287,10 @@ bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, void SceNetInet::CloseAllRemainingSockets() const { for (const auto &[first, second] : mInetSocketIdToNativeSocket) { - if (second) { - close(second->GetNativeSocketId()); + if (!second) { + continue; } + close(second->GetNativeSocketId()); } } diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h index 584ec77109..b5998ce737 100644 --- a/Core/HLE/sceNetInet.h +++ b/Core/HLE/sceNetInet.h @@ -49,6 +49,48 @@ enum { ERROR_NET_INET_INVALID_ARG = 0x8041020b, }; +enum PspInetAddressFamily { + PSP_NET_INET_AF_UNSPEC = 0, + PSP_NET_INET_AF_LOCAL = 1, + PSP_NET_INET_AF_INET = 2, +}; + +enum PspInetSocketLevel { + PSP_NET_INET_SOL_SOCKET = 0xFFFF, +}; + +enum PspInetSocketType { + PSP_NET_INET_SOCK_STREAM = 1, + PSP_NET_INET_SOCK_DGRAM = 2, + PSP_NET_INET_SOCK_RAW = 3, + PSP_NET_INET_SOCK_RDM = 4, + PSP_NET_INET_SOCK_SEQPACKET = 5, + PSP_NET_INET_SOCK_DCCP = 6, + PSP_NET_INET_SOCK_PACKET = 10, + PSP_NET_INET_SOCK_TYPE_MASK = 0xF, +}; + +enum PspInetSocketTypeFlag { + PSP_NET_INET_SOCK_CLOEXEC = 0x10000000, + PSP_NET_INET_SOCK_NONBLOCK = 0x20000000, + PSP_NET_INET_SOCK_NOSIGPIPE = 0x40000000, + PSP_NET_INET_SOCK_FLAGS_MASK = 0xF0000000, +}; + +// TODO: revisit protocols, not all are necessary +enum PspInetProtocol { + PSP_NET_INET_IPPROTO_IP = 0, // dummy for IP + PSP_NET_INET_IPPROTO_UNSPEC = 0, // 0 will defaulted to the only existing protocol for that particular domain/family and type + PSP_NET_INET_IPPROTO_ICMP = 1, // control message protocol + PSP_NET_INET_IPPROTO_IGMP = 2, // group mgmt protocol + PSP_NET_INET_IPPROTO_TCP = 6, // tcp + PSP_NET_INET_IPPROTO_EGP = 8, // exterior gateway protocol + PSP_NET_INET_IPPROTO_PUP = 12, // pup + PSP_NET_INET_IPPROTO_UDP = 17, // user datagram protocol + PSP_NET_INET_IPPROTO_IDP = 22, // xns idp + PSP_NET_INET_IPPROTO_RAW = 255, // raw IP packet +}; + class SceNetInet { public: static bool Init(); @@ -57,12 +99,20 @@ public: return gInstance; } + // TODO: document that errno should be set to EAFNOSUPPORT when this returns false + static bool TranslateInetAddressFamilyToNative(int &destAddressFamily, int srcAddressFamily); + static inline bool TranslateInetSocketLevelToNative(int &destSocketLevel, int srcSocketLevel); + // TODO: document that errno should be set to ESOMETHING when this returns false + static bool TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType); + // TODO: document that errno should be set to EPROTONOSUPPORT when this returns false + static bool TranslateInetProtocolToNative(int &destProtocol, int srcProtocol); + // TODO: document int GetLastError(); void SetLastError(int error); int SetLastErrorToMatchPlatform(); - std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId); + std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking); std::shared_ptr GetInetSocket(int inetSocketId); bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId); bool EraseNativeSocket(int inetSocketId); @@ -73,6 +123,10 @@ private: static std::shared_ptr gInstance; static std::shared_mutex gLock; + static std::unordered_map gInetAddressFamilyToNativeAddressFamily; + // TODO: document that this does not include flags + static std::unordered_map gInetSocketTypeToNativeSocketType; + static std::unordered_map gInetProtocolToNativeProtocol; int mLastError = 0; std::unordered_map> mInetSocketIdToNativeSocket;