| File: System\IO\Pipes\AnonymousPipeServerStream.cs | Web Access |
| Project: src\runtime\src\libraries\System.IO.Pipes\src\System.IO.Pipes.csproj (System.IO.Pipes) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Win32.SafeHandles; namespace System.IO.Pipes { /// <summary> /// Anonymous pipe server stream /// </summary> public sealed partial class AnonymousPipeServerStream : PipeStream { private SafePipeHandle _clientHandle = null!; private bool _clientHandleExposed, _clientHandleExposedAsString; private readonly HandleInheritability _inheritability; public AnonymousPipeServerStream() : this(PipeDirection.Out, HandleInheritability.None, 0) { } public AnonymousPipeServerStream(PipeDirection direction) : this(direction, HandleInheritability.None, 0) { } public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability) : this(direction, inheritability, 0) { } // Create an AnonymousPipeServerStream from two existing pipe handles. public AnonymousPipeServerStream(PipeDirection direction, SafePipeHandle serverSafePipeHandle, SafePipeHandle clientSafePipeHandle) : base(direction, 0) { if (direction == PipeDirection.InOut) { throw new NotSupportedException(SR.NotSupported_AnonymousPipeUnidirectional); } ArgumentNullException.ThrowIfNull(serverSafePipeHandle); ArgumentNullException.ThrowIfNull(clientSafePipeHandle); if (serverSafePipeHandle.IsInvalid) { throw new ArgumentException(SR.Argument_InvalidHandle, nameof(serverSafePipeHandle)); } if (clientSafePipeHandle.IsInvalid) { throw new ArgumentException(SR.Argument_InvalidHandle, nameof(clientSafePipeHandle)); } ValidateHandleIsPipe(serverSafePipeHandle); ValidateHandleIsPipe(clientSafePipeHandle); InitializeHandle(serverSafePipeHandle, true, false); _clientHandle = clientSafePipeHandle; _clientHandleExposed = true; State = PipeState.Connected; } // bufferSize is used as a suggestion; specify 0 to let OS decide // This constructor instantiates the PipeSecurity using just the inheritability flag public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability, int bufferSize) : base(direction, bufferSize) { if (direction == PipeDirection.InOut) { throw new NotSupportedException(SR.NotSupported_AnonymousPipeUnidirectional); } if (inheritability < HandleInheritability.None || inheritability > HandleInheritability.Inheritable) { throw new ArgumentOutOfRangeException(nameof(inheritability), SR.ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable); } Create(direction, inheritability, bufferSize); _inheritability = inheritability; } ~AnonymousPipeServerStream() { Dispose(false); } // This method should exist until we add a first class way of passing handles between parent and child // processes. For now, people do it via command line arguments. public string GetClientHandleAsString() { _clientHandleExposedAsString = _clientHandleExposed = true; GC.SuppressFinalize(_clientHandle); return _clientHandle.DangerousGetHandle().ToString(); } public SafePipeHandle ClientSafePipeHandle { get { _clientHandleExposed = true; return _clientHandle; } } // This method is an annoying one but it has to exist at least until we make passing handles between // processes first class. We need this because once the child handle is inherited, the OS considers // the parent and child's handles to be different. Therefore, if a child closes its handle, our // Read/Write methods won't throw because the OS will think that there is still a child handle around // that can still Write/Read to/from the other end of the pipe. // // Ideally, we would want the Process class to close this handle after it has been inherited. See // the pipe spec future features section for more information. // // Right now, this is the best signal to set the anonymous pipe as connected; if this is called, we // know the client has been passed the handle and so the connection is live. public void DisposeLocalCopyOfClientHandle() { if (_clientHandle != null && !_clientHandle.IsClosed) { _clientHandle.Dispose(); } } protected override void Dispose(bool disposing) { try { // We should dispose of the client handle when it was not exposed at all OR // it was exposed as a string (handle finalization has been suppressed) and created inheritable (out-of-proc communication). if (!_clientHandleExposed || (_clientHandleExposedAsString && _inheritability == HandleInheritability.Inheritable)) { DisposeLocalCopyOfClientHandle(); } } finally { base.Dispose(disposing); } } // Anonymous pipes do not support message mode so there is no need to use the base version that P/Invokes here. public override PipeTransmissionMode TransmissionMode { get { return PipeTransmissionMode.Byte; } } public override PipeTransmissionMode ReadMode { set { CheckPipePropertyOperations(); if (value < PipeTransmissionMode.Byte || value > PipeTransmissionMode.Message) { throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_TransmissionModeByteOrMsg); } if (value == PipeTransmissionMode.Message) { throw new NotSupportedException(SR.NotSupported_AnonymousPipeMessagesNotSupported); } } } } }