mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-27 17:11:00 +01:00
dmnt: enable experimental standalone usage of gdbstub, while starlink is in dev
This commit is contained in:
parent
a73e0e8f16
commit
29ffa4b7fd
2
Makefile
2
Makefile
@ -112,6 +112,7 @@ dist-no-debug: all
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623
|
||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
|
||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
|
||||
@ -125,6 +126,7 @@ dist-no-debug: all
|
||||
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||
cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
||||
cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp
|
||||
cp stratosphere/dmnt.gen2/dmnt.gen2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp
|
||||
cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp
|
||||
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
|
||||
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
|
||||
|
@ -118,12 +118,12 @@ namespace ams::fssystem {
|
||||
|
||||
/* Copy API. */
|
||||
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
|
||||
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||
ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
|
||||
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||
ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
@ -148,11 +148,11 @@ namespace ams::fssystem {
|
||||
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
|
||||
template<typename F>
|
||||
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
|
||||
template<s64 RetryMilliSeconds = 100>
|
||||
ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) {
|
||||
/* Retry up to 10 times, 100ms between retries. */
|
||||
constexpr s32 MaxRetryCount = 10;
|
||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(100);
|
||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds);
|
||||
|
||||
s32 remaining_retries = MaxRetryCount;
|
||||
while (true) {
|
||||
|
@ -43,6 +43,7 @@ namespace ams::socket {
|
||||
|
||||
s32 Shutdown(s32 desc, ShutdownMethod how);
|
||||
|
||||
s32 Socket(Family domain, Type type, Protocol protocol);
|
||||
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
||||
|
||||
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
||||
|
@ -57,4 +57,42 @@ namespace ams::socket {
|
||||
}
|
||||
};
|
||||
|
||||
class SystemConfigLightDefault : public Config {
|
||||
public:
|
||||
static constexpr size_t DefaultTcpInitialSendBufferSize = 16_KB;
|
||||
static constexpr size_t DefaultTcpInitialReceiveBufferSize = 16_KB;
|
||||
static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 0_KB;
|
||||
static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 0_KB;
|
||||
static constexpr size_t DefaultUdpSendBufferSize = 9_KB;
|
||||
static constexpr size_t DefaultUdpReceiveBufferSize = 42240;
|
||||
static constexpr auto DefaultSocketBufferEfficiency = 2;
|
||||
static constexpr auto DefaultConcurrency = 2;
|
||||
static constexpr size_t DefaultAllocatorPoolSize = 64_KB;
|
||||
|
||||
static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] {
|
||||
constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax));
|
||||
constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax));
|
||||
|
||||
return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||
}();
|
||||
|
||||
static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] {
|
||||
constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize);
|
||||
constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize);
|
||||
|
||||
return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||
}();
|
||||
public:
|
||||
constexpr SystemConfigLightDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency)
|
||||
: Config(mp, mp_sz, ap,
|
||||
DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize,
|
||||
DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax,
|
||||
DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize,
|
||||
DefaultSocketBufferEfficiency, c)
|
||||
{
|
||||
/* Mark as system. */
|
||||
m_system = true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -188,6 +188,12 @@ namespace ams::boot2 {
|
||||
return enable_htc != 0;
|
||||
}
|
||||
|
||||
bool IsStandaloneGdbstubEnabled() {
|
||||
u8 enable_gdbstub = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
|
||||
return enable_gdbstub != 0;
|
||||
}
|
||||
|
||||
bool IsAtmosphereLogManagerEnabled() {
|
||||
/* If htc is enabled, ams log manager is enabled. */
|
||||
if (IsHtcEnabled()) {
|
||||
@ -403,6 +409,9 @@ namespace ams::boot2 {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||
} else if (IsStandaloneGdbstubEnabled()) {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||
} else {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||
|
@ -41,6 +41,7 @@ namespace ams::socket::impl {
|
||||
|
||||
s32 Shutdown(s32 desc, ShutdownMethod how);
|
||||
|
||||
s32 Socket(Family domain, Type type, Protocol protocol);
|
||||
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
||||
|
||||
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
||||
|
@ -206,6 +206,8 @@ namespace ams::socket::impl {
|
||||
|
||||
/* TODO: socket::resolver::EnableResolverCalls()? Not necessary in our case (htc), but consider calling it. */
|
||||
|
||||
g_initialized = true;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@ -422,6 +424,22 @@ namespace ams::socket::impl {
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 Socket(Family domain, Type type, Protocol protocol) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ABORT_UNLESS(IsInitialized());
|
||||
|
||||
/* Perform the call. */
|
||||
Errno error = Errno::ESuccess;
|
||||
int result = ::bsdSocket(static_cast<int>(domain), static_cast<int>(type), static_cast<int>(protocol));
|
||||
TranslateResultToBsdError(error, result);
|
||||
|
||||
if (result < 0) {
|
||||
socket::impl::SetLastError(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ABORT_UNLESS(IsInitialized());
|
||||
|
@ -74,6 +74,10 @@ namespace ams::socket {
|
||||
return impl::Shutdown(desc, how);
|
||||
}
|
||||
|
||||
s32 Socket(Family domain, Type type, Protocol protocol) {
|
||||
return impl::Socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
s32 SocketExempt(Family domain, Type type, Protocol protocol) {
|
||||
return impl::SocketExempt(domain, type, protocol);
|
||||
}
|
||||
|
@ -378,6 +378,12 @@ namespace ams::settings::fwdbg {
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0"));
|
||||
|
||||
/* Controls whether atmosphere's dmnt.gen2 gdbstub should run as a standalone via sockets. */
|
||||
/* Note that this setting is ignored (and treated as 0) when htc is enabled. */
|
||||
/* Note that this setting may disappear in the future. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_standalone_gdbstub", "u8!0x0"));
|
||||
|
||||
/* Controls whether atmosphere's log manager is enabled. */
|
||||
/* Note that this setting is ignored (and treated as 1) when htc is enabled. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
|
@ -15,7 +15,7 @@
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
"service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs"],
|
||||
"service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs", "bsd:s"],
|
||||
"service_host": [],
|
||||
"kernel_capabilities": [{
|
||||
"type": "kernel_flags",
|
||||
|
@ -16,7 +16,8 @@
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_debug_log.hpp"
|
||||
|
||||
#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
|
||||
// TODO: This should be converted to use log manager. */
|
||||
//#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
|
||||
|
||||
#if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG)
|
||||
|
||||
@ -164,15 +165,78 @@ namespace ams::dmnt {
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
//#define AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG
|
||||
|
||||
#if defined(AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG)
|
||||
|
||||
namespace {
|
||||
|
||||
alignas(0x40) constinit u8 g_buffer[os::MemoryPageSize * 4];
|
||||
constinit lmem::HeapHandle g_debug_log_heap;
|
||||
constinit fs::FileHandle g_debug_log_file;
|
||||
|
||||
constinit os::SdkMutex g_fs_mutex;
|
||||
constinit s64 g_fs_offset = 0;
|
||||
|
||||
void *Allocate(size_t size) {
|
||||
return lmem::AllocateFromExpHeap(g_debug_log_heap, size);
|
||||
}
|
||||
|
||||
void Deallocate(void *p, size_t size) {
|
||||
AMS_UNUSED(size);
|
||||
return lmem::FreeToExpHeap(g_debug_log_heap, p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeDebugLog() {
|
||||
/* Do nothing. */
|
||||
g_debug_log_heap = lmem::CreateExpHeap(g_buffer, sizeof(g_buffer), lmem::CreateOption_ThreadSafe);
|
||||
|
||||
fs::SetAllocator(Allocate, Deallocate);
|
||||
fs::InitializeForSystem();
|
||||
fs::SetEnabledAutoAbort(false);
|
||||
|
||||
R_ABORT_UNLESS(fs::MountSdCard("sdmc"));
|
||||
|
||||
fs::DeleteFile("sdmc:/dmnt2.log");
|
||||
R_ABORT_UNLESS(fs::CreateFile("sdmc:/dmnt2.log", 0));
|
||||
R_ABORT_UNLESS(fs::OpenFile(std::addressof(g_debug_log_file), "sdmc:/dmnt2.log", fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||
}
|
||||
|
||||
void DebugLog(const char *prefix, const char *fmt, ...) {
|
||||
/* Do nothing. */
|
||||
char buffer[0x200];
|
||||
{
|
||||
const auto prefix_len = std::strlen(prefix);
|
||||
std::memcpy(buffer, prefix, prefix_len);
|
||||
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
util::VSNPrintf(buffer + prefix_len, sizeof(buffer) - prefix_len, fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
const auto len = std::strlen(buffer);
|
||||
|
||||
std::scoped_lock lk(g_fs_mutex);
|
||||
R_ABORT_UNLESS(fs::WriteFile(g_debug_log_file, g_fs_offset, buffer, len, fs::WriteOption::Flush));
|
||||
g_fs_offset += len;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void InitializeDebugLog() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void DebugLog(const char *prefix, const char *fmt, ...) {
|
||||
AMS_UNUSED(prefix, fmt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace ams::dmnt {
|
||||
|
||||
}
|
||||
|
||||
void GdbPacketIo::SendPacket(bool *out_break, const char *src, HtcsSession *session) {
|
||||
void GdbPacketIo::SendPacket(bool *out_break, const char *src, TransportSession *session) {
|
||||
/* Default to not breaked. */
|
||||
*out_break = false;
|
||||
|
||||
@ -99,7 +99,7 @@ namespace ams::dmnt {
|
||||
}
|
||||
}
|
||||
|
||||
char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session) {
|
||||
char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session) {
|
||||
/* Default to not breaked. */
|
||||
*out_break = false;
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_htcs_session.hpp"
|
||||
#include "dmnt2_transport_session.hpp"
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
@ -30,8 +30,8 @@ namespace ams::dmnt {
|
||||
|
||||
void SetNoAck() { m_no_ack = true; }
|
||||
|
||||
void SendPacket(bool *out_break, const char *src, HtcsSession *session);
|
||||
char *ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session);
|
||||
void SendPacket(bool *out_break, const char *src, TransportSession *session);
|
||||
char *ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session);
|
||||
};
|
||||
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_debug_log.hpp"
|
||||
#include "dmnt2_transport_layer.hpp"
|
||||
#include "dmnt2_gdb_server.hpp"
|
||||
#include "dmnt2_gdb_server_impl.hpp"
|
||||
|
||||
@ -36,34 +37,28 @@ namespace ams::dmnt {
|
||||
while (true) {
|
||||
/* Get a socket. */
|
||||
int fd;
|
||||
while ((fd = htcs::Socket()) == -1) {
|
||||
while ((fd = transport::Socket()) == -1) {
|
||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||
}
|
||||
|
||||
/* Ensure we cleanup the socket when we're done with it. */
|
||||
ON_SCOPE_EXIT {
|
||||
htcs::Close(fd);
|
||||
transport::Close(fd);
|
||||
os::SleepThread(TimeSpan::FromSeconds(1));
|
||||
};
|
||||
|
||||
/* Create a sock addr for our server. */
|
||||
htcs::SockAddrHtcs addr;
|
||||
addr.family = htcs::HTCS_AF_HTCS;
|
||||
addr.peer_name = htcs::GetPeerNameAny();
|
||||
std::strcpy(addr.port_name.name, "iywys@$gdb");
|
||||
|
||||
/* Bind. */
|
||||
if (htcs::Bind(fd, std::addressof(addr)) == -1) {
|
||||
if (transport::Bind(fd, transport::PortName_GdbServer) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Listen on our port. */
|
||||
while (htcs::Listen(fd, 0) == 0) {
|
||||
while (transport::Listen(fd, 0) == 0) {
|
||||
/* Continue accepting clients, so long as we can. */
|
||||
int client_fd;
|
||||
while (true) {
|
||||
/* Try to accept a client. */
|
||||
if (client_fd = htcs::Accept(fd, std::addressof(addr)); client_fd < 0) {
|
||||
if (client_fd = transport::Accept(fd); client_fd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -77,7 +72,7 @@ namespace ams::dmnt {
|
||||
}
|
||||
|
||||
/* Close the client socket. */
|
||||
htcs::Close(client_fd);
|
||||
transport::Close(client_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ namespace ams::dmnt {
|
||||
};
|
||||
private:
|
||||
int m_socket;
|
||||
HtcsSession m_session;
|
||||
TransportSession m_session;
|
||||
GdbPacketIo m_packet_io;
|
||||
char *m_receive_packet{nullptr};
|
||||
char *m_reply_packet{nullptr};
|
||||
|
@ -16,15 +16,22 @@
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_debug_log.hpp"
|
||||
#include "dmnt2_gdb_server.hpp"
|
||||
#include "dmnt2_transport_layer.hpp"
|
||||
|
||||
namespace ams {
|
||||
|
||||
namespace dmnt {
|
||||
namespace {
|
||||
|
||||
namespace {
|
||||
|
||||
alignas(0x40) constinit u8 g_htcs_buffer[4_KB];
|
||||
bool IsHtcEnabled() {
|
||||
u8 enable_htc = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_htc), sizeof(enable_htc), "atmosphere", "enable_htc");
|
||||
return enable_htc != 0;
|
||||
}
|
||||
|
||||
bool IsStandaloneGdbstubEnabled() {
|
||||
u8 enable_gdbstub = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
|
||||
return enable_gdbstub != 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -50,11 +57,23 @@ namespace ams {
|
||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main));
|
||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main));
|
||||
|
||||
/* Initialize htcs. */
|
||||
constexpr auto HtcsSocketCountMax = 8;
|
||||
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
|
||||
AMS_ABORT_UNLESS(sizeof(dmnt::g_htcs_buffer) >= buffer_size);
|
||||
htcs::InitializeForSystem(dmnt::g_htcs_buffer, buffer_size, HtcsSocketCountMax);
|
||||
bool use_htcs = false, use_tcp = false;
|
||||
{
|
||||
R_ABORT_UNLESS(::setsysInitialize());
|
||||
ON_SCOPE_EXIT { ::setsysExit(); };
|
||||
|
||||
use_htcs = IsHtcEnabled();
|
||||
use_tcp = IsStandaloneGdbstubEnabled();
|
||||
}
|
||||
|
||||
/* Initialize transport layer. */
|
||||
if (use_htcs) {
|
||||
dmnt::transport::InitializeByHtcs();
|
||||
} else if (use_tcp) {
|
||||
dmnt::transport::InitializeByTcp();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize debug log thread. */
|
||||
dmnt::InitializeDebugLog();
|
||||
|
196
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.cpp
Normal file
196
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_transport_layer.hpp"
|
||||
|
||||
namespace ams::dmnt::transport {
|
||||
|
||||
namespace {
|
||||
|
||||
enum SocketMode {
|
||||
SocketMode_Invalid,
|
||||
SocketMode_Htcs,
|
||||
SocketMode_Tcp,
|
||||
};
|
||||
|
||||
constexpr inline const u16 ListenPort_GdbServer = 22225;
|
||||
constexpr inline const u16 ListenPort_GdbDebugLog = 22227;
|
||||
|
||||
constinit os::SdkMutex g_socket_init_mutex;
|
||||
constinit SocketMode g_socket_mode = SocketMode_Invalid;
|
||||
|
||||
constexpr inline size_t RequiredAlignment = std::max(os::ThreadStackAlignment, os::MemoryPageSize);
|
||||
|
||||
using SocketConfigType = socket::SystemConfigLightDefault;
|
||||
|
||||
/* TODO: If we ever use resolvers, increase this. */
|
||||
constexpr inline size_t SocketAllocatorSize = 4_KB;
|
||||
constexpr inline size_t SocketMemoryPoolSize = util::AlignUp(SocketConfigType::PerTcpSocketWorstCaseMemoryPoolSize + SocketConfigType::PerUdpSocketWorstCaseMemoryPoolSize, os::MemoryPageSize);
|
||||
|
||||
constexpr inline size_t SocketRequiredSize = util::AlignUp(SocketMemoryPoolSize + SocketAllocatorSize, os::MemoryPageSize);
|
||||
|
||||
/* Declare the memory pool. */
|
||||
alignas(RequiredAlignment) constinit u8 g_socket_memory[SocketRequiredSize];
|
||||
|
||||
constexpr inline const SocketConfigType SocketConfig(g_socket_memory, SocketRequiredSize, SocketAllocatorSize, 2);
|
||||
|
||||
}
|
||||
|
||||
void InitializeByHtcs() {
|
||||
std::scoped_lock lk(g_socket_init_mutex);
|
||||
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
|
||||
|
||||
constexpr auto HtcsSocketCountMax = 8;
|
||||
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
|
||||
AMS_ABORT_UNLESS(sizeof(g_socket_memory) >= buffer_size);
|
||||
htcs::InitializeForSystem(g_socket_memory, sizeof(g_socket_memory), HtcsSocketCountMax);
|
||||
|
||||
g_socket_mode = SocketMode_Htcs;
|
||||
}
|
||||
|
||||
void InitializeByTcp() {
|
||||
std::scoped_lock lk(g_socket_init_mutex);
|
||||
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
|
||||
|
||||
R_ABORT_UNLESS(socket::Initialize(SocketConfig));
|
||||
|
||||
g_socket_mode = SocketMode_Tcp;
|
||||
}
|
||||
|
||||
s32 Socket() {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Socket();
|
||||
case SocketMode_Tcp: return socket::Socket(socket::Family::Af_Inet, socket::Type::Sock_Stream, socket::Protocol::IpProto_Tcp);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 Close(s32 desc) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Close(desc);
|
||||
case SocketMode_Tcp: return socket::Close(desc);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 Bind(s32 desc, PortName port_name) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs:
|
||||
{
|
||||
htcs::SockAddrHtcs addr;
|
||||
addr.family = htcs::HTCS_AF_HTCS;
|
||||
addr.peer_name = htcs::GetPeerNameAny();
|
||||
switch (port_name) {
|
||||
case PortName_GdbServer: std::strcpy(addr.port_name.name, "iywys@$gdb"); break;
|
||||
case PortName_GdbDebugLog: std::strcpy(addr.port_name.name, "iywys@$dmnt2_log"); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
return htcs::Bind(desc, std::addressof(addr));
|
||||
}
|
||||
break;
|
||||
case SocketMode_Tcp:
|
||||
{
|
||||
socket::SockAddrIn addr = {};
|
||||
addr.sin_family = socket::Family::Af_Inet;
|
||||
addr.sin_addr.s_addr = socket::InAddr_Any;
|
||||
|
||||
switch (port_name){
|
||||
case PortName_GdbServer: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbServer)); break;
|
||||
case PortName_GdbDebugLog: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbDebugLog)); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
return socket::Bind(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), sizeof(addr));
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 Listen(s32 desc, s32 backlog_count) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Listen(desc, backlog_count);
|
||||
case SocketMode_Tcp: return socket::Listen(desc, backlog_count);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 Accept(s32 desc) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs:
|
||||
{
|
||||
htcs::SockAddrHtcs addr;
|
||||
addr.family = htcs::HTCS_AF_HTCS;
|
||||
addr.peer_name = htcs::GetPeerNameAny();
|
||||
addr.port_name.name[0] = '\x00';
|
||||
|
||||
return htcs::Accept(desc, std::addressof(addr));
|
||||
}
|
||||
break;
|
||||
case SocketMode_Tcp:
|
||||
{
|
||||
socket::SockAddrIn addr = {};
|
||||
socket::SockLenT addr_len = sizeof(addr);
|
||||
|
||||
return socket::Accept(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), std::addressof(addr_len));
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 Shutdown(s32 desc) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Shutdown(desc, htcs::HTCS_SHUT_RDWR);
|
||||
case SocketMode_Tcp: return socket::Shutdown(desc, socket::ShutdownMethod::Shut_RdWr);
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Recv(desc, buffer, buffer_size, flags);
|
||||
case SocketMode_Tcp: return socket::Recv(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags) {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::Send(desc, buffer, buffer_size, flags);
|
||||
case SocketMode_Tcp: return socket::Send(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 GetLastError() {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::GetLastError();
|
||||
case SocketMode_Tcp: return static_cast<s32>(socket::GetLastError());
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLastErrorEAgain() {
|
||||
switch (g_socket_mode) {
|
||||
case SocketMode_Htcs: return htcs::GetLastError() == htcs::HTCS_EAGAIN;
|
||||
case SocketMode_Tcp: return socket::GetLastError() == socket::Errno::EAgain;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
42
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.hpp
Normal file
42
stratosphere/dmnt.gen2/source/dmnt2_transport_layer.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::dmnt::transport {
|
||||
|
||||
void InitializeByHtcs();
|
||||
void InitializeByTcp();
|
||||
|
||||
enum PortName {
|
||||
PortName_GdbServer,
|
||||
PortName_GdbDebugLog,
|
||||
};
|
||||
|
||||
s32 Socket();
|
||||
s32 Close(s32 desc);
|
||||
s32 Bind(s32 desc, PortName port_name);
|
||||
s32 Listen(s32 desc, s32 backlog_count);
|
||||
s32 Accept(s32 desc);
|
||||
s32 Shutdown(s32 desc);
|
||||
|
||||
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags);
|
||||
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags);
|
||||
|
||||
s32 GetLastError();
|
||||
bool IsLastErrorEAgain();
|
||||
|
||||
}
|
@ -14,11 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_htcs_receive_buffer.hpp"
|
||||
#include "dmnt2_transport_receive_buffer.hpp"
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
ssize_t HtcsReceiveBuffer::Read(void *dst, size_t size) {
|
||||
ssize_t TransportReceiveBuffer::Read(void *dst, size_t size) {
|
||||
/* Acquire exclusive access to ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
@ -50,7 +50,7 @@ namespace ams::dmnt {
|
||||
return readable;
|
||||
}
|
||||
|
||||
ssize_t HtcsReceiveBuffer::Write(const void *src, size_t size) {
|
||||
ssize_t TransportReceiveBuffer::Write(const void *src, size_t size) {
|
||||
/* Acquire exclusive access to ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
@ -71,7 +71,7 @@ namespace ams::dmnt {
|
||||
return size;
|
||||
}
|
||||
|
||||
bool HtcsReceiveBuffer::WaitToBeReadable() {
|
||||
bool TransportReceiveBuffer::WaitToBeReadable() {
|
||||
/* Check if we're already readable. */
|
||||
{
|
||||
std::scoped_lock lk(m_mutex);
|
||||
@ -91,7 +91,7 @@ namespace ams::dmnt {
|
||||
return this->IsValid();
|
||||
}
|
||||
|
||||
bool HtcsReceiveBuffer::WaitToBeReadable(TimeSpan timeout) {
|
||||
bool TransportReceiveBuffer::WaitToBeReadable(TimeSpan timeout) {
|
||||
/* Check if we're already readable. */
|
||||
{
|
||||
std::scoped_lock lk(m_mutex);
|
||||
@ -111,7 +111,7 @@ namespace ams::dmnt {
|
||||
return res && this->IsValid();
|
||||
}
|
||||
|
||||
bool HtcsReceiveBuffer::WaitToBeWritable() {
|
||||
bool TransportReceiveBuffer::WaitToBeWritable() {
|
||||
/* Check if we're already writable. */
|
||||
{
|
||||
std::scoped_lock lk(m_mutex);
|
||||
@ -131,7 +131,7 @@ namespace ams::dmnt {
|
||||
return this->IsValid();
|
||||
}
|
||||
|
||||
void HtcsReceiveBuffer::Invalidate() {
|
||||
void TransportReceiveBuffer::Invalidate() {
|
||||
/* Acquire exclusive access to ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
class HtcsReceiveBuffer {
|
||||
class TransportReceiveBuffer {
|
||||
public:
|
||||
static constexpr size_t ReceiveBufferSize = 4_KB;
|
||||
private:
|
||||
@ -30,7 +30,7 @@ namespace ams::dmnt {
|
||||
size_t m_offset;
|
||||
bool m_valid;
|
||||
public:
|
||||
HtcsReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ }
|
||||
TransportReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE bool IsReadable() const { return m_readable_size != 0; }
|
||||
ALWAYS_INLINE bool IsWritable() const { return m_readable_size == 0; }
|
@ -14,12 +14,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_htcs_session.hpp"
|
||||
#include "dmnt2_transport_layer.hpp"
|
||||
#include "dmnt2_transport_session.hpp"
|
||||
#include "dmnt2_debug_log.hpp"
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
HtcsSession::HtcsSession(int fd) : m_socket(fd), m_valid(true) {
|
||||
TransportSession::TransportSession(int fd) : m_socket(fd), m_valid(true) {
|
||||
/* Create our thread. */
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_receive_thread), ReceiveThreadEntry, this, m_receive_thread_stack, sizeof(m_receive_thread_stack), os::HighestThreadPriority - 1));
|
||||
|
||||
@ -30,7 +31,7 @@ namespace ams::dmnt {
|
||||
AMS_DMNT2_GDB_LOG_INFO("Created Session %d\n", m_socket);
|
||||
}
|
||||
|
||||
HtcsSession::~HtcsSession() {
|
||||
TransportSession::~TransportSession() {
|
||||
/* Note that we connected. */
|
||||
AMS_DMNT2_GDB_LOG_INFO("Closing Session %d\n", m_socket);
|
||||
|
||||
@ -38,25 +39,25 @@ namespace ams::dmnt {
|
||||
m_receive_buffer.Invalidate();
|
||||
|
||||
/* Shutdown our socket. */
|
||||
htcs::Shutdown(m_socket, htcs::HTCS_SHUT_RDWR);
|
||||
transport::Shutdown(m_socket);
|
||||
|
||||
/* Wait for our thread. */
|
||||
os::WaitThread(std::addressof(m_receive_thread));
|
||||
os::DestroyThread(std::addressof(m_receive_thread));
|
||||
|
||||
/* Close our socket. */
|
||||
htcs::Close(m_socket);
|
||||
transport::Close(m_socket);
|
||||
}
|
||||
|
||||
bool HtcsSession::WaitToBeReadable() {
|
||||
bool TransportSession::WaitToBeReadable() {
|
||||
return m_receive_buffer.WaitToBeReadable();
|
||||
}
|
||||
|
||||
bool HtcsSession::WaitToBeReadable(TimeSpan timeout) {
|
||||
bool TransportSession::WaitToBeReadable(TimeSpan timeout) {
|
||||
return m_receive_buffer.WaitToBeReadable(timeout);
|
||||
}
|
||||
|
||||
util::optional<char> HtcsSession::GetChar() {
|
||||
util::optional<char> TransportSession::GetChar() {
|
||||
/* Wait for us to have data. */
|
||||
m_receive_buffer.WaitToBeReadable();
|
||||
|
||||
@ -69,9 +70,9 @@ namespace ams::dmnt {
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t HtcsSession::PutChar(char c) {
|
||||
ssize_t TransportSession::PutChar(char c) {
|
||||
/* Send the character. */
|
||||
const auto sent = htcs::Send(m_socket, std::addressof(c), sizeof(c), 0);
|
||||
const auto sent = transport::Send(m_socket, std::addressof(c), sizeof(c), 0);
|
||||
if (sent < 0) {
|
||||
m_valid = false;
|
||||
}
|
||||
@ -79,13 +80,13 @@ namespace ams::dmnt {
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t HtcsSession::PutString(const char *str) {
|
||||
ssize_t TransportSession::PutString(const char *str) {
|
||||
/* Repeatedly send until all is sent. */
|
||||
const size_t len = std::strlen(str);
|
||||
|
||||
size_t remaining = len;
|
||||
while (remaining > 0) {
|
||||
const auto sent = htcs::Send(m_socket, str, remaining, 0);
|
||||
const auto sent = transport::Send(m_socket, str, remaining, 0);
|
||||
if (sent >= 0) {
|
||||
remaining -= sent;
|
||||
str += sent;
|
||||
@ -98,22 +99,22 @@ namespace ams::dmnt {
|
||||
return len;
|
||||
}
|
||||
|
||||
void HtcsSession::ReceiveThreadFunction() {
|
||||
void TransportSession::ReceiveThreadFunction() {
|
||||
/* Create temporary buffer. */
|
||||
u8 buffer[HtcsReceiveBuffer::ReceiveBufferSize];
|
||||
u8 buffer[TransportReceiveBuffer::ReceiveBufferSize];
|
||||
|
||||
/* Loop receiving data. */
|
||||
while (true) {
|
||||
/* Receive data. */
|
||||
const auto res = htcs::Recv(m_socket, buffer, sizeof(buffer), 0);
|
||||
const auto res = transport::Recv(m_socket, buffer, sizeof(buffer), 0);
|
||||
if (res > 0) {
|
||||
/* Write the data to our buffer. */
|
||||
m_receive_buffer.WaitToBeWritable();
|
||||
m_receive_buffer.Write(buffer, res);
|
||||
} else {
|
||||
/* Otherwise, if we got an error other than "try again", we're done. */
|
||||
if (htcs::GetLastError() != htcs::HTCS_EAGAIN) {
|
||||
AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(htcs::GetLastError()));
|
||||
if (!transport::IsLastErrorEAgain()) {
|
||||
AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(transport::GetLastError()));
|
||||
m_valid = false;
|
||||
break;
|
||||
}
|
@ -15,20 +15,20 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "dmnt2_htcs_receive_buffer.hpp"
|
||||
#include "dmnt2_transport_receive_buffer.hpp"
|
||||
|
||||
namespace ams::dmnt {
|
||||
|
||||
class HtcsSession {
|
||||
class TransportSession {
|
||||
private:
|
||||
alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + HtcsReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)];
|
||||
HtcsReceiveBuffer m_receive_buffer;
|
||||
alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + TransportReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)];
|
||||
TransportReceiveBuffer m_receive_buffer;
|
||||
os::ThreadType m_receive_thread;
|
||||
int m_socket;
|
||||
bool m_valid;
|
||||
public:
|
||||
HtcsSession(int fd);
|
||||
~HtcsSession();
|
||||
TransportSession(int fd);
|
||||
~TransportSession();
|
||||
|
||||
ALWAYS_INLINE bool IsValid() const { return m_valid; }
|
||||
|
||||
@ -41,7 +41,7 @@ namespace ams::dmnt {
|
||||
|
||||
private:
|
||||
static void ReceiveThreadEntry(void *arg) {
|
||||
static_cast<HtcsSession *>(arg)->ReceiveThreadFunction();
|
||||
static_cast<TransportSession *>(arg)->ReceiveThreadFunction();
|
||||
}
|
||||
|
||||
void ReceiveThreadFunction();
|
Loading…
Reference in New Issue
Block a user