From 536e3e99a89825a34833047c7fcb60ba4da1fb6e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 17 Feb 2021 23:28:05 -0800 Subject: [PATCH] htcs: hook up CreateSocket/RpcClient Begin<>/End<> --- .../source/htc/server/rpc/htc_rpc_client.hpp | 103 ++++++++++++++++++ .../source/htc/server/rpc/htc_rpc_tasks.hpp | 6 +- .../source/htcs/impl/htcs_manager.cpp | 10 +- .../source/htcs/impl/htcs_manager_impl.cpp | 2 +- .../source/htcs/impl/htcs_service.cpp | 48 ++++++++ .../source/htcs/impl/htcs_service.hpp | 2 + .../source/htcs/impl/htcs_util.cpp | 2 +- .../source/htcs/impl/rpc/htcs_rpc_tasks.hpp | 66 +++++++++++ .../include/vapours/results/htc_results.hpp | 10 +- 9 files changed, 235 insertions(+), 14 deletions(-) create mode 100644 libraries/libstratosphere/source/htcs/impl/htcs_service.cpp create mode 100644 libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp index 1d8bf9fa3..ef13c7f7b 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp @@ -22,6 +22,27 @@ namespace ams::htc::server::rpc { + template + concept IsRpcTask = std::derived_from; + + struct RpcTaskFunctionTraits { + public: + template + static std::tuple GetArgsImpl(R(C::*)(A...)); + }; + + template requires IsRpcTask + using RpcTaskArgumentsType = decltype(RpcTaskFunctionTraits::GetArgsImpl(&T::SetArguments)); + + template requires IsRpcTask + using RpcTaskResultType = decltype(RpcTaskFunctionTraits::GetArgsImpl(&T::GetResult)); + + template + concept IsRpcTaskArgumentsType = IsRpcTask && std::same_as, RpcTaskArgumentsType>; + + template + concept IsRpcTaskResultType = IsRpcTask && std::same_as, RpcTaskResultType>; + class RpcClient { private: /* TODO: where is this value coming from, again? */ @@ -68,6 +89,88 @@ namespace ams::htc::server::rpc { Result ReceiveHeader(RpcPacket *header); Result ReceiveBody(char *dst, size_t size); Result SendRequest(const char *src, size_t size); + public: + void Wait(u32 task_id) { + os::WaitEvent(m_task_table.Get(task_id)->GetEvent()); + } + + template requires IsRpcTaskArgumentsType + Result Begin(u32 *out_task_id, Args... args) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Allocate a free task id. */ + u32 task_id; + R_TRY(m_task_id_free_list.Allocate(std::addressof(task_id))); + + /* Create the new task. */ + T *task = m_task_table.New(task_id); + m_task_active[task_id] = true; + + /* Ensure we clean up the task, if we fail after this. */ + auto task_guard = SCOPE_GUARD { + m_task_active[task_id] = false; + m_task_table.Delete(task_id); + m_task_id_free_list.Free(task_id); + }; + + /* Set the task arguments. */ + R_TRY(task->SetArguments(args...)); + + /* Clear the task's events. */ + os::ClearEvent(std::addressof(m_receive_buffer_available_events[task_id])); + os::ClearEvent(std::addressof(m_send_buffer_available_events[task_id])); + + /* Add the task to our queue if we can, or cancel it. */ + if (m_thread_running) { + m_task_queue.Add(task_id, PacketCategory::Request); + } else { + task->Cancel(RpcTaskCancelReason::QueueNotAvailable); + } + + /* Set the output task id. */ + *out_task_id = task_id; + + /* We succeeded. */ + task_guard.Cancel(); + return ResultSuccess(); + } + + template requires IsRpcTaskResultType + Result End(u32 task_id, Args... args) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Get the task. */ + T *task = m_task_table.Get(task_id); + R_UNLESS(task != nullptr, htc::ResultInvalidTaskId()); + + /* Ensure the task is freed if it needs to be, when we're done. */ + auto task_guard = SCOPE_GUARD { + m_task_active[task_id] = false; + m_task_table.Delete(task_id); + m_task_id_free_list.Free(task_id); + }; + + /* If the task was cancelled, handle that. */ + if (task->GetTaskState() == RpcTaskState::Cancelled) { + switch (task->GetTaskCancelReason()) { + case RpcTaskCancelReason::One: + task_guard.Cancel(); + return htc::ResultUnknown2021(); + case RpcTaskCancelReason::Two: + return htc::ResultCancelled(); + case RpcTaskCancelReason::QueueNotAvailable: + return htc::ResultTaskQueueNotAvailable(); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + /* Get the task's result. */ + R_TRY(task->GetResult(args...)); + + return ResultSuccess(); + } }; } diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp index 848c1ee3c..18de1cf54 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp @@ -39,8 +39,10 @@ namespace ams::htc::server::rpc { static_assert(sizeof(RpcPacket) == 0x40); enum class RpcTaskCancelReason { - None = 0, - /* ... */ + None = 0, + One = 1, + Two = 2, + QueueNotAvailable = 3, }; enum class RpcTaskState { diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp index 51e7a7296..2d20fd85a 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp @@ -220,7 +220,7 @@ namespace ams::htcs::impl { } else { if (htc::ResultCancelled::Includes(result)) { *out_err = HTCS_ENETDOWN; - } else if (htc::ResultUnknown2033::Includes(result)) { + } else if (htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_err = HTCS_EINTR; } else { *out_err = ConvertResultToErrorCode(result); @@ -247,7 +247,7 @@ namespace ams::htcs::impl { *out_size = -1; } } else { - if (htc::ResultUnknown2033::Includes(result)) { + if (htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_err = HTCS_EINTR; } else { *out_err = ConvertResultToErrorCode(result); @@ -279,7 +279,7 @@ namespace ams::htcs::impl { *out_size = -1; } } else { - if (htc::ResultUnknown2033::Includes(result)) { + if (htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_err = HTCS_EINTR; } else { *out_err = ConvertResultToErrorCode(result); @@ -320,7 +320,7 @@ namespace ams::htcs::impl { *out_size = -1; } } else { - if (htc::ResultUnknown2033::Includes(result)) { + if (htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_err = HTCS_EINTR; } else { *out_err = ConvertResultToErrorCode(result); @@ -348,7 +348,7 @@ namespace ams::htcs::impl { *out_size = -1; } } else { - if (htc::ResultCancelled::Includes(result) || htc::ResultUnknown2033::Includes(result)) { + if (htc::ResultCancelled::Includes(result) || htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_err = 0; } else { *out_err = ConvertResultToErrorCode(result); diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp index 0c0b30daa..75312e134 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp @@ -107,7 +107,7 @@ namespace ams::htcs::impl { /* Continue the send. */ s64 continue_size; const Result result = m_service.SendSmallContinue(std::addressof(continue_size), buffer, size, task_id, desc); - if (R_SUCCEEDED(result) || htcs::ResultUnknown2023::Includes(result) || htc::ResultUnknown2033::Includes(result)) { + if (R_SUCCEEDED(result) || htcs::ResultUnknown2023::Includes(result) || htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_task_id = task_id; *out_handle = handle; } else { diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp new file mode 100644 index 000000000..893ce65ed --- /dev/null +++ b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "htcs_service.hpp" +#include "rpc/htcs_rpc_tasks.hpp" + +namespace ams::htcs::impl { + + void HtcsService::WaitTask(u32 task_id) { + return m_rpc_client->Wait(task_id); + } + + Result HtcsService::CreateSocket(s32 *out_err, s32 *out_desc, bool enable_disconnection_emulation) { + /* Set disconnection emulation enabled. */ + m_driver->SetDisconnectionEmulationEnabled(enable_disconnection_emulation); + + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id))); + + /* Wait for the task to complete. */ + this->WaitTask(task_id); + + /* Finish the task. */ + htcs::SocketError err; + s32 desc; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), std::addressof(desc))); + + /* Set output. */ + *out_err = err; + *out_desc = desc; + return ResultSuccess(); + } + +} diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp b/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp index e00b887c2..2ae89cf55 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp @@ -62,6 +62,8 @@ namespace ams::htcs::impl { Result SelectStart(u32 *out_task_id, Handle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec); Result SelectEnd(s32 *out_err, s32 *out_res, Span read_handles, Span write_handles, Span exception_handles, u32 task_id); + private: + void WaitTask(u32 task_id); }; } diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp index 448648c8d..b30fdb749 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp @@ -32,7 +32,7 @@ namespace ams::htcs::impl { R_CATCH(htc::ResultUnknown2021) { return HTCS_EINTR; } R_CATCH(htc::ResultInvalidTaskId) { return HTCS_EINTR; } R_CATCH(htc::ResultCancelled) { return HTCS_EINTR; } - R_CATCH(htc::ResultUnknown2033) { return HTCS_ENETDOWN; } + R_CATCH(htc::ResultTaskQueueNotAvailable) { return HTCS_ENETDOWN; } R_CATCH(htclow::ResultConnectionFailure) { return HTCS_ENETDOWN; } R_CATCH(htclow::ResultChannelNotExist) { return HTCS_ENOTCONN; } R_CATCH_ALL() { return HTCS_EUNKNOWN; } diff --git a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp new file mode 100644 index 000000000..efc87f224 --- /dev/null +++ b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "../../../htc/server/rpc/htc_rpc_tasks.hpp" + +namespace ams::htcs::impl::rpc { + + enum class HtcsTaskType { + Receive = 0, + Send = 1, + Shutdown = 2, + Close = 3, + Connect = 4, + Listen = 5, + Accept = 6, + Socket = 7, + Bind = 8, + Fcntl = 9, + ReceiveSmall = 10, + SendSmall = 11, + Select = 12, + }; + + constexpr inline const s16 ProtocolVersion = 4; + + class HtcsTask : public htc::server::rpc::Task { + private: + HtcsTaskType m_task_type; + s16 m_version; + public: + HtcsTask(HtcsTaskType type) : m_task_type(type), m_version(ProtocolVersion) { /* ... */ } + + HtcsTaskType GetTaskType() const { return m_task_type; } + s16 GetVersion() const { return m_version; } + }; + + class SocketTask : public HtcsTask { + private: + htcs::SocketError m_err; + s32 m_desc; + public: + SocketTask() : HtcsTask(HtcsTaskType::Socket) { /* ... */ } + + Result SetArguments(); + void Complete(htcs::SocketError err, s32 desc); + Result GetResult(htcs::SocketError *out_err, s32 *out_desc); + public: + virtual Result ProcessResponse(const char *data, size_t size) override; + virtual Result CreateRequest(size_t *out, char *data, size_t size, u32 task_id) override; + }; + +} diff --git a/libraries/libvapours/include/vapours/results/htc_results.hpp b/libraries/libvapours/include/vapours/results/htc_results.hpp index 8ff7ee0f9..3f1a5752b 100644 --- a/libraries/libvapours/include/vapours/results/htc_results.hpp +++ b/libraries/libvapours/include/vapours/results/htc_results.hpp @@ -28,11 +28,11 @@ namespace ams::htc { R_DEFINE_ERROR_RESULT(Unknown, 1023); - R_DEFINE_ERROR_RESULT(Unknown2001, 2001); - R_DEFINE_ERROR_RESULT(InvalidTaskId, 2003); - R_DEFINE_ERROR_RESULT(InvalidSize, 2011); - R_DEFINE_ERROR_RESULT(Unknown2021, 2021); - R_DEFINE_ERROR_RESULT(Unknown2033, 2033); + R_DEFINE_ERROR_RESULT(Unknown2001, 2001); + R_DEFINE_ERROR_RESULT(InvalidTaskId, 2003); + R_DEFINE_ERROR_RESULT(InvalidSize, 2011); + R_DEFINE_ERROR_RESULT(Unknown2021, 2021); + R_DEFINE_ERROR_RESULT(TaskQueueNotAvailable, 2033); R_DEFINE_ERROR_RESULT(Unknown2101, 2101); R_DEFINE_ERROR_RESULT(OutOfRpcTask, 2102);