From 2c1e119c4a57fdd26dc8249d9b5fca3111195777 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 10 May 2021 16:18:30 -0700
Subject: [PATCH] hle: service: sm: Add TIPC support.

- Fixes our error checking of names as well.
---
 src/core/hle/service/sm/sm.cpp | 102 ++++++++++++++++++++-------------
 src/core/hle/service/sm/sm.h   |   9 ++-
 2 files changed, 68 insertions(+), 43 deletions(-)

diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 726bef4c33..391db48b1d 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -9,6 +9,7 @@
 #include "core/hle/kernel/k_client_port.h"
 #include "core/hle/kernel/k_client_session.h"
 #include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
 #include "core/hle/kernel/k_server_port.h"
 #include "core/hle/kernel/k_server_session.h"
 #include "core/hle/kernel/k_session.h"
@@ -18,6 +19,7 @@
 
 namespace Service::SM {
 
+constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
 constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
 constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
 constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
@@ -34,20 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) {
         LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
         return ERR_INVALID_NAME;
     }
-    if (name.rfind('\0') != std::string::npos) {
-        LOG_ERROR(Service_SM, "A non null terminated service was passed");
-        return ERR_INVALID_NAME;
-    }
     return RESULT_SUCCESS;
 }
 
-void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) {
-    ASSERT(self->sm_interface.expired());
+Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
+    ASSERT(self.sm_interface.expired());
 
     auto sm = std::make_shared<SM>(self, system);
-    sm->InstallAsNamedPort(system.Kernel());
-    self->sm_interface = sm;
-    self->controller_interface = std::make_unique<Controller>(system);
+    self.sm_interface = sm;
+    self.controller_interface = std::make_unique<Controller>(system);
+
+    return sm->CreatePort(system.Kernel());
 }
 
 ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
@@ -114,21 +113,47 @@ void SM::Initialize(Kernel::HLERequestContext& ctx) {
 }
 
 void SM::GetService(Kernel::HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    auto name_buf = rp.PopRaw<std::array<char, 8>>();
-    auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
-
-    std::string name(name_buf.begin(), end);
-
-    auto result = service_manager->GetServicePort(name);
-    if (result.Failed()) {
+    auto result = GetServiceImpl(ctx);
+    if (result.Succeeded()) {
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+        rb.Push(result.Code());
+        rb.PushMoveObjects(result.Unwrap());
+    } else {
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(result.Code());
+    }
+}
+
+void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
+    auto result = GetServiceImpl(ctx);
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+    rb.Push(result.Code());
+    rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
+}
+
+static std::string PopServiceName(IPC::RequestParser& rp) {
+    auto name_buf = rp.PopRaw<std::array<char, 8>>();
+    std::string result;
+    for (const auto& c : name_buf) {
+        if (c >= ' ' && c <= '~') {
+            result.push_back(c);
+        }
+    }
+    return result;
+}
+
+ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
+    if (!is_initialized) {
+        return ERR_NOT_INITIALIZED;
+    }
+
+    IPC::RequestParser rp{ctx};
+    std::string name(PopServiceName(rp));
+
+    auto result = service_manager.GetServicePort(name);
+    if (result.Failed()) {
         LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
-        if (name.length() == 0)
-            return; // LibNX Fix
-        UNIMPLEMENTED();
-        return;
+        return result.Code();
     }
 
     auto* port = result.Unwrap();
@@ -150,18 +175,12 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
     }
 
     LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
-    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
-    rb.Push(RESULT_SUCCESS);
-    rb.PushMoveObjects(session->GetClientSession());
+    return MakeResult(&session->GetClientSession());
 }
 
 void SM::RegisterService(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
-
-    const auto name_buf = rp.PopRaw<std::array<char, 8>>();
-    const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
-
-    const std::string name(name_buf.begin(), end);
+    std::string name(PopServiceName(rp));
 
     const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
     const auto max_session_count = rp.PopRaw<u32>();
@@ -169,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
               max_session_count, is_light);
 
-    auto handle = service_manager->RegisterService(name, max_session_count);
+    auto handle = service_manager.RegisterService(name, max_session_count);
     if (handle.Failed()) {
         LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
                   handle.Code().raw);
@@ -187,28 +206,31 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
 
 void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
+    std::string name(PopServiceName(rp));
 
-    const auto name_buf = rp.PopRaw<std::array<char, 8>>();
-    const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
-
-    const std::string name(name_buf.begin(), end);
     LOG_DEBUG(Service_SM, "called with name={}", name);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(service_manager->UnregisterService(name));
+    rb.Push(service_manager.UnregisterService(name));
 }
 
-SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
+SM::SM(ServiceManager& service_manager_, Core::System& system_)
     : ServiceFramework{system_, "sm:", 4},
-      service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
-    static const FunctionInfo functions[] = {
+      service_manager{service_manager_}, kernel{system_.Kernel()} {
+    RegisterHandlers({
         {0, &SM::Initialize, "Initialize"},
         {1, &SM::GetService, "GetService"},
         {2, &SM::RegisterService, "RegisterService"},
         {3, &SM::UnregisterService, "UnregisterService"},
         {4, nullptr, "DetachClient"},
-    };
-    RegisterHandlers(functions);
+    });
+    RegisterHandlersTipc({
+        {0, &SM::Initialize, "Initialize"},
+        {1, &SM::GetServiceTipc, "GetService"},
+        {2, &SM::RegisterService, "RegisterService"},
+        {3, &SM::UnregisterService, "UnregisterService"},
+        {4, nullptr, "DetachClient"},
+    });
 }
 
 } // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index fed65af4f2..60f0b3f8a8 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -34,23 +34,26 @@ class Controller;
 /// Interface to "sm:" service
 class SM final : public ServiceFramework<SM> {
 public:
-    explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_);
+    explicit SM(ServiceManager& service_manager_, Core::System& system_);
     ~SM() override;
 
 private:
     void Initialize(Kernel::HLERequestContext& ctx);
     void GetService(Kernel::HLERequestContext& ctx);
+    void GetServiceTipc(Kernel::HLERequestContext& ctx);
     void RegisterService(Kernel::HLERequestContext& ctx);
     void UnregisterService(Kernel::HLERequestContext& ctx);
 
-    std::shared_ptr<ServiceManager> service_manager;
+    ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx);
+
+    ServiceManager& service_manager;
     bool is_initialized{};
     Kernel::KernelCore& kernel;
 };
 
 class ServiceManager {
 public:
-    static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system);
+    static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
 
     explicit ServiceManager(Kernel::KernelCore& kernel_);
     ~ServiceManager();