diff --git a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp index 16c2ab463..9a0a83e41 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp @@ -632,8 +632,9 @@ namespace ams::sf::impl { private: MoveHandle move_handles[NumMove]; CopyHandle copy_handles[NumCopy]; + bool copy_managed[NumCopy]; public: - constexpr OutHandleHolder() : move_handles(), copy_handles() { /* ... */ } + constexpr OutHandleHolder() : move_handles(), copy_handles(), copy_managed() { /* ... */ } template constexpr inline MoveHandle *GetMoveHandlePointer() { @@ -647,8 +648,15 @@ namespace ams::sf::impl { return ©_handles[Index]; } - constexpr inline void CopyTo(const HipcRequest &response, const size_t num_out_object_handles) { - #define _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { response.copy_handles[n] = copy_handles[n].GetValue(); } } while (0) + template + constexpr inline bool *GetCopyHandleManagedPointer() { + static_assert(Index < NumCopy, "Index < NumCopy"); + return ©_managed[Index]; + } + + constexpr inline void CopyTo(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, const size_t num_out_object_handles) { + ctx.handles_to_close->num_handles = 0; + #define _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { const auto handle = copy_handles[n].GetValue(); response.copy_handles[n] = handle; if (copy_managed[n]) { ctx.handles_to_close->handles[ctx.handles_to_close->num_handles++] = handle; } } } while (0) _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(2); @@ -1035,7 +1043,7 @@ namespace ams::sf::impl { if constexpr (std::is_same>::value) { return T(out_handles_holder.template GetMoveHandlePointer()); } else if constexpr (std::is_same>::value) { - return T(out_handles_holder.template GetCopyHandlePointer()); + return T(out_handles_holder.template GetCopyHandlePointer(), out_handles_holder.template GetCopyHandleManagedPointer()); } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); } @@ -1179,7 +1187,7 @@ namespace ams::sf::impl { ImplProcessorType::SetOutBuffers(response, buffers, is_buffer_map_alias); /* Set out handles. */ - out_handles_holder.CopyTo(response, runtime_metadata.GetOutObjectCount()); + out_handles_holder.CopyTo(ctx, response, runtime_metadata.GetOutObjectCount()); /* Set output objects. */ #define _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(n) do { \ diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp index 52999127e..047a18737 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp @@ -133,8 +133,11 @@ namespace ams::sf { private: using T = CopyHandle; using Base = impl::OutHandleImpl; + private: + bool *m_managed; public: - constexpr Out(T *p) : Base(p) { /* ... */ } + constexpr Out(T *p) : Base(p), m_managed(nullptr) { /* ... */ } + constexpr Out(T *p, bool *m) : Base(p), m_managed(m) { /* ... */ } constexpr void SetValue(const Handle &value) { Base::SetValue(value); @@ -144,6 +147,11 @@ namespace ams::sf { Base::SetValue(value); } + constexpr void SetManaged(bool m) { + AMS_ASSERT(m_managed != nullptr); + *m_managed = m; + } + constexpr const T &GetValue() const { return Base::GetValue(); } diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp index b0250db4a..68d1175be 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp @@ -42,6 +42,7 @@ namespace ams::htc::server::rpc { m_task_id_free_list(g_task_id_free_list), m_task_table(g_task_table), m_task_active(), + m_is_htcs_task(), m_task_queue(), m_cancelled(false), m_thread_running(false) @@ -63,6 +64,7 @@ namespace ams::htc::server::rpc { m_task_id_free_list(g_task_id_free_list), m_task_table(g_task_table), m_task_active(), + m_is_htcs_task(), m_task_queue(), m_cancelled(false), m_thread_running(false) @@ -173,8 +175,7 @@ namespace ams::htc::server::rpc { /* Cancel all tasks. */ for (size_t i = 0; i < MaxRpcCount; ++i) { if (m_task_active[i]) { - /* TODO: enum member */ - m_task_table.Get(i)->Cancel(static_cast(2)); + m_task_table.Get(i)->Cancel(RpcTaskCancelReason::ClientFinalized); } } } @@ -235,6 +236,7 @@ namespace ams::htc::server::rpc { /* If the task is canceled, free it. */ if (task->GetTaskState() == RpcTaskState::Cancelled) { m_task_active[header->task_id] = false; + m_is_htcs_task[header->task_id] = false; m_task_table.Delete(header->task_id); m_task_id_free_list.Free(header->task_id); continue; @@ -340,4 +342,128 @@ namespace ams::htc::server::rpc { return ResultSuccess(); } + void RpcClient::CancelBySocket(s32 handle) { + /* Check if we need to cancel each task. */ + for (size_t i = 0; i < MaxRpcCount; ++i) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that the task is active and is an htcs task. */ + if (!m_task_active[i] || !m_is_htcs_task[i]) { + continue; + } + + /* Get the htcs task. */ + auto *htcs_task = m_task_table.Get(i); + + /* Handle the case where the task handle is the one we're cancelling. */ + if (this->GetTaskHandle(i) == handle) { + /* If the task is complete, free it. */ + if (htcs_task->GetTaskState() == RpcTaskState::Completed) { + m_task_active[i] = false; + m_is_htcs_task[i] = false; + m_task_table.Delete(i); + m_task_id_free_list.Free(i); + } else { + /* If the task is a send task, notify. */ + if (htcs_task->GetTaskType() == htcs::impl::rpc::HtcsTaskType::Send) { + m_task_queue.Add(i, PacketCategory::Notification); + } + + /* Cancel the task. */ + htcs_task->Cancel(RpcTaskCancelReason::BySocket); + } + + /* The task has been cancelled, so we can move on. */ + continue; + } + + /* Handle the case where the task is a select task. */ + if (htcs_task->GetTaskType() == htcs::impl::rpc::HtcsTaskType::Select) { + /* Get the select task. */ + auto *select_task = m_task_table.Get(i); + + /* Get the handle counts. */ + const auto num_read = select_task->GetReadHandleCount(); + const auto num_write = select_task->GetWriteHandleCount(); + const auto num_exception = select_task->GetExceptionHandleCount(); + const auto total = num_read + num_write + num_exception; + + /* Get the handle array. */ + const auto *handles = select_task->GetHandles(); + + /* Check each handle. */ + for (auto handle_idx = 0; handle_idx < total; ++handle_idx) { + if (handles[handle_idx] == handle) { + /* If the select is complete, free it. */ + if (select_task->GetTaskState() == RpcTaskState::Completed) { + m_task_active[i] = false; + m_is_htcs_task[i] = false; + m_task_table.Delete(i); + m_task_id_free_list.Free(i); + } else { + /* Cancel the task. */ + select_task->Cancel(RpcTaskCancelReason::BySocket); + } + } + } + } + } + } + + s32 RpcClient::GetTaskHandle(u32 task_id) { + /* Check pre-conditions. */ + AMS_ASSERT(m_task_active[task_id]); + AMS_ASSERT(m_is_htcs_task[task_id]); + + /* Get the htcs task. */ + auto *task = m_task_table.Get(task_id); + + /* Check that the task has a handle. */ + if (!m_task_active[task_id] || !m_is_htcs_task[task_id] || task == nullptr) { + return -1; + } + + /* Get the task's type. */ + const auto type = task->GetTaskType(); + + /* Check that the task is new enough. */ + if (task->GetVersion() == 3) { + if (type == htcs::impl::rpc::HtcsTaskType::Receive || type == htcs::impl::rpc::HtcsTaskType::Send) { + return -1; + } + } + + /* Get the handle from the task. */ + switch (type) { + case htcs::impl::rpc::HtcsTaskType::Receive: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Send: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Shutdown: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Close: + return -1; + case htcs::impl::rpc::HtcsTaskType::Connect: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Listen: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Accept: + return static_cast(task)->GetServerHandle(); + case htcs::impl::rpc::HtcsTaskType::Socket: + return -1; + case htcs::impl::rpc::HtcsTaskType::Bind: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Fcntl: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::ReceiveSmall: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::SendSmall: + return static_cast(task)->GetHandle(); + case htcs::impl::rpc::HtcsTaskType::Select: + return -1; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + } 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 9b44488c4..c4715652a 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp @@ -19,6 +19,7 @@ #include "htc_rpc_task_table.hpp" #include "htc_rpc_task_queue.hpp" #include "htc_rpc_task_id_free_list.hpp" +#include "../../../htcs/impl/rpc/htcs_rpc_tasks.hpp" namespace ams::htc::server::rpc { @@ -61,6 +62,7 @@ namespace ams::htc::server::rpc { RpcTaskIdFreeList &m_task_id_free_list; RpcTaskTable &m_task_table; bool m_task_active[MaxRpcCount]; + bool m_is_htcs_task[MaxRpcCount]; RpcTaskQueue m_task_queue; bool m_cancelled; bool m_thread_running; @@ -104,10 +106,12 @@ namespace ams::htc::server::rpc { /* Create the new task. */ T *task = m_task_table.New(task_id); m_task_active[task_id] = true; + m_is_htcs_task[task_id] = htcs::impl::rpc::IsHtcsTask; /* Ensure we clean up the task, if we fail after this. */ auto task_guard = SCOPE_GUARD { m_task_active[task_id] = false; + m_is_htcs_task[task_id] = false; m_task_table.Delete(task_id); m_task_id_free_list.Free(task_id); }; @@ -134,6 +138,24 @@ namespace ams::htc::server::rpc { return ResultSuccess(); } + template requires IsRpcTask + ALWAYS_INLINE Result GetResultImpl(std::index_sequence, u32 task_id, RpcTaskResultType... 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()); + + /* Check that the task is completed. */ + R_UNLESS(task->GetTaskState() == RpcTaskState::Completed, htc::ResultTaskNotCompleted()); + + /* Get the task's result. */ + R_TRY(task->GetResult(args...)); + + return ResultSuccess(); + } + template requires IsRpcTask ALWAYS_INLINE Result EndImpl(std::index_sequence, u32 task_id, RpcTaskResultType... args) { /* Lock ourselves. */ @@ -146,6 +168,7 @@ namespace ams::htc::server::rpc { /* 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_is_htcs_task[task_id] = false; m_task_table.Delete(task_id); m_task_id_free_list.Free(task_id); }; @@ -153,10 +176,10 @@ namespace ams::htc::server::rpc { /* If the task was cancelled, handle that. */ if (task->GetTaskState() == RpcTaskState::Cancelled) { switch (task->GetTaskCancelReason()) { - case RpcTaskCancelReason::One: + case RpcTaskCancelReason::BySocket: task_guard.Cancel(); - return htc::ResultUnknown2021(); - case RpcTaskCancelReason::Two: + return htc::ResultTaskCancelled(); + case RpcTaskCancelReason::ClientFinalized: return htc::ResultCancelled(); case RpcTaskCancelReason::QueueNotAvailable: return htc::ResultTaskQueueNotAvailable(); @@ -169,20 +192,178 @@ namespace ams::htc::server::rpc { return ResultSuccess(); } + + s32 GetTaskHandle(u32 task_id); public: void Wait(u32 task_id) { os::WaitEvent(m_task_table.Get(task_id)->GetEvent()); } + Handle DetachReadableHandle(u32 task_id) { + return os::DetachReadableHandleOfSystemEvent(m_task_table.Get(task_id)->GetSystemEvent()); + } + + void CancelBySocket(s32 handle); + template requires (IsRpcTask && sizeof...(Args) == std::tuple_size>::value) Result Begin(u32 *out_task_id, Args &&... args) { return this->BeginImpl(std::make_index_sequence>::value>(), out_task_id, std::forward(args)...); } + template requires (IsRpcTask && sizeof...(Args) == std::tuple_size>::value) + Result GetResult(u32 task_id, Args &&... args) { + return this->GetResultImpl(std::make_index_sequence>::value>(), task_id, std::forward(args)...); + } + template requires (IsRpcTask && sizeof...(Args) == std::tuple_size>::value) Result End(u32 task_id, Args &&... args) { return this->EndImpl(std::make_index_sequence>::value>(), task_id, std::forward(args)...); } + + template requires IsRpcTask + Result VerifyTaskIdWitHandle(u32 task_id, s32 handle) { + /* 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()); + + /* Check the task handle. */ + R_UNLESS(task->GetHandle() == handle, htc::ResultInvalidTaskId()); + + return ResultSuccess(); + } + + template requires IsRpcTask + Result Notify(u32 task_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that our queue is available. */ + R_UNLESS(m_thread_running, htc::ResultTaskQueueNotAvailable()); + + /* Get the task. */ + T *task = m_task_table.Get(task_id); + R_UNLESS(task != nullptr, htc::ResultInvalidTaskId()); + + /* Add notification to our queue. */ + m_task_queue.Add(task_id, PacketCategory::Notification); + + return ResultSuccess(); + } + + template requires IsRpcTask + void WaitNotification(u32 task_id) { + /* Get the task from the table, releasing our lock afterwards. */ + T *task; + { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Get the task. */ + task = m_task_table.Get(task_id); + } + + /* Wait for a notification. */ + task->WaitNotification(); + } + + template requires IsRpcTask + bool IsCancelled(u32 task_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Get the task. */ + T *task = m_task_table.Get(task_id); + + /* Check the task state. */ + return task != nullptr && task->GetTaskState() == RpcTaskState::Cancelled; + } + + template requires IsRpcTask + bool IsCompleted(u32 task_id) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Get the task. */ + T *task = m_task_table.Get(task_id); + + /* Check the task state. */ + return task != nullptr && task->GetTaskState() == RpcTaskState::Completed; + } + + template requires IsRpcTask + Result SendContinue(u32 task_id, const void *buffer, s64 buffer_size) { + /* 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()); + + /* If the task was cancelled, handle that. */ + if (task->GetTaskState() == RpcTaskState::Cancelled) { + switch (task->GetTaskCancelReason()) { + case RpcTaskCancelReason::QueueNotAvailable: + return htc::ResultTaskQueueNotAvailable(); + default: + return htc::ResultTaskCancelled(); + } + } + + /* Set the task's buffer. */ + if (buffer_size > 0) { + task->SetBuffer(buffer, buffer_size); + os::SignalEvent(std::addressof(m_send_buffer_available_events[task_id])); + } + + return ResultSuccess(); + } + + template requires IsRpcTask + Result ReceiveContinue(u32 task_id, void *buffer, s64 buffer_size) { + /* Get the task's buffer, and prepare to receive. */ + const void *result_buffer; + s64 result_size; + { + /* 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()); + + /* If the task was cancelled, handle that. */ + if (task->GetTaskState() == RpcTaskState::Cancelled) { + switch (task->GetTaskCancelReason()) { + case RpcTaskCancelReason::QueueNotAvailable: + return htc::ResultTaskQueueNotAvailable(); + default: + return htc::ResultTaskCancelled(); + } + } + + /* Get the result size. */ + result_size = task->GetResultSize(); + R_SUCCEED_IF(result_size == 0); + + /* Get the result buffer. */ + result_buffer = task->GetBuffer(); + } + + /* Wait for the receive buffer to become available. */ + os::WaitEvent(std::addressof(m_receive_buffer_available_events[task_id])); + + /* Check that we weren't cancelled. */ + R_UNLESS(!m_cancelled, htc::ResultCancelled()); + + /* Copy the received data. */ + AMS_ASSERT(0 <= result_size && result_size <= buffer_size); + std::memcpy(buffer, result_buffer, result_size); + + return ResultSuccess(); + } }; } diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp index f283f9232..91f472e33 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp @@ -31,9 +31,10 @@ namespace ams::htc::server::rpc { class RpcTaskTable { private: - /* TODO: How is this variable derived...? */ - /* Nintendo has a value of 0xE1D8, which is deeply magic. */ - static constexpr size_t MaxTaskSize = 0xA000; + /* htcs::ReceiveSmallTask/htcs::ReceiveSendTask are the largest tasks, containing an inline 0xE000 buffer. */ + /* We allow for ~0x100 task overhead from the additional events those contain. */ + /* NOTE: Nintnedo hardcodes a maximum size of 0xE1D8, despite SendSmallTask being 0xE098 as of latest check. */ + static constexpr size_t MaxTaskSize = 0xE100; using TaskStorage = typename std::aligned_storage::type; private: bool m_valid[MaxRpcCount]; 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 18de1cf54..0b6019dc8 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp @@ -40,8 +40,8 @@ namespace ams::htc::server::rpc { enum class RpcTaskCancelReason { None = 0, - One = 1, - Two = 2, + BySocket = 1, + ClientFinalized = 2, QueueNotAvailable = 3, }; diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp index 6b5aff2e3..0999b284d 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp @@ -296,7 +296,7 @@ namespace ams::htcs::impl { s64 size; R_TRY_CATCH(m_impl->ContinueSend(std::addressof(size), buffer, buffer_size, task_id, desc)) { R_CONVERT(htclow::ResultInvalidChannelState, tma::ResultUnknown()) - R_CONVERT(htc::ResultUnknown2021, tma::ResultUnknown()) + R_CONVERT(htc::ResultTaskCancelled, tma::ResultUnknown()) } R_END_TRY_CATCH; /* Set output. */ @@ -359,7 +359,7 @@ namespace ams::htcs::impl { Result HtcsManager::StartSelect(u32 *out_task_id, Handle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec) { /* Invoke our implementation. */ R_TRY_CATCH(m_impl->StartSelect(out_task_id, out_handle, read_handles, write_handles, exception_handles, tv_sec, tv_usec)) { - R_CONVERT(htc::ResultUnknown2021, tma::ResultUnknown()) + R_CONVERT(htc::ResultTaskCancelled, tma::ResultUnknown()) } R_END_TRY_CATCH; return ResultSuccess(); @@ -367,11 +367,12 @@ namespace ams::htcs::impl { Result HtcsManager::EndSelect(s32 *out_err, s32 *out_count, Span read_handles, Span write_handles, Span exception_handles, u32 task_id) { /* Invoke our implementation. */ - s32 err, res; - const Result result = m_impl->EndSelect(std::addressof(err), std::addressof(res), read_handles, write_handles, exception_handles, task_id); + s32 err; + bool empty; + const Result result = m_impl->EndSelect(std::addressof(err), std::addressof(empty), read_handles, write_handles, exception_handles, task_id); /* Set output. */ - if (R_SUCCEEDED(result) && res == 0) { + if (R_SUCCEEDED(result) && !empty) { *out_err = err; if (err == 0) { const auto num_read = std::count_if(read_handles.begin(), read_handles.end(), [](int handle) { return handle != 0; }); diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp index 37644a727..9b4fb5c11 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::ResultTaskQueueNotAvailable::Includes(result)) { + if (R_SUCCEEDED(result) || htcs::ResultCompleted::Includes(result) || htc::ResultTaskQueueNotAvailable::Includes(result)) { *out_task_id = task_id; *out_handle = handle; } else { @@ -162,12 +162,13 @@ namespace ams::htcs::impl { const Result result = m_service.SelectStart(std::addressof(task_id), std::addressof(handle), read_handles, write_handles, exception_handles, tv_sec, tv_usec); /* Ensure our state ends up clean. */ - if (htcs::ResultUnknown2021::Includes(result)) { + if (htcs::ResultCancelled::Includes(result)) { os::SystemEventType event; os::AttachReadableHandleToSystemEvent(std::addressof(event), handle, true, os::EventClearMode_ManualClear); - s32 err, res; - m_service.SelectEnd(std::addressof(err), std::addressof(res), Span{}, Span{}, Span{}, task_id); + s32 err; + bool empty; + m_service.SelectEnd(std::addressof(err), std::addressof(empty), Span{}, Span{}, Span{}, task_id); os::DestroySystemEvent(std::addressof(event)); } else { @@ -178,8 +179,8 @@ namespace ams::htcs::impl { return result; } - Result HtcsManagerImpl::EndSelect(s32 *out_err, s32 *out_res, Span read_handles, Span write_handles, Span exception_handles, u32 task_id) { - return m_service.SelectEnd(out_err, out_res, read_handles, write_handles, exception_handles, task_id); + Result HtcsManagerImpl::EndSelect(s32 *out_err, bool *out_empty, Span read_handles, Span write_handles, Span exception_handles, u32 task_id) { + return m_service.SelectEnd(out_err, out_empty, read_handles, write_handles, exception_handles, task_id); } } diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.hpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.hpp index 5b2926864..921a00f76 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.hpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.hpp @@ -70,7 +70,7 @@ namespace ams::htcs::impl { Result EndRecv(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc); Result StartSelect(u32 *out_task_id, Handle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec); - Result EndSelect(s32 *out_err, s32 *out_res, Span read_handles, Span write_handles, Span exception_handles, u32 task_id); + Result EndSelect(s32 *out_err, bool *out_empty, Span read_handles, Span write_handles, Span exception_handles, u32 task_id); }; } diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp index 5f4f3697a..6fd77f87a 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp @@ -82,7 +82,7 @@ namespace ams::htcs::impl { R_TRY(m_rpc_client->End(task_id, std::addressof(err))); /* Set output. */ - *out_err = err; + *out_err = err; return ResultSuccess(); } @@ -104,34 +104,302 @@ namespace ams::htcs::impl { R_TRY(m_rpc_client->End(task_id, std::addressof(err))); /* Set output. */ - *out_err = err; + *out_err = err; return ResultSuccess(); } - Result HtcsService::Listen(s32 *out_err, s32 desc, s32 backlog_count); - Result HtcsService::Receive(s32 *out_err, s64 *out_size, char *buffer, size_t size, s32 desc, s32 flags); - Result HtcsService::Send(s32 *out_err, s64 *out_size, const char *buffer, size_t size, s32 desc, s32 flags); - Result HtcsService::Shutdown(s32 *out_err, s32 desc, s32 how); - Result HtcsService::Fcntl(s32 *out_err, s32 *out_res, s32 desc, s32 command, s32 value); + Result HtcsService::Listen(s32 *out_err, s32 desc, s32 backlog_count) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, backlog_count)); - Result HtcsService::AcceptStart(u32 *out_task_id, Handle *out_handle, s32 desc); - Result HtcsService::AcceptResults(s32 *out_err, s32 *out_desc, SockAddrHtcs *out_address, u32 task_id, s32 desc); + /* Wait for the task to complete. */ + this->WaitTask(task_id); - Result HtcsService::ReceiveSmallStart(u32 *out_task_id, Handle *out_handle, s64 size, s32 desc, s32 flags); - Result HtcsService::ReceiveSmallResults(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc); + /* Finish the task. */ + htcs::SocketError err; + R_TRY(m_rpc_client->End(task_id, std::addressof(err))); - Result HtcsService::SendSmallStart(u32 *out_task_id, Handle *out_handle, s32 desc, s64 size, s32 flags); - Result HtcsService::SendSmallContinue(s64 *out_size, const char *buffer, s64 buffer_size, u32 task_id, s32 desc); - Result HtcsService::SendSmallResults(s32 *out_err, s64 *out_size, u32 task_id, s32 desc); + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } - Result HtcsService::SendStart(u32 *out_task_id, Handle *out_handle, s32 desc, s64 size, s32 flags); - Result HtcsService::SendContinue(s64 *out_size, const char *buffer, s64 buffer_size, u32 task_id, s32 desc); - Result HtcsService::SendResults(s32 *out_err, s64 *out_size, u32 task_id, s32 desc); + Result HtcsService::Receive(s32 *out_err, s64 *out_size, char *buffer, s64 size, s32 desc, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); - Result HtcsService::ReceiveStart(u32 *out_task_id, Handle *out_handle, s64 size, s32 desc, s32 flags); - Result HtcsService::ReceiveResults(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc); + /* Wait for the task to complete. */ + this->WaitTask(task_id); - Result HtcsService::SelectStart(u32 *out_task_id, Handle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec); - Result HtcsService::SelectEnd(s32 *out_err, s32 *out_res, Span read_handles, Span write_handles, Span exception_handles, u32 task_id); + /* Finish the task. */ + R_TRY(this->ReceiveResults(out_err, out_size, buffer, size, task_id, desc)); + + return ResultSuccess(); + } + + Result HtcsService::Send(s32 *out_err, s64 *out_size, const char *buffer, s64 size, s32 desc, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); + + /* Send the data. */ + s64 cont_size; + const Result result = this->SendContinue(std::addressof(cont_size), buffer, size, task_id, desc); + if (R_FAILED(result)) { + return this->SendResults(out_err, out_size, task_id, desc); + } + + /* Wait for the task to complete. */ + this->WaitTask(task_id); + + /* Finish the task. */ + R_TRY(this->SendResults(out_err, out_size, task_id, desc)); + + return ResultSuccess(); + } + + Result HtcsService::Shutdown(s32 *out_err, s32 desc, s32 how) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, static_cast(how))); + + /* Wait for the task to complete. */ + this->WaitTask(task_id); + + /* Finish the task. */ + htcs::SocketError err; + R_TRY(m_rpc_client->End(task_id, std::addressof(err))); + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + Result HtcsService::Fcntl(s32 *out_err, s32 *out_res, s32 desc, s32 command, s32 value) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, command, value)); + + /* Wait for the task to complete. */ + this->WaitTask(task_id); + + /* Finish the task. */ + htcs::SocketError err; + s32 res; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), std::addressof(res))); + + /* Set output. */ + *out_err = err; + *out_res = res; + return ResultSuccess(); + } + + Result HtcsService::AcceptStart(u32 *out_task_id, Handle *out_handle, s32 desc) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc)); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::AcceptResults(s32 *out_err, s32 *out_desc, SockAddrHtcs *out_address, u32 task_id, s32 desc) { + /* Finish the task. */ + htcs::SocketError err; + s32 ret_desc; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), std::addressof(ret_desc), desc)); + + /* Set output. */ + *out_err = err; + *out_desc = ret_desc; + return ResultSuccess(); + } + + Result HtcsService::ReceiveSmallStart(u32 *out_task_id, Handle *out_handle, s64 size, s32 desc, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::ReceiveSmallResults(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc) { + /* Continue the task. */ + m_rpc_client->ReceiveContinue(task_id, buffer, buffer_size); + + /* Finish the task. */ + htcs::SocketError err; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + Result HtcsService::SendSmallStart(u32 *out_task_id, Handle *out_handle, s32 desc, s64 size, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::SendSmallContinue(s64 *out_size, const char *buffer, s64 buffer_size, u32 task_id, s32 desc) { + /* Verify the task. */ + R_TRY(m_rpc_client->VerifyTaskIdWitHandle(task_id, desc)); + + /* Continue the task. */ + R_TRY(m_rpc_client->SendContinue(task_id, buffer, buffer_size)); + + /* Set output. */ + *out_size = buffer_size; + return ResultSuccess(); + } + + Result HtcsService::SendSmallResults(s32 *out_err, s64 *out_size, u32 task_id, s32 desc) { + /* Finish the task. */ + htcs::SocketError err; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + Result HtcsService::SendStart(u32 *out_task_id, Handle *out_handle, s32 desc, s64 size, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::SendContinue(s64 *out_size, const char *buffer, s64 buffer_size, u32 task_id, s32 desc) { + /* Verify the task. */ + R_TRY(m_rpc_client->VerifyTaskIdWitHandle(task_id, desc)); + + /* Wait for the task to notify. */ + m_rpc_client->WaitNotification(task_id); + + /* Check the task status. */ + R_UNLESS(!m_rpc_client->IsCompleted(task_id), htcs::ResultCompleted()); + R_UNLESS(!m_rpc_client->IsCancelled(task_id), htcs::ResultCancelled()); + + /* Send the data. */ + if (buffer_size > 0) { + R_TRY(m_data_channel_manager->Send(buffer, buffer_size, task_id)); + } + + return ResultSuccess(); + } + + Result HtcsService::SendResults(s32 *out_err, s64 *out_size, u32 task_id, s32 desc) { + /* Verify the task. */ + R_TRY(m_rpc_client->VerifyTaskIdWitHandle(task_id, desc)); + + /* Finish the task. */ + htcs::SocketError err; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + Result HtcsService::ReceiveStart(u32 *out_task_id, Handle *out_handle, s64 size, s32 desc, s32 flags) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::ReceiveResults(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc) { + /* Verify the task. */ + R_TRY(m_rpc_client->VerifyTaskIdWitHandle(task_id, desc)); + + /* Get the result. */ + htcs::SocketError err; + s64 recv_size; + const Result result = m_rpc_client->GetResult(task_id, std::addressof(err), std::addressof(recv_size)); + if (R_FAILED(result) || err != HTCS_ENONE) { + /* Finish the task. */ + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + /* Check the size. */ + R_UNLESS(recv_size <= buffer_size, htcs::ResultInvalidArgument()); + + /* Perform remaining processing. */ + if (recv_size > 0) { + /* Receive data. */ + const Result recv_result = m_data_channel_manager->Receive(buffer, recv_size, task_id); + + /* Finish the task. */ + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + + /* Check that our receive succeeded. */ + R_TRY(recv_result); + } else { + /* Finish the task. */ + R_TRY(m_rpc_client->End(task_id, std::addressof(err), out_size)); + } + + /* Set output. */ + *out_err = err; + return ResultSuccess(); + } + + Result HtcsService::SelectStart(u32 *out_task_id, Handle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec) { + /* Begin the task. */ + u32 task_id; + R_TRY(m_rpc_client->Begin(std::addressof(task_id), read_handles, write_handles, exception_handles, tv_sec, tv_usec)); + + /* Check that the task isn't cancelled. */ + R_UNLESS(!m_rpc_client->IsCancelled(task_id), htcs::ResultCancelled()); + + /* Detach the task. */ + *out_task_id = task_id; + *out_handle = m_rpc_client->DetachReadableHandle(task_id); + + return ResultSuccess(); + } + + Result HtcsService::SelectEnd(s32 *out_err, bool *out_empty, Span read_handles, Span write_handles, Span exception_handles, u32 task_id) { + /* Finish the task. */ + htcs::SocketError err; + bool empty; + R_TRY(m_rpc_client->End(task_id, std::addressof(err), std::addressof(empty), read_handles, write_handles, exception_handles)); + + /* Set output. */ + *out_err = err; + *out_empty = empty; + return ResultSuccess(); + } } diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp b/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp index 5546ca128..8d656c86b 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_service.hpp @@ -38,8 +38,8 @@ namespace ams::htcs::impl { Result Connect(s32 *out_err, s32 desc, const SockAddrHtcs &address); Result Bind(s32 *out_err, s32 desc, const SockAddrHtcs &address); Result Listen(s32 *out_err, s32 desc, s32 backlog_count); - Result Receive(s32 *out_err, s64 *out_size, char *buffer, size_t size, s32 desc, s32 flags); - Result Send(s32 *out_err, s64 *out_size, const char *buffer, size_t size, s32 desc, s32 flags); + Result Receive(s32 *out_err, s64 *out_size, char *buffer, s64 size, s32 desc, s32 flags); + Result Send(s32 *out_err, s64 *out_size, const char *buffer, s64 size, s32 desc, s32 flags); Result Shutdown(s32 *out_err, s32 desc, s32 how); Result Fcntl(s32 *out_err, s32 *out_res, s32 desc, s32 command, s32 value); @@ -61,7 +61,7 @@ namespace ams::htcs::impl { Result ReceiveResults(s32 *out_err, s64 *out_size, char *buffer, s64 buffer_size, u32 task_id, s32 desc); 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); + Result SelectEnd(s32 *out_err, bool *out_empty, 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 b30fdb749..993bea17e 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_util.cpp @@ -29,7 +29,7 @@ namespace ams::htcs::impl { R_CATCH(htcs::ResultInvalidHandle) { return HTCS_EBADF; } R_CATCH(htc::ResultUnknown2001) { return HTCS_EINVAL; } R_CATCH(htc::ResultUnknown2101) { return HTCS_EMFILE; } - R_CATCH(htc::ResultUnknown2021) { return HTCS_EINTR; } + R_CATCH(htc::ResultTaskCancelled) { return HTCS_EINTR; } R_CATCH(htc::ResultInvalidTaskId) { return HTCS_EINTR; } R_CATCH(htc::ResultCancelled) { return HTCS_EINTR; } R_CATCH(htc::ResultTaskQueueNotAvailable) { return HTCS_ENETDOWN; } diff --git a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.hpp b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.hpp index 7d683e523..aaac64d48 100644 --- a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.hpp +++ b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.hpp @@ -28,7 +28,8 @@ namespace ams::htcs::impl::rpc { public: DataChannelManager(htc::server::rpc::RpcClient *client, htclow::HtclowManager *htclow_manager) : m_rpc_client(client), m_htclow_manager(htclow_manager), m_module(htclow::ModuleId::Htcs) { /* ... */ } public: - /* TODO */ + Result Send(const void *buffer, s64 buffer_size, u32 task_id); + Result Receive(void *buffer, s64 buffer_size, u32 task_id); }; } diff --git a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp index cf872e877..582b62858 100644 --- a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp @@ -48,6 +48,9 @@ namespace ams::htcs::impl::rpc { s16 GetVersion() const { return m_version; } }; + template + concept IsHtcsTask = std::derived_from; + class HtcsSignalingTask : public HtcsTask { private: os::SystemEventType m_system_event; @@ -72,6 +75,8 @@ namespace ams::htcs::impl::rpc { }; class ReceiveTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Receive; private: s32 m_handle; s64 m_size; @@ -81,7 +86,7 @@ namespace ams::htcs::impl::rpc { htcs::SocketError m_err; s64 m_result_size; public: - ReceiveTask() : HtcsSignalingTask(HtcsTaskType::Receive) { /* ... */ } + ReceiveTask() : HtcsSignalingTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } s64 GetSize() const { return m_size; } @@ -104,6 +109,8 @@ namespace ams::htcs::impl::rpc { }; class SendTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Send; private: os::Event m_ready_event; s32 m_handle; @@ -114,7 +121,7 @@ namespace ams::htcs::impl::rpc { htcs::SocketError m_err; s64 m_result_size; public: - SendTask() : HtcsSignalingTask(HtcsTaskType::Send), m_ready_event(os::EventClearMode_ManualClear) { /* ... */ } + SendTask() : HtcsSignalingTask(TaskType), m_ready_event(os::EventClearMode_ManualClear) { /* ... */ } s32 GetHandle() const { return m_handle; } s64 GetSize() const { return m_size; } @@ -138,12 +145,14 @@ namespace ams::htcs::impl::rpc { }; class ShutdownTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Shutdown; private: s32 m_handle; ShutdownType m_how; htcs::SocketError m_err; public: - ShutdownTask() : HtcsTask(HtcsTaskType::Shutdown) { /* ... */ } + ShutdownTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } ShutdownType GetHow() const { return m_how; } @@ -157,11 +166,13 @@ namespace ams::htcs::impl::rpc { }; class CloseTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Close; private: s32 m_handle; htcs::SocketError m_err; public: - CloseTask() : HtcsTask(HtcsTaskType::Close) { /* ... */ } + CloseTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } public: @@ -174,13 +185,15 @@ namespace ams::htcs::impl::rpc { }; class ConnectTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Connect; private: s32 m_handle; HtcsPeerName m_peer_name; HtcsPortName m_port_name; htcs::SocketError m_err; public: - ConnectTask() : HtcsTask(HtcsTaskType::Connect) { /* ... */ } + ConnectTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } const HtcsPeerName &GetPeerName() const { return m_peer_name; } @@ -195,12 +208,14 @@ namespace ams::htcs::impl::rpc { }; class ListenTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Listen; private: s32 m_handle; s32 m_backlog; htcs::SocketError m_err; public: - ListenTask() : HtcsTask(HtcsTaskType::Listen) { /* ... */ } + ListenTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } s32 GetBacklog() const { return m_backlog; } @@ -214,12 +229,14 @@ namespace ams::htcs::impl::rpc { }; class AcceptTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Accept; private: s32 m_server_handle; htcs::SocketError m_err; s32 m_desc; public: - AcceptTask() : HtcsSignalingTask(HtcsTaskType::Accept) { /* ... */ } + AcceptTask() : HtcsSignalingTask(TaskType) { /* ... */ } s32 GetServerHandle() const { return m_server_handle; } public: @@ -232,11 +249,13 @@ namespace ams::htcs::impl::rpc { }; class SocketTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Socket; private: htcs::SocketError m_err; s32 m_desc; public: - SocketTask() : HtcsTask(HtcsTaskType::Socket) { /* ... */ } + SocketTask() : HtcsTask(TaskType) { /* ... */ } public: Result SetArguments(); void Complete(htcs::SocketError err, s32 desc); @@ -247,13 +266,15 @@ namespace ams::htcs::impl::rpc { }; class BindTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Bind; private: s32 m_handle; HtcsPeerName m_peer_name; HtcsPortName m_port_name; htcs::SocketError m_err; public: - BindTask() : HtcsTask(HtcsTaskType::Bind) { /* ... */ } + BindTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } const HtcsPeerName &GetPeerName() const { return m_peer_name; } @@ -268,6 +289,8 @@ namespace ams::htcs::impl::rpc { }; class FcntlTask : public HtcsTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Fcntl; private: s32 m_handle; s32 m_command; @@ -275,7 +298,7 @@ namespace ams::htcs::impl::rpc { htcs::SocketError m_err; s32 m_res; public: - FcntlTask() : HtcsTask(HtcsTaskType::Fcntl) { /* ... */ } + FcntlTask() : HtcsTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } s32 GetCommand() const { return m_command; } @@ -290,6 +313,8 @@ namespace ams::htcs::impl::rpc { }; class ReceiveSmallTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::ReceiveSmall; private: s32 m_handle; s64 m_size; @@ -298,7 +323,7 @@ namespace ams::htcs::impl::rpc { htcs::SocketError m_err; s64 m_result_size; public: - ReceiveSmallTask() : HtcsSignalingTask(HtcsTaskType::ReceiveSmall) { /* ... */ } + ReceiveSmallTask() : HtcsSignalingTask(TaskType) { /* ... */ } s32 GetHandle() const { return m_handle; } s64 GetSize() const { return m_size; } @@ -321,6 +346,8 @@ namespace ams::htcs::impl::rpc { }; class SendSmallTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::SendSmall; private: os::Event m_ready_event; s32 m_handle; @@ -331,7 +358,7 @@ namespace ams::htcs::impl::rpc { htcs::SocketError m_err; s64 m_result_size; public: - SendSmallTask() : HtcsSignalingTask(HtcsTaskType::SendSmall), m_ready_event(os::EventClearMode_ManualClear) { /* ... */ } + SendSmallTask() : HtcsSignalingTask(TaskType), m_ready_event(os::EventClearMode_ManualClear) { /* ... */ } s32 GetHandle() const { return m_handle; } s64 GetSize() const { return m_size; } @@ -354,6 +381,8 @@ namespace ams::htcs::impl::rpc { }; class SelectTask : public HtcsSignalingTask { + public: + static constexpr inline HtcsTaskType TaskType = HtcsTaskType::Select; private: s32 m_handles[SocketCountMax * 3]; s32 m_read_handle_count; @@ -367,7 +396,7 @@ namespace ams::htcs::impl::rpc { s32 m_out_write_handle_count; s32 m_out_exception_handle_count; public: - SelectTask() : HtcsSignalingTask(HtcsTaskType::Select) { /* ... */ } + SelectTask() : HtcsSignalingTask(TaskType) { /* ... */ } const s32 *GetHandles() const { return m_handles; } s32 GetReadHandleCount() const { return m_read_handle_count; } diff --git a/libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.cpp b/libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.cpp index d0c6a6bb0..1f9b2ab8d 100644 --- a/libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.cpp +++ b/libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.cpp @@ -79,7 +79,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the select. */ - return manager->StartSelect(out_task_id.GetPointer(), out_event.GetHandlePointer(), read_handles.ToSpan(), write_handles.ToSpan(), exception_handles.ToSpan(), tv_sec, tv_usec); + R_TRY(manager->StartSelect(out_task_id.GetPointer(), out_event.GetHandlePointer(), read_handles.ToSpan(), write_handles.ToSpan(), exception_handles.ToSpan(), tv_sec, tv_usec)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result ManagerServiceObject::EndSelect(sf::Out out_err, sf::Out out_count, const sf::OutMapAliasArray &read_handles, const sf::OutMapAliasArray &write_handles, const sf::OutMapAliasArray &exception_handles, u32 task_id) { diff --git a/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp b/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp index 9e7e31692..bb0619cda 100644 --- a/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp +++ b/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp @@ -118,7 +118,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the accept. */ - return manager->AcceptStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), m_desc); + R_TRY(manager->AcceptStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), m_desc)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::AcceptResults(sf::Out out_err, sf::Out> out, sf::Out out_address, u32 task_id) { @@ -143,7 +147,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the recv. */ - return manager->RecvStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), mem_size, m_desc, flags); + R_TRY(manager->RecvStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), mem_size, m_desc, flags)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::RecvResults(sf::Out out_err, sf::Out out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id) { @@ -174,7 +182,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the large receive. */ - return manager->RecvStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), unaligned_size_start + aligned_size + unaligned_size_end, m_desc, flags); + R_TRY(manager->RecvStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), unaligned_size_start + aligned_size + unaligned_size_end, m_desc, flags)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::SendStartOld(sf::Out out_task_id, sf::OutCopyHandle out_event, const sf::InAutoSelectBuffer &buffer, s32 flags) { @@ -205,7 +217,11 @@ namespace ams::htcs::server { const char *pointers[NumBuffers] = { reinterpret_cast(start_buffer.GetPointer()), static_cast(address), reinterpret_cast(end_buffer.GetPointer()) }; s64 sizes[NumBuffers] = { static_cast(start_buffer.GetSize()), aligned_size, static_cast(end_buffer.GetSize()) }; - return manager->SendLargeStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), pointers, sizes, NumBuffers, m_desc, flags); + R_TRY(manager->SendLargeStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), pointers, sizes, NumBuffers, m_desc, flags)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::SendResults(sf::Out out_err, sf::Out out_size, u32 task_id) { @@ -227,6 +243,9 @@ namespace ams::htcs::server { /* Set the output max size to the size. */ *out_max_size = size; + + /* Mark the output event as managed. */ + out_event.SetManaged(true); return ResultSuccess(); } @@ -249,7 +268,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the recv. */ - return manager->StartRecv(out_task_id.GetPointer(), out_event.GetHandlePointer(), size, m_desc, flags); + R_TRY(manager->StartRecv(out_task_id.GetPointer(), out_event.GetHandlePointer(), size, m_desc, flags)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::EndRecv(sf::Out out_err, sf::Out out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id) { @@ -270,7 +293,11 @@ namespace ams::htcs::server { auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the send. */ - return manager->SendStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), m_desc, flags); + R_TRY(manager->SendStart(out_task_id.GetPointer(), out_event.GetHandlePointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), m_desc, flags)); + + /* Mark the output event as managed. */ + out_event.SetManaged(true); + return ResultSuccess(); } Result SocketServiceObject::ContinueSend(sf::Out out_size, sf::Out out_wait, const sf::InNonSecureAutoSelectBuffer &buffer, u32 task_id) { diff --git a/libraries/libvapours/include/vapours/results/htc_results.hpp b/libraries/libvapours/include/vapours/results/htc_results.hpp index 3f1a5752b..1a402f988 100644 --- a/libraries/libvapours/include/vapours/results/htc_results.hpp +++ b/libraries/libvapours/include/vapours/results/htc_results.hpp @@ -31,7 +31,8 @@ namespace ams::htc { 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(TaskCancelled, 2021); + R_DEFINE_ERROR_RESULT(TaskNotCompleted, 2022); R_DEFINE_ERROR_RESULT(TaskQueueNotAvailable, 2033); R_DEFINE_ERROR_RESULT(Unknown2101, 2101); diff --git a/libraries/libvapours/include/vapours/results/htcs_results.hpp b/libraries/libvapours/include/vapours/results/htcs_results.hpp index 7903cb4bd..3b3bc0a5d 100644 --- a/libraries/libvapours/include/vapours/results/htcs_results.hpp +++ b/libraries/libvapours/include/vapours/results/htcs_results.hpp @@ -24,7 +24,7 @@ namespace ams::htcs { R_DEFINE_ERROR_RESULT(InvalidArgument, 2001); R_DEFINE_ERROR_RESULT(InvalidSize, 2014); - R_DEFINE_ERROR_RESULT(Unknown2021, 2021); - R_DEFINE_ERROR_RESULT(Unknown2023, 2023); + R_DEFINE_ERROR_RESULT(Cancelled, 2021); + R_DEFINE_ERROR_RESULT(Completed, 2023); }