public void MultipleProcessesCanWriteToTheLog() { var logFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); TimestampedFileLogger logger = new(logFile); // Log requests operates using PipeTransmissionMode.Message NamedPipeServerStream np1 = CreateServerPipe("np1"); PipeStreamSetupLogger pssl1 = new PipeStreamSetupLogger(np1, "np1"); NamedPipeServerStream np2 = CreateServerPipe("np2"); PipeStreamSetupLogger pssl2 = new PipeStreamSetupLogger(np2, "np2"); logger.AddNamedPipe("np1"); logger.AddNamedPipe("np2"); logger.LogMessage("Foo"); var t1 = Task.Run(() => { pssl1.Connect(); pssl1.LogMessage("Hello from np1"); }); var t2 = Task.Run(() => { pssl2.Connect(); pssl2.LogMessage("Hello from np2"); }); // Give the other threads time to connect to the logging thread. Task.WaitAll(t1, t2); logger.Dispose(); string logContent = File.ReadAllText(logFile); Assert.Contains("Hello from np1", logContent); Assert.Contains("Hello from np2", logContent); }
private void LogTask(string pipeName) { using NamedPipeServerStream serverPipe = CreateServerPipe(pipeName); PipeStreamSetupLogger logger = new PipeStreamSetupLogger(serverPipe, pipeName); logger.Connect(); for (int i = 0; i < 10; i++) { logger.LogMessage($"Hello from {pipeName} ({i})."); } }
/// <summary> /// Creates a new <see cref="NetSdkMsiInstallerServer"/> instance. /// </summary> /// <returns></returns> public static NetSdkMsiInstallerServer Create() { if (!WindowsUtils.IsAdministrator()) { throw new UnauthorizedAccessException(LocalizableStrings.InsufficientPrivilegeToStartServer); } // Best effort to verify that the server was not started indirectly or being spoofed. if ((ParentProcess == null) || (ParentProcess.StartTime > CurrentProcess.StartTime) || string.IsNullOrWhiteSpace(CurrentProcess.MainModule.FileName) || !string.Equals(ParentProcess.MainModule.FileName, CurrentProcess.MainModule.FileName, StringComparison.OrdinalIgnoreCase)) { throw new SecurityException(String.Format(LocalizableStrings.NoTrustWithParentPID, ParentProcess?.Id)); } // Configure pipe DACLs SecurityIdentifier authenticatedUserIdentifier = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null); SecurityIdentifier currentOwnerIdentifier = WindowsIdentity.GetCurrent().Owner; PipeSecurity pipeSecurity = new(); // The current user has full control and should be running as Administrator. pipeSecurity.SetOwner(currentOwnerIdentifier); pipeSecurity.AddAccessRule(new PipeAccessRule(currentOwnerIdentifier, PipeAccessRights.FullControl, AccessControlType.Allow)); // Restrict read/write access to authenticated users pipeSecurity.AddAccessRule(new PipeAccessRule(authenticatedUserIdentifier, PipeAccessRights.Read | PipeAccessRights.Write | PipeAccessRights.Synchronize, AccessControlType.Allow)); // Initialize the named pipe for dispatching commands. The name of the pipe is based off the server PID since // the client knows this value and ensures both processes can generate the same name. string pipeName = WindowsUtils.CreatePipeName(CurrentProcess.Id); NamedPipeServerStream serverPipe = NamedPipeServerStreamAcl.Create(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 65535, 65535, pipeSecurity); InstallMessageDispatcher dispatcher = new(serverPipe); // The client process will generate the actual log file. The server will log messages through a separate pipe. string logPipeName = WindowsUtils.CreatePipeName(CurrentProcess.Id, "log"); NamedPipeServerStream logPipe = NamedPipeServerStreamAcl.Create(logPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 65535, 65535, pipeSecurity); PipeStreamSetupLogger logger = new PipeStreamSetupLogger(logPipe, logPipeName); InstallServerElevationContext elevationContext = new(serverPipe); return(new NetSdkMsiInstallerServer(elevationContext, logger)); }
public NetSdkMsiInstallerServer(InstallElevationContextBase elevationContext, PipeStreamSetupLogger logger) : base(elevationContext, logger) { // Establish a connection with the install client and logger. We're relying on tasks to handle // this, otherwise, the ordering needs to be lined up with how the client configures // the underlying pipe streams to avoid deadlock. Task dispatchTask = new Task(() => Dispatcher.Connect()); Task loggerTask = new Task(() => logger.Connect()); dispatchTask.Start(); loggerTask.Start(); Task.WaitAll(dispatchTask, loggerTask); }