diff --git a/src/LibHac/Bcat/BcatServer.cs b/src/LibHac/Bcat/BcatServer.cs
index 1ddf0c96..20e72bf1 100644
--- a/src/LibHac/Bcat/BcatServer.cs
+++ b/src/LibHac/Bcat/BcatServer.cs
@@ -34,7 +34,7 @@ namespace LibHac.Bcat
IServiceCreator service = GetServiceCreator(type);
- Result rc = Hos.Sm.RegisterService(service, name);
+ Result rc = Hos.Sm.RegisterService(new BcatServiceObject(service), name);
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Abort");
diff --git a/src/LibHac/Bcat/Detail/Ipc/BcatServiceObject.cs b/src/LibHac/Bcat/Detail/Ipc/BcatServiceObject.cs
new file mode 100644
index 00000000..cff3d6f7
--- /dev/null
+++ b/src/LibHac/Bcat/Detail/Ipc/BcatServiceObject.cs
@@ -0,0 +1,20 @@
+using LibHac.Sm;
+
+namespace LibHac.Bcat.Detail.Ipc
+{
+ internal class BcatServiceObject : IServiceObject
+ {
+ private IServiceCreator _serviceCreator;
+
+ public BcatServiceObject(IServiceCreator serviceCreator)
+ {
+ _serviceCreator = serviceCreator;
+ }
+
+ public Result GetServiceObject(out object serviceObject)
+ {
+ serviceObject = _serviceCreator;
+ return Result.Success;
+ }
+ }
+}
diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs
index 7b9b86d0..1f605a9b 100644
--- a/src/LibHac/Fs/FileSystemClient.cs
+++ b/src/LibHac/Fs/FileSystemClient.cs
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
+using LibHac.Diag;
using LibHac.Fs.Accessors;
using LibHac.Fs.Fsa;
using LibHac.FsSrv;
@@ -11,7 +12,7 @@ namespace LibHac.Fs
{
public partial class FileSystemClient
{
- private FileSystemServer FsSrv { get; }
+ private HorizonClient Hos { get; }
private IFileSystemProxy FsProxy { get; set; }
private readonly object _fspInitLocker = new object();
@@ -26,22 +27,17 @@ namespace LibHac.Fs
Time = timer ?? new StopWatchTimeSpanGenerator();
}
- public FileSystemClient(FileSystemServer fsServer, ITimeSpanGenerator timer)
+ public FileSystemClient(HorizonClient horizonClient)
{
- FsSrv = fsServer;
- Time = timer ?? new StopWatchTimeSpanGenerator();
- }
+ Hos = horizonClient;
+ Time = horizonClient.Time;
- internal FileSystemClient(FileSystemServer fsServer, IFileSystemProxy fsProxy, ITimeSpanGenerator timer)
- {
- FsSrv = fsServer;
- FsProxy = fsProxy;
- Time = timer ?? new StopWatchTimeSpanGenerator();
+ Assert.NotNull(Time);
}
public bool HasFileSystemServer()
{
- return FsSrv != null;
+ return Hos != null;
}
public IFileSystemProxy GetFileSystemProxyServiceObject()
@@ -57,8 +53,16 @@ namespace LibHac.Fs
throw new InvalidOperationException("Client was not initialized with a server object.");
}
- FsProxy = FsSrv.CreateFileSystemProxyService();
+ Result rc = Hos.Sm.GetService(out IFileSystemProxy fsProxy, "fsp-srv");
+ if (rc.IsFailure())
+ {
+ throw new HorizonResultException(rc, "Failed to create file system proxy service object.");
+ }
+
+ fsProxy.SetCurrentProcess(Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
+
+ FsProxy = fsProxy;
return FsProxy;
}
}
diff --git a/src/LibHac/FsSrv/FileSystemProxy.cs b/src/LibHac/FsSrv/FileSystemProxy.cs
index ede552e8..b38c46d0 100644
--- a/src/LibHac/FsSrv/FileSystemProxy.cs
+++ b/src/LibHac/FsSrv/FileSystemProxy.cs
@@ -15,7 +15,7 @@ namespace LibHac.FsSrv
public class FileSystemProxy : IFileSystemProxy
{
private FileSystemProxyCore FsProxyCore { get; }
- internal FileSystemServer FsServer { get; }
+ internal HorizonClient Hos { get; }
public ulong CurrentProcess { get; private set; }
@@ -24,10 +24,10 @@ namespace LibHac.FsSrv
public FsPath SaveDataRootPath { get; }
public bool AutoCreateSaveData { get; private set; }
- internal FileSystemProxy(FileSystemProxyCore fsProxyCore, FileSystemServer fsServer)
+ internal FileSystemProxy(HorizonClient horizonClient, FileSystemProxyCore fsProxyCore)
{
FsProxyCore = fsProxyCore;
- FsServer = fsServer;
+ Hos = horizonClient;
CurrentProcess = ulong.MaxValue;
SaveDataSize = 0x2000000;
diff --git a/src/LibHac/FsSrv/FileSystemServer.cs b/src/LibHac/FsSrv/FileSystemServer.cs
index 0a54e754..c07765d1 100644
--- a/src/LibHac/FsSrv/FileSystemServer.cs
+++ b/src/LibHac/FsSrv/FileSystemServer.cs
@@ -3,6 +3,7 @@ using LibHac.Fs;
using LibHac.Fs.Impl;
using LibHac.Fs.Shim;
using LibHac.FsSrv.Creators;
+using LibHac.Sm;
namespace LibHac.FsSrv
{
@@ -13,15 +14,17 @@ namespace LibHac.FsSrv
private FileSystemProxyCore FsProxyCore { get; }
/// The client instance to be used for internal operations like save indexer access.
- public FileSystemClient FsClient { get; }
+ public HorizonClient Hos { get; }
+
public bool IsDebugMode { get; }
private ITimeSpanGenerator Timer { get; }
///
- /// Creates a new .
+ /// Creates a new and registers its services using the provided HOS client.
///
+ /// The that will be used by this server.
/// The configuration for the created .
- public FileSystemServer(FileSystemServerConfig config)
+ public FileSystemServer(HorizonClient horizonClient, FileSystemServerConfig config)
{
if (config.FsCreators == null)
throw new ArgumentException("FsCreators must not be null");
@@ -29,6 +32,8 @@ namespace LibHac.FsSrv
if (config.DeviceOperator == null)
throw new ArgumentException("DeviceOperator must not be null");
+ Hos = horizonClient;
+
IsDebugMode = false;
ExternalKeySet externalKeySet = config.ExternalKeySet ?? new ExternalKeySet();
@@ -41,17 +46,19 @@ namespace LibHac.FsSrv
};
FsProxyCore = new FileSystemProxyCore(fspConfig, externalKeySet, config.DeviceOperator);
- var fsProxy = new FileSystemProxy(FsProxyCore, this);
- FsClient = new FileSystemClient(this, fsProxy, Timer);
- // NS usually takes care of this
- if (FsClient.IsSdCardInserted())
- FsClient.SetSdCardAccessibility(true);
-
- FsProxyCore.SetSaveDataIndexerManager(new SaveDataIndexerManager(FsClient, SaveIndexerId,
+ FsProxyCore.SetSaveDataIndexerManager(new SaveDataIndexerManager(Hos.Fs, SaveIndexerId,
new ArrayPoolMemoryResource(), new SdHandleManager(), false));
+ FileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
+ fsProxy.SetCurrentProcess(Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
fsProxy.CleanUpTemporaryStorage().IgnoreResult();
+
+ Hos.Sm.RegisterService(new FileSystemProxyService(this), "fsp-srv").IgnoreResult();
+
+ // NS usually takes care of this
+ if (Hos.Fs.IsSdCardInserted())
+ Hos.Fs.SetSdCardAccessibility(true);
}
///
@@ -69,12 +76,35 @@ namespace LibHac.FsSrv
/// The created .
public FileSystemClient CreateFileSystemClient(ITimeSpanGenerator timer)
{
- return new FileSystemClient(this, timer);
+ return new FileSystemClient(Hos);
}
- public IFileSystemProxy CreateFileSystemProxyService()
+ private FileSystemProxy GetFileSystemProxyServiceObject()
{
- return new FileSystemProxy(FsProxyCore, this);
+ return new FileSystemProxy(Hos, FsProxyCore);
+ }
+
+ internal bool IsCurrentProcess(ulong processId)
+ {
+ ulong currentId = Hos.Os.GetCurrentProcessId().Value;
+
+ return processId == currentId;
+ }
+
+ private class FileSystemProxyService : IServiceObject
+ {
+ private readonly FileSystemServer _server;
+
+ public FileSystemProxyService(FileSystemServer server)
+ {
+ _server = server;
+ }
+
+ public Result GetServiceObject(out object serviceObject)
+ {
+ serviceObject = _server.GetFileSystemProxyServiceObject();
+ return Result.Success;
+ }
}
}
diff --git a/src/LibHac/FsSrv/Impl/MultiCommitManager.cs b/src/LibHac/FsSrv/Impl/MultiCommitManager.cs
index db2827b0..ea44f8e1 100644
--- a/src/LibHac/FsSrv/Impl/MultiCommitManager.cs
+++ b/src/LibHac/FsSrv/Impl/MultiCommitManager.cs
@@ -109,7 +109,7 @@ namespace LibHac.FsSrv.Impl
return rc;
}
- rc = FsProxy.FsServer.FsClient.CreateSystemSaveData(SaveDataId, SaveDataSize, SaveJournalSize,
+ rc = FsProxy.Hos.Fs.CreateSystemSaveData(SaveDataId, SaveDataSize, SaveJournalSize,
SaveDataFlags.None);
if (rc.IsFailure()) return rc;
}
diff --git a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs
index df866f7e..1f9c5ebf 100644
--- a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs
+++ b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs
@@ -183,12 +183,6 @@ namespace LibHac.FsSrv.Impl
return initialProcessIdLowerBound >= processId && processId <= initialProcessIdUpperBound;
}
- public static bool IsCurrentProcess(ulong processId)
- {
- // Todo: Don't use hardcoded value
- return true;
- }
-
internal static ProgramInfo CreateProgramInfoForInitialProcess(FileSystemServer fsServer)
{
return new ProgramInfo(fsServer, InitialProcessAccessControlDataHeader,
diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs
index 2f6509cf..85c5f110 100644
--- a/src/LibHac/Horizon.cs
+++ b/src/LibHac/Horizon.cs
@@ -1,7 +1,7 @@
-using LibHac.Common;
-using LibHac.Fs;
+using System.Threading;
+using LibHac.Bcat;
using LibHac.FsSrv;
-using LibHac.FsSrv.Creators;
+using LibHac.Os;
using LibHac.Sm;
namespace LibHac
@@ -9,63 +9,32 @@ namespace LibHac
public class Horizon
{
internal ITimeSpanGenerator Time { get; }
- private FileSystemServer FileSystemServer { get; set; }
internal ServiceManager ServiceManager { get; }
- private readonly object _initLocker = new object();
+ // long instead of ulong because the ulong Interlocked.Increment overload
+ // wasn't added until .NET 5
+ private long _currentProcessId;
- public Horizon(ITimeSpanGenerator timer)
+ public Horizon(ITimeSpanGenerator timer, FileSystemServerConfig fsServerConfig)
{
+ _currentProcessId = 0;
+
Time = timer ?? new StopWatchTimeSpanGenerator();
- ServiceManager = new ServiceManager(this);
+ ServiceManager = new ServiceManager();
+
+ // ReSharper disable ObjectCreationAsStatement
+ new FileSystemServer(CreateHorizonClient(), fsServerConfig);
+ new BcatServer(CreateHorizonClient());
+ // ReSharper restore ObjectCreationAsStatement
}
- public Horizon(ITimeSpanGenerator timer, FileSystemServer fsServer)
+ public HorizonClient CreateHorizonClient()
{
- Time = timer ?? new StopWatchTimeSpanGenerator();
- FileSystemServer = fsServer;
- ServiceManager = new ServiceManager(this);
- }
+ ulong processId = (ulong)Interlocked.Increment(ref _currentProcessId);
- private Result OpenFileSystemClient(out FileSystemClient client)
- {
- if (FileSystemServer is null)
- {
- client = default;
- return ResultLibHac.ServiceNotInitialized.Log();
- }
+ // Todo: Register process with FS
- client = FileSystemServer.CreateFileSystemClient();
- return Result.Success;
- }
-
- public Result CreateHorizonClient(out HorizonClient client)
- {
- Result rc = OpenFileSystemClient(out FileSystemClient fsClient);
- if (rc.IsFailure())
- {
- client = default;
- return rc;
- }
-
- client = new HorizonClient(this, fsClient);
- return Result.Success;
- }
-
- public void InitializeFileSystemServer(FileSystemCreators fsCreators, IDeviceOperator deviceOperator)
- {
- if (FileSystemServer != null) return;
-
- lock (_initLocker)
- {
- if (FileSystemServer != null) return;
-
- var config = new FileSystemServerConfig();
- config.FsCreators = fsCreators;
- config.DeviceOperator = deviceOperator;
-
- FileSystemServer = new FileSystemServer(config);
- }
+ return new HorizonClient(this, new ProcessId(processId));
}
}
}
diff --git a/src/LibHac/HorizonClient.cs b/src/LibHac/HorizonClient.cs
index 0801e6d6..029c698f 100644
--- a/src/LibHac/HorizonClient.cs
+++ b/src/LibHac/HorizonClient.cs
@@ -1,6 +1,7 @@
using System;
using LibHac.Arp;
using LibHac.Fs;
+using LibHac.Os;
using LibHac.Sm;
namespace LibHac
@@ -9,19 +10,25 @@ namespace LibHac
{
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private Horizon Horizon { get; }
+ internal ProcessId ProcessId { get; }
private Lazy ArpLazy { get; }
public FileSystemClient Fs { get; }
public ServiceManagerClient Sm { get; }
+ public OsClient Os { get; }
public ArpClient Arp => ArpLazy.Value;
- internal HorizonClient(Horizon horizon, FileSystemClient fsClient)
+ public ITimeSpanGenerator Time => Horizon.Time;
+
+ internal HorizonClient(Horizon horizon, ProcessId processId)
{
Horizon = horizon;
+ ProcessId = processId;
- Fs = fsClient;
+ Fs = new FileSystemClient(this);
Sm = new ServiceManagerClient(horizon.ServiceManager);
+ Os = new OsClient(this);
ArpLazy = new Lazy(InitArpClient, true);
}
diff --git a/src/LibHac/Os/OsClient.cs b/src/LibHac/Os/OsClient.cs
new file mode 100644
index 00000000..ec9b6e0e
--- /dev/null
+++ b/src/LibHac/Os/OsClient.cs
@@ -0,0 +1,17 @@
+namespace LibHac.Os
+{
+ public class OsClient
+ {
+ private HorizonClient Hos { get; }
+
+ internal OsClient(HorizonClient horizonClient)
+ {
+ Hos = horizonClient;
+ }
+
+ public ProcessId GetCurrentProcessId()
+ {
+ return Hos.ProcessId;
+ }
+ }
+}
diff --git a/src/LibHac/Os/ProcessId.cs b/src/LibHac/Os/ProcessId.cs
new file mode 100644
index 00000000..6f77a0d4
--- /dev/null
+++ b/src/LibHac/Os/ProcessId.cs
@@ -0,0 +1,11 @@
+namespace LibHac.Os
+{
+ public readonly struct ProcessId
+ {
+ public static ProcessId InvalidId => new ProcessId(ulong.MaxValue);
+
+ public readonly ulong Value;
+
+ public ProcessId(ulong value) => Value = value;
+ }
+}
diff --git a/src/LibHac/Sm/IServiceObject.cs b/src/LibHac/Sm/IServiceObject.cs
new file mode 100644
index 00000000..34cf7969
--- /dev/null
+++ b/src/LibHac/Sm/IServiceObject.cs
@@ -0,0 +1,9 @@
+namespace LibHac.Sm
+{
+ // This interface is being used as a stop-gap solution so we can
+ // have at least some sort of service system for now
+ public interface IServiceObject
+ {
+ Result GetServiceObject(out object serviceObject);
+ }
+}
diff --git a/src/LibHac/Sm/ServiceManager.cs b/src/LibHac/Sm/ServiceManager.cs
index 0ecd38f4..2bd5ae31 100644
--- a/src/LibHac/Sm/ServiceManager.cs
+++ b/src/LibHac/Sm/ServiceManager.cs
@@ -11,14 +11,7 @@ namespace LibHac.Sm
// isn't blocked waiting for something better.
internal class ServiceManager
{
- // ReSharper disable once UnusedAutoPropertyAccessor.Local
- private Horizon Horizon { get; }
- private Dictionary Services { get; } = new Dictionary();
-
- public ServiceManager(Horizon horizon)
- {
- Horizon = horizon;
- }
+ private Dictionary Services { get; } = new Dictionary();
internal Result GetService(out object serviceObject, ServiceName serviceName)
{
@@ -27,20 +20,20 @@ namespace LibHac.Sm
Result rc = ValidateServiceName(serviceName);
if (rc.IsFailure()) return rc;
- if (!Services.TryGetValue(serviceName, out serviceObject))
+ if (!Services.TryGetValue(serviceName, out IServiceObject service))
{
return ResultSf.RequestDeferredByUser.Log();
}
- return Result.Success;
+ return service.GetServiceObject(out serviceObject);
}
- internal Result RegisterService(object serviceObject, ServiceName serviceName)
+ internal Result RegisterService(IServiceObject service, ServiceName serviceName)
{
Result rc = ValidateServiceName(serviceName);
if (rc.IsFailure()) return rc;
- if (!Services.TryAdd(serviceName, serviceObject))
+ if (!Services.TryAdd(serviceName, service))
{
return ResultSm.AlreadyRegistered.Log();
}
@@ -53,11 +46,12 @@ namespace LibHac.Sm
Result rc = ValidateServiceName(serviceName);
if (rc.IsFailure()) return rc;
- if (!Services.Remove(serviceName, out object service))
+ if (!Services.Remove(serviceName, out IServiceObject service))
{
return ResultSm.NotRegistered.Log();
}
+ // ReSharper disable once SuspiciousTypeConversion.Global
if (service is IDisposable disposable)
{
disposable.Dispose();
diff --git a/src/LibHac/Sm/ServiceManagerClient.cs b/src/LibHac/Sm/ServiceManagerClient.cs
index 0930e6ed..b5f77934 100644
--- a/src/LibHac/Sm/ServiceManagerClient.cs
+++ b/src/LibHac/Sm/ServiceManagerClient.cs
@@ -29,7 +29,7 @@ namespace LibHac.Sm
throw new InvalidCastException("The service object is not of the specified type.");
}
- public Result RegisterService(object serviceObject, ReadOnlySpan name)
+ public Result RegisterService(IServiceObject serviceObject, ReadOnlySpan name)
{
return Server.RegisterService(serviceObject, ServiceName.Encode(name));
}
diff --git a/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs b/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs
index ee815fc5..7f4c8135 100644
--- a/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs
+++ b/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs
@@ -6,7 +6,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests
{
public static class FileSystemServerFactory
{
- public static FileSystemServer CreateServer(bool sdCardInserted, out IFileSystem rootFs)
+ private static FileSystemClient CreateClientImpl(bool sdCardInserted, out IFileSystem rootFs)
{
rootFs = new InMemoryFileSystem();
@@ -19,23 +19,21 @@ namespace LibHac.Tests.Fs.FileSystemClientTests
config.DeviceOperator = defaultObjects.DeviceOperator;
config.ExternalKeySet = new ExternalKeySet();
- var fsServer = new FileSystemServer(config);
+ var horizon = new Horizon(new StopWatchTimeSpanGenerator(), config);
- return fsServer;
+ HorizonClient horizonClient = horizon.CreateHorizonClient();
+
+ return horizonClient.Fs;
}
public static FileSystemClient CreateClient(bool sdCardInserted)
{
- FileSystemServer fsServer = CreateServer(sdCardInserted, out _);
-
- return fsServer.CreateFileSystemClient();
+ return CreateClientImpl(sdCardInserted, out _);
}
public static FileSystemClient CreateClient(out IFileSystem rootFs)
{
- FileSystemServer fsServer = CreateServer(false, out rootFs);
-
- return fsServer.CreateFileSystemClient();
+ return CreateClientImpl(false, out rootFs);
}
}
}