mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 00:59:41 +01:00
Merge pull request #19880 from hrydgard/online-resolver-refactor
sceNetResolver and sockopt refactoring
This commit is contained in:
7 files changed
+207
-279
No files matched your search
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
+14
-19
@@ -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;
|
||||
@@ -67,8 +62,6 @@ u32 netThread2Addr = 0;
|
||||
|
||||
static struct SceNetMallocStat netMallocStat;
|
||||
|
||||
static std::map<int, NetResolver> netResolvers;
|
||||
|
||||
static std::map<int, ApctlHandler> apctlHandlers;
|
||||
|
||||
std::string defaultNetConfigName = "NetConf";
|
||||
@@ -201,7 +194,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 +202,14 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) {
|
||||
bool found = false;
|
||||
|
||||
std::vector<std::string> 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 +224,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) {
|
||||
@@ -405,7 +400,7 @@ void __NetShutdown() {
|
||||
// Network Cleanup
|
||||
Net_Term();
|
||||
|
||||
SceNetResolver::Shutdown();
|
||||
__NetResolverShutdown();
|
||||
__NetInetShutdown();
|
||||
__NetApctlShutdown();
|
||||
__ResetInitNetLib();
|
||||
@@ -500,7 +495,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,10 +989,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);
|
||||
}
|
||||
|
||||
|
||||
+38
-31
@@ -458,39 +458,46 @@ 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) {
|
||||
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) {
|
||||
//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
|
||||
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)
|
||||
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)
|
||||
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 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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
+146
-174
@@ -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"
|
||||
|
||||
@@ -46,54 +45,67 @@
|
||||
#include "Core/HLE/sceNetResolver.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
#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
|
||||
struct NetResolver {
|
||||
int id = 0;
|
||||
bool isRunning = false;
|
||||
u32 bufferAddr = 0;
|
||||
u32 bufferLen = 0;
|
||||
};
|
||||
|
||||
static int g_currentNetResolverId = 1;
|
||||
static std::unordered_map<u32, NetResolver> 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;
|
||||
|
||||
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);
|
||||
|
||||
const auto resolver = sceNetResolver->GetNetResolver(resolverId);
|
||||
if (resolver == nullptr) {
|
||||
return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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 +128,86 @@ 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.isRunning = 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.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
|
||||
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.isRunning = 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 +215,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 +223,83 @@ 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] = NetResolver{
|
||||
currentNetResolverId, // id
|
||||
false,
|
||||
bufferPtr, // bufferPtr
|
||||
(u32)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.isRunning) {
|
||||
return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId);
|
||||
}
|
||||
|
||||
resolverIter->second.isRunning = 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>, "sceNetResolverStartNtoA", 'i', "ixxii"},
|
||||
{0X244172AF, &WrapI_UUI<sceNetResolverCreate>, "sceNetResolverCreate", 'i', "xxi"},
|
||||
{0X94523E09, &WrapI_U<sceNetResolverDelete>, "sceNetResolverDelete", 'i', "i"},
|
||||
{0XF3370E61, &WrapI_V<sceNetResolverInit>, "sceNetResolverInit", 'i', ""},
|
||||
{0X808F6063, &WrapI_U<sceNetResolverStop>, "sceNetResolverStop", 'i', "i"},
|
||||
{0X6138194A, &WrapI_V<sceNetResolverTerm>, "sceNetResolverTerm", 'i', ""},
|
||||
{0X629E2FB7, &WrapI_IUUIII<sceNetResolverStartAtoN>, "sceNetResolverStartAtoN", 'i', "ixxiii"},
|
||||
{0X14C17EF9, &WrapI_IUUII<sceNetResolverStartNtoAAsync>, "sceNetResolverStartNtoAAsync", 'i', "ixxii"},
|
||||
{0XAAC09184, &WrapI_IUUIII<sceNetResolverStartAtoNAsync>, "sceNetResolverStartAtoNAsync", 'i', "ixxiii"},
|
||||
{0X12748EB9, &WrapI_IU<sceNetResolverWaitAsync>, "sceNetResolverWaitAsync", 'i', "ix"},
|
||||
{0X4EE99358, &WrapI_IU<sceNetResolverPollAsync>, "sceNetResolverPollAsync", 'i', "ix"},
|
||||
{0X224C5F44, &WrapI_IUUII<sceNetResolverStartNtoA>, "sceNetResolverStartNtoA", 'i', "ixxii"},
|
||||
{0X244172AF, &WrapI_UUI<sceNetResolverCreate>, "sceNetResolverCreate", 'i', "xxi"},
|
||||
{0X94523E09, &WrapI_U<sceNetResolverDelete>, "sceNetResolverDelete", 'i', "i"},
|
||||
{0XF3370E61, &WrapI_V<sceNetResolverInit>, "sceNetResolverInit", 'i', ""},
|
||||
{0X808F6063, &WrapI_U<sceNetResolverStop>, "sceNetResolverStop", 'i', "i"},
|
||||
{0X6138194A, &WrapI_V<sceNetResolverTerm>, "sceNetResolverTerm", 'i', ""},
|
||||
{0X629E2FB7, &WrapI_IUUIII<sceNetResolverStartAtoN>, "sceNetResolverStartAtoN", 'i', "ixxiii"},
|
||||
{0X14C17EF9, &WrapI_IUUII<sceNetResolverStartNtoAAsync>, "sceNetResolverStartNtoAAsync", 'i', "ixxii"},
|
||||
{0XAAC09184, &WrapI_IUUIII<sceNetResolverStartAtoNAsync>, "sceNetResolverStartAtoNAsync", 'i', "ixxiii"},
|
||||
{0X12748EB9, &WrapI_IU<sceNetResolverWaitAsync>, "sceNetResolverWaitAsync", 'i', "ix"},
|
||||
{0X4EE99358, &WrapI_IU<sceNetResolverPollAsync>, "sceNetResolverPollAsync", 'i', "ix"},
|
||||
};
|
||||
|
||||
std::shared_ptr<SceNetResolver> SceNetResolver::gInstance;
|
||||
std::shared_mutex SceNetResolver::gLock;
|
||||
|
||||
void SceNetResolver::Init() {
|
||||
auto lock = std::unique_lock(gLock);
|
||||
gInstance = std::make_shared<SceNetResolver>();
|
||||
}
|
||||
|
||||
void SceNetResolver::Shutdown() {
|
||||
auto lock = std::unique_lock(gLock);
|
||||
gInstance = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SceNetResolver> SceNetResolver::Get() {
|
||||
auto lock = std::shared_lock(gLock);
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
std::shared_ptr<NetResolver> 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<NetResolver> 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<NetResolver>(
|
||||
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);
|
||||
}
|
||||
@@ -19,39 +19,6 @@
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
|
||||
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,
|
||||
@@ -79,25 +46,6 @@ enum {
|
||||
ERROR_NET_RESOLVER_INTERNAL = 0x80410417,
|
||||
};
|
||||
|
||||
class SceNetResolver {
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
static std::shared_ptr<SceNetResolver> Get();
|
||||
|
||||
std::shared_ptr<NetResolver> GetNetResolver(u32 resolverId);
|
||||
std::shared_ptr<NetResolver> CreateNetResolver(u32 bufferPtr, u32 bufferLen);
|
||||
bool TerminateNetResolver(u32 resolverId);
|
||||
bool DeleteNetResolver(u32 resolverId);
|
||||
void ClearNetResolvers();
|
||||
|
||||
private:
|
||||
static std::shared_ptr<SceNetResolver> gInstance;
|
||||
static std::shared_mutex gLock;
|
||||
|
||||
int mCurrentNetResolverId = 1;
|
||||
std::unordered_map<u32, std::shared_ptr<NetResolver>> mNetResolvers;
|
||||
std::shared_mutex mNetResolversLock;
|
||||
};
|
||||
void __NetResolverShutdown();
|
||||
|
||||
void Register_sceNetResolver();
|
||||
Reference in new issue
Block a user