Download infra-dns.json from metadata.ppsspp.org

This commit is contained in:
Henrik Rydgård 2025-01-22 22:49:53 +01:00
parent b2fceaa3be
commit c3cc3da8fe
9 changed files with 91 additions and 23 deletions

View file

@ -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);
}

View file

@ -61,4 +61,6 @@ private:
u32 scanInfosAddr = 0;
int scanStep = 0;
u64 startTime = 0;
bool jsonReady_ = false;
};

View file

@ -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) {

View file

@ -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<uint8_t[]> 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<http::Request> 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<uint8_t[]> 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);

View file

@ -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();

View file

@ -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();

View file

@ -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;
};

View file

@ -441,6 +441,10 @@
<DeploymentContent>true</DeploymentContent>
<Link>Content\%(Filename)%(Extension)</Link>
</None>
<None Include="..\Assets\infra-dns.json">
<DeploymentContent>true</DeploymentContent>
<Link>Content\%(Filename)%(Extension)</Link>
</None>
<None Include="..\Assets\knownfuncs.ini">
<DeploymentContent>true</DeploymentContent>
<Link>Content\%(Filename)%(Extension)</Link>

View file

@ -186,6 +186,9 @@
<None Include="..\Assets\langregion.ini">
<Filter>Content</Filter>
</None>
<None Include="..\Assets\infra-dns.json">
<Filter>Content</Filter>
</None>
<None Include="..\Assets\redump.csv">
<Filter>Content</Filter>
</None>