diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp
index 632c0e446..3ed5d71e7 100644
--- a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp
+++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp
@@ -111,7 +111,6 @@ namespace ams::htc::server {
if (m_rpc_client.WaitAny(htclow::ChannelState_Disconnected, m_cancel_event.GetBase()) != 0) {
break;
}
-
}
}
@@ -150,7 +149,6 @@ namespace ams::htc::server {
if (m_rpc_server.WaitAny(htclow::ChannelState_Disconnected, m_cancel_event.GetBase()) != 0) {
break;
}
-
}
}
diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp
new file mode 100644
index 000000000..b7ff385be
--- /dev/null
+++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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 "htcfs_client_impl.hpp"
+#include "../htclow/htclow_default_channel_config.hpp"
+
+namespace ams::htcfs {
+
+ namespace {
+
+ /* TODO: Move to a header? */
+ constexpr u16 RpcChannelId = 0;
+
+ alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize];
+
+ constinit u8 g_cache[32_KB];
+
+ }
+
+ ClientImpl::ClientImpl(htclow::HtclowManager *manager)
+ : m_htclow_manager(manager),
+ m_cache_manager(g_cache, sizeof(g_cache)),
+ m_header_factory(),
+ m_mutex(),
+ m_module(htclow::ModuleId::Htcfs),
+ m_rpc_channel(manager),
+ m_data_channel(manager),
+ m_connected(false),
+ m_event(os::EventClearMode_ManualClear)
+ {
+ /* Start our thread. */
+ this->Start();
+ }
+
+ void ClientImpl::Start() {
+ /* Create our thread. */
+ os::CreateThread(std::addressof(m_monitor_thread), ThreadEntry, this, g_monitor_thread_stack, sizeof(g_monitor_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsMonitor));
+
+ /* Set thread name pointer. */
+ os::SetThreadNamePointer(std::addressof(m_monitor_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcfsMonitor));
+
+ /* Start our thread. */
+ os::StartThread(std::addressof(m_monitor_thread));
+ }
+
+ void ClientImpl::Cancel() {
+ /* Signal our event. */
+ m_event.Signal();
+ }
+
+ void ClientImpl::Wait() {
+ /* Wait for and destroy our thread. */
+ os::WaitThread(std::addressof(m_monitor_thread));
+ os::DestroyThread(std::addressof(m_monitor_thread));
+ }
+
+ void ClientImpl::ThreadBody() {
+ /* Loop forever, until we're cancelled. */
+ while (!m_event.TryWait()) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Open our channel. */
+ R_ABORT_UNLESS(m_rpc_channel.Open(std::addressof(m_module), RpcChannelId));
+
+ /* Ensure that we clean up our channel when we're done. */
+ ON_SCOPE_EXIT {
+ m_rpc_channel.Close();
+ m_cache_manager.Invalidate();
+ };
+
+ /* Set our channel config and buffers. */
+ m_rpc_channel.SetConfig(htclow::DefaultChannelConfig);
+ m_rpc_channel.SetReceiveBuffer(m_receive_buffer, sizeof(m_receive_buffer));
+ m_rpc_channel.SetSendBuffer(m_send_buffer, sizeof(m_send_buffer));
+
+ /* Wait for our channel state to be connectable. */
+ if (this->WaitAny(htclow::ChannelState_Connectable, m_event.GetBase()) != 0) {
+ return;
+ }
+
+ /* Ensure that when we're done, we reset our connected status. */
+ ON_SCOPE_EXIT { m_connected = false; };
+
+ /* Try to connect. */
+ const Result conn_result = m_rpc_channel.Connect();
+ if (R_FAILED(conn_result)) {
+ /* DEBUG */
+ R_ABORT_UNLESS(conn_result);
+ continue;
+ }
+
+ /* Ensure that we manage our connection correctly. */
+ auto conn_guard = SCOPE_GUARD { m_rpc_channel.Shutdown(); };
+
+ /* Try to set up the protocol. */
+ const Result setup_result = this->SetUpProtocol();
+ if (R_FAILED(setup_result)) {
+ R_ABORT_UNLESS(setup_result);
+ continue;
+ }
+
+ /* We're properly connected now. */
+ m_connected = true;
+ conn_guard.Cancel();
+
+ /* Tear down the protocol when we're done processing. */
+ ON_SCOPE_EXIT { this->TearDownProtocol(); };
+
+ /* Wait to become disconnected. */
+ if (this->WaitAny(htclow::ChannelState_Disconnected, m_event.GetBase()) != 0) {
+ break;
+ }
+ }
+ }
+
+ int ClientImpl::WaitAny(htclow::ChannelState state, os::EventType *event) {
+ /* Wait. */
+ int idx = 0;
+ while (m_rpc_channel.GetChannelState() != state) {
+ /* Get the channel state event. */
+ os::EventType *channel_state_event = m_rpc_channel.GetChannelStateEvent();
+
+ /* Perform wait with lock temporarily not held. */
+ {
+ m_mutex.Unlock();
+ idx = os::WaitAny(channel_state_event, event);
+ m_mutex.Lock();
+ }
+
+ /* If we're cancel-signalled, we're done. */
+ if (idx != 0) {
+ break;
+ }
+
+ /* Clear the channel state event. */
+ os::ClearEvent(channel_state_event);;
+ }
+ return idx;
+ }
+
+ Result ClientImpl::SetUpProtocol() {
+ /* TODO: Actual client <-> host RPC here. */
+ m_header_factory.SetVersion(1);
+ return ResultSuccess();
+ }
+
+ void ClientImpl::TearDownProtocol() {
+ /* Set the header factory version to zero. */
+ m_header_factory.SetVersion(0);
+ }
+
+}
diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp
index fd5508c62..8403186d1 100644
--- a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp
+++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp
@@ -32,11 +32,15 @@ namespace ams::htcfs {
HeaderFactory m_header_factory;
os::SdkMutex m_mutex;
htclow::Module m_module;
- htclow::Channel m_channel;
+ htclow::Channel m_rpc_channel;
htclow::Channel m_data_channel;
bool m_connected;
os::ThreadType m_monitor_thread;
os::Event m_event;
+ private:
+ static void ThreadEntry(void *arg) { static_cast(arg)->ThreadBody(); }
+
+ void ThreadBody();
public:
ClientImpl(htclow::HtclowManager *manager);
@@ -48,6 +52,11 @@ namespace ams::htcfs {
void Start();
void Cancel();
void Wait();
+ private:
+ int WaitAny(htclow::ChannelState state, os::EventType *event);
+
+ Result SetUpProtocol();
+ void TearDownProtocol();
};
}
diff --git a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp
index 643c98653..8fe691f5b 100644
--- a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp
+++ b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp
@@ -24,7 +24,8 @@ namespace ams::htcfs {
public:
HeaderFactory() : m_version() { /* ... */ }
public:
- /* ... */
+ s16 GetVersion() const { return m_version; }
+ void SetVersion(s16 version) { m_version = version; }
};
}
diff --git a/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp b/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp
index f550aa9b4..c23db56f2 100644
--- a/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp
+++ b/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp
@@ -23,7 +23,7 @@ namespace ams::htcfs {
static constexpr inline size_t NumServers = 1;
static constexpr inline size_t MaxSessions = 30;
- static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("htcfs");
+ static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("file_io");
struct ServerOptions {
static constexpr size_t PointerBufferSize = 0x1000;
diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp
index 2a64382ce..48d27b132 100644
--- a/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp
+++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp
@@ -21,6 +21,8 @@ namespace ams::htclow::ctrl {
namespace {
+ constexpr auto JsonParseFlags = rapidjson::kParseTrailingCommasFlag | rapidjson::kParseInsituFlag;
+
void ParseBody(s16 *out_version, const char **out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) {
/* Create JSON handler. */
JsonHandler json_handler(out_version, out_channels, out_num_channels, max_channels);
@@ -32,7 +34,7 @@ namespace ams::htclow::ctrl {
rapidjson::InsituStringStream json_stream(static_cast(str));
/* Parse the json. */
- json_reader.Parse(json_stream, json_handler);
+ json_reader.Parse(json_stream, json_handler);
}
constexpr bool IsNumericCharacter(char c) {
diff --git a/stratosphere/htc/source/htc_main.cpp b/stratosphere/htc/source/htc_main.cpp
index a3e651a12..5f2bc88fd 100644
--- a/stratosphere/htc/source/htc_main.cpp
+++ b/stratosphere/htc/source/htc_main.cpp
@@ -303,4 +303,3 @@ int main(int argc, char **argv)
return 0;
}
-