summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2023-05-01 01:19:11 +0100
committerGitHub <noreply@github.com>2023-05-01 01:19:11 +0100
commit0eeeac2487cebe8e8eeae95d40c4e6c9ed640424 (patch)
treebb9775421a9990c132b91330e7029f3cfd1f01e7 /Source
parent2e39c79984490e21a7428fd5f47ea99a0359cf64 (diff)
parent467b961e9cf63d7bc5cd5f0632a8b458dc397c8f (diff)
Merge pull request #11736 from noahpistilli/get-scheduler-stat
IOS/Network/KD: Implement GetSchedulerStat
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Common/HttpRequest.cpp13
-rw-r--r--Source/Core/Common/HttpRequest.h1
-rw-r--r--Source/Core/Core/IOS/Network/KD/NWC24Config.h2
-rw-r--r--Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp73
-rw-r--r--Source/Core/Core/IOS/Network/KD/NetKDRequest.h16
-rw-r--r--Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp6
6 files changed, 100 insertions, 11 deletions
diff --git a/Source/Core/Common/HttpRequest.cpp b/Source/Core/Common/HttpRequest.cpp
index b9c6756624..b3dfb0dc0c 100644
--- a/Source/Core/Common/HttpRequest.cpp
+++ b/Source/Core/Common/HttpRequest.cpp
@@ -30,6 +30,7 @@ public:
void SetCookies(const std::string& cookies);
void UseIPv4();
void FollowRedirects(long max);
+ s32 GetLastResponseCode();
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
@@ -76,6 +77,11 @@ std::string HttpRequest::EscapeComponent(const std::string& string)
return m_impl->EscapeComponent(string);
}
+s32 HttpRequest::GetLastResponseCode() const
+{
+ return m_impl->GetLastResponseCode();
+}
+
HttpRequest::Response HttpRequest::Get(const std::string& url, const Headers& headers,
AllowedReturnCodes codes)
{
@@ -144,6 +150,13 @@ bool HttpRequest::Impl::IsValid() const
return m_curl != nullptr;
}
+s32 HttpRequest::Impl::GetLastResponseCode()
+{
+ s32 response_code{};
+ curl_easy_getinfo(m_curl.get(), CURLINFO_RESPONSE_CODE, &response_code);
+ return response_code;
+}
+
void HttpRequest::Impl::SetCookies(const std::string& cookies)
{
curl_easy_setopt(m_curl.get(), CURLOPT_COOKIE, cookies.c_str());
diff --git a/Source/Core/Common/HttpRequest.h b/Source/Core/Common/HttpRequest.h
index 17b9fd3413..0b8afb1b1b 100644
--- a/Source/Core/Common/HttpRequest.h
+++ b/Source/Core/Common/HttpRequest.h
@@ -38,6 +38,7 @@ public:
void SetCookies(const std::string& cookies);
void UseIPv4();
void FollowRedirects(long max = 1);
+ s32 GetLastResponseCode() const;
std::string EscapeComponent(const std::string& string);
Response Get(const std::string& url, const Headers& headers = {},
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
diff --git a/Source/Core/Core/IOS/Network/KD/NWC24Config.h b/Source/Core/Core/IOS/Network/KD/NWC24Config.h
index be8f4c9bc9..0f3682449e 100644
--- a/Source/Core/Core/IOS/Network/KD/NWC24Config.h
+++ b/Source/Core/Core/IOS/Network/KD/NWC24Config.h
@@ -19,6 +19,8 @@ enum ErrorCode : s32
{
WC24_OK = 0,
WC24_ERR_FATAL = -1,
+ WC24_ERR_INVALID_VALUE = -3,
+ WC24_ERR_NULL = -5,
WC24_ERR_NOT_FOUND = -13,
WC24_ERR_BROKEN = -14,
WC24_ERR_FILE_OPEN = -16,
diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp
index aa99a5a177..66fb23193d 100644
--- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp
+++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp
@@ -150,6 +150,9 @@ s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, HardwareModel h
NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name)
: EmulationDevice(ios, device_name), config{ios.GetFS()}, m_dl_list{ios.GetFS()}
{
+ // Enable all NWC24 permissions
+ m_scheduler_buffer[1] = Common::swap32(-1);
+
m_work_queue.Reset("WiiConnect24 Worker", [this](AsyncTask task) {
const IPCReply reply = task.handler();
{
@@ -179,6 +182,34 @@ void NetKDRequestDevice::Update()
}
}
+void NetKDRequestDevice::LogError(ErrorType error_type, s32 error_code)
+{
+ s32 new_code{};
+ switch (error_type)
+ {
+ case ErrorType::Account:
+ new_code = -(101200 - error_code);
+ break;
+ case ErrorType::Client:
+ new_code = -(107300 - error_code);
+ break;
+ case ErrorType::KD_Download:
+ new_code = -(107200 - error_code);
+ break;
+ case ErrorType::Server:
+ new_code = -(117000 + error_code);
+ break;
+ }
+
+ std::lock_guard lg(m_scheduler_buffer_lock);
+
+ m_scheduler_buffer[32 + (m_error_count % 32)] = Common::swap32(new_code);
+ m_error_count++;
+
+ m_scheduler_buffer[5] = Common::swap32(m_error_count);
+ m_scheduler_buffer[2] = Common::swap32(new_code);
+}
+
NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
const std::optional<u8> subtask_id)
{
@@ -196,7 +227,14 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
if (!response)
{
- ERROR_LOG_FMT(IOS_WC24, "Failed to request data at {}", url);
+ const s32 last_response_code = m_http.GetLastResponseCode();
+ ERROR_LOG_FMT(IOS_WC24, "Failed to request data at {}. HTTP Status Code: {}", url,
+ last_response_code);
+
+ // On a real Wii, KD throws 107305 if it cannot connect to the host. While other issues other
+ // than invalid host may arise, this code is essentially a catch-all for HTTP client failure.
+ LogError(last_response_code ? ErrorType::Server : ErrorType::Client,
+ last_response_code ? last_response_code : NWC24::WC24_ERR_NULL);
return NWC24::WC24_ERR_SERVER;
}
@@ -204,6 +242,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
if (response->size() < sizeof(NWC24::WC24File))
{
ERROR_LOG_FMT(IOS_WC24, "File at {} is too small to be a valid file.", url);
+ LogError(ErrorType::KD_Download, NWC24::WC24_ERR_BROKEN);
return NWC24::WC24_ERR_BROKEN;
}
@@ -230,6 +269,9 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
NWC24::ErrorCode reply = IOS::HLE::NWC24::OpenVFF(m_dl_list.GetVFFPath(entry_index), content_name,
m_ios.GetFS(), file_data);
+ if (reply != NWC24::WC24_OK)
+ LogError(ErrorType::KD_Download, reply);
+
return reply;
}
@@ -252,15 +294,17 @@ IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& reques
if (entry_index >= NWC24::NWC24Dl::MAX_ENTRIES)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Entry index out of range.");
- WriteReturnValue(NWC24::WC24_ERR_BROKEN, request.buffer_out);
- return IPCReply(NWC24::WC24_ERR_BROKEN);
+ LogError(ErrorType::KD_Download, NWC24::WC24_ERR_INVALID_VALUE);
+ WriteReturnValue(NWC24::WC24_ERR_INVALID_VALUE, request.buffer_out);
+ return IPCReply(IPC_SUCCESS);
}
if (!m_dl_list.DoesEntryExist(entry_index))
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Requested entry does not exist in download list!");
+ LogError(ErrorType::KD_Download, NWC24::WC24_ERR_NOT_FOUND);
WriteReturnValue(NWC24::WC24_ERR_NOT_FOUND, request.buffer_out);
- return IPCReply(NWC24::WC24_ERR_NOT_FOUND);
+ return IPCReply(IPC_SUCCESS);
}
// While in theory reply will always get initialized by KDDownload, things happen.
@@ -290,7 +334,7 @@ IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& reques
}
WriteReturnValue(reply, request.buffer_out);
- return IPCReply(reply);
+ return IPCReply(IPC_SUCCESS);
}
std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
@@ -408,6 +452,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
}
else
{
+ LogError(ErrorType::Account, NWC24::WC24_ERR_INVALID_VALUE);
WriteReturnValue(NWC24::WC24_ERR_FATAL, request.buffer_out);
}
}
@@ -424,8 +469,24 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
break;
case IOCTL_NWC24_GET_SCHEDULER_STAT:
- INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT - NI");
+ {
+ if (request.buffer_out == 0 || request.buffer_out % 4 != 0 || request.buffer_out_size < 16)
+ {
+ return_value = IPC_EINVAL;
+ ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT = IPC_EINVAL");
+ break;
+ }
+
+ INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULER_STAT - buffer out size: {}",
+ request.buffer_out_size);
+
+ // On a real Wii, GetSchedulerStat copies memory containing a list of error codes recorded by
+ // KD among other things. In most instances there will never be more than one error code
+ // recorded as we do not have a scheduler.
+ const u32 out_size = std::min(request.buffer_out_size, 256U);
+ memory.CopyToEmu(request.buffer_out, m_scheduler_buffer.data(), out_size);
break;
+ }
case IOCTL_NWC24_SAVE_MAIL_NOW:
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI");
diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.h b/Source/Core/Core/IOS/Network/KD/NetKDRequest.h
index 7e0a986a10..035b4a286b 100644
--- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.h
+++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.h
@@ -3,6 +3,7 @@
#pragma once
+#include <array>
#include <queue>
#include <string>
@@ -16,8 +17,6 @@
namespace IOS::HLE
{
-constexpr const char DL_CNT_PATH[] = "/" WII_WC24CONF_DIR "/dlcnt.bin";
-
// KD is the IOS module responsible for implementing WiiConnect24 functionality.
// It can perform HTTPS downloads, send and receive mail via SMTP, and execute a
// JavaScript-like language while the Wii is in standby mode.
@@ -52,11 +51,24 @@ private:
return std::nullopt;
}
+ enum class ErrorType
+ {
+ Account,
+ KD_Download,
+ Client,
+ Server,
+ };
+
+ void LogError(ErrorType error_type, s32 error_code);
+
NWC24::NWC24Config config;
NWC24::NWC24Dl m_dl_list;
Common::WorkQueueThread<AsyncTask> m_work_queue;
std::mutex m_async_reply_lock;
+ std::mutex m_scheduler_buffer_lock;
std::queue<AsyncReply> m_async_replies;
+ u32 m_error_count = 0;
+ std::array<u32, 256> m_scheduler_buffer{};
// TODO: Maybe move away from Common::HttpRequest?
Common::HttpRequest m_http{std::chrono::minutes{1}};
};
diff --git a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp
index 16ba1b1ad7..4a1389c626 100644
--- a/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp
+++ b/Source/Core/Core/IOS/Network/KD/VFF/VFFUtil.cpp
@@ -267,7 +267,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
if (!temp)
{
ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path);
- return_value = WC24_ERR_NOT_FOUND;
+ return_value = WC24_ERR_FILE_OPEN;
return;
}
@@ -281,7 +281,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
{
// The VFF is most likely broken.
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
- return_value = WC24_ERR_BROKEN;
+ return_value = WC24_ERR_FILE_READ;
return;
}
@@ -290,7 +290,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
{
// The VFF is most likely broken.
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
- return_value = WC24_ERR_BROKEN;
+ return_value = WC24_ERR_FILE_READ;
return;
}