From 298a18e1e27750ca8e6c6927376f3fa659adf91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 17 Jan 2025 09:22:33 +0100 Subject: [PATCH 1/5] Parsing fix for infra-dns.json, minor logging improvement --- Core/HLE/NetInetConstants.cpp | 2 +- Core/HLE/sceNet.cpp | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Core/HLE/NetInetConstants.cpp b/Core/HLE/NetInetConstants.cpp index ddb4cb8e09..b9af8719ac 100644 --- a/Core/HLE/NetInetConstants.cpp +++ b/Core/HLE/NetInetConstants.cpp @@ -563,7 +563,7 @@ int convertSockoptNamePSP2Host(int optname, int level) { #endif } } - return hleLogError(Log::sceNet, optname, "Unknown PSP's SockOpt Name (Level = %08x)", level); + return hleLogError(Log::sceNet, optname, "Unknown or unsupported PSP's SockOpt Name (Level = %08x)", level); } int convertSockoptNameHost2PSP(int optname, int level) { diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 424475bacf..a68b440266 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -201,7 +201,7 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { const JsonNode *workingIdsNode = game.getArray("known_working_ids"); const JsonNode *otherIdsNode = game.getArray("other_ids"); const JsonNode *notWorkingIdsNode = game.getArray("not_working_ids"); - if (!workingIdsNode) { + if (!workingIdsNode && !otherIdsNode && !notWorkingIdsNode) { // We ignore this game. continue; } @@ -209,12 +209,14 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { bool found = false; std::vector ids; - JsonGet(workingIdsNode->value).getStringVector(&ids); - for (auto &id : ids) { - if (id == gameID) { - found = true; - dns->state = InfraGameState::Working; - break; + if (workingIdsNode) { + JsonGet(workingIdsNode->value).getStringVector(&ids); + for (auto &id : ids) { + if (id == gameID) { + found = true; + dns->state = InfraGameState::Working; + break; + } } } if (!found && notWorkingIdsNode) { @@ -229,7 +231,7 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { } } if (!found && otherIdsNode) { - // Check the "other" array, not sure what we do with these. + // Check the "other" array, we're gonna try this, but less confidently :P JsonGet(otherIdsNode->value).getStringVector(&ids); for (auto &id : ids) { if (id == gameID) { @@ -994,10 +996,10 @@ void NetApctl_InitInfo(int confId) { // The reason we need autoconfig is that private Servers may need to use custom DNS Server - and most games are now // best played on private servers (only a few official ones remain, if any). if (g_Config.bInfrastructureAutoDNS) { - INFO_LOG(Log::sceNet, "Responding to game query with AutoDNS address"); + INFO_LOG(Log::sceNet, "Responding to game query with AutoDNS address: %s", g_infraDNSConfig.dns.c_str()); truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_infraDNSConfig.dns); } else { - INFO_LOG(Log::sceNet, "Responding to game query with manual DNS address"); + INFO_LOG(Log::sceNet, "Responding to game query with manual DNS address: %s", g_Config.sInfrastructureDNSServer.c_str()); truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_Config.sInfrastructureDNSServer); } From 852c41d124d930a192e52f3757f31264a3034942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 17 Jan 2025 09:25:30 +0100 Subject: [PATCH 2/5] sockopt refactor part #1 --- Core/HLE/NetInetConstants.h | 3 +- Core/HLE/sceNetInet.cpp | 65 +++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Core/HLE/NetInetConstants.h b/Core/HLE/NetInetConstants.h index 0745a11e15..b7fc4ed2b1 100644 --- a/Core/HLE/NetInetConstants.h +++ b/Core/HLE/NetInetConstants.h @@ -116,9 +116,10 @@ enum { #define PSP_NET_INET_SO_RCVTIMEO 0x1006 // receive timeout #define PSP_NET_INET_SO_ERROR 0x1007 // get error status and clear #define PSP_NET_INET_SO_TYPE 0x1008 // get socket type -#define PSP_NET_INET_SO_NBIO 0x1009 // SO_NONBLOCK ? // set to non-blocking I/O mode (on true, returning 0x80 when retrieved using getsockopt?) +#define PSP_NET_INET_SO_NBIO 0x1009 // SO_NONBLOCK ? // set to non-blocking I/O mode (on true, returning 0x80 when retrieved using getsockopt?). Unclear if correct. #define PSP_NET_INET_SO_BIO 0x100a // set to blocking I/O mode (not using the optval just like SO_NBIO?) //#define PSP_NET_INET_SO_NONBLOCK 0x100b // set to blocking or non-blocking I/O mode (using the optval) +#define PSP_NET_INET_SO_NOSIGPIPE 0x1022 // WARNING: SPECULATION // User-settable options (used with setsockopt) #define PSP_NET_INET_TCP_NODELAY 0x01 // don't delay send to coalesce packets diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index ecaee6790e..eb19e31f55 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -458,39 +458,42 @@ static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPt timeval tval{}; // TODO: Ignoring SO_NBIO/SO_NONBLOCK flag if we always use non-blocking mode (ie. simulated blocking mode) - if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_NBIO) { - inetSock->nonblocking = optval; - return hleLogSuccessI(Log::sceNet, 0); - } - // FIXME: Should we ignore SO_BROADCAST flag since we are using fake broadcast (ie. only broadcast to friends), - // But Infrastructure/Online play might need to use broadcast for SSDP and to support LAN MP with real PSP - /*else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_BROADCAST) { - //memcpy(&sock->so_broadcast, (int*)optval, std::min(sizeof(sock->so_broadcast), optlen)); - return hleLogSuccessI(Log::sceNet, 0); - }*/ - // TODO: Ignoring SO_REUSEADDR flag to prevent disrupting multiple-instance feature - else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_REUSEADDR) { - //memcpy(&sock->reuseaddr, (int*)optval, std::min(sizeof(sock->reuseaddr), optlen)); - return hleLogSuccessI(Log::sceNet, 0); - } - // TODO: Ignoring SO_REUSEPORT flag to prevent disrupting multiple-instance feature (not sure if PSP has SO_REUSEPORT or not tho, defined as 15 on Android) - else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_REUSEPORT) { // 15 - //memcpy(&sock->reuseport, (int*)optval, std::min(sizeof(sock->reuseport), optlen)); - return hleLogSuccessI(Log::sceNet, 0); - } - // TODO: Ignoring SO_NOSIGPIPE flag to prevent crashing PPSSPP (not sure if PSP has NOSIGPIPE or not tho, defined as 0x1022 on Darwin) - else if (level == PSP_NET_INET_SOL_SOCKET && optname == 0x1022) { // PSP_NET_INET_SO_NOSIGPIPE ? - //memcpy(&sock->nosigpipe, (int*)optval, std::min(sizeof(sock->nosigpipe), optlen)); - return hleLogSuccessI(Log::sceNet, 0); - } - // It seems UNO game will try to set socket buffer size with a very large size and ended getting error (-1), so we should also limit the buffer size to replicate PSP behavior - else if (level == PSP_NET_INET_SOL_SOCKET && (optname == PSP_NET_INET_SO_RCVBUF || optname == PSP_NET_INET_SO_SNDBUF)) { // PSP_NET_INET_SO_NOSIGPIPE ? - // TODO: For SOCK_STREAM max buffer size is 8 Mb on BSD, while max SOCK_DGRAM is 65535 minus the IP & UDP Header size - if (optval > 8 * 1024 * 1024) { - UpdateErrnoFromHost(ENOBUFS, __FUNCTION__); // FIXME: return ENOBUFS for SOCK_STREAM, and EINVAL for SOCK_DGRAM - return hleLogError(Log::sceNet, -1, "buffer size too large?"); + if (level == PSP_NET_INET_SOL_SOCKET) { + if (optname == PSP_NET_INET_SO_NBIO) { + inetSock->nonblocking = optval; + return hleLogSuccessI(Log::sceNet, 0); + } + // FIXME: Should we ignore SO_BROADCAST flag since we are using fake broadcast (ie. only broadcast to friends), + // But Infrastructure/Online play might need to use broadcast for SSDP and to support LAN MP with real PSP + /*else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_BROADCAST) { + //memcpy(&sock->so_broadcast, (int*)optval, std::min(sizeof(sock->so_broadcast), optlen)); + return hleLogSuccessI(Log::sceNet, 0); + }*/ + // TODO: Ignoring SO_REUSEADDR flag to prevent disrupting multiple-instance feature + else if (optname == PSP_NET_INET_SO_REUSEADDR) { + //memcpy(&sock->reuseaddr, (int*)optval, std::min(sizeof(sock->reuseaddr), optlen)); + return hleLogSuccessI(Log::sceNet, 0); + } + // TODO: Ignoring SO_REUSEPORT flag to prevent disrupting multiple-instance feature (not sure if PSP has SO_REUSEPORT or not tho, defined as 15 on Android) + else if (optname == PSP_NET_INET_SO_REUSEPORT) { // 15 + //memcpy(&sock->reuseport, (int*)optval, std::min(sizeof(sock->reuseport), optlen)); + return hleLogSuccessI(Log::sceNet, 0); + } + // TODO: Ignoring SO_NOSIGPIPE flag to prevent crashing PPSSPP (not sure if PSP has NOSIGPIPE or not tho, defined as 0x1022 on Darwin) + else if (optname == 0x1022) { // PSP_NET_INET_SO_NOSIGPIPE ? + //memcpy(&sock->nosigpipe, (int*)optval, std::min(sizeof(sock->nosigpipe), optlen)); + return hleLogSuccessI(Log::sceNet, 0); + } + // It seems UNO game will try to set socket buffer size with a very large size and ended getting error (-1), so we should also limit the buffer size to replicate PSP behavior + else if (optname == PSP_NET_INET_SO_RCVBUF || optname == PSP_NET_INET_SO_SNDBUF) { // PSP_NET_INET_SO_NOSIGPIPE ? + // TODO: For SOCK_STREAM max buffer size is 8 Mb on BSD, while max SOCK_DGRAM is 65535 minus the IP & UDP Header size + if (optval > 8 * 1024 * 1024) { + UpdateErrnoFromHost(ENOBUFS, __FUNCTION__); // FIXME: return ENOBUFS for SOCK_STREAM, and EINVAL for SOCK_DGRAM + return hleLogError(Log::sceNet, -1, "buffer size too large?"); + } } } + int retval = 0; // PSP timeout are a single 32bit value (micro seconds) if (level == PSP_NET_INET_SOL_SOCKET && optval && (optname == PSP_NET_INET_SO_RCVTIMEO || optname == PSP_NET_INET_SO_SNDTIMEO)) { From bfcef44c48c137c5530c74ae0b37f3b351d74a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 17 Jan 2025 09:31:38 +0100 Subject: [PATCH 3/5] setsockopt refactor part #2 --- Core/HLE/sceNetInet.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index eb19e31f55..43a948df55 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -459,10 +459,10 @@ static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPt timeval tval{}; // TODO: Ignoring SO_NBIO/SO_NONBLOCK flag if we always use non-blocking mode (ie. simulated blocking mode) if (level == PSP_NET_INET_SOL_SOCKET) { - if (optname == PSP_NET_INET_SO_NBIO) { + switch (optname) { + case PSP_NET_INET_SO_NBIO: inetSock->nonblocking = optval; return hleLogSuccessI(Log::sceNet, 0); - } // FIXME: Should we ignore SO_BROADCAST flag since we are using fake broadcast (ie. only broadcast to friends), // But Infrastructure/Online play might need to use broadcast for SSDP and to support LAN MP with real PSP /*else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_BROADCAST) { @@ -470,27 +470,31 @@ static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPt return hleLogSuccessI(Log::sceNet, 0); }*/ // TODO: Ignoring SO_REUSEADDR flag to prevent disrupting multiple-instance feature - else if (optname == PSP_NET_INET_SO_REUSEADDR) { + case PSP_NET_INET_SO_REUSEADDR: //memcpy(&sock->reuseaddr, (int*)optval, std::min(sizeof(sock->reuseaddr), optlen)); return hleLogSuccessI(Log::sceNet, 0); - } + // TODO: Ignoring SO_REUSEPORT flag to prevent disrupting multiple-instance feature (not sure if PSP has SO_REUSEPORT or not tho, defined as 15 on Android) - else if (optname == PSP_NET_INET_SO_REUSEPORT) { // 15 + case PSP_NET_INET_SO_REUSEPORT: // 15 //memcpy(&sock->reuseport, (int*)optval, std::min(sizeof(sock->reuseport), optlen)); return hleLogSuccessI(Log::sceNet, 0); - } + // TODO: Ignoring SO_NOSIGPIPE flag to prevent crashing PPSSPP (not sure if PSP has NOSIGPIPE or not tho, defined as 0x1022 on Darwin) - else if (optname == 0x1022) { // PSP_NET_INET_SO_NOSIGPIPE ? + case PSP_NET_INET_SO_NOSIGPIPE: // WARNING: Not sure about this one. But we definitely don't want signals, so we ignore it. //memcpy(&sock->nosigpipe, (int*)optval, std::min(sizeof(sock->nosigpipe), optlen)); - return hleLogSuccessI(Log::sceNet, 0); - } + return hleLogWarning(Log::sceNet, 0, "NOSIGPIPE should never be modified (should always be off)"); + // It seems UNO game will try to set socket buffer size with a very large size and ended getting error (-1), so we should also limit the buffer size to replicate PSP behavior - else if (optname == PSP_NET_INET_SO_RCVBUF || optname == PSP_NET_INET_SO_SNDBUF) { // PSP_NET_INET_SO_NOSIGPIPE ? + case PSP_NET_INET_SO_RCVBUF: + case PSP_NET_INET_SO_SNDBUF: // PSP_NET_INET_SO_NOSIGPIPE ? // TODO: For SOCK_STREAM max buffer size is 8 Mb on BSD, while max SOCK_DGRAM is 65535 minus the IP & UDP Header size if (optval > 8 * 1024 * 1024) { UpdateErrnoFromHost(ENOBUFS, __FUNCTION__); // FIXME: return ENOBUFS for SOCK_STREAM, and EINVAL for SOCK_DGRAM return hleLogError(Log::sceNet, -1, "buffer size too large?"); } + break; + default: + break; } } From b94b9b077dc05ced4a8d559d2b2ec0994908d2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 17 Jan 2025 09:37:40 +0100 Subject: [PATCH 4/5] Refactor away the unnecessary wrapper from sceNetResolver --- Common/Net/SocketCompat.h | 5 + Core/HLE/sceNet.cpp | 9 +- Core/HLE/sceNetResolver.cpp | 308 ++++++++++++++++-------------------- Core/HLE/sceNetResolver.h | 21 +-- 4 files changed, 142 insertions(+), 201 deletions(-) diff --git a/Common/Net/SocketCompat.h b/Common/Net/SocketCompat.h index 49e82df860..575815ecb5 100644 --- a/Common/Net/SocketCompat.h +++ b/Common/Net/SocketCompat.h @@ -37,6 +37,11 @@ extern "C" struct hostent *gethostbyname(const char *name); #endif // defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH) +#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) +// Missing toolchain define +#define INADDR_NONE 0xFFFFFFFF +#endif + // TODO: move this to some common set #if PPSSPP_PLATFORM(WINDOWS) #undef ESHUTDOWN diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index a68b440266..d6279b1bd1 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -52,11 +52,6 @@ #include "Core/HLE/sceNetInet.h" #include "Core/HLE/sceNetResolver.h" -#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) -// Missing toolchain define -#define INADDR_NONE 0xFFFFFFFF -#endif - bool netInited; u32 netDropRate = 0; @@ -407,7 +402,7 @@ void __NetShutdown() { // Network Cleanup Net_Term(); - SceNetResolver::Shutdown(); + __NetResolverShutdown(); __NetInetShutdown(); __NetApctlShutdown(); __ResetInitNetLib(); @@ -502,7 +497,7 @@ void __NetDoState(PointerWrap &p) { // Discard leftover events apctlEvents.clear(); // Discard created resolvers for now (since i'm not sure whether the information in the struct is sufficient or not, and we don't support multi-threading yet anyway) - SceNetResolver::Shutdown(); + __NetResolverShutdown(); } } diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index 316b713a33..654066e6c9 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -33,7 +33,6 @@ #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPS.h" -#include "Core/Config.h" #include "Core/MemMapHelpers.h" #include "Core/Util/PortManager.h" @@ -48,52 +47,57 @@ #include #include -#include "sceNet.h" +#include "Core/HLE/sceNet.h" #include "Core/HLE/sceNp.h" #include "Core/Reporting.h" #include "Core/Instance.h" -#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) -// Missing toolchain define -#define INADDR_NONE 0xFFFFFFFF -#endif +static int g_currentNetResolverId = 1; +static std::unordered_map> g_netResolvers; +static std::shared_mutex g_netResolversLock; + +// NOTE: It starts as true, needed for Outrun 2006. +static bool g_netResolverInitialized = true; static int sceNetResolverInit() { - g_Config.mHostToAlias["socomftb2.psp.online.scea.com"] = "67.222.156.250"; - g_Config.mHostToAlias["socompsp-prod.muis.pdonline.scea.com"] = "67.222.156.250"; - SceNetResolver::Init(); - return hleLogSuccessInfoI(Log::sceNet, 0); + // TODO: Move this to infra-jns.config! This isn't ok. + // However obviously don't remove the mHostToAlias mechanism. + g_Config.mHostToAlias["socomftb2.psp.online.scea.com"] = "67.222.156.250"; + g_Config.mHostToAlias["socompsp-prod.muis.pdonline.scea.com"] = "67.222.156.250"; + + return hleLogSuccessInfoI(Log::sceNet, 0); +} + +void __NetResolverShutdown() { + std::unique_lock lock(g_netResolversLock); + g_netResolvers.clear(); } static int sceNetResolverTerm() { - SceNetResolver::Shutdown(); + g_netResolverInitialized = false; + __NetResolverShutdown(); return hleLogSuccessInfoI(Log::sceNet, 0); } // Note: timeouts are in seconds -int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { - auto sceNetResolver = SceNetResolver::Get(); - if (!sceNetResolver) { - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Net Resolver Subsystem Shutdown: Resolver %i", - resolverId); - } +static int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { + std::unique_lock lock(g_netResolversLock); + auto iter = g_netResolvers.find(resolverId); + if (iter == g_netResolvers.end()) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + } - const auto resolver = sceNetResolver->GetNetResolver(resolverId); - if (resolver == nullptr) { - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); - } + addrinfo* resolved = nullptr; + std::string err, hostname = std::string(safe_string(Memory::GetCharPointer(hostnamePtr))); + SockAddrIN4 addr{}; + addr.in.sin_addr.s_addr = INADDR_NONE; - addrinfo* resolved = nullptr; - std::string err, hostname = std::string(safe_string(Memory::GetCharPointer(hostnamePtr))); - SockAddrIN4 addr{}; - addr.in.sin_addr.s_addr = INADDR_NONE; - - // Resolve any aliases. First check the ini file, then check the hardcoded DNS config. + // Resolve any aliases. First check the ini file, then check the hardcoded DNS config. auto aliasIter = g_Config.mHostToAlias.find(hostname); - if (aliasIter != g_Config.mHostToAlias.end()) { - const std::string& alias = aliasIter->second; - INFO_LOG(Log::sceNet, "%s - Resolved alias %s from hostname %s", __FUNCTION__, alias.c_str(), hostname.c_str()); - hostname = alias; + if (aliasIter != g_Config.mHostToAlias.end()) { + const std::string& alias = aliasIter->second; + INFO_LOG(Log::sceNet, "%s - Resolved alias %s from hostname %s", __FUNCTION__, alias.c_str(), hostname.c_str()); + hostname = alias; } if (g_Config.bInfrastructureAutoDNS) { @@ -116,78 +120,85 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti } // Flag resolver as in-progress - not relevant for sync functions but potentially relevant for async - resolver->SetIsRunning(true); + iter->second->SetIsRunning(true); // Now use the configured primary DNS server to do a lookup. // If auto DNS, use the server from that config. const std::string &dnsServer = (g_Config.bInfrastructureAutoDNS && !g_infraDNSConfig.dns.empty()) ? g_infraDNSConfig.dns : g_Config.sInfrastructureDNSServer; if (net::DirectDNSLookupIPV4(dnsServer.c_str(), hostname.c_str(), &resolvedAddr)) { - INFO_LOG(Log::sceNet, "Direct lookup of '%s' from '%s' succeeded: %08x", hostname.c_str(), dnsServer.c_str(), resolvedAddr); - resolver->SetIsRunning(false); + char temp[32]; + inet_ntop(AF_INET, &resolvedAddr, temp, sizeof(temp)); + INFO_LOG(Log::sceNet, "Direct lookup of '%s' from '%s' succeeded: %s (%08x)", hostname.c_str(), dnsServer.c_str(), temp, resolvedAddr); + iter->second->SetIsRunning(false); Memory::Write_U32(resolvedAddr, inAddrPtr); return 0; } WARN_LOG(Log::sceNet, "Direct DNS lookup of '%s' at DNS server '%s' failed. Trying OS DNS...", hostname.c_str(), g_Config.sInfrastructureDNSServer.c_str()); // Attempt to execute a DNS resolution - if (!net::DNSResolve(hostname, "", &resolved, err)) { - // TODO: Return an error based on the outputted "err" (unfortunately it's already converted to string) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_HOST, "OS DNS Error Resolving %s (%s)\n", hostname.c_str(), - err.c_str()); - } + if (!net::DNSResolve(hostname, "", &resolved, err)) { + // TODO: Return an error based on the outputted "err" (unfortunately it's already converted to string) + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_HOST, "OS DNS Error Resolving %s (%s)\n", hostname.c_str(), + err.c_str()); + } - // If successful, write to memory - if (resolved != nullptr) { - for (auto ptr = resolved; ptr != nullptr; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - addr.in = *(sockaddr_in *) ptr->ai_addr; - break; - } - } - net::DNSResolveFree(resolved); + // If successful, write to memory + if (resolved != nullptr) { + for (auto ptr = resolved; ptr != nullptr; ptr = ptr->ai_next) { + switch (ptr->ai_family) { + case AF_INET: + addr.in = *(sockaddr_in *)ptr->ai_addr; + break; + } + } + net::DNSResolveFree(resolved); - Memory::Write_U32(addr.in.sin_addr.s_addr, inAddrPtr); - INFO_LOG(Log::sceNet, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), - ip2str(addr.in.sin_addr, false).c_str()); - } + Memory::Write_U32(addr.in.sin_addr.s_addr, inAddrPtr); + INFO_LOG(Log::sceNet, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), + ip2str(addr.in.sin_addr, false).c_str()); + } - // Flag resolver as complete - resolver->SetIsRunning(false); - return 0; + // Flag resolver as complete + iter->second->SetIsRunning(false); + return 0; } static int sceNetResolverStartNtoA(int resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { - for (int attempt = 0; attempt < retry; ++attempt) { - if (const int status = NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); status >= 0) { - return hleLogSuccessInfoI(Log::sceNet, status); - } - } - return -1; + if (!g_netResolverInitialized) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", resolverId); + } + + for (int attempt = 0; attempt < retry; ++attempt) { + if (const int status = NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); status >= 0) { + return hleLogSuccessInfoI(Log::sceNet, status); + } + } + return -1; } static int sceNetResolverStartNtoAAsync(int resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { - ERROR_LOG_REPORT_ONCE(sceNetResolverStartNtoAAsync, Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %d, %d) at %08x", + if (!g_netResolverInitialized) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", + resolverId); + } + ERROR_LOG_REPORT_ONCE(sceNetResolverStartNtoAAsync, Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %d, %d) at %08x", __FUNCTION__, resolverId, hostnamePtr, inAddrPtr, timeout, retry, currentMIPS->pc); return NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); } static int sceNetResolverPollAsync(int resolverId, u32 unknown) { - ERROR_LOG_REPORT_ONCE(sceNetResolverPollAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, - unknown, currentMIPS->pc); + ERROR_LOG_REPORT_ONCE(sceNetResolverPollAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, unknown, currentMIPS->pc); // TODO: Implement after confirming that this returns the state of resolver.isRunning return 0; } static int sceNetResolverWaitAsync(int resolverId, u32 unknown) { - ERROR_LOG_REPORT_ONCE(sceNetResolverWaitAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, - unknown, currentMIPS->pc); + ERROR_LOG_REPORT_ONCE(sceNetResolverWaitAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, unknown, currentMIPS->pc); // TODO: Implement after confirming that this blocks current thread until resolver.isRunning flips to false return 0; } -static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, - int retry) { +static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, int retry) { ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoN, Log::sceNet, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, hostnameLength, timeout, retry, currentMIPS->pc); @@ -195,8 +206,7 @@ static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, return 0; } -static int sceNetResolverStartAtoNAsync(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, - int retry) { +static int sceNetResolverStartAtoNAsync(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, int retry) { ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoNAsync, Log::sceNet, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, hostnameLength, timeout, retry, currentMIPS->pc); @@ -204,130 +214,80 @@ static int sceNetResolverStartAtoNAsync(int resolverId, u32 inAddr, u32 hostname } static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen) { - if (!Memory::IsValidRange(resolverIdPtr, 4)) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr); + if (!Memory::IsValidRange(resolverIdPtr, 4)) + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr); - if (Memory::IsValidRange(bufferPtr, 4) && bufferLen < 1) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen); + if (Memory::IsValidRange(bufferPtr, 4) && bufferLen < 1) + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen); - auto sceNetResolver = SceNetResolver::Get(); - if (!sceNetResolver) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + if (!g_netResolverInitialized) { + // Possibly don't check this? Or auto-initialized? Outrun seems to assume it's not needed. + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + } - const auto resolver = sceNetResolver->CreateNetResolver(bufferPtr, bufferLen); + // TODO: Consider using SceUidManager instead of this 1-indexed id + // TODO: Implement ERROR_NET_RESOLVER_ID_MAX (possibly 32?) + std::unique_lock lock(g_netResolversLock); + int currentNetResolverId = g_currentNetResolverId++; + g_netResolvers[currentNetResolverId] = std::make_shared( + currentNetResolverId, // id + bufferPtr, // bufferPtr + bufferLen // bufferLen + ); - Memory::Write_U32(resolver->GetId(), resolverIdPtr); - return hleLogSuccessInfoI(Log::sceNet, 0, "ID: %d", Memory::Read_U32(resolverIdPtr)); + Memory::Write_U32(currentNetResolverId, resolverIdPtr); + return hleLogSuccessInfoI(Log::sceNet, 0, "ID: %d", Memory::Read_U32(resolverIdPtr)); } static int sceNetResolverStop(u32 resolverId) { - auto sceNetResolver = SceNetResolver::Get(); - if (!sceNetResolver) { - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", - resolverId); - } + if (!g_netResolverInitialized) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + } - const auto resolver = sceNetResolver->GetNetResolver(resolverId); + std::unique_lock lock(g_netResolversLock); - if (resolver == nullptr) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + const auto resolverIter = g_netResolvers.find(resolverId); - if (!resolver->GetIsRunning()) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); + if (resolverIter == g_netResolvers.end()) + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); - resolver->SetIsRunning(false); - return hleLogSuccessInfoI(Log::sceNet, 0); + if (resolverIter->second->GetIsRunning()) + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); + + resolverIter->second->SetIsRunning(false); + return hleLogSuccessInfoI(Log::sceNet, 0); } static int sceNetResolverDelete(u32 resolverId) { - auto sceNetResolver = SceNetResolver::Get(); - if (!sceNetResolver) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", - resolverId); + if (!g_netResolverInitialized) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + } - if (!sceNetResolver->DeleteNetResolver(resolverId)) - return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + std::unique_lock lock(g_netResolversLock); + + const auto resolverIter = g_netResolvers.find(resolverId); + if (resolverIter == g_netResolvers.end()) { + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + } + g_netResolvers.erase(resolverIter); return hleLogSuccessInfoI(Log::sceNet, 0); } const HLEFunction sceNetResolver[] = { - {0X224C5F44, &WrapI_IUUII, "sceNetResolverStartNtoA", 'i', "ixxii"}, - {0X244172AF, &WrapI_UUI, "sceNetResolverCreate", 'i', "xxi"}, - {0X94523E09, &WrapI_U, "sceNetResolverDelete", 'i', "i"}, - {0XF3370E61, &WrapI_V, "sceNetResolverInit", 'i', ""}, - {0X808F6063, &WrapI_U, "sceNetResolverStop", 'i', "i"}, - {0X6138194A, &WrapI_V, "sceNetResolverTerm", 'i', ""}, - {0X629E2FB7, &WrapI_IUUIII, "sceNetResolverStartAtoN", 'i', "ixxiii"}, - {0X14C17EF9, &WrapI_IUUII, "sceNetResolverStartNtoAAsync", 'i', "ixxii"}, - {0XAAC09184, &WrapI_IUUIII, "sceNetResolverStartAtoNAsync", 'i', "ixxiii"}, - {0X12748EB9, &WrapI_IU, "sceNetResolverWaitAsync", 'i', "ix"}, - {0X4EE99358, &WrapI_IU, "sceNetResolverPollAsync", 'i', "ix"}, + {0X224C5F44, &WrapI_IUUII, "sceNetResolverStartNtoA", 'i', "ixxii"}, + {0X244172AF, &WrapI_UUI, "sceNetResolverCreate", 'i', "xxi"}, + {0X94523E09, &WrapI_U, "sceNetResolverDelete", 'i', "i"}, + {0XF3370E61, &WrapI_V, "sceNetResolverInit", 'i', ""}, + {0X808F6063, &WrapI_U, "sceNetResolverStop", 'i', "i"}, + {0X6138194A, &WrapI_V, "sceNetResolverTerm", 'i', ""}, + {0X629E2FB7, &WrapI_IUUIII, "sceNetResolverStartAtoN", 'i', "ixxiii"}, + {0X14C17EF9, &WrapI_IUUII, "sceNetResolverStartNtoAAsync", 'i', "ixxii"}, + {0XAAC09184, &WrapI_IUUIII, "sceNetResolverStartAtoNAsync", 'i', "ixxiii"}, + {0X12748EB9, &WrapI_IU, "sceNetResolverWaitAsync", 'i', "ix"}, + {0X4EE99358, &WrapI_IU, "sceNetResolverPollAsync", 'i', "ix"}, }; -std::shared_ptr SceNetResolver::gInstance; -std::shared_mutex SceNetResolver::gLock; - -void SceNetResolver::Init() { - auto lock = std::unique_lock(gLock); - gInstance = std::make_shared(); -} - -void SceNetResolver::Shutdown() { - auto lock = std::unique_lock(gLock); - gInstance = nullptr; -} - -std::shared_ptr SceNetResolver::Get() { - auto lock = std::shared_lock(gLock); - return gInstance; -} - -std::shared_ptr SceNetResolver::GetNetResolver(u32 resolverId) { - std::shared_lock lock(mNetResolversLock); - const auto it = mNetResolvers.find(resolverId); - return it != mNetResolvers.end() ? it->second : nullptr; -} - -std::shared_ptr SceNetResolver::CreateNetResolver(u32 bufferPtr, u32 bufferLen) { - // TODO: Consider using SceUidManager instead of this 1-indexed id - // TODO: Implement ERROR_NET_RESOLVER_ID_MAX (possibly 32?) - std::unique_lock lock(mNetResolversLock); - int currentNetResolverId = mCurrentNetResolverId++; - return mNetResolvers[currentNetResolverId] = std::make_shared( - currentNetResolverId, // id - bufferPtr, // bufferPtr - bufferLen // bufferLen - ); -} - -bool SceNetResolver::TerminateNetResolver(u32 resolverId) { - const auto netResolver = GetNetResolver(resolverId); - if (netResolver == nullptr) { - return false; - } - netResolver->SetIsRunning(false); - return true; -} - -bool SceNetResolver::DeleteNetResolver(u32 resolverId) { - std::unique_lock lock(mNetResolversLock); - const auto it = mNetResolvers.find(resolverId); - if (it == mNetResolvers.end()) { - return false; - } - mNetResolvers.erase(it); - return true; -} - -void SceNetResolver::ClearNetResolvers() { - std::unique_lock lock(mNetResolversLock); - for (auto &[first, second]: mNetResolvers) { - second->SetIsRunning(false); - } - mNetResolvers.clear(); -} - void Register_sceNetResolver() { - RegisterModule("sceNetResolver", ARRAY_SIZE(sceNetResolver), sceNetResolver); + RegisterModule("sceNetResolver", ARRAY_SIZE(sceNetResolver), sceNetResolver); } diff --git a/Core/HLE/sceNetResolver.h b/Core/HLE/sceNetResolver.h index 5e155c6adf..a85669d8f9 100644 --- a/Core/HLE/sceNetResolver.h +++ b/Core/HLE/sceNetResolver.h @@ -79,25 +79,6 @@ enum { ERROR_NET_RESOLVER_INTERNAL = 0x80410417, }; -class SceNetResolver { -public: - static void Init(); - static void Shutdown(); - static std::shared_ptr Get(); - - std::shared_ptr GetNetResolver(u32 resolverId); - std::shared_ptr CreateNetResolver(u32 bufferPtr, u32 bufferLen); - bool TerminateNetResolver(u32 resolverId); - bool DeleteNetResolver(u32 resolverId); - void ClearNetResolvers(); - -private: - static std::shared_ptr gInstance; - static std::shared_mutex gLock; - - int mCurrentNetResolverId = 1; - std::unordered_map> mNetResolvers; - std::shared_mutex mNetResolversLock; -}; +void __NetResolverShutdown(); void Register_sceNetResolver(); From 4757f8c872476e026d9dc21055c1ba5b423f25af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 17 Jan 2025 09:44:13 +0100 Subject: [PATCH 5/5] Replace the NetResolver class with a simple struct --- Core/HLE/sceNet.cpp | 2 -- Core/HLE/sceNetResolver.cpp | 36 ++++++++++++++++++++++++------------ Core/HLE/sceNetResolver.h | 33 --------------------------------- 3 files changed, 24 insertions(+), 47 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index d6279b1bd1..5d45ca5c41 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -62,8 +62,6 @@ u32 netThread2Addr = 0; static struct SceNetMallocStat netMallocStat; -static std::map netResolvers; - static std::map apctlHandlers; std::string defaultNetConfigName = "NetConf"; diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index 654066e6c9..7d12968bbf 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -45,16 +45,23 @@ #include "Core/HLE/sceNetResolver.h" #include -#include +#include #include "Core/HLE/sceNet.h" #include "Core/HLE/sceNp.h" #include "Core/Reporting.h" #include "Core/Instance.h" +struct NetResolver { + int id = 0; + bool isRunning = false; + u32 bufferAddr = 0; + u32 bufferLen = 0; +}; + static int g_currentNetResolverId = 1; -static std::unordered_map> g_netResolvers; -static std::shared_mutex g_netResolversLock; +static std::unordered_map g_netResolvers; +static std::mutex g_netResolversLock; // Do we really need this? // NOTE: It starts as true, needed for Outrun 2006. static bool g_netResolverInitialized = true; @@ -82,6 +89,7 @@ static int sceNetResolverTerm() { // Note: timeouts are in seconds static int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { std::unique_lock lock(g_netResolversLock); + auto iter = g_netResolvers.find(resolverId); if (iter == g_netResolvers.end()) { return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); @@ -120,7 +128,7 @@ static int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, } // Flag resolver as in-progress - not relevant for sync functions but potentially relevant for async - iter->second->SetIsRunning(true); + iter->second.isRunning = true; // Now use the configured primary DNS server to do a lookup. // If auto DNS, use the server from that config. @@ -129,10 +137,11 @@ static int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, char temp[32]; inet_ntop(AF_INET, &resolvedAddr, temp, sizeof(temp)); INFO_LOG(Log::sceNet, "Direct lookup of '%s' from '%s' succeeded: %s (%08x)", hostname.c_str(), dnsServer.c_str(), temp, resolvedAddr); - iter->second->SetIsRunning(false); + iter->second.isRunning = false; Memory::Write_U32(resolvedAddr, inAddrPtr); return 0; } + WARN_LOG(Log::sceNet, "Direct DNS lookup of '%s' at DNS server '%s' failed. Trying OS DNS...", hostname.c_str(), g_Config.sInfrastructureDNSServer.c_str()); // Attempt to execute a DNS resolution @@ -159,7 +168,7 @@ static int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, } // Flag resolver as complete - iter->second->SetIsRunning(false); + iter->second.isRunning = false; return 0; } @@ -229,11 +238,12 @@ static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen) // TODO: Implement ERROR_NET_RESOLVER_ID_MAX (possibly 32?) std::unique_lock lock(g_netResolversLock); int currentNetResolverId = g_currentNetResolverId++; - g_netResolvers[currentNetResolverId] = std::make_shared( + g_netResolvers[currentNetResolverId] = NetResolver{ currentNetResolverId, // id + false, bufferPtr, // bufferPtr - bufferLen // bufferLen - ); + (u32)bufferLen // bufferLen + }; Memory::Write_U32(currentNetResolverId, resolverIdPtr); return hleLogSuccessInfoI(Log::sceNet, 0, "ID: %d", Memory::Read_U32(resolverIdPtr)); @@ -248,13 +258,15 @@ static int sceNetResolverStop(u32 resolverId) { const auto resolverIter = g_netResolvers.find(resolverId); - if (resolverIter == g_netResolvers.end()) + if (resolverIter == g_netResolvers.end()) { return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + } - if (resolverIter->second->GetIsRunning()) + if (resolverIter->second.isRunning) { return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); + } - resolverIter->second->SetIsRunning(false); + resolverIter->second.isRunning = false; return hleLogSuccessInfoI(Log::sceNet, 0); } diff --git a/Core/HLE/sceNetResolver.h b/Core/HLE/sceNetResolver.h index a85669d8f9..257f330875 100644 --- a/Core/HLE/sceNetResolver.h +++ b/Core/HLE/sceNetResolver.h @@ -19,39 +19,6 @@ #include #include -class SceNetResolver; - -class NetResolver { -public: - NetResolver(const NetResolver& other) = default; - - NetResolver() : - mId(0), - mIsRunning(false), - mBufferAddr(0), - mBufferLen(0) { - } - - NetResolver(const int id, const u32 bufferAddr, const int bufferLen) : - mId(id), - mIsRunning(false), - mBufferAddr(bufferAddr), - mBufferLen(bufferLen) { - } - - int GetId() const { return mId; } - - bool GetIsRunning() const { return mIsRunning; } - - void SetIsRunning(const bool isRunning) { this->mIsRunning = isRunning; } - -private: - int mId; - bool mIsRunning; - u32 mBufferAddr; - u32 mBufferLen; -}; - enum { // pspnet_resolver ERROR_NET_RESOLVER_NOT_TERMINATED = 0x80410401,