mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-26 13:52:21 +00:00
scs: implement DoShellServer
This commit is contained in:
parent
e9849c74cf
commit
aa2dce7316
3 changed files with 169 additions and 6 deletions
|
@ -26,7 +26,7 @@ namespace ams::scs {
|
||||||
|
|
||||||
void RegisterCommonProcessEventHandler(ProcessEventHandler on_start, ProcessEventHandler on_exit, ProcessEventHandler on_jit_debug);
|
void RegisterCommonProcessEventHandler(ProcessEventHandler on_start, ProcessEventHandler on_exit, ProcessEventHandler on_jit_debug);
|
||||||
|
|
||||||
bool RegisterSocket(s32 socket);
|
Result RegisterSocket(s32 socket, u64 id);
|
||||||
void UnregisterSocket(s32 socket);
|
void UnregisterSocket(s32 socket);
|
||||||
|
|
||||||
Result LaunchProgram(os::ProcessId *out, ncm::ProgramId program_id, const void *args, size_t args_size, u32 process_flags);
|
Result LaunchProgram(os::ProcessId *out, ncm::ProgramId program_id, const void *args, size_t args_size, u32 process_flags);
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace ams::scs {
|
||||||
|
|
||||||
class SocketInfoManager {
|
class SocketInfoManager {
|
||||||
private:
|
private:
|
||||||
SocketInfo m_infos[MaxProgramInfo];
|
SocketInfo m_infos[MaxSocketInfo];
|
||||||
int m_count;
|
int m_count;
|
||||||
public:
|
public:
|
||||||
constexpr SocketInfoManager() = default;
|
constexpr SocketInfoManager() = default;
|
||||||
|
@ -48,6 +48,42 @@ namespace ams::scs {
|
||||||
/* Clear our count. */
|
/* Clear our count. */
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result Register(s32 socket, u64 id) {
|
||||||
|
/* Check that the socket isn't already registered. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
R_UNLESS(m_infos[i].socket != socket, scs::ResultNoSocket());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that we can allocate a new socket info. */
|
||||||
|
if (m_count >= MaxSocketInfo) {
|
||||||
|
/* NOTE: Nintendo aborts with this result here. */
|
||||||
|
R_ABORT_UNLESS(scs::ResultOutOfResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the new socket info. */
|
||||||
|
m_infos[m_count++] = {
|
||||||
|
.id = id,
|
||||||
|
.socket = socket,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unregister(s32 socket) {
|
||||||
|
/* Unregister the socket, if it's registered. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
if (m_infos[i].socket == socket) {
|
||||||
|
/* Ensure that the valid socket infos remain in bounds. */
|
||||||
|
std::memcpy(m_infos + i, m_infos + i + 1, (m_count - (i + 1)) * sizeof(*m_infos));
|
||||||
|
|
||||||
|
/* Note that we now have one fewer socket info. */
|
||||||
|
--m_count;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProgramInfoManager {
|
class ProgramInfoManager {
|
||||||
|
@ -77,6 +113,8 @@ namespace ams::scs {
|
||||||
constinit SocketInfoManager g_socket_info_manager;
|
constinit SocketInfoManager g_socket_info_manager;
|
||||||
constinit ProgramInfoManager g_program_info_manager;
|
constinit ProgramInfoManager g_program_info_manager;
|
||||||
|
|
||||||
|
constinit os::SdkMutex g_manager_mutex;
|
||||||
|
|
||||||
void EventHandlerThread(void *) {
|
void EventHandlerThread(void *) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
AMS_ABORT("scs::EventHandlerThread");
|
AMS_ABORT("scs::EventHandlerThread");
|
||||||
|
@ -130,8 +168,21 @@ namespace ams::scs {
|
||||||
g_common_jit_debug_handler = on_jit_debug;
|
g_common_jit_debug_handler = on_jit_debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegisterSocket(s32 socket);
|
Result RegisterSocket(s32 socket, u64 id) {
|
||||||
void UnregisterSocket(s32 socket);
|
/* Acquire exclusive access to the socket info manager. */
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
/* Register the socket. */
|
||||||
|
return g_socket_info_manager.Register(socket, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnregisterSocket(s32 socket) {
|
||||||
|
/* Acquire exclusive access to the socket info manager. */
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
/* Unregister the socket. */
|
||||||
|
return g_socket_info_manager.Unregister(socket);
|
||||||
|
}
|
||||||
|
|
||||||
Result LaunchProgram(os::ProcessId *out, ncm::ProgramId program_id, const void *args, size_t args_size, u32 process_flags) {
|
Result LaunchProgram(os::ProcessId *out, ncm::ProgramId program_id, const void *args, size_t args_size, u32 process_flags) {
|
||||||
/* Set up the arguments. */
|
/* Set up the arguments. */
|
||||||
|
|
|
@ -17,6 +17,73 @@
|
||||||
|
|
||||||
namespace ams::scs {
|
namespace ams::scs {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
s32 CreateSocket() {
|
||||||
|
while (true) {
|
||||||
|
/* Try to create a socket. */
|
||||||
|
if (const auto desc = htcs::Socket(); desc >= 0) {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait 100ms before trying again. */
|
||||||
|
os::SleepThread(TimeSpan::FromMilliSeconds(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AcceptSocket(s32 listen_socket) {
|
||||||
|
htcs::SockAddrHtcs temp;
|
||||||
|
return htcs::Accept(listen_socket, std::addressof(temp));
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Bind(s32 socket, const htcs::HtcsPortName &port_name) {
|
||||||
|
/* Set up the bind address. */
|
||||||
|
htcs::SockAddrHtcs addr;
|
||||||
|
addr.family = htcs::HTCS_AF_HTCS;
|
||||||
|
addr.peer_name = htcs::GetPeerNameAny();
|
||||||
|
std::strcpy(addr.port_name.name, port_name.name);
|
||||||
|
|
||||||
|
/* Bind. */
|
||||||
|
return htcs::Bind(socket, std::addressof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
htcs::ssize_t Receive(s32 socket, void *buffer, size_t size) {
|
||||||
|
u8 *dst = static_cast<u8 *>(buffer);
|
||||||
|
size_t received = 0;
|
||||||
|
|
||||||
|
while (received < size) {
|
||||||
|
const auto ret = htcs::Recv(socket, dst + received, size - received, 0);
|
||||||
|
if (ret <= 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
received += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<htcs::ssize_t>(received);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReceiveCommand(CommandHeader *header, void *buffer, size_t buffer_size, s32 socket) {
|
||||||
|
/* Receive the header. */
|
||||||
|
if (Receive(socket, header, sizeof(*header)) != sizeof(*header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the body will fit in the buffer. */
|
||||||
|
if (header->body_size >= buffer_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive the body. */
|
||||||
|
if(Receive(socket, buffer, header->body_size) != static_cast<htcs::ssize_t>(header->body_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ShellServer::Initialize(const char *port_name, void *stack, size_t stack_size, CommandProcessor *command_processor) {
|
void ShellServer::Initialize(const char *port_name, void *stack, size_t stack_size, CommandProcessor *command_processor) {
|
||||||
/* Set our variables. */
|
/* Set our variables. */
|
||||||
m_command_processor = command_processor;
|
m_command_processor = command_processor;
|
||||||
|
@ -34,8 +101,53 @@ namespace ams::scs {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShellServer::DoShellServer() {
|
void ShellServer::DoShellServer() {
|
||||||
/* TODO */
|
/* Loop servicing the shell server. */
|
||||||
AMS_ABORT("ShellServer::DoShellServer");
|
while (true) {
|
||||||
|
/* Create a socket to listen on. */
|
||||||
|
const auto listen_socket = CreateSocket();
|
||||||
|
ON_SCOPE_EXIT { htcs::Close(listen_socket); };
|
||||||
|
|
||||||
|
/* Bind to the listen socket. */
|
||||||
|
if (Bind(listen_socket, m_port_name) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop processing on our bound socket. */
|
||||||
|
while (true) {
|
||||||
|
/* Listen on the socket. */
|
||||||
|
if (const s32 listen_result = htcs::Listen(listen_socket, 0); listen_result != 0) {
|
||||||
|
/* TODO: logging. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accept a socket. */
|
||||||
|
const s32 socket = AcceptSocket(listen_socket);
|
||||||
|
if (socket <= 0) {
|
||||||
|
/* TODO: logging. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that the socket is cleaned up when we're done with it. */
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
UnregisterSocket(socket);
|
||||||
|
htcs::Close(socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Loop servicing the socket. */
|
||||||
|
while (true) {
|
||||||
|
/* Receive a command header. */
|
||||||
|
CommandHeader header;
|
||||||
|
if (!ReceiveCommand(std::addressof(header), m_buffer, sizeof(m_buffer), socket)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the command. */
|
||||||
|
if (!m_command_processor->ProcessCommand(header, m_buffer, socket)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue