Merge pull request #11736 from noahpistilli/get-scheduler-stat
IOS/Network/KD: Implement GetSchedulerStat
This commit is contained in:
commit
0eeeac2487
|
@ -30,6 +30,7 @@ public:
|
||||||
void SetCookies(const std::string& cookies);
|
void SetCookies(const std::string& cookies);
|
||||||
void UseIPv4();
|
void UseIPv4();
|
||||||
void FollowRedirects(long max);
|
void FollowRedirects(long max);
|
||||||
|
s32 GetLastResponseCode();
|
||||||
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
|
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
|
||||||
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
|
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);
|
return m_impl->EscapeComponent(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 HttpRequest::GetLastResponseCode() const
|
||||||
|
{
|
||||||
|
return m_impl->GetLastResponseCode();
|
||||||
|
}
|
||||||
|
|
||||||
HttpRequest::Response HttpRequest::Get(const std::string& url, const Headers& headers,
|
HttpRequest::Response HttpRequest::Get(const std::string& url, const Headers& headers,
|
||||||
AllowedReturnCodes codes)
|
AllowedReturnCodes codes)
|
||||||
{
|
{
|
||||||
|
@ -144,6 +150,13 @@ bool HttpRequest::Impl::IsValid() const
|
||||||
return m_curl != nullptr;
|
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)
|
void HttpRequest::Impl::SetCookies(const std::string& cookies)
|
||||||
{
|
{
|
||||||
curl_easy_setopt(m_curl.get(), CURLOPT_COOKIE, cookies.c_str());
|
curl_easy_setopt(m_curl.get(), CURLOPT_COOKIE, cookies.c_str());
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
void SetCookies(const std::string& cookies);
|
void SetCookies(const std::string& cookies);
|
||||||
void UseIPv4();
|
void UseIPv4();
|
||||||
void FollowRedirects(long max = 1);
|
void FollowRedirects(long max = 1);
|
||||||
|
s32 GetLastResponseCode() const;
|
||||||
std::string EscapeComponent(const std::string& string);
|
std::string EscapeComponent(const std::string& string);
|
||||||
Response Get(const std::string& url, const Headers& headers = {},
|
Response Get(const std::string& url, const Headers& headers = {},
|
||||||
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
|
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
|
||||||
|
|
|
@ -19,6 +19,8 @@ enum ErrorCode : s32
|
||||||
{
|
{
|
||||||
WC24_OK = 0,
|
WC24_OK = 0,
|
||||||
WC24_ERR_FATAL = -1,
|
WC24_ERR_FATAL = -1,
|
||||||
|
WC24_ERR_INVALID_VALUE = -3,
|
||||||
|
WC24_ERR_NULL = -5,
|
||||||
WC24_ERR_NOT_FOUND = -13,
|
WC24_ERR_NOT_FOUND = -13,
|
||||||
WC24_ERR_BROKEN = -14,
|
WC24_ERR_BROKEN = -14,
|
||||||
WC24_ERR_FILE_OPEN = -16,
|
WC24_ERR_FILE_OPEN = -16,
|
||||||
|
|
|
@ -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)
|
NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name)
|
||||||
: EmulationDevice(ios, device_name), config{ios.GetFS()}, m_dl_list{ios.GetFS()}
|
: 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) {
|
m_work_queue.Reset("WiiConnect24 Worker", [this](AsyncTask task) {
|
||||||
const IPCReply reply = task.handler();
|
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,
|
NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
|
||||||
const std::optional<u8> subtask_id)
|
const std::optional<u8> subtask_id)
|
||||||
{
|
{
|
||||||
|
@ -196,7 +227,14 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
|
||||||
|
|
||||||
if (!response)
|
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;
|
return NWC24::WC24_ERR_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +242,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
|
||||||
if (response->size() < sizeof(NWC24::WC24File))
|
if (response->size() < sizeof(NWC24::WC24File))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_WC24, "File at {} is too small to be a valid file.", url);
|
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;
|
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,
|
NWC24::ErrorCode reply = IOS::HLE::NWC24::OpenVFF(m_dl_list.GetVFFPath(entry_index), content_name,
|
||||||
m_ios.GetFS(), file_data);
|
m_ios.GetFS(), file_data);
|
||||||
|
|
||||||
|
if (reply != NWC24::WC24_OK)
|
||||||
|
LogError(ErrorType::KD_Download, reply);
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,15 +294,17 @@ IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& reques
|
||||||
if (entry_index >= NWC24::NWC24Dl::MAX_ENTRIES)
|
if (entry_index >= NWC24::NWC24Dl::MAX_ENTRIES)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Entry index out of range.");
|
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Entry index out of range.");
|
||||||
WriteReturnValue(NWC24::WC24_ERR_BROKEN, request.buffer_out);
|
LogError(ErrorType::KD_Download, NWC24::WC24_ERR_INVALID_VALUE);
|
||||||
return IPCReply(NWC24::WC24_ERR_BROKEN);
|
WriteReturnValue(NWC24::WC24_ERR_INVALID_VALUE, request.buffer_out);
|
||||||
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_dl_list.DoesEntryExist(entry_index))
|
if (!m_dl_list.DoesEntryExist(entry_index))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: Requested entry does not exist in download list!");
|
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);
|
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.
|
// 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);
|
WriteReturnValue(reply, request.buffer_out);
|
||||||
return IPCReply(reply);
|
return IPCReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
||||||
|
@ -408,6 +452,7 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LogError(ErrorType::Account, NWC24::WC24_ERR_INVALID_VALUE);
|
||||||
WriteReturnValue(NWC24::WC24_ERR_FATAL, request.buffer_out);
|
WriteReturnValue(NWC24::WC24_ERR_FATAL, request.buffer_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,8 +469,24 @@ std::optional<IPCReply> NetKDRequestDevice::IOCtl(const IOCtlRequest& request)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_NWC24_GET_SCHEDULER_STAT:
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IOCTL_NWC24_SAVE_MAIL_NOW:
|
case IOCTL_NWC24_SAVE_MAIL_NOW:
|
||||||
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI");
|
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI");
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -16,8 +17,6 @@
|
||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
constexpr const char DL_CNT_PATH[] = "/" WII_WC24CONF_DIR "/dlcnt.bin";
|
|
||||||
|
|
||||||
// KD is the IOS module responsible for implementing WiiConnect24 functionality.
|
// KD is the IOS module responsible for implementing WiiConnect24 functionality.
|
||||||
// It can perform HTTPS downloads, send and receive mail via SMTP, and execute a
|
// It can perform HTTPS downloads, send and receive mail via SMTP, and execute a
|
||||||
// JavaScript-like language while the Wii is in standby mode.
|
// JavaScript-like language while the Wii is in standby mode.
|
||||||
|
@ -52,11 +51,24 @@ private:
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class ErrorType
|
||||||
|
{
|
||||||
|
Account,
|
||||||
|
KD_Download,
|
||||||
|
Client,
|
||||||
|
Server,
|
||||||
|
};
|
||||||
|
|
||||||
|
void LogError(ErrorType error_type, s32 error_code);
|
||||||
|
|
||||||
NWC24::NWC24Config config;
|
NWC24::NWC24Config config;
|
||||||
NWC24::NWC24Dl m_dl_list;
|
NWC24::NWC24Dl m_dl_list;
|
||||||
Common::WorkQueueThread<AsyncTask> m_work_queue;
|
Common::WorkQueueThread<AsyncTask> m_work_queue;
|
||||||
std::mutex m_async_reply_lock;
|
std::mutex m_async_reply_lock;
|
||||||
|
std::mutex m_scheduler_buffer_lock;
|
||||||
std::queue<AsyncReply> m_async_replies;
|
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?
|
// TODO: Maybe move away from Common::HttpRequest?
|
||||||
Common::HttpRequest m_http{std::chrono::minutes{1}};
|
Common::HttpRequest m_http{std::chrono::minutes{1}};
|
||||||
};
|
};
|
||||||
|
|
|
@ -267,7 +267,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
|
||||||
if (!temp)
|
if (!temp)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path);
|
ERROR_LOG_FMT(IOS_WC24, "Failed to open VFF at: {}", path);
|
||||||
return_value = WC24_ERR_NOT_FOUND;
|
return_value = WC24_ERR_FILE_OPEN;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
|
||||||
{
|
{
|
||||||
// The VFF is most likely broken.
|
// The VFF is most likely broken.
|
||||||
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
|
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
|
||||||
return_value = WC24_ERR_BROKEN;
|
return_value = WC24_ERR_FILE_READ;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ ErrorCode OpenVFF(const std::string& path, const std::string& filename,
|
||||||
{
|
{
|
||||||
// The VFF is most likely broken.
|
// The VFF is most likely broken.
|
||||||
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
|
ERROR_LOG_FMT(IOS_WC24, "Failed to mount VFF at: {}", path);
|
||||||
return_value = WC24_ERR_BROKEN;
|
return_value = WC24_ERR_FILE_READ;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue