From c3cc3da8fe13d07d140b575a597c77ee0242a89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Jan 2025 22:49:53 +0100 Subject: [PATCH] Download infra-dns.json from metadata.ppsspp.org --- Core/Dialog/PSPNetconfDialog.cpp | 23 ++++++++--- Core/Dialog/PSPNetconfDialog.h | 2 + Core/HLE/sceIo.cpp | 3 +- Core/HLE/sceNet.cpp | 68 +++++++++++++++++++++++++------- Core/HLE/sceNet.h | 5 +++ UI/PauseScreen.cpp | 3 +- UI/PauseScreen.h | 3 ++ UWP/UWP.vcxproj | 4 ++ UWP/UWP.vcxproj.filters | 3 ++ 9 files changed, 91 insertions(+), 23 deletions(-) diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 16570b52e8..ae3e159996 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -58,6 +58,9 @@ int PSPNetconfDialog::Init(u32 paramAddr) { if (ReadStatus() != SCE_UTILITY_STATUS_NONE) return SCE_ERROR_UTILITY_INVALID_STATUS; + // Kick off a request to the infra-dns.json since we'll need it later. + StartInfraJsonDownload(); + requestAddr = paramAddr; int size = Memory::Read_U32(paramAddr); memset(&request, 0, sizeof(request)); @@ -106,6 +109,17 @@ int PSPNetconfDialog::Update(int animSpeed) { auto di = GetI18NCategory(I18NCat::DIALOG); u64 now = (u64)(time_now_d() * 1000000.0); + std::string json; + if (!jsonReady_ && PollInfraJsonDownload(&json)) { + if (!json.empty()) { + INFO_LOG(Log::sceNet, "Got and processed the json."); + } else { + // TODO: Show a notice? + WARN_LOG(Log::sceNet, "Failed to get json file. Autoconfig will not work."); + } + jsonReady_ = true; + } + // It seems JPCSP doesn't check for NETCONF_STATUS_APNET if (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET || request.netAction == NETCONF_CONNECT_APNET_LAST) { int state = NetApctl_GetState(); @@ -161,15 +175,14 @@ int PSPNetconfDialog::Update(int animSpeed) { } DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel")); - // The Netconf dialog stays visible until the network reaches the state PSP_NET_APCTL_STATE_GOT_IP. - if (state == PSP_NET_APCTL_STATE_GOT_IP) { + // The Netconf dialog stays visible until the network reaches the state PSP_NET_APCTL_STATE_GOT_IP, + // *AND* we have the json. + if (state == PSP_NET_APCTL_STATE_GOT_IP && jsonReady_) { if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) { StartFade(false); ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US); } - } - - else if (state == PSP_NET_APCTL_STATE_JOINING) { + } else if (state == PSP_NET_APCTL_STATE_JOINING) { // Switch to the next message StartFade(true); } diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h index 1fe1dd0cd7..4f8ae4731c 100644 --- a/Core/Dialog/PSPNetconfDialog.h +++ b/Core/Dialog/PSPNetconfDialog.h @@ -61,4 +61,6 @@ private: u32 scanInfosAddr = 0; int scanStep = 0; u64 startTime = 0; + + bool jsonReady_ = false; }; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index b79012cef2..f39c980df6 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2791,8 +2791,7 @@ int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 out return hleLogDebug(Log::sceIo, 0); } -u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen) -{ +u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen) { int usec = 0; int result = __IoIoctl(id, cmd, indataPtr, inlen, outdataPtr, outlen, usec); if (usec != 0) { diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 0a6483eccd..ef6480dee1 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -159,21 +159,11 @@ void AfterApctlMipsCall::SetData(int HandlerID, int OldState, int NewState, int argsAddr = ArgsAddr; } -bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { +bool LoadDNSForGameID(std::string_view gameID, std::string_view jsonStr, InfraDNSConfig *dns) { using namespace json; *dns = {}; - // 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; - } - - dns->loaded = true; - - 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 DNS JSON"); @@ -277,17 +267,18 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) { break; } + dns->loaded = true; return true; } -void LoadAutoDNS() { +static void LoadAutoDNS(std::string_view json) { if (!g_Config.bInfrastructureAutoDNS) { return; } // Load the automatic DNS config for this game - or the defaults. std::string discID = g_paramSFO.GetDiscID(); - LoadDNSForGameID(discID, &g_infraDNSConfig); + LoadDNSForGameID(discID, json, &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... @@ -326,6 +317,55 @@ void LoadAutoDNS() { } } +std::shared_ptr g_infraDL; + +void StartInfraJsonDownload() { + if (!g_Config.bInfrastructureAutoDNS) { + return; + } + + if (g_infraDL) { + INFO_LOG(Log::sceNet, "json is already being downloaded"); + } + const char *acceptMime = "application/json, text/*; q=0.9, */*; q=0.8"; + g_infraDL = g_DownloadManager.StartDownload("http://metadata.ppsspp.org/infra-dns.json", Path(), http::ProgressBarMode::NONE, acceptMime); +} + +bool PollInfraJsonDownload(std::string *jsonOutput) { + if (!g_Config.bInfrastructureAutoDNS) { + return true; + } + + if (!g_infraDL) { + INFO_LOG(Log::sceNet, "No json download going on"); + return false; + } + + if (!g_infraDL->Done()) { + return false; + } + + // The request is done, but did it fail? + if (g_infraDL->Failed()) { + // Let's just grab the assets file. Because later this will mean that we didn't even get the cached copy. + size_t jsonSize = 0; + std::unique_ptr jsonStr(g_VFS.ReadFile("infra-dns.json", &jsonSize)); + if (!jsonStr) { + jsonOutput->clear(); + return true; // A clear output but returning true means something vent very wrong. + } + *jsonOutput = std::string((const char *)jsonStr.get(), jsonSize); + return true; + } + + // OK, we actually got data. Load it! + INFO_LOG(Log::sceNet, "json downloaded"); + g_infraDL->buffer().TakeAll(jsonOutput); + + LoadAutoDNS(*jsonOutput); + return true; +} + void InitLocalhostIP() { // The entire 127.*.*.* is reserved for loopback. uint32_t localIP = 0x7F000001 + PPSSPP_ID - 1; @@ -820,8 +860,6 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini // Clear Socket Translator Memory memset(&adhocSockets, 0, sizeof(adhocSockets)); - LoadAutoDNS(); - g_netInited = true; auto n = GetI18NCategory(I18NCat::NETWORKING); diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index a9afcc6cb0..9a234e4901 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -134,6 +134,11 @@ int sceNetApctlConnect(int connIndex); // Are we connected - for the purpose of disabling speed consoles and savestates etc. bool IsNetworkConnected(); +// Kicks off a fetch of the json download, unless it's cached and new enough. +void StartInfraJsonDownload(); +// Polls the fetch, if returns true, jsonOutput should be looked at. If it's empty, something went very wrong as we fallback on the asset file. +bool PollInfraJsonDownload(std::string *jsonOutput); + // These return false if allowed to be consistent with the similar function for achievements. bool NetworkWarnUserIfOnlineAndCantSavestate(); bool NetworkWarnUserIfOnlineAndCantSpeed(); diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 4aae99dceb..3c2381037d 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -279,13 +279,14 @@ void GamePauseScreen::update() { } const bool networkConnected = IsNetworkConnected(); - if (g_netInited != lastNetInited_ || netInetInited != lastNetInetInited_ || lastAdhocServerConnected_ != g_adhocServerConnected || lastOnline_ != networkConnected) { + if (g_netInited != lastNetInited_ || netInetInited != lastNetInetInited_ || lastAdhocServerConnected_ != g_adhocServerConnected || lastOnline_ != networkConnected || lastDNSConfigLoaded_ != g_infraDNSConfig.loaded) { INFO_LOG(Log::sceNet, "Network status changed, recreating views"); RecreateViews(); lastNetInetInited_ = netInetInited; lastNetInited_ = g_netInited; lastAdhocServerConnected_ = g_adhocServerConnected; lastOnline_ = networkConnected; + lastDNSConfigLoaded_ = g_infraDNSConfig.loaded; } const bool mustRunBehind = MustRunBehind(); diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 2b753bf23b..910bc82a96 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -64,8 +64,11 @@ private: DialogResult finishNextFrameResult_ = DR_CANCEL; UI::Button *playButton_ = nullptr; + + // State change tracking, a bit ugly heh, but works. bool lastOnline_ = false; bool lastNetInited_ = false; bool lastNetInetInited_ = false; bool lastAdhocServerConnected_ = false; + bool lastDNSConfigLoaded_ = false; }; diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 64fc723dfb..1467a92068 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -441,6 +441,10 @@ true Content\%(Filename)%(Extension) + + true + Content\%(Filename)%(Extension) + true Content\%(Filename)%(Extension) diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 31ed833775..eb9a73dcc8 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -186,6 +186,9 @@ Content + + Content + Content