// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_object_name.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/svc.h" namespace Kernel::Svc { Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr user_name) { // Copy the provided name from user memory to kernel memory. auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax); std::array name{}; std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1); // Validate that the name is valid. R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange); // Get the current handle table. auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); // Find the client port. auto port = KObjectName::Find(system.Kernel(), name.data()); R_UNLESS(port.IsNotNull(), ResultNotFound); // Reserve a handle for the port. // NOTE: Nintendo really does write directly to the output handle here. R_TRY(handle_table.Reserve(out)); ON_RESULT_FAILURE { handle_table.Unreserve(*out); }; // Create a session. KClientSession* session; R_TRY(port->CreateSession(std::addressof(session))); // Register the session in the table, close the extra reference. handle_table.Register(*out, session); session->Close(); // We succeeded. R_SUCCEED(); } Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, int32_t max_sessions, bool is_light, uint64_t name) { UNIMPLEMENTED(); R_THROW(ResultNotImplemented); } Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { UNIMPLEMENTED(); R_THROW(ResultNotImplemented); } Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, int32_t max_sessions) { // Copy the provided name from user memory to kernel memory. auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax); // Copy the provided name from user memory to kernel memory. std::array name{}; std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1); // Validate that sessions and name are valid. R_UNLESS(max_sessions >= 0, ResultOutOfRange); R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange); if (max_sessions > 0) { // Get the current handle table. auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); // Create a new port. KPort* port = KPort::Create(system.Kernel()); R_UNLESS(port != nullptr, ResultOutOfResource); // Initialize the new port. port->Initialize(max_sessions, false, 0); // Register the port. KPort::Register(system.Kernel(), port); // Ensure that our only reference to the port is in the handle table when we're done. SCOPE_EXIT({ port->GetClientPort().Close(); port->GetServerPort().Close(); }); // Register the handle in the table. R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); ON_RESULT_FAILURE { handle_table.Remove(*out_server_handle); }; // Create a new object name. R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()), name.data())); } else /* if (max_sessions == 0) */ { // Ensure that this else case is correct. ASSERT(max_sessions == 0); // If we're closing, there's no server handle. *out_server_handle = InvalidHandle; // Delete the object. R_TRY(KObjectName::Delete(system.Kernel(), name.data())); } R_SUCCEED(); } Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) { R_RETURN(ConnectToNamedPort(system, out_handle, name)); } Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name) { R_RETURN( CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name)); } Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions) { R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions)); } Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port) { R_RETURN(ConnectToPort(system, out_handle, port)); } Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name) { R_RETURN(ConnectToNamedPort(system, out_handle, name)); } Result CreatePort64From32(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint32_t name) { R_RETURN( CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name)); } Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name, int32_t max_sessions) { R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions)); } Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) { R_RETURN(ConnectToPort(system, out_handle, port)); } } // namespace Kernel::Svc