using System.IO.Pipes; using System.Security.Principal; using H.Formatters; using H.Pipes; using H.Pipes.AccessControl; namespace InABox.Rpc { public class RpcServerPipeTransport : RpcServerTransport>, IDisposable { private PipeServer _transport; public override bool IsSecure() => false; 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)); _transport.SetPipeSecurity(pipeSecurity); #pragma warning restore CA1416 } public RpcServerPipeTransport(string name) { _transport = new PipeServer(name, formatter:new MessagePackFormatter()); #if WINDOWS SetPipeSecurity(); #endif _transport.ClientConnected += Transport_OnConnected; _transport.ClientDisconnected += Transport_OnDisconnected; _transport.MessageReceived += Transport_OnMessage; _transport.ExceptionOccurred += Transport_OnException; } public override void Start() { _transport.StartAsync().Wait(); } public override void Stop() { _transport.StopAsync().Wait(); } private void Transport_OnConnected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { DoOpen(e.Connection); } private void Transport_OnMessage(object? sender, H.Pipes.Args.ConnectionMessageEventArgs e) { Task.Run(() => { var response = DoMessage(e.Connection, e.Message); e.Connection.WriteAsync(response); }); } public override void Send(PipeConnection connection, RpcMessage message) { connection.WriteAsync(message); } private void Transport_OnDisconnected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { DoClose(e.Connection, RpcTransportCloseEventType.Closed); e.Connection.DisposeAsync(); } private void Transport_OnException(object? sender, H.Pipes.Args.ExceptionEventArgs e) { DoException(null, e.Exception); } public void Dispose() { _transport.DisposeAsync().AsTask().Wait(); } ~RpcServerPipeTransport() { Dispose(); } } }