From 970f2284d8df0ecb630f1606243a3be934c2496f Mon Sep 17 00:00:00 2001 From: Tobias Date: Wed, 2 Aug 2023 00:37:56 +0200 Subject: [PATCH] http/soc: Various implementations and fixes (#6828) --- src/core/CMakeLists.txt | 24 +- src/core/core.cpp | 2 +- src/core/hle/service/ac/ac.cpp | 2 +- src/core/hle/service/{ => cam}/y2r_u.cpp | 2 +- src/core/hle/service/{ => cam}/y2r_u.h | 0 src/core/hle/service/{ => err}/err_f.cpp | 2 +- src/core/hle/service/{ => err}/err_f.h | 0 src/core/hle/service/{ => http}/http_c.cpp | 368 +++++++++++---------- src/core/hle/service/{ => http}/http_c.h | 83 ++++- src/core/hle/service/{ => mic}/mic_u.cpp | 2 +- src/core/hle/service/{ => mic}/mic_u.h | 0 src/core/hle/service/service.cpp | 12 +- src/core/hle/service/{ => soc}/soc_u.cpp | 23 +- src/core/hle/service/{ => soc}/soc_u.h | 0 src/core/hle/service/{ => ssl}/ssl_c.cpp | 2 +- src/core/hle/service/{ => ssl}/ssl_c.h | 0 src/core/hw/y2r.cpp | 2 +- 17 files changed, 322 insertions(+), 202 deletions(-) rename src/core/hle/service/{ => cam}/y2r_u.cpp (99%) rename src/core/hle/service/{ => cam}/y2r_u.h (100%) rename src/core/hle/service/{ => err}/err_f.cpp (99%) rename src/core/hle/service/{ => err}/err_f.h (100%) rename src/core/hle/service/{ => http}/http_c.cpp (83%) rename src/core/hle/service/{ => http}/http_c.h (83%) rename src/core/hle/service/{ => mic}/mic_u.cpp (99%) rename src/core/hle/service/{ => mic}/mic_u.h (100%) rename src/core/hle/service/{ => soc}/soc_u.cpp (98%) rename src/core/hle/service/{ => soc}/soc_u.h (100%) rename src/core/hle/service/{ => ssl}/ssl_c.cpp (98%) rename src/core/hle/service/{ => ssl}/ssl_c.h (100%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ae71ccc37..f507b5dc4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -247,6 +247,8 @@ add_library(citra_core STATIC hle/service/cam/cam_s.h hle/service/cam/cam_u.cpp hle/service/cam/cam_u.h + hle/service/cam/y2r_u.cpp + hle/service/cam/y2r_u.h hle/service/cecd/cecd.cpp hle/service/cecd/cecd.h hle/service/cecd/cecd_ndm.cpp @@ -279,8 +281,8 @@ add_library(citra_core STATIC hle/service/dlp/dlp_srvr.h hle/service/dsp/dsp_dsp.cpp hle/service/dsp/dsp_dsp.h - hle/service/err_f.cpp - hle/service/err_f.h + hle/service/err/err_f.cpp + hle/service/err/err_f.h hle/service/frd/frd.cpp hle/service/frd/frd.h hle/service/frd/frd_a.cpp @@ -307,8 +309,8 @@ add_library(citra_core STATIC hle/service/hid/hid_spvr.h hle/service/hid/hid_user.cpp hle/service/hid/hid_user.h - hle/service/http_c.cpp - hle/service/http_c.h + hle/service/http/http_c.cpp + hle/service/http/http_c.h hle/service/ir/extra_hid.cpp hle/service/ir/extra_hid.h hle/service/ir/ir.cpp @@ -323,8 +325,8 @@ add_library(citra_core STATIC hle/service/ldr_ro/cro_helper.h hle/service/ldr_ro/ldr_ro.cpp hle/service/ldr_ro/ldr_ro.h - hle/service/mic_u.cpp - hle/service/mic_u.h + hle/service/mic/mic_u.cpp + hle/service/mic/mic_u.h hle/service/mvd/mvd.cpp hle/service/mvd/mvd.h hle/service/mvd/mvd_std.cpp @@ -421,12 +423,10 @@ add_library(citra_core STATIC hle/service/sm/sm.h hle/service/sm/srv.cpp hle/service/sm/srv.h - hle/service/soc_u.cpp - hle/service/soc_u.h - hle/service/ssl_c.cpp - hle/service/ssl_c.h - hle/service/y2r_u.cpp - hle/service/y2r_u.h + hle/service/soc/soc_u.cpp + hle/service/soc/soc_u.h + hle/service/ssl/ssl_c.cpp + hle/service/ssl/ssl_c.h hw/aes/arithmetic128.cpp hw/aes/arithmetic128.h hw/aes/ccm.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index ac1ce5234..f0528724e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,7 +36,7 @@ #include "core/hle/service/fs/archive.h" #include "core/hle/service/gsp/gsp.h" #include "core/hle/service/ir/ir_rst.h" -#include "core/hle/service/mic_u.h" +#include "core/hle/service/mic/mic_u.h" #include "core/hle/service/plgldr/plgldr.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp index 3293eb611..c1a61126b 100644 --- a/src/core/hle/service/ac/ac.cpp +++ b/src/core/hle/service/ac/ac.cpp @@ -16,7 +16,7 @@ #include "core/hle/service/ac/ac.h" #include "core/hle/service/ac/ac_i.h" #include "core/hle/service/ac/ac_u.h" -#include "core/hle/service/soc_u.h" +#include "core/hle/service/soc/soc_u.h" #include "core/memory.h" namespace Service::AC { diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/cam/y2r_u.cpp similarity index 99% rename from src/core/hle/service/y2r_u.cpp rename to src/core/hle/service/cam/y2r_u.cpp index 1cdab3ff5..db1b52f15 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/cam/y2r_u.cpp @@ -11,7 +11,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/process.h" -#include "core/hle/service/y2r_u.h" +#include "core/hle/service/cam/y2r_u.h" #include "core/hw/y2r.h" SERVICE_CONSTRUCT_IMPL(Service::Y2R::Y2R_U) diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/cam/y2r_u.h similarity index 100% rename from src/core/hle/service/y2r_u.h rename to src/core/hle/service/cam/y2r_u.h diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err/err_f.cpp similarity index 99% rename from src/core/hle/service/err_f.cpp rename to src/core/hle/service/err/err_f.cpp index 986ad8415..896306cf1 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err/err_f.cpp @@ -14,7 +14,7 @@ #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" #include "core/hle/result.h" -#include "core/hle/service/err_f.h" +#include "core/hle/service/err/err_f.h" #undef exception_info // We use 'exception_info' as a plain identifier, but MSVC defines this in one // of its many headers. diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err/err_f.h similarity index 100% rename from src/core/hle/service/err_f.h rename to src/core/hle/service/err/err_f.h diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http/http_c.cpp similarity index 83% rename from src/core/hle/service/http_c.cpp rename to src/core/hle/service/http/http_c.cpp index 094f908ba..f3583982c 100644 --- a/src/core/hle/service/http_c.cpp +++ b/src/core/hle/service/http/http_c.cpp @@ -15,7 +15,7 @@ #include "core/hle/kernel/ipc.h" #include "core/hle/romfs.h" #include "core/hle/service/fs/archive.h" -#include "core/hle/service/http_c.h" +#include "core/hle/service/http/http_c.h" #include "core/hw/aes/key.h" SERIALIZE_EXPORT_IMPL(Service::HTTP::HTTP_C) @@ -55,11 +55,31 @@ const ResultCode ERROR_WRONG_CERT_HANDLE = // 0xD8A0A0C9 const ResultCode ERROR_CERT_ALREADY_SET = // 0xD8A0A03D ResultCode(61, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent); +static std::pair SplitUrl(const std::string& url) { + const std::string prefix = "://"; + const auto scheme_end = url.find(prefix); + const auto prefix_end = scheme_end == std::string::npos ? 0 : scheme_end + prefix.length(); + + const auto path_index = url.find("/", prefix_end); + std::string host; + std::string path; + if (path_index == std::string::npos) { + // If no path is specified after the host, set it to "/" + host = url; + path = "/"; + } else { + host = url.substr(0, path_index); + path = url.substr(path_index); + } + return std::make_pair(host, path); +} + void Context::MakeRequest() { ASSERT(state == RequestState::NotStarted); #ifdef ENABLE_WEB_SERVICE - std::unique_ptr client = std::make_unique(url.c_str()); + const auto& [host, path] = SplitUrl(url); + const auto client = std::make_unique(host); SSL_CTX* ctx = client->ssl_context(); if (ctx) { if (auto client_cert = ssl_config.client_cert_ctx.lock()) { @@ -87,7 +107,7 @@ void Context::MakeRequest() { httplib::Request request; httplib::Error error; request.method = request_method_strings.at(method); - request.path = url; + request.path = path; // TODO(B3N30): Add post data body request.progress = [this](u64 current, u64 total) -> bool { // TODO(B3N30): Is there a state that shows response header are available @@ -101,7 +121,7 @@ void Context::MakeRequest() { } if (!client->send(request, response, error)) { - LOG_ERROR(Service_HTTP, "Request failed: {}", error); + LOG_ERROR(Service_HTTP, "Request failed: {}: {}", error, httplib::to_string(error)); state = RequestState::TimedOut; } else { LOG_DEBUG(Service_HTTP, "Request successful"); @@ -185,33 +205,7 @@ void HTTP_C::BeginRequest(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_HTTP, "(STUBBED) called, context_id={}", context_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to make a request on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); - return; - } - - // This command can only be called with a bound context - if (!session_data->current_http_context) { - LOG_ERROR(Service_HTTP, "Tried to make a request without a bound context"); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, - ErrorSummary::Internal, ErrorLevel::Permanent)); - return; - } - - if (session_data->current_http_context != context_handle) { - LOG_ERROR( - Service_HTTP, - "Tried to make a request on a mismatched session input context={} session context={}", - context_handle, *session_data->current_http_context); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); + if (!PerformStateChecks(ctx, rp, context_handle)) { return; } @@ -238,33 +232,7 @@ void HTTP_C::BeginRequestAsync(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_HTTP, "(STUBBED) called, context_id={}", context_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to make a request on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); - return; - } - - // This command can only be called with a bound context - if (!session_data->current_http_context) { - LOG_ERROR(Service_HTTP, "Tried to make a request without a bound context"); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, - ErrorSummary::Internal, ErrorLevel::Permanent)); - return; - } - - if (session_data->current_http_context != context_handle) { - LOG_ERROR( - Service_HTTP, - "Tried to make a request on a mismatched session input context={} session context={}", - context_handle, *session_data->current_http_context); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); + if (!PerformStateChecks(ctx, rp, context_handle)) { return; } @@ -285,6 +253,44 @@ void HTTP_C::BeginRequestAsync(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void HTTP_C::ReceiveData(Kernel::HLERequestContext& ctx) { + ReceiveDataImpl(ctx, false); +} + +void HTTP_C::ReceiveDataTimeout(Kernel::HLERequestContext& ctx) { + ReceiveDataImpl(ctx, true); +} + +void HTTP_C::ReceiveDataImpl(Kernel::HLERequestContext& ctx, bool timeout) { + IPC::RequestParser rp(ctx); + const Context::Handle context_handle = rp.Pop(); + [[maybe_unused]] const u32 buffer_size = rp.Pop(); + u64 timeout_nanos = 0; + if (timeout) { + timeout_nanos = rp.Pop(); + LOG_WARNING(Service_HTTP, "(STUBBED) called, timeout={}", timeout_nanos); + } else { + LOG_WARNING(Service_HTTP, "(STUBBED) called"); + } + + if (!PerformStateChecks(ctx, rp, context_handle)) { + return; + } + + auto itr = contexts.find(context_handle); + ASSERT(itr != contexts.end()); + + if (timeout) { + itr->second.request_future.wait_for(std::chrono::nanoseconds(timeout_nanos)); + // TODO (flTobi): Return error on timeout + } else { + itr->second.request_future.wait(); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + void HTTP_C::CreateContext(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); const u32 url_size = rp.Pop(); @@ -297,14 +303,8 @@ void HTTP_C::CreateContext(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HTTP, "called, url_size={}, url={}, method={}", url_size, url, method); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to create a context on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ERROR_STATE_ERROR); - rb.PushMappedBuffer(buffer); + auto* session_data = EnsureSessionInitialized(ctx, rp); + if (!session_data) { return; } @@ -365,13 +365,8 @@ void HTTP_C::CloseContext(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_HTTP, "(STUBBED) called, handle={}", context_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to close a context on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); + auto* session_data = EnsureSessionInitialized(ctx, rp); + if (!session_data) { return; } @@ -416,36 +411,7 @@ void HTTP_C::AddRequestHeader(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HTTP, "called, name={}, value={}, context_handle={}", name, value, context_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to add a request header on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ERROR_STATE_ERROR); - rb.PushMappedBuffer(value_buffer); - return; - } - - // This command can only be called with a bound context - if (!session_data->current_http_context) { - LOG_ERROR(Service_HTTP, "Command called without a bound context"); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, - ErrorSummary::Internal, ErrorLevel::Permanent)); - rb.PushMappedBuffer(value_buffer); - return; - } - - if (session_data->current_http_context != context_handle) { - LOG_ERROR(Service_HTTP, - "Tried to add a request header on a mismatched session input context={} session " - "context={}", - context_handle, *session_data->current_http_context); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ERROR_STATE_ERROR); - rb.PushMappedBuffer(value_buffer); + if (!PerformStateChecks(ctx, rp, context_handle)) { return; } @@ -492,36 +458,7 @@ void HTTP_C::AddPostDataAscii(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HTTP, "called, name={}, value={}, context_handle={}", name, value, context_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to add post data on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ERROR_STATE_ERROR); - rb.PushMappedBuffer(value_buffer); - return; - } - - // This command can only be called with a bound context - if (!session_data->current_http_context) { - LOG_ERROR(Service_HTTP, "Command called without a bound context"); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, - ErrorSummary::Internal, ErrorLevel::Permanent)); - rb.PushMappedBuffer(value_buffer); - return; - } - - if (session_data->current_http_context != context_handle) { - LOG_ERROR(Service_HTTP, - "Tried to add post data on a mismatched session input context={} session " - "context={}", - context_handle, *session_data->current_http_context); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(ERROR_STATE_ERROR); - rb.PushMappedBuffer(value_buffer); + if (!PerformStateChecks(ctx, rp, context_handle)) { return; } @@ -549,6 +486,46 @@ void HTTP_C::AddPostDataAscii(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(value_buffer); } +void HTTP_C::GetResponseStatusCode(Kernel::HLERequestContext& ctx) { + GetResponseStatusCodeImpl(ctx, false); +} + +void HTTP_C::GetResponseStatusCodeTimeout(Kernel::HLERequestContext& ctx) { + GetResponseStatusCodeImpl(ctx, true); +} + +void HTTP_C::GetResponseStatusCodeImpl(Kernel::HLERequestContext& ctx, bool timeout) { + IPC::RequestParser rp(ctx); + const Context::Handle context_handle = rp.Pop(); + u64 timeout_nanos = 0; + if (timeout) { + timeout_nanos = rp.Pop(); + LOG_INFO(Service_HTTP, "called, timeout={}", timeout_nanos); + } else { + LOG_INFO(Service_HTTP, "called"); + } + + if (!PerformStateChecks(ctx, rp, context_handle)) { + return; + } + + auto itr = contexts.find(context_handle); + ASSERT(itr != contexts.end()); + + if (timeout) { + itr->second.request_future.wait_for(std::chrono::nanoseconds(timeout)); + // TODO (flTobi): Return error on timeout + } else { + itr->second.request_future.wait(); + } + + const u32 response_code = itr->second.response.status; + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(response_code); +} + void HTTP_C::SetClientCertContext(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); const u32 context_handle = rp.Pop(); @@ -557,32 +534,7 @@ void HTTP_C::SetClientCertContext(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HTTP, "called with context_handle={} client_cert_handle={}", context_handle, client_cert_handle); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Tried to set client cert on an uninitialized session"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); - return; - } - - // This command can only be called with a bound context - if (!session_data->current_http_context) { - LOG_ERROR(Service_HTTP, "Tried to set client cert without a bound context"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, - ErrorSummary::Internal, ErrorLevel::Permanent)); - return; - } - - if (session_data->current_http_context != context_handle) { - LOG_ERROR(Service_HTTP, - "Tried to add set client cert on a mismatched session input context={} session " - "context={}", - context_handle, *session_data->current_http_context); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); + if (!PerformStateChecks(ctx, rp, context_handle)) { return; } @@ -683,13 +635,8 @@ void HTTP_C::OpenDefaultClientCertContext(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HTTP, "called, cert_id={} cert_handle={}", cert_id, client_certs_counter); - auto* session_data = GetSessionData(ctx.Session()); - ASSERT(session_data); - - if (!session_data->initialized) { - LOG_ERROR(Service_HTTP, "Command called without Initialize"); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(ERROR_STATE_ERROR); + auto* session_data = EnsureSessionInitialized(ctx, rp); + if (!session_data) { return; } @@ -792,6 +739,85 @@ void HTTP_C::Finalize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_HTTP, "(STUBBED) called"); } +void HTTP_C::GetDownloadSizeState(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + const Context::Handle context_handle = rp.Pop(); + + LOG_INFO(Service_HTTP, "called"); + + const auto* session_data = EnsureSessionInitialized(ctx, rp); + if (!session_data) { + return; + } + + auto itr = contexts.find(context_handle); + ASSERT(itr != contexts.end()); + + // On the real console, the current downloaded progress and the total size of the content gets + // returned. Since we do not support chunked downloads on the host, always return the content + // length if the download is complete and 0 otherwise. + u32 content_length = 0; + const bool is_complete = itr->second.request_future.wait_for(std::chrono::milliseconds(0)) == + std::future_status::ready; + if (is_complete) { + const auto& headers = itr->second.response.headers; + const auto& it = headers.find("Content-Length"); + if (it != headers.end()) { + content_length = std::stoi(it->second); + } + } + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(content_length); + rb.Push(content_length); +} + +SessionData* HTTP_C::EnsureSessionInitialized(Kernel::HLERequestContext& ctx, + IPC::RequestParser rp) { + auto* session_data = GetSessionData(ctx.Session()); + ASSERT(session_data); + + if (!session_data->initialized) { + LOG_ERROR(Service_HTTP, "Tried to make a request on an uninitialized session"); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ERROR_STATE_ERROR); + return nullptr; + } + + return session_data; +} + +bool HTTP_C::PerformStateChecks(Kernel::HLERequestContext& ctx, IPC::RequestParser rp, + Context::Handle context_handle) { + const auto* session_data = EnsureSessionInitialized(ctx, rp); + if (!session_data) { + return false; + } + + // This command can only be called with a bound context + if (!session_data->current_http_context) { + LOG_ERROR(Service_HTTP, "Tried to make a request without a bound context"); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP, + ErrorSummary::Internal, ErrorLevel::Permanent)); + return false; + } + + if (session_data->current_http_context != context_handle) { + LOG_ERROR( + Service_HTTP, + "Tried to make a request on a mismatched session input context={} session context={}", + context_handle, *session_data->current_http_context); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ERROR_STATE_ERROR); + return false; + } + + return true; +} + void HTTP_C::DecryptClCertA() { static constexpr u32 iv_length = 16; @@ -875,13 +901,13 @@ HTTP_C::HTTP_C() : ServiceFramework("http:C", 32) { {0x0003, &HTTP_C::CloseContext, "CloseContext"}, {0x0004, nullptr, "CancelConnection"}, {0x0005, nullptr, "GetRequestState"}, - {0x0006, nullptr, "GetDownloadSizeState"}, + {0x0006, &HTTP_C::GetDownloadSizeState, "GetDownloadSizeState"}, {0x0007, nullptr, "GetRequestError"}, {0x0008, &HTTP_C::InitializeConnectionSession, "InitializeConnectionSession"}, {0x0009, &HTTP_C::BeginRequest, "BeginRequest"}, {0x000A, &HTTP_C::BeginRequestAsync, "BeginRequestAsync"}, - {0x000B, nullptr, "ReceiveData"}, - {0x000C, nullptr, "ReceiveDataTimeout"}, + {0x000B, &HTTP_C::ReceiveData, "ReceiveData"}, + {0x000C, &HTTP_C::ReceiveDataTimeout, "ReceiveDataTimeout"}, {0x000D, nullptr, "SetProxy"}, {0x000E, nullptr, "SetProxyDefault"}, {0x000F, nullptr, "SetBasicAuthorization"}, @@ -903,8 +929,8 @@ HTTP_C::HTTP_C() : ServiceFramework("http:C", 32) { {0x001F, nullptr, "GetResponseHeaderTimeout"}, {0x0020, nullptr, "GetResponseData"}, {0x0021, nullptr, "GetResponseDataTimeout"}, - {0x0022, nullptr, "GetResponseStatusCode"}, - {0x0023, nullptr, "GetResponseStatusCodeTimeout"}, + {0x0022, &HTTP_C::GetResponseStatusCode, "GetResponseStatusCode"}, + {0x0023, &HTTP_C::GetResponseStatusCodeTimeout, "GetResponseStatusCodeTimeout"}, {0x0024, nullptr, "AddTrustedRootCA"}, {0x0025, nullptr, "AddDefaultCert"}, {0x0026, nullptr, "SelectRootCertChain"}, diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http/http_c.h similarity index 83% rename from src/core/hle/service/http_c.h rename to src/core/hle/service/http/http_c.h index 490e06648..7b2045465 100644 --- a/src/core/hle/service/http_c.h +++ b/src/core/hle/service/http/http_c.h @@ -30,6 +30,10 @@ namespace Core { class System; } +namespace IPC { +class RequestParser; +} + namespace Service::HTTP { enum class RequestMethod : u8 { @@ -288,6 +292,17 @@ private: */ void CloseContext(Kernel::HLERequestContext& ctx); + /** + * HTTP_C::GetDownloadSizeState service function + * Inputs: + * 1 : Context handle + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Total content data downloaded so far + * 3 : Total content size from the "Content-Length" response header + */ + void GetDownloadSizeState(Kernel::HLERequestContext& ctx); + /** * HTTP_C::InitializeConnectionSession service function * Inputs: @@ -302,7 +317,7 @@ private: /** * HTTP_C::BeginRequest service function * Inputs: - * 1 : Context handle + * 1 : Context handle * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ @@ -311,12 +326,43 @@ private: /** * HTTP_C::BeginRequestAsync service function * Inputs: - * 1 : Context handle + * 1 : Context handle * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ void BeginRequestAsync(Kernel::HLERequestContext& ctx); + /** + * HTTP_C::ReceiveData service function + * Inputs: + * 1 : Context handle + * 2 : Buffer size + * 3 : (OutSize<<4) | 12 + * 4 : Output data pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void ReceiveData(Kernel::HLERequestContext& ctx); + + /** + * HTTP_C::ReceiveDataTimeout service function + * Inputs: + * 1 : Context handle + * 2 : Buffer size + * 3-4 : u64 nanoseconds delay + * 5 : (OutSize<<4) | 12 + * 6 : Output data pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void ReceiveDataTimeout(Kernel::HLERequestContext& ctx); + + /** + * ReceiveDataImpl: + * Implements ReceiveData and ReceiveDataTimeout service functions + */ + void ReceiveDataImpl(Kernel::HLERequestContext& ctx, bool timeout); + /** * HTTP_C::AddRequestHeader service function * Inputs: @@ -347,6 +393,33 @@ private: */ void AddPostDataAscii(Kernel::HLERequestContext& ctx); + /** + * HTTP_C::GetResponseStatusCode service function + * Inputs: + * 1 : Context handle + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : HTTP response status code + */ + void GetResponseStatusCode(Kernel::HLERequestContext& ctx); + + /** + * HTTP_C::GetResponseStatusCode service function + * Inputs: + * 1 : Context handle + * 2-3 : u64 nanoseconds timeout + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : HTTP response status code + */ + void GetResponseStatusCodeTimeout(Kernel::HLERequestContext& ctx); + + /** + * GetResponseStatusCodeImpl: + * Implements GetResponseStatusCode and GetResponseStatusCodeTimeout service functions + */ + void GetResponseStatusCodeImpl(Kernel::HLERequestContext& ctx, bool timeout); + /** * HTTP_C::SetClientCertContext service function * Inputs: @@ -408,6 +481,12 @@ private: */ void Finalize(Kernel::HLERequestContext& ctx); + [[nodiscard]] SessionData* EnsureSessionInitialized(Kernel::HLERequestContext& ctx, + IPC::RequestParser rp); + + [[nodiscard]] bool PerformStateChecks(Kernel::HLERequestContext& ctx, IPC::RequestParser rp, + Context::Handle context_handle); + void DecryptClCertA(); std::shared_ptr shared_memory = nullptr; diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic/mic_u.cpp similarity index 99% rename from src/core/hle/service/mic_u.cpp rename to src/core/hle/service/mic/mic_u.cpp index 95c12a9f9..bca6177c0 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic/mic_u.cpp @@ -16,7 +16,7 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" -#include "core/hle/service/mic_u.h" +#include "core/hle/service/mic/mic_u.h" SERVICE_CONSTRUCT_IMPL(Service::MIC::MIC_U) SERIALIZE_EXPORT_IMPL(Service::MIC::MIC_U) diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic/mic_u.h similarity index 100% rename from src/core/hle/service/mic_u.h rename to src/core/hle/service/mic/mic_u.h diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 91b56b12c..668b6cbb5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -19,22 +19,23 @@ #include "core/hle/service/apt/apt.h" #include "core/hle/service/boss/boss.h" #include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/y2r_u.h" #include "core/hle/service/cecd/cecd.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/csnd/csnd_snd.h" #include "core/hle/service/dlp/dlp.h" #include "core/hle/service/dsp/dsp_dsp.h" -#include "core/hle/service/err_f.h" +#include "core/hle/service/err/err_f.h" #include "core/hle/service/frd/frd.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" #include "core/hle/service/gsp/gsp.h" #include "core/hle/service/gsp/gsp_lcd.h" #include "core/hle/service/hid/hid.h" -#include "core/hle/service/http_c.h" +#include "core/hle/service/http/http_c.h" #include "core/hle/service/ir/ir.h" #include "core/hle/service/ldr_ro/ldr_ro.h" -#include "core/hle/service/mic_u.h" +#include "core/hle/service/mic/mic_u.h" #include "core/hle/service/mvd/mvd.h" #include "core/hle/service/ndm/ndm_u.h" #include "core/hle/service/news/news.h" @@ -50,9 +51,8 @@ #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/srv.h" -#include "core/hle/service/soc_u.h" -#include "core/hle/service/ssl_c.h" -#include "core/hle/service/y2r_u.h" +#include "core/hle/service/soc/soc_u.h" +#include "core/hle/service/ssl/ssl_c.h" #include "core/loader/loader.h" namespace Service { diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc/soc_u.cpp similarity index 98% rename from src/core/hle/service/soc_u.cpp rename to src/core/hle/service/soc/soc_u.cpp index 60e5f92ea..1b91fdaae 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc/soc_u.cpp @@ -18,7 +18,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" -#include "core/hle/service/soc_u.h" +#include "core/hle/service/soc/soc_u.h" #ifdef _WIN32 #include @@ -868,7 +868,7 @@ void SOC_U::Accept(Kernel::HLERequestContext& ctx) { rb.Push(ERR_INVALID_HANDLE); return; } - [[maybe_unused]] const auto max_addr_len = static_cast(rp.Pop()); + const auto max_addr_len = rp.Pop(); rp.PopPID(); sockaddr addr; socklen_t addr_len = sizeof(addr); @@ -889,6 +889,11 @@ void SOC_U::Accept(Kernel::HLERequestContext& ctx) { std::memcpy(ctr_addr_buf.data(), &ctr_addr, sizeof(ctr_addr)); } + if (ctr_addr_buf.size() > max_addr_len) { + LOG_WARNING(Frontend, "CTRSockAddr is too long, truncating data."); + ctr_addr_buf.resize(max_addr_len); + } + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); rb.Push(ret); @@ -1264,7 +1269,7 @@ void SOC_U::GetSockName(Kernel::HLERequestContext& ctx) { rb.Push(ERR_INVALID_HANDLE); return; } - [[maybe_unused]] const auto max_addr_len = rp.Pop(); + const auto max_addr_len = rp.Pop(); rp.PopPID(); sockaddr dest_addr; @@ -1278,6 +1283,11 @@ void SOC_U::GetSockName(Kernel::HLERequestContext& ctx) { if (ret != 0) ret = TranslateError(GET_ERRNO); + if (dest_addr_buff.size() > max_addr_len) { + LOG_WARNING(Frontend, "CTRSockAddr is too long, truncating data."); + dest_addr_buff.resize(max_addr_len); + } + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); rb.Push(ret); @@ -1358,7 +1368,7 @@ void SOC_U::GetPeerName(Kernel::HLERequestContext& ctx) { rb.Push(ERR_INVALID_HANDLE); return; } - [[maybe_unused]] const auto max_addr_len = rp.Pop(); + const auto max_addr_len = rp.Pop(); rp.PopPID(); sockaddr dest_addr; @@ -1374,6 +1384,11 @@ void SOC_U::GetPeerName(Kernel::HLERequestContext& ctx) { result = TranslateError(GET_ERRNO); } + if (dest_addr_buff.size() > max_addr_len) { + LOG_WARNING(Frontend, "CTRSockAddr is too long, truncating data."); + dest_addr_buff.resize(max_addr_len); + } + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); rb.Push(result); diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc/soc_u.h similarity index 100% rename from src/core/hle/service/soc_u.h rename to src/core/hle/service/soc/soc_u.h diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl/ssl_c.cpp similarity index 98% rename from src/core/hle/service/ssl_c.cpp rename to src/core/hle/service/ssl/ssl_c.cpp index 4eb41da17..df95a72aa 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl/ssl_c.cpp @@ -7,7 +7,7 @@ #include "core/core.h" #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/service/ssl_c.h" +#include "core/hle/service/ssl/ssl_c.h" SERIALIZE_EXPORT_IMPL(Service::SSL::SSL_C) namespace Service::SSL { diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl/ssl_c.h similarity index 100% rename from src/core/hle/service/ssl_c.h rename to src/core/hle/service/ssl/ssl_c.h diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp index d6f7023f7..5ea646924 100644 --- a/src/core/hw/y2r.cpp +++ b/src/core/hw/y2r.cpp @@ -12,7 +12,7 @@ #include "common/microprofileui.h" #include "common/vector_math.h" #include "core/core.h" -#include "core/hle/service/y2r_u.h" +#include "core/hle/service/cam/y2r_u.h" #include "core/hw/y2r.h" #include "core/memory.h"