diff --git a/Core/Config.cpp b/Core/Config.cpp index c28ac8a476..0f4be8e9af 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 1f321f7552..3a87cef419 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -461,6 +461,7 @@ public: 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 4cbd670f94..8bbc49017f 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 9b7fb052b2..a3521c08f3 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 1cda047d24..e0b1840121 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")));