diff options
Diffstat (limited to 'Ryujinx.Horizon/Sm/Impl/ServiceManager.cs')
-rw-r--r-- | Ryujinx.Horizon/Sm/Impl/ServiceManager.cs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs new file mode 100644 index 00000000..cdf2d17f --- /dev/null +++ b/Ryujinx.Horizon/Sm/Impl/ServiceManager.cs @@ -0,0 +1,197 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Sm.Impl +{ + class ServiceManager + { + private const int MaxServicesCount = 256; + + private readonly ServiceInfo[] _services; + + public ServiceManager() + { + _services = new ServiceInfo[MaxServicesCount]; + } + + public Result GetService(out int handle, ulong processId, ServiceName name) + { + handle = 0; + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + + int serviceIndex = GetServiceInfo(name); + + if (serviceIndex < 0) + { + return SfResult.RequestDeferredByUser; + } + + result = GetServiceImpl(out handle, ref _services[serviceIndex]); + + if (result == KernelResult.SessionCountExceeded) + { + return SmResult.OutOfSessions; + } + + return result; + } + + private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo) + { + return HorizonStatic.Syscall.ConnectToPort(out handle, serviceInfo.PortHandle); + } + + public Result RegisterService(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight) + { + handle = 0; + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + + if (HasServiceInfo(name)) + { + return SmResult.AlreadyRegistered; + } + + return RegisterServiceImpl(out handle, processId, name, maxSessions, isLight); + } + + public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions) + { + return RegisterServiceImpl(out handle, Os.GetCurrentProcessId(), name, maxSessions, false); + } + + private Result RegisterServiceImpl(out int handle, ulong processId, ServiceName name, int maxSessions, bool isLight) + { + handle = 0; + + Result result = ValidateServiceName(name); + + if (!result.IsSuccess) + { + return result; + } + + if (HasServiceInfo(name)) + { + return SmResult.AlreadyRegistered; + } + + int freeServiceIndex = GetFreeService(); + + if (freeServiceIndex < 0) + { + return SmResult.OutOfServices; + } + + ref ServiceInfo freeService = ref _services[freeServiceIndex]; + + result = HorizonStatic.Syscall.CreatePort(out handle, out int clientPort, maxSessions, isLight, null); + + if (!result.IsSuccess) + { + return result; + } + + freeService.PortHandle = clientPort; + freeService.Name = name; + freeService.OwnerProcessId = processId; + + return Result.Success; + } + + public Result UnregisterService(ulong processId, ServiceName name) + { + Result result = ValidateServiceName(name); + + if (result.IsFailure) + { + return result; + } + + // TODO: Validation with GetProcessInfo etc. + + int serviceIndex = GetServiceInfo(name); + + if (serviceIndex < 0) + { + return SmResult.NotRegistered; + } + + ref var serviceInfo = ref _services[serviceIndex]; + + if (serviceInfo.OwnerProcessId != processId) + { + return SmResult.NotAllowed; + } + + serviceInfo.Free(); + return Result.Success; + } + + private static Result ValidateServiceName(ServiceName name) + { + if (name[0] == 0) + { + return SmResult.InvalidServiceName; + } + + int nameLength = 1; + + for (; nameLength < name.Length; nameLength++) + { + if (name[nameLength] == 0) + { + break; + } + } + + while (nameLength < name.Length) + { + if (name[nameLength++] != 0) + { + return SmResult.InvalidServiceName; + } + } + + return Result.Success; + } + + private bool HasServiceInfo(ServiceName name) + { + return GetServiceInfo(name) != -1; + } + + private int GetFreeService() + { + return GetServiceInfo(ServiceName.Invalid); + } + + private int GetServiceInfo(ServiceName name) + { + for (int index = 0; index < MaxServicesCount; index++) + { + if (_services[index].Name == name) + { + return index; + } + } + + return -1; + } + } +} |