/* * 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 "client/htcs_session.hpp" #include "client/htcs_virtual_socket_collection.hpp" namespace ams::htcs { namespace { constinit bool g_initialized = false; constinit bool g_enable_disconnection_emulation = false; constinit AllocateFunction g_allocate_function = nullptr; constinit DeallocateFunction g_deallocate_function = nullptr; constinit void *g_buffer = nullptr; constinit size_t g_buffer_size = 0; constinit os::TlsSlot g_tls_slot; constinit tma::IHtcsManager *g_manager = nullptr; constinit tma::IHtcsManager *g_monitor = nullptr; constinit client::VirtualSocketCollection *g_sockets = nullptr; void InitializeImpl(void *buffer, size_t buffer_size, int num_sessions) { /* Check the session count. */ AMS_ASSERT(0 < num_sessions && num_sessions <= SessionCountMax); /* Initialize the manager and monitor. */ client::InitializeSessionManager(std::addressof(g_manager), std::addressof(g_monitor)); /* Register the process. */ const sf::ClientProcessId process_id{0}; R_ABORT_UNLESS(g_manager->RegisterProcessId(process_id)); R_ABORT_UNLESS(g_monitor->MonitorManager(process_id)); /* Allocate a tls slot for our last error. */ os::SdkAllocateTlsSlot(std::addressof(g_tls_slot), nullptr); /* Setup the virtual socket collection. */ AMS_ASSERT(buffer != nullptr); g_sockets = reinterpret_cast(buffer); std::construct_at(g_sockets); g_sockets->Init(static_cast(buffer) + sizeof(*g_sockets), buffer_size - sizeof(*g_sockets)); /* Mark initialized. */ g_initialized = true; } void InitializeImpl(AllocateFunction allocate, DeallocateFunction deallocate, int num_sessions, int num_sockets) { /* Check the session count. */ AMS_ASSERT(0 < num_sessions && num_sessions <= SessionCountMax); /* Set the allocation functions. */ g_allocate_function = allocate; g_deallocate_function = deallocate; /* Allocate a buffer. */ g_buffer_size = sizeof(client::VirtualSocketCollection) + client::VirtualSocketCollection::GetWorkingMemorySize(num_sockets); g_buffer = g_allocate_function(g_buffer_size); /* Initialize. */ InitializeImpl(g_buffer, g_buffer_size, num_sessions); } } bool IsInitialized() { return g_initialized; } size_t GetWorkingMemorySize(int num_sockets) { AMS_ASSERT(num_sockets <= SocketCountMax); return sizeof(client::VirtualSocketCollection) + client::VirtualSocketCollection::GetWorkingMemorySize(num_sockets); } void Initialize(AllocateFunction allocate, DeallocateFunction deallocate, int num_sessions) { /* Check that we're not already initialized. */ AMS_ASSERT(!IsInitialized()); /* Configure disconnection emulation. */ g_enable_disconnection_emulation = true; /* Initialize. */ InitializeImpl(allocate, deallocate, num_sessions, htcs::SocketCountMax); } void Initialize(void *buffer, size_t buffer_size) { /* Check that we're not already initialized. */ AMS_ASSERT(!IsInitialized()); /* Configure disconnection emulation. */ g_enable_disconnection_emulation = true; /* Initialize. */ InitializeImpl(buffer, buffer_size, htcs::SessionCountMax); } void InitializeForDisableDisconnectionEmulation(AllocateFunction allocate, DeallocateFunction deallocate, int num_sessions) { /* Check that we're not already initialized. */ AMS_ASSERT(!IsInitialized()); /* Configure disconnection emulation. */ g_enable_disconnection_emulation = false; /* Initialize. */ InitializeImpl(allocate, deallocate, num_sessions, htcs::SocketCountMax); } void InitializeForDisableDisconnectionEmulation(void *buffer, size_t buffer_size) { /* Check that we're not already initialized. */ AMS_ASSERT(!IsInitialized()); /* Configure disconnection emulation. */ g_enable_disconnection_emulation = false; /* Initialize. */ InitializeImpl(buffer, buffer_size, htcs::SessionCountMax); } void InitializeForSystem(void *buffer, size_t buffer_size, int num_sessions) { /* Check that we're not already initialized. */ AMS_ASSERT(!IsInitialized()); /* Configure disconnection emulation. */ g_enable_disconnection_emulation = true; /* Initialize. */ InitializeImpl(buffer, buffer_size, num_sessions); } void Finalize() { /* Check that we're initialized. */ AMS_ASSERT(IsInitialized()); /* Set not initialized. */ g_initialized = false; /* Destroy the virtual socket collection. */ std::destroy_at(g_sockets); g_sockets = nullptr; /* Free the buffer, if we have one. */ if (g_buffer != nullptr) { g_deallocate_function(g_buffer, g_buffer_size); g_buffer = nullptr; g_buffer_size = 0; } /* Free the tls slot. */ os::FreeTlsSlot(g_tls_slot); /* Release the manager objects. */ sf::ReleaseSharedObject(g_manager); sf::ReleaseSharedObject(g_monitor); g_manager = nullptr; g_monitor = nullptr; /* Finalize the bsd client sessions. */ client::FinalizeSessionManager(); } }