/* * Copyright (c) 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_socket_service_object.hpp" #include "htcs_service_object_allocator.hpp" #include "../impl/htcs_manager.hpp" namespace ams::htcs::server { SocketServiceObject::SocketServiceObject(ManagerServiceObject *manager, s32 desc) : m_manager(manager, true), m_desc(desc) { /* ... */ } SocketServiceObject::~SocketServiceObject() { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Close the underlying socket. */ s32 dummy_err, dummy_res; manager->Close(std::addressof(dummy_err), std::addressof(dummy_res), m_desc); } Result SocketServiceObject::Close(sf::Out out_err, sf::Out out_res) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Close the underlying socket. */ manager->Close(out_err.GetPointer(), out_res.GetPointer(), m_desc); R_SUCCEED(); } Result SocketServiceObject::Connect(sf::Out out_err, sf::Out out_res, const htcs::SockAddrHtcs &address) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the connect. */ manager->Connect(out_err.GetPointer(), out_res.GetPointer(), address, m_desc); R_SUCCEED(); } Result SocketServiceObject::Bind(sf::Out out_err, sf::Out out_res, const htcs::SockAddrHtcs &address) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the bind. */ manager->Bind(out_err.GetPointer(), out_res.GetPointer(), address, m_desc); R_SUCCEED(); } Result SocketServiceObject::Listen(sf::Out out_err, sf::Out out_res, s32 backlog_count) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the listen. */ manager->Listen(out_err.GetPointer(), out_res.GetPointer(), backlog_count, m_desc); R_SUCCEED(); } Result SocketServiceObject::Recv(sf::Out out_err, sf::Out out_size, const sf::OutAutoSelectBuffer &buffer, s32 flags) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the recv. */ manager->Recv(out_err.GetPointer(), out_size.GetPointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), flags, m_desc); R_SUCCEED(); } Result SocketServiceObject::Send(sf::Out out_err, sf::Out out_size, const sf::InAutoSelectBuffer &buffer, s32 flags) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the send. */ manager->Send(out_err.GetPointer(), out_size.GetPointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), flags, m_desc); R_SUCCEED(); } Result SocketServiceObject::Shutdown(sf::Out out_err, sf::Out out_res, s32 how) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the shutdown. */ manager->Shutdown(out_err.GetPointer(), out_res.GetPointer(), how, m_desc); R_SUCCEED(); } Result SocketServiceObject::Fcntl(sf::Out out_err, sf::Out out_res, s32 command, s32 value) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Perform the fcntl. */ manager->Fcntl(out_err.GetPointer(), out_res.GetPointer(), command, value, m_desc); R_SUCCEED(); } Result SocketServiceObject::AcceptStart(sf::Out out_task_id, sf::OutCopyHandle out_event) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the accept. */ os::NativeHandle event_handle; R_TRY(manager->AcceptStart(out_task_id.GetPointer(), std::addressof(event_handle), m_desc)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::AcceptResults(sf::Out out_err, sf::Out> out, sf::Out out_address, u32 task_id) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Get the accept results. */ s32 desc = -1; manager->AcceptResults(out_err.GetPointer(), std::addressof(desc), out_address.GetPointer(), task_id, m_desc); /* If an error occurred, we're done. */ R_SUCCEED_IF(*out_err != 0); /* Create a new socket object. */ *out = ServiceObjectFactory::CreateSharedEmplaced(m_manager.Get(), desc); R_SUCCEED(); } Result SocketServiceObject::RecvStart(sf::Out out_task_id, sf::OutCopyHandle out_event, s32 mem_size, s32 flags) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the recv. */ os::NativeHandle event_handle; R_TRY(manager->RecvStart(out_task_id.GetPointer(), std::addressof(event_handle), mem_size, m_desc, flags)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::RecvResults(sf::Out out_err, sf::Out out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Get the recv results. */ manager->RecvResults(out_err.GetPointer(), out_size.GetPointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), task_id, m_desc); R_SUCCEED(); } Result SocketServiceObject::RecvLargeStart(sf::Out out_task_id, sf::OutCopyHandle out_event, s32 unaligned_size_start, s32 unaligned_size_end, s64 aligned_size, sf::CopyHandle &&mem_handle, s32 flags) { /* Check that the transfer memory size is okay. */ R_UNLESS(util::IsIntValueRepresentable(aligned_size), htcs::ResultInvalidSize()); /* Attach the transfer memory. */ os::TransferMemoryType tmem; os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetOsHandle(), mem_handle.IsManaged()); mem_handle.Detach(); ON_SCOPE_EXIT { os::DestroyTransferMemory(std::addressof(tmem)); }; /* Map the transfer memory. */ void *address; R_TRY(os::MapTransferMemory(std::addressof(address), std::addressof(tmem), os::MemoryPermission_None)); ON_SCOPE_EXIT { os::UnmapTransferMemory(std::addressof(tmem)); }; /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the large receive. */ os::NativeHandle event_handle; R_TRY(manager->RecvStart(out_task_id.GetPointer(), std::addressof(event_handle), unaligned_size_start + aligned_size + unaligned_size_end, m_desc, flags)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::SendStartOld(sf::Out out_task_id, sf::OutCopyHandle out_event, const sf::InAutoSelectBuffer &buffer, s32 flags) { return this->SendStart(out_task_id, out_event, sf::InNonSecureAutoSelectBuffer(buffer.GetPointer(), buffer.GetSize()), flags); } Result SocketServiceObject::SendLargeStart(sf::Out out_task_id, sf::OutCopyHandle out_event, const sf::InAutoSelectBuffer &start_buffer, const sf::InAutoSelectBuffer &end_buffer, sf::CopyHandle &&mem_handle, s64 aligned_size, s32 flags) { /* Check that the sizes are okay. */ R_UNLESS(util::IsIntValueRepresentable(start_buffer.GetSize()), htcs::ResultInvalidSize()); R_UNLESS(util::IsIntValueRepresentable(end_buffer.GetSize()), htcs::ResultInvalidSize()); R_UNLESS(util::IsIntValueRepresentable(aligned_size), htcs::ResultInvalidSize()); /* Attach the transfer memory. */ os::TransferMemoryType tmem; os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetOsHandle(), mem_handle.IsManaged()); mem_handle.Detach(); ON_SCOPE_EXIT { os::DestroyTransferMemory(std::addressof(tmem)); }; /* Map the transfer memory. */ void *address; R_TRY(os::MapTransferMemory(std::addressof(address), std::addressof(tmem), os::MemoryPermission_None)); ON_SCOPE_EXIT { os::UnmapTransferMemory(std::addressof(tmem)); }; /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the large send. */ constexpr auto NumBuffers = 3; 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()) }; os::NativeHandle event_handle; R_TRY(manager->SendLargeStart(out_task_id.GetPointer(), std::addressof(event_handle), pointers, sizes, NumBuffers, m_desc, flags)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::SendResults(sf::Out out_err, sf::Out out_size, u32 task_id) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Get the send results. */ manager->SendResults(out_err.GetPointer(), out_size.GetPointer(), task_id, m_desc); R_SUCCEED(); } Result SocketServiceObject::StartSend(sf::Out out_task_id, sf::OutCopyHandle out_event, sf::Out out_max_size, s64 size, s32 flags) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the send. */ os::NativeHandle event_handle; R_TRY(manager->StartSend(out_task_id.GetPointer(), std::addressof(event_handle), m_desc, size, flags)); /* Set the output max size to the size. */ *out_max_size = size; /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::ContinueSendOld(sf::Out out_size, sf::Out out_wait, const sf::InAutoSelectBuffer &buffer, u32 task_id) { return this->ContinueSend(out_size, out_wait, sf::InNonSecureAutoSelectBuffer(buffer.GetPointer(), buffer.GetSize()), task_id); } Result SocketServiceObject::EndSend(sf::Out out_err, sf::Out out_size, u32 task_id) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* End the send. */ manager->EndSend(out_err.GetPointer(), out_size.GetPointer(), task_id, m_desc); R_SUCCEED(); } Result SocketServiceObject::StartRecv(sf::Out out_task_id, sf::OutCopyHandle out_event, s64 size, s32 flags) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the recv. */ os::NativeHandle event_handle; R_TRY(manager->StartRecv(out_task_id.GetPointer(), std::addressof(event_handle), size, m_desc, flags)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::EndRecv(sf::Out out_err, sf::Out out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id) { /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* End the recv. */ manager->EndRecv(out_err.GetPointer(), out_size.GetPointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), task_id, m_desc); R_SUCCEED(); } Result SocketServiceObject::SendStart(sf::Out out_task_id, sf::OutCopyHandle out_event, const sf::InNonSecureAutoSelectBuffer &buffer, s32 flags) { /* Check that the sizes are okay. */ R_UNLESS(util::IsIntValueRepresentable(buffer.GetSize()), htcs::ResultInvalidSize()); /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Start the send. */ os::NativeHandle event_handle; R_TRY(manager->SendStart(out_task_id.GetPointer(), std::addressof(event_handle), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), m_desc, flags)); /* Set the output event handle. */ out_event.SetValue(event_handle, true); R_SUCCEED(); } Result SocketServiceObject::ContinueSend(sf::Out out_size, sf::Out out_wait, const sf::InNonSecureAutoSelectBuffer &buffer, u32 task_id) { /* Check that the sizes are okay. */ R_UNLESS(util::IsIntValueRepresentable(buffer.GetSize()), htcs::ResultInvalidSize()); /* Get the htcs manager. */ auto *manager = impl::HtcsManagerHolder::GetHtcsManager(); /* Continue the send. */ R_TRY(manager->ContinueSend(out_size.GetPointer(), reinterpret_cast(buffer.GetPointer()), buffer.GetSize(), task_id, m_desc)); /* We aren't doing a waiting send. */ *out_wait = false; R_SUCCEED(); } Result SocketServiceObject::GetPrimitive(sf::Out out) { /* Get our descriptor. */ *out = m_desc; R_SUCCEED(); } }