using System.IO.Pipes; using System.Security.Principal; using H.Pipes; using H.Pipes.AccessControl; using InABox.Core; namespace InABox.IPC { public class RPCServerTransport : IDisposable { PipeServer Server; private Dictionary _commands = new Dictionary(); public void AddCommandHandler(RPCCommandHandler commandHandler) where TCommand : IRPCCommand where TSender : class { _commands[typeof(TCommand).Name] = commandHandler; } public event LogFunction? OnLog; private void SetPipeSecurity() { #pragma warning disable CA1416 var pipeSecurity = new PipeSecurity(); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSid, null), PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null), PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow)); pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow)); Server.SetPipeSecurity(pipeSecurity); #pragma warning restore CA1416 } public RPCServerTransport(string name) { Server = new PipeServer(name); #if WINDOWS SetPipeSecurity(); #endif Server.ClientConnected += Server_ClientConnected; Server.ClientDisconnected += Server_ClientDisconnected; Server.MessageReceived += Server_MessageReceived; Server.ExceptionOccurred += Server_ExceptionOccurred; } private void Server_ExceptionOccurred(object? sender, H.Pipes.Args.ExceptionEventArgs e) { OnLog?.Invoke(LogType.Error, "", $"Exception Occurred: {e.Exception.Message}"); } public void Start() { Server.StartAsync().Wait(); } private void Server_MessageReceived(object? sender, H.Pipes.Args.ConnectionMessageEventArgs e) { Task.Run(() => { if (e.Message != null) { RPCMessage message = new RPCMessage(e.Message.RequestID, e.Message.Command, ""); if (!_commands.TryGetValue(e.Message.Command, out var command)) message.Error = RPCError.COMMANDNOTFOUND; else { try { message.Payload = command.Execute(sender!, e.Message.Payload) ?? ""; } catch (Exception err) { OnLog?.Invoke(LogType.Error, "", err.Message); message.Error = RPCError.SERVERERROR; } } e.Connection.WriteAsync(message); } else OnLog?.Invoke(LogType.Error, "", "Null Message Received"); } ); } private void Server_ClientDisconnected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { OnLog?.Invoke(LogType.Information, "", "Client Disconnected"); e.Connection.DisposeAsync(); } private void Server_ClientConnected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { OnLog?.Invoke(LogType.Information, "", "Client Connected"); } public void Dispose() { Server.DisposeAsync().AsTask().Wait(); } ~RPCServerTransport() { Dispose(); } } }