From c5cde0f218d2758f0f1a5560666b2208091ecf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 13:41:31 +0100 Subject: [PATCH 1/7] Remove "Secondary DNS" as a setting. --- Common/Net/Resolve.cpp | 21 +++++++++++++-------- Core/Config.cpp | 3 +-- Core/Config.h | 10 +++++----- Core/HLE/sceNet.cpp | 4 ++-- Core/HLE/sceNetResolver.cpp | 4 ++-- UI/GameSettingsScreen.cpp | 3 +-- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Common/Net/Resolve.cpp b/Common/Net/Resolve.cpp index 47cfb3e37f5d..11b206c42a80 100644 --- a/Common/Net/Resolve.cpp +++ b/Common/Net/Resolve.cpp @@ -322,19 +322,24 @@ struct DNSHeader { }; // Function to convert a domain name to DNS query format +// http://www.tcpipguide.com/free/t_DNSNameNotationandMessageCompressionTechnique.htm static void encode_domain_name(const char *domain, unsigned char *encoded) { const char *pos = domain; unsigned char *ptr = encoded; while (*pos) { const char *start = pos; - while (*pos && *pos != '.') pos++; + while (*pos && *pos != '.') { + pos++; + } - *ptr++ = (unsigned char)(pos - start); + *ptr++ = (unsigned char)(pos - start); // length field memcpy(ptr, start, pos - start); ptr += pos - start; - if (*pos == '.') pos++; + if (*pos == '.') { + pos++; + } } *ptr = 0; // End of domain name } @@ -418,20 +423,20 @@ bool DirectDNSLookupIPV4(const char *dns_server_ip, const char *domain, uint32_t return false; } - int sockfd; + SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0); // Create UDP socket - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if (sockfd < 0) { ERROR_LOG(Log::sceNet, "Socket creation for direct DNS failed"); return 1; } - struct sockaddr_in server_addr {}; + struct sockaddr_in server_addr{}; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(DNS_PORT); if (net::inet_pton(AF_INET, dns_server_ip, &server_addr.sin_addr) <= 0) { ERROR_LOG(Log::sceNet,"Invalid DNS server IP address %s", dns_server_ip); - close(sockfd); + closesocket(sockfd); return 1; } @@ -451,7 +456,7 @@ bool DirectDNSLookupIPV4(const char *dns_server_ip, const char *domain, uint32_t // Send DNS query size_t query_len = sizeof(DNSHeader) + (qinfo - buffer) + 4; - if (sendto(sockfd, (const char *)buffer, query_len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + if (sendto(sockfd, (const char *)buffer, (int)query_len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { ERROR_LOG(Log::sceNet, "Failed to send DNS query"); closesocket(sockfd); return 1; diff --git a/Core/Config.cpp b/Core/Config.cpp index 8779b16674b3..c28ac8a4769a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -901,8 +901,7 @@ static const ConfigSetting networkSettings[] = { ConfigSetting("EnableAdhocServer", &g_Config.bEnableAdhocServer, false, CfgFlag::PER_GAME), ConfigSetting("proAdhocServer", &g_Config.proAdhocServer, "socom.cc", CfgFlag::PER_GAME), ConfigSetting("PortOffset", &g_Config.iPortOffset, 10000, CfgFlag::PER_GAME), - ConfigSetting("PrimaryDNSServer", &g_Config.primaryDNSServer, "67.222.156.250", CfgFlag::PER_GAME), - ConfigSetting("SecondaryDNSServer", &g_Config.secondaryDNSServer, "0.0.0.0", CfgFlag::PER_GAME), + ConfigSetting("PrimaryDNSServer", &g_Config.sInfrastructureDNSServer, "67.222.156.250", CfgFlag::PER_GAME), ConfigSetting("MinTimeout", &g_Config.iMinTimeout, 0, CfgFlag::PER_GAME), ConfigSetting("ForcedFirstConnect", &g_Config.bForcedFirstConnect, false, CfgFlag::PER_GAME), ConfigSetting("EnableUPnP", &g_Config.bEnableUPnP, false, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 5215ab47352f..1f321f755210 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -457,13 +457,13 @@ struct Config { bool bSavedataUpgrade; // Networking + bool bEnableAdhocServer; std::string proAdhocServer; - std::string primaryDNSServer; - std::string secondaryDNSServer; + std::string sInfrastructureDNSServer; std::string sInfrastructureUsername; // Username used for Infrastructure play. Different restrictions. + bool bEnableWlan; - std::map mHostToAlias; // TODO: mPostShaderSetting - bool bEnableAdhocServer; + std::map mHostToAlias; // Local DNS database stored in ini file bool bEnableUPnP; bool bUPnPUseOriginalPort; bool bForcedFirstConnect; @@ -472,7 +472,7 @@ struct Config { int iWlanAdhocChannel; bool bWlanPowerSave; bool bEnableNetworkChat; - //for chat position , moveable buttons is better than this + int iChatButtonPosition; int iChatScreenPosition; diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 80a841ba4950..4cbd670f9447 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -785,10 +785,10 @@ void NetApctl_InitInfo(int confId) { truncate_cpy(netApctlInfo.gateway, sizeof(netApctlInfo.gateway), ipstr); // We should probably use public DNS Server instead of localhost IP since most people don't have DNS Server running on localhost (ie. Untold Legends The Warrior's Code is trying to lookup dns using the primary dns), but accessing public DNS Server from localhost may result to ENETUNREACH error if the gateway can't access the public server (ie. using SO_DONTROUTE) //if (strcmp(ipstr, "127.0.0.1") == 0) - truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_Config.primaryDNSServer.c_str()); // Private Servers may need to use custom DNS Server + truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_Config.sInfrastructureDNSServer.c_str()); // Private Servers may need to use custom DNS Server //else // truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), ipstr); - truncate_cpy(netApctlInfo.secondaryDns, sizeof(netApctlInfo.secondaryDns), g_Config.secondaryDNSServer.c_str()); // Fireteam Bravo 2 seems to try to use secondary DNS too if it's not 0.0.0.0 + truncate_cpy(netApctlInfo.secondaryDns, sizeof(netApctlInfo.secondaryDns), "0.0.0.0"); // Fireteam Bravo 2 seems to try to use secondary DNS too if it's not 0.0.0.0 truncate_cpy(netApctlInfo.subNetMask, sizeof(netApctlInfo.subNetMask), "255.255.255.0"); } diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index dc60d0128801..0b31fa1b5222 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -109,14 +109,14 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti // Now use the configured primary DNS server to do a lookup. // TODO: Pick a DNS server per-game according to a table downloaded from ppsspp.org. - if (net::DirectDNSLookupIPV4(g_Config.primaryDNSServer.c_str(), hostname.c_str(), &resolvedAddr)) { + if (net::DirectDNSLookupIPV4(g_Config.sInfrastructureDNSServer.c_str(), hostname.c_str(), &resolvedAddr)) { INFO_LOG(Log::sceNet, "Direct lookup of '%s' succeeded: %08x", hostname.c_str(), resolvedAddr); resolver->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.primaryDNSServer.c_str()); + 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)) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ca39aea5a37a..1cda047d24bc 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -951,8 +951,7 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti return UI::EVENT_DONE; }); - networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.primaryDNSServer, n->T("Primary DNS server"), "", 32, screenManager())); - networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.secondaryDNSServer, n->T("Secondary DNS server"), "", 32, screenManager())); + networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sInfrastructureDNSServer, n->T("DNS server"), "", 32, screenManager())); networkingSettings->Add(new ItemHeader(n->T("Chat"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableNetworkChat, n->T("Enable network chat", "Enable network chat"))); From b796481bb4ca59e0e728dfa6f4f61fcc2a8c30e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 14:05:36 +0100 Subject: [PATCH 2/7] Add initial infra-dns.json --- CMakeLists.txt | 1 + Core/Core.vcxproj | 1 + Core/Core.vcxproj.filters | 1 + assets/infra-dns.json | 60 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 assets/infra-dns.json diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a0a6959463..8cef70686de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2743,6 +2743,7 @@ set(NativeAssets assets/Roboto-Condensed.ttf assets/7z.png assets/compat.ini + assets/infra-dns.json assets/gamecontrollerdb.txt assets/langregion.ini assets/ppge_atlas.zim diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 41d33dcc3463..116cb6755667 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -1480,6 +1480,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 4093ef8d2e57..fa295bccbf83 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -2166,6 +2166,7 @@ Ext\libzip + diff --git a/assets/infra-dns.json b/assets/infra-dns.json new file mode 100644 index 000000000000..7f8d0e141089 --- /dev/null +++ b/assets/infra-dns.json @@ -0,0 +1,60 @@ +{ + "comment": "This file contains our built-in DNS used by the Auto mode in Infrastructure. In addition to being shipped, it'll also be hosted on ppsspp.org. Key names below are not important.", + "default": { + "dns": "67.222.156.251", + }, + "Medal of Honor: Heroes": { + "comment": { + "en_US": "Works, but not on Windows", + }, + "dns": "142.24.13.25", + "score": 5, + "known_working_ids": [ + "ULES00557" + ], + "not_working_ids": [], + "other_ids": [ + "ULUS10141", + "ULJM05213", + "ULUS-10141", + "NPJH50306" + ], + "not_working_platforms": [ + "Windows" + ], + }, + "Wipeout Pulse": { + "comment": { + "en_US": "Great", + }, + "dns": "145.239.30.230", + "score": 5, + "known_working_ids": [ + "UCES00465", + "UCUS98712" + ], + "not_working_ids": [], + "other_ids": [ + "UCKS45078" + ], + "not_working_platforms": [], + }, + "Motorstorm: Artic Edge": { + "comment": { + "en_US": "Works", + }, + "dns": "145.239.30.230", + "score": 5, + "known_working_ids": [ + "UCES01250", + ], + "not_working_ids": [], + "other_ids": [ + "UCAS40266", + "UCUS98743", + "UCKS45124", + "UCJS10104", + "NPJG00047" + ], + } +} From 608ff2ff3922c364c38beaa71de5ea92cafdc904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 19:17:44 +0100 Subject: [PATCH 3/7] Initial custom DNS config json parsing --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/HLE/sceNet.cpp | 90 +++++++++++++++++++++++++++++++++++++++ Core/HLE/sceNet.h | 20 ++++++++- UI/GameSettingsScreen.cpp | 3 ++ 5 files changed, 113 insertions(+), 2 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index c28ac8a4769a..0f4be8e9af15 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -907,6 +907,7 @@ static const ConfigSetting networkSettings[] = { ConfigSetting("EnableUPnP", &g_Config.bEnableUPnP, false, CfgFlag::PER_GAME), ConfigSetting("UPnPUseOriginalPort", &g_Config.bUPnPUseOriginalPort, false, CfgFlag::PER_GAME), ConfigSetting("InfrastructureUsername", &g_Config.sInfrastructureUsername, &DefaultInfrastructureUsername, CfgFlag::PER_GAME), + ConfigSetting("InfrastructureAutoDNS", &g_Config.bInfrastructureAutoDNS, true, CfgFlag::PER_GAME), ConfigSetting("EnableNetworkChat", &g_Config.bEnableNetworkChat, false, CfgFlag::PER_GAME), ConfigSetting("ChatButtonPosition", &g_Config.iChatButtonPosition, (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 1f321f755210..3a87cef41917 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -461,6 +461,7 @@ struct Config { std::string proAdhocServer; std::string sInfrastructureDNSServer; std::string sInfrastructureUsername; // Username used for Infrastructure play. Different restrictions. + bool bInfrastructureAutoDNS; bool bEnableWlan; std::map mHostToAlias; // Local DNS database stored in ini file diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 4cbd670f9447..8bbc49017fd9 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -21,10 +21,12 @@ #include "Common/Net/Resolve.h" #include "Common/Net/SocketCompat.h" #include "Common/Data/Text/Parsers.h" +#include "Common/File/VFS/VFS.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/Serialize/SerializeMap.h" +#include "Common/Data/Format/JSONReader.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelMemory.h" @@ -87,6 +89,9 @@ int actionAfterApctlMipsCall; std::recursive_mutex apctlEvtMtx; std::deque apctlEvents; +// Loaded auto-config +InfraDNSConfig g_infraDNSConfig; + u32 Net_Term(); int NetApctl_Term(); void NetApctl_InitDefaultInfo(); @@ -129,6 +134,82 @@ void AfterApctlMipsCall::SetData(int HandlerID, int OldState, int NewState, int argsAddr = ArgsAddr; } +bool LoadDNSForGameID(std::string_view jsonStr, std::string_view gameID, InfraDNSConfig *dns) { + using namespace json; + json::JsonReader reader(jsonStr.data(), jsonStr.length()); + if (!reader.ok() || !reader.root()) { + ERROR_LOG(Log::IO, "Error parsing JSON from store"); + return false; + } + const JsonGet root = reader.root(); + const JsonGet def = root.getDict("default"); + + // Load the default DNS. + dns->dns = def.getStringOr("dns", "");; + + const JsonNode *games = root.getArray("games"); + for (const JsonNode *iter : games->value) { + JsonGet game = iter->value; + // Goddamn I have to change the json reader we're using. So ugly. + 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) { + // We ignore this game. + continue; + } + + 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 (!found && notWorkingIdsNode) { + // Check the non working array + JsonGet(notWorkingIdsNode->value).getStringVector(&ids); + for (auto &id : ids) { + if (id == gameID) { + found = true; + dns->state = InfraGameState::NotWorking; + break; + } + } + } + if (!found && otherIdsNode) { + // Check the "other" array, not sure what we do with these. + JsonGet(otherIdsNode->value).getStringVector(&ids); + for (auto &id : ids) { + if (id == gameID) { + found = true; + dns->state = InfraGameState::Unknown; + break; + } + } + } + + if (!found) { + continue; + } + + std::string name = game.getStringOr("name", ""); + dns->dns = game.getStringOr("dns", dns->dns.c_str()); + + // const JsonGet domains = game.getDict("domains"); + + // TODO: Check for not working platforms + + break; + } + + return true; +} + void InitLocalhostIP() { // The entire 127.*.*.* is reserved for loopback. uint32_t localIP = 0x7F000001 + PPSSPP_ID - 1; @@ -224,6 +305,15 @@ void __NetCallbackInit() { } void __NetInit() { + // Load the DNS config. + std::string discID = g_paramSFO.GetDiscID(); + size_t jsonSize; + uint8_t *data = g_VFS.ReadFile("infra-dns.json", &jsonSize); + if (data && g_Config.bInfrastructureAutoDNS) { + std::string_view json = std::string_view((const char *)data, jsonSize); + LoadDNSForGameID(json, discID, &g_infraDNSConfig); + } + // Windows: Assuming WSAStartup already called beforehand portOffset = g_Config.iPortOffset; isOriPort = g_Config.bEnableUPnP && g_Config.bUPnPUseOriginalPort; diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index 9b7fb052b2bc..a3521c08f3aa 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -121,7 +121,6 @@ void Register_sceWlanDrv(); void Register_sceNetUpnp(); void Register_sceNetIfhandle(); - void __NetInit(); void __NetShutdown(); void __NetDoState(PointerWrap &p); @@ -129,5 +128,22 @@ void __NetDoState(PointerWrap &p); int NetApctl_GetState(); int sceNetApctlConnect(int connIndex); -int sceNetInetPoll(void *fds, u32 nfds, int timeout); int sceNetApctlTerm(); + +enum class InfraGameState { + Unknown, + Working, + NotWorking, +}; + +// Loaded an interpreted for a specific game from the JSON - doesn't represent the entire JSON. +struct InfraDNSConfig { + std::string gameName; + std::string dns; + InfraGameState state; + std::map fixedDNS; + int score; + std::string comment; +}; + +extern InfraDNSConfig g_infraDNSConfig; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1cda047d24bc..e0b1840121ba 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -951,7 +951,10 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti return UI::EVENT_DONE; }); + + networkingSettings->Add(new CheckBox(&g_Config.bInfrastructureAutoDNS, "Auto DNS")); networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sInfrastructureDNSServer, n->T("DNS server"), "", 32, screenManager())); + networkingSettings->SetDisabledPtr(&g_Config.bInfrastructureAutoDNS); networkingSettings->Add(new ItemHeader(n->T("Chat"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableNetworkChat, n->T("Enable network chat", "Enable network chat"))); From 05906bc8f3917eadae24d0f1d133fdfbce652567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 19:38:29 +0100 Subject: [PATCH 4/7] Finish the format, actually use the things from it --- Core/HLE/sceNet.cpp | 29 ++++++--- Core/HLE/sceNetResolver.cpp | 26 +++++--- UI/GameSettingsScreen.cpp | 4 +- assets/infra-dns.json | 119 ++++++++++++++++++++---------------- 4 files changed, 107 insertions(+), 71 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 8bbc49017fd9..889fbc95135c 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -200,7 +200,14 @@ bool LoadDNSForGameID(std::string_view jsonStr, std::string_view gameID, InfraDN std::string name = game.getStringOr("name", ""); dns->dns = game.getStringOr("dns", dns->dns.c_str()); - // const JsonGet domains = game.getDict("domains"); + if (game.hasChild("domains", JSON_OBJECT)) { + const JsonGet domains = game.getDict("domains"); + for (auto iter : domains.value_) { + std::string domain = std::string(iter->key); + std::string ipAddr = std::string(iter->value.toString()); + dns->fixedDNS[domain] = ipAddr; + } + } // TODO: Check for not working platforms @@ -305,15 +312,6 @@ void __NetCallbackInit() { } void __NetInit() { - // Load the DNS config. - std::string discID = g_paramSFO.GetDiscID(); - size_t jsonSize; - uint8_t *data = g_VFS.ReadFile("infra-dns.json", &jsonSize); - if (data && g_Config.bInfrastructureAutoDNS) { - std::string_view json = std::string_view((const char *)data, jsonSize); - LoadDNSForGameID(json, discID, &g_infraDNSConfig); - } - // Windows: Assuming WSAStartup already called beforehand portOffset = g_Config.iPortOffset; isOriPort = g_Config.bEnableUPnP && g_Config.bUPnPUseOriginalPort; @@ -703,6 +701,17 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini // Clear Socket Translator Memory memset(&adhocSockets, 0, sizeof(adhocSockets)); + if (g_Config.bInfrastructureAutoDNS) { + // Load the automatic DNS config. + std::string discID = g_paramSFO.GetDiscID(); + size_t jsonSize; + uint8_t *data = g_VFS.ReadFile("infra-dns.json", &jsonSize); + if (data && g_Config.bInfrastructureAutoDNS) { + std::string_view json = std::string_view((const char *)data, jsonSize); + LoadDNSForGameID(json, discID, &g_infraDNSConfig); + } + } + netInited = true; return hleLogSuccessI(Log::sceNet, 0); } diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index 0b31fa1b5222..6c01c5fab462 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -88,15 +88,26 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti SockAddrIN4 addr{}; addr.in.sin_addr.s_addr = INADDR_NONE; - // Resolve any aliases - if (g_Config.mHostToAlias.find(hostname) != g_Config.mHostToAlias.end()) { - const std::string& alias = g_Config.mHostToAlias[hostname]; + // 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 (g_Config.bInfrastructureAutoDNS) { + // Also look up into the preconfigured fixed DNS JSON. + auto fixedDNSIter = g_infraDNSConfig.fixedDNS.find(hostname); + if (fixedDNSIter != g_infraDNSConfig.fixedDNS.end()) { + const std::string& domainIP = fixedDNSIter->second; + INFO_LOG(Log::sceNet, "%s - Resolved IP %s from fixed DNS lookup with '%s'", __FUNCTION__, domainIP.c_str(), hostname.c_str()); + hostname = domainIP; + } + } + // Check if hostname is already an IPv4 address, if so we do not need further lookup. This usually happens - // after the mHostToAlias lookup, which effectively is hardcoded DNS. + // after the mHostToAlias or fixedDNSIter lookups, which effectively both are hardcoded DNS. uint32_t resolvedAddr; if (inet_pton(AF_INET, hostname.c_str(), &resolvedAddr)) { INFO_LOG(Log::sceNet, "Not looking up '%s', already an IP address.", hostname.c_str()); @@ -108,9 +119,10 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti resolver->SetIsRunning(true); // Now use the configured primary DNS server to do a lookup. - // TODO: Pick a DNS server per-game according to a table downloaded from ppsspp.org. - if (net::DirectDNSLookupIPV4(g_Config.sInfrastructureDNSServer.c_str(), hostname.c_str(), &resolvedAddr)) { - INFO_LOG(Log::sceNet, "Direct lookup of '%s' succeeded: %08x", hostname.c_str(), resolvedAddr); + // 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); Memory::Write_U32(resolvedAddr, inAddrPtr); return 0; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index e0b1840121ba..65f440989be0 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -953,8 +953,8 @@ void GameSettingsScreen::CreateNetworkingSettings(UI::ViewGroup *networkingSetti networkingSettings->Add(new CheckBox(&g_Config.bInfrastructureAutoDNS, "Auto DNS")); - networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sInfrastructureDNSServer, n->T("DNS server"), "", 32, screenManager())); - networkingSettings->SetDisabledPtr(&g_Config.bInfrastructureAutoDNS); + auto *dnsServer = networkingSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &g_Config.sInfrastructureDNSServer, n->T("DNS server"), "", 32, screenManager())); + dnsServer->SetDisabledPtr(&g_Config.bInfrastructureAutoDNS); networkingSettings->Add(new ItemHeader(n->T("Chat"))); networkingSettings->Add(new CheckBox(&g_Config.bEnableNetworkChat, n->T("Enable network chat", "Enable network chat"))); diff --git a/assets/infra-dns.json b/assets/infra-dns.json index 7f8d0e141089..f0c4378c0df0 100644 --- a/assets/infra-dns.json +++ b/assets/infra-dns.json @@ -3,58 +3,73 @@ "default": { "dns": "67.222.156.251", }, - "Medal of Honor: Heroes": { - "comment": { - "en_US": "Works, but not on Windows", + "games": [ + { + "name": "Medal of Honor: Heroes", + "comment": { + "en_US": "Works, but not on Windows", + }, + "dns": "86.223.243.173", + "domains": { + "pspmoh07.ea.com": "86.223.243.173", + "pspmoh08.ea.com": "86.223.243.173", + "tos.ea.com": "86.223.243.173" + }, + "score": 5, + "known_working_ids": [ + "ULES00557", + "ULES00558", + "ULES00559", + "ULES00560", + "ULES00561", + "ULES00562" + ], + "not_working_ids": [], + "other_ids": [ + "ULUS10141", + "ULJM05213", + "ULUS10141", + "NPJH50306" + ], + "not_working_platforms": [ + "Windows" + ], }, - "dns": "142.24.13.25", - "score": 5, - "known_working_ids": [ - "ULES00557" - ], - "not_working_ids": [], - "other_ids": [ - "ULUS10141", - "ULJM05213", - "ULUS-10141", - "NPJH50306" - ], - "not_working_platforms": [ - "Windows" - ], - }, - "Wipeout Pulse": { - "comment": { - "en_US": "Great", - }, - "dns": "145.239.30.230", - "score": 5, - "known_working_ids": [ - "UCES00465", - "UCUS98712" - ], - "not_working_ids": [], - "other_ids": [ - "UCKS45078" - ], - "not_working_platforms": [], - }, - "Motorstorm: Artic Edge": { - "comment": { - "en_US": "Works", + { + "name": "Wipeout Pulse", + "comment": { + "en_US": "Great", + }, + "dns": "145.239.30.230", + "score": 5, + "known_working_ids": [ + "UCES00465", + "UCUS98712" + ], + "not_working_ids": [], + "other_ids": [ + "UCKS45078" + ], + "not_working_platforms": [], }, - "dns": "145.239.30.230", - "score": 5, - "known_working_ids": [ - "UCES01250", - ], - "not_working_ids": [], - "other_ids": [ - "UCAS40266", - "UCUS98743", - "UCKS45124", - "UCJS10104", - "NPJG00047" - ], - } + { + "name": "Motorstorm: Artic Edge", + "comment": { + "en_US": "Works", + }, + "dns": "145.239.30.230", + "score": 5, + "known_working_ids": [ + "UCES01250", + ], + "not_working_ids": [], + "other_ids": [ + "UCAS40266", + "UCUS98743", + "UCKS45124", + "UCJS10104", + "NPJG00047" + ], + } + ] } From 5815c3e3be74c23c5265635b8925d3709f7a1a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 20:20:33 +0100 Subject: [PATCH 5/7] JSON updates --- assets/infra-dns.json | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/assets/infra-dns.json b/assets/infra-dns.json index f0c4378c0df0..2933f461ae2f 100644 --- a/assets/infra-dns.json +++ b/assets/infra-dns.json @@ -2,6 +2,10 @@ "comment": "This file contains our built-in DNS used by the Auto mode in Infrastructure. In addition to being shipped, it'll also be hosted on ppsspp.org. Key names below are not important.", "default": { "dns": "67.222.156.251", + "revival_credits": { + "group": "PS Rewired", + "url": "https://psrewired.com/" + } }, "games": [ { @@ -9,6 +13,11 @@ "comment": { "en_US": "Works, but not on Windows", }, + "revival_credits": { + "group": "MOHH Revival", + "url": "https://mohh-revival.pages.dev/" + }, + "credit": "AG ", "dns": "86.223.243.173", "domains": { "pspmoh07.ea.com": "86.223.243.173", @@ -40,6 +49,10 @@ "comment": { "en_US": "Great", }, + "revival_credits": { + "group": "The AG Racing Foundation", + "url": "https://agracingfoundation.org/" + }, "dns": "145.239.30.230", "score": 5, "known_working_ids": [ @@ -57,17 +70,21 @@ "comment": { "en_US": "Works", }, + "revival_credits": { + "group": "The AG Racing Foundation", + "url": "https://agracingfoundation.org/" + }, "dns": "145.239.30.230", "score": 5, "known_working_ids": [ "UCES01250", + "UCUS98743", + "UCJS10104", ], "not_working_ids": [], "other_ids": [ "UCAS40266", - "UCUS98743", "UCKS45124", - "UCJS10104", "NPJG00047" ], } From ae15cba56ca971d2ecbd25b6fb57b87935bcdffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Jan 2025 23:31:20 +0100 Subject: [PATCH 6/7] Move the logic for loading the json file to the function. Minor cleanup. --- Core/HLE/sceNet.cpp | 23 ++++++++++++++--------- UI/PauseScreen.cpp | 5 +++-- assets/infra-dns.json | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 889fbc95135c..51d9b9b2aae8 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -134,13 +134,23 @@ void AfterApctlMipsCall::SetData(int HandlerID, int OldState, int NewState, int argsAddr = ArgsAddr; } -bool LoadDNSForGameID(std::string_view jsonStr, std::string_view gameID, InfraDNSConfig *dns) { +bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { using namespace json; + + // TODO: Load from cache instead of zip (if possible), and sometimes update it. + size_t jsonSize; + std::unique_ptr data(g_VFS.ReadFile("infra-dns.json", &jsonSize)); + if (!data) { + return false; + } + + std::string_view jsonStr = std::string_view((const char *)data.get(), jsonSize); json::JsonReader reader(jsonStr.data(), jsonStr.length()); if (!reader.ok() || !reader.root()) { - ERROR_LOG(Log::IO, "Error parsing JSON from store"); + ERROR_LOG(Log::IO, "Error parsing DNS JSON"); return false; } + const JsonGet root = reader.root(); const JsonGet def = root.getDict("default"); @@ -210,7 +220,6 @@ bool LoadDNSForGameID(std::string_view jsonStr, std::string_view gameID, InfraDN } // TODO: Check for not working platforms - break; } @@ -637,6 +646,7 @@ u32 Net_Term() { FreeUser(netThread2Addr); netInited = false; + g_infraDNSConfig = {}; return 0; } @@ -704,12 +714,7 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini if (g_Config.bInfrastructureAutoDNS) { // Load the automatic DNS config. std::string discID = g_paramSFO.GetDiscID(); - size_t jsonSize; - uint8_t *data = g_VFS.ReadFile("infra-dns.json", &jsonSize); - if (data && g_Config.bInfrastructureAutoDNS) { - std::string_view json = std::string_view((const char *)data, jsonSize); - LoadDNSForGameID(json, discID, &g_infraDNSConfig); - } + LoadDNSForGameID(discID, &g_infraDNSConfig); } netInited = true; diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 55dc6ecbb787..56128b2d58d7 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -42,6 +42,7 @@ #include "Core/ELF/ParamSFO.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceUmd.h" +#include "Core/HLE/sceNet.h" #include "GPU/GPUCommon.h" #include "GPU/GPUState.h" @@ -415,8 +416,8 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); rightColumnItems->Add(new Choice(pa->T("Create Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnCreateConfig); } - UI::Choice *displayEditor_ = rightColumnItems->Add(new Choice(gr->T("Display layout & effects"))); - displayEditor_->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { + + rightColumnItems->Add(new Choice(gr->T("Display layout & effects")))->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { screenManager()->push(new DisplayLayoutScreen(gamePath_)); return UI::EVENT_DONE; }); diff --git a/assets/infra-dns.json b/assets/infra-dns.json index 2933f461ae2f..dbf3176c7221 100644 --- a/assets/infra-dns.json +++ b/assets/infra-dns.json @@ -1,5 +1,5 @@ { - "comment": "This file contains our built-in DNS used by the Auto mode in Infrastructure. In addition to being shipped, it'll also be hosted on ppsspp.org. Key names below are not important.", + "comment": "This file contains our built-in DNS used by the Auto mode in Infrastructure. In addition to being shipped, it'll also be hosted on ppsspp.org. Game names below are not important.", "default": { "dns": "67.222.156.251", "revival_credits": { From 0349f91a9e54b7974fdd9fdfba8fbeacc178bee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Jan 2025 17:55:42 +0100 Subject: [PATCH 7/7] Add "dyndns" or DNS server lookup by domain name as requested by ablondel. JSON updated. --- Core/HLE/sceNet.cpp | 42 ++++++++++++++++++++++++++++++++-- Core/HLE/sceNet.h | 1 + assets/infra-dns.json | 53 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 51d9b9b2aae8..b4ac564df3ee 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -26,6 +26,7 @@ #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/Serialize/SerializeMap.h" +#include "Common/System/OSD.h" #include "Common/Data/Format/JSONReader.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -208,8 +209,9 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { } std::string name = game.getStringOr("name", ""); + std::string dyn_dns = game.getStringOr("dyn_dns", dns->dns.c_str()); dns->dns = game.getStringOr("dns", dns->dns.c_str()); - + dns->dyn_dns = game.getStringOr("dyn_dns", ""); if (game.hasChild("domains", JSON_OBJECT)) { const JsonGet domains = game.getDict("domains"); for (auto iter : domains.value_) { @@ -712,9 +714,45 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini memset(&adhocSockets, 0, sizeof(adhocSockets)); if (g_Config.bInfrastructureAutoDNS) { - // Load the automatic DNS config. + // Load the automatic DNS config for this game - or the defaults. std::string discID = g_paramSFO.GetDiscID(); LoadDNSForGameID(discID, &g_infraDNSConfig); + + // If dyn_dns is non-empty, try to use it to replace the specified DNS. + // If fails, we just use the dns. TODO: Do this in the background somehow... + const auto &dns = g_infraDNSConfig.dns; + const auto &dyn_dns = g_infraDNSConfig.dyn_dns; + if (!dyn_dns.empty()) { + // Try to look it up in system DNS + INFO_LOG(Log::sceNet, "DynDNS requested, trying to resolve '%s'...", dyn_dns.c_str()); + addrinfo *resolved = nullptr; + std::string err; + if (!net::DNSResolve(dyn_dns, "", &resolved, err)) { + ERROR_LOG(Log::sceNet, "Error resolving, falling back to '%s'", dns.c_str()); + } else if (resolved) { + bool found = false; + for (auto ptr = resolved; ptr && !found; ptr = ptr->ai_next) { + switch (ptr->ai_family) { + case AF_INET: + { + char ipstr[256]; + if (inet_ntop(ptr->ai_family, &(((struct sockaddr_in*)ptr->ai_addr)->sin_addr), ipstr, sizeof(ipstr)) != 0) { + INFO_LOG(Log::sceNet, "Successfully resolved '%s' to '%s', overriding DNS.", dyn_dns.c_str(), ipstr); + if (g_infraDNSConfig.dns != ipstr) { + WARN_LOG(Log::sceNet, "Replacing specified DNS IP %s with dyndns %s!", g_infraDNSConfig.dns.c_str(), ipstr); + g_infraDNSConfig.dns = ipstr; + } else { + INFO_LOG(Log::sceNet, "DynDNS: %s already up to date", g_infraDNSConfig.dns.c_str()); + } + found = true; + } + break; + } + } + } + net::DNSResolveFree(resolved); + } + } } netInited = true; diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index a3521c08f3aa..533d32a40aa8 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -140,6 +140,7 @@ enum class InfraGameState { struct InfraDNSConfig { std::string gameName; std::string dns; + std::string dyn_dns; InfraGameState state; std::map fixedDNS; int score; diff --git a/assets/infra-dns.json b/assets/infra-dns.json index dbf3176c7221..b4fbf3c62de0 100644 --- a/assets/infra-dns.json +++ b/assets/infra-dns.json @@ -17,11 +17,10 @@ "group": "MOHH Revival", "url": "https://mohh-revival.pages.dev/" }, - "credit": "AG ", "dns": "86.223.243.173", + "dyn_dns": "ablondel.ddns.net", "domains": { "pspmoh07.ea.com": "86.223.243.173", - "pspmoh08.ea.com": "86.223.243.173", "tos.ea.com": "86.223.243.173" }, "score": 5, @@ -40,9 +39,53 @@ "ULUS10141", "NPJH50306" ], - "not_working_platforms": [ - "Windows" + }, + { + "name": "Medal of Honor 2", + "comment": { + "en_US": "Only the menu works!" + }, + "revival_credits": { + "group": "MOHH Revival", + "url": "https://mohh-revival.pages.dev/" + }, + "dns": "86.223.243.173", + "dyn_dns": "ablondel.ddns.net", + "domains": { + "pspmoh08.ea.com": "86.223.243.173", + "tos.ea.com": "86.223.243.173" + }, + "score": 1, + "known_working_ids": [ + "ULUS10310", + "ULES00955", + "ULES00956", + "ULES00988" ], + "not_working_ids": [ + "ULJM05301", + ] + }, + { + "name": "Wipeout Pure", + "comment": { + "en_US": "Web browser only, no multiplayer" + }, + "revival_credits": { + "group": "The AG Racing Foundation", + "url": "https://agracingfoundation.org/" + }, + "dns": "145.239.30.230", + "domains": { + "hub.psnexus.net": "145.239.30.230", + }, + "other_ids": [ + "UCUS98612", + "UCJS10007", + "UCES00001", + "UCKS45008", + "NPJG00059" + ] }, { "name": "Wipeout Pulse", @@ -79,7 +122,7 @@ "known_working_ids": [ "UCES01250", "UCUS98743", - "UCJS10104", + "UCJS10104" ], "not_working_ids": [], "other_ids": [