File: System\ServiceModel\Channels\PipeConnection.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Security.AccessControl;
    using System.ComponentModel;
    using System.Security;
    using System.Security.Cryptography;
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Diagnostics.Application;
    using System.ServiceModel.Security;
    using System.Text;
    using System.Threading;
    using SafeCloseHandle = System.ServiceModel.Activation.SafeCloseHandle;
 
    sealed class PipeConnection : IConnection
    {
        // common state
        PipeHandle pipe;
        CloseState closeState;
        bool aborted;
        bool isBoundToCompletionPort;
        bool autoBindToCompletionPort;
        TraceEventType exceptionEventType;
        static byte[] zeroBuffer;
 
        // read state
        object readLock = new object();
        bool inReadingState;     // This keeps track of the state machine (IConnection interface).
        bool isReadOutstanding;  // This tracks whether an actual I/O is pending.
        OverlappedContext readOverlapped;
        byte[] asyncReadBuffer;
        int readBufferSize;
        ManualResetEvent atEOFEvent;
        bool isAtEOF;
        OverlappedIOCompleteCallback onAsyncReadComplete;
        Exception asyncReadException;
        WaitCallback asyncReadCallback;
        object asyncReadCallbackState;
        int asyncBytesRead;
 
        // write state
        object writeLock = new object();
        bool inWritingState;      // This keeps track of the state machine (IConnection interface).
        bool isWriteOutstanding;  // This tracks whether an actual I/O is pending.
        OverlappedContext writeOverlapped;
        Exception asyncWriteException;
        WaitCallback asyncWriteCallback;
        object asyncWriteCallbackState;
        int asyncBytesToWrite;
        bool isShutdownWritten;
        int syncWriteSize;
        byte[] pendingWriteBuffer;
        BufferManager pendingWriteBufferManager;
        OverlappedIOCompleteCallback onAsyncWriteComplete;
        int writeBufferSize;
 
        // timeout support
        TimeSpan readTimeout;
        IOThreadTimer readTimer;
        static Action<object> onReadTimeout;
        string timeoutErrorString;
        TransferOperation timeoutErrorTransferOperation;
        TimeSpan writeTimeout;
        IOThreadTimer writeTimer;
        static Action<object> onWriteTimeout;
 
        public PipeConnection(PipeHandle pipe, int connectionBufferSize, bool isBoundToCompletionPort, bool autoBindToCompletionPort)
        {
            if (pipe == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
            if (pipe.IsInvalid)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
 
            this.closeState = CloseState.Open;
            this.exceptionEventType = TraceEventType.Error;
            this.isBoundToCompletionPort = isBoundToCompletionPort;
            this.autoBindToCompletionPort = autoBindToCompletionPort;
            this.pipe = pipe;
            this.readBufferSize = connectionBufferSize;
            this.writeBufferSize = connectionBufferSize;
            this.readOverlapped = new OverlappedContext();
            this.asyncReadBuffer = DiagnosticUtility.Utility.AllocateByteArray(connectionBufferSize);
            this.writeOverlapped = new OverlappedContext();
            this.atEOFEvent = new ManualResetEvent(false);
            this.onAsyncReadComplete = new OverlappedIOCompleteCallback(OnAsyncReadComplete);
            this.onAsyncWriteComplete = new OverlappedIOCompleteCallback(OnAsyncWriteComplete);
        }
 
        public int AsyncReadBufferSize
        {
            get
            {
                return this.readBufferSize;
            }
        }
 
        public byte[] AsyncReadBuffer
        {
            get
            {
                return this.asyncReadBuffer;
            }
        }
 
        static byte[] ZeroBuffer
        {
            get
            {
                if (PipeConnection.zeroBuffer == null)
                {
                    PipeConnection.zeroBuffer = new byte[1];
                }
                return PipeConnection.zeroBuffer;
            }
        }
 
        public TraceEventType ExceptionEventType
        {
            get { return this.exceptionEventType; }
            set { this.exceptionEventType = value; }
        }
 
        public IPEndPoint RemoteIPEndPoint
        {
            get { return null; }
        }
 
        IOThreadTimer ReadTimer
        {
            get
            {
                if (this.readTimer == null)
                {
                    if (onReadTimeout == null)
                    {
                        onReadTimeout = new Action<object>(OnReadTimeout);
                    }
 
                    this.readTimer = new IOThreadTimer(onReadTimeout, this, false);
                }
 
                return this.readTimer;
            }
        }
        IOThreadTimer WriteTimer
        {
            get
            {
                if (this.writeTimer == null)
                {
                    if (onWriteTimeout == null)
                    {
                        onWriteTimeout = new Action<object>(OnWriteTimeout);
                    }
 
                    this.writeTimer = new IOThreadTimer(onWriteTimeout, this, false);
                }
 
                return this.writeTimer;
            }
        }
 
        static void OnReadTimeout(object state)
        {
            PipeConnection thisPtr = (PipeConnection)state;
            thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, thisPtr.readTimeout), TransferOperation.Read);
        }
 
        static void OnWriteTimeout(object state)
        {
            PipeConnection thisPtr = (PipeConnection)state;
            thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, thisPtr.writeTimeout), TransferOperation.Write);
        }
 
        public void Abort()
        {
            Abort(null, TransferOperation.Undefined);
        }
 
        void Abort(string timeoutErrorString, TransferOperation transferOperation)
        {
            CloseHandle(true, timeoutErrorString, transferOperation);
        }
 
        Exception ConvertPipeException(PipeException pipeException, TransferOperation transferOperation)
        {
            return ConvertPipeException(pipeException.Message, pipeException, transferOperation);
        }
 
        Exception ConvertPipeException(string exceptionMessage, PipeException pipeException, TransferOperation transferOperation)
        {
            if (this.timeoutErrorString != null)
            {
                if (transferOperation == this.timeoutErrorTransferOperation)
                {
                    return new TimeoutException(this.timeoutErrorString, pipeException);
                }
                else
                {
                    return new CommunicationException(this.timeoutErrorString, pipeException);
                }
            }
            else if (this.aborted)
            {
                return new CommunicationObjectAbortedException(exceptionMessage, pipeException);
            }
            else
            {
                return new CommunicationException(exceptionMessage, pipeException);
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public unsafe AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
            WaitCallback callback, object state)
        {
            ConnectionUtilities.ValidateBufferBounds(AsyncReadBuffer, offset, size);
 
            lock (readLock)
            {
                try
                {
                    ValidateEnterReadingState(true);
 
                    if (isAtEOF)
                    {
                        asyncBytesRead = 0;
                        asyncReadException = null;
                        return AsyncCompletionResult.Completed;
                    }
 
                    if (autoBindToCompletionPort)
                    {
                        if (!isBoundToCompletionPort)
                        {
                            lock (writeLock)
                            {
                                // readLock, writeLock acquired in order to prevent deadlock
                                EnsureBoundToCompletionPort();
                            }
                        }
                    }
 
                    if (this.isReadOutstanding)
                    {
                        throw Fx.AssertAndThrow("Read I/O already pending when BeginRead called.");
                    }
                    try
                    {
                        this.readTimeout = timeout;
 
                        if (this.readTimeout != TimeSpan.MaxValue)
                        {
                            this.ReadTimer.Set(this.readTimeout);
                        }
 
                        this.asyncReadCallback = callback;
                        this.asyncReadCallbackState = state;
 
                        this.isReadOutstanding = true;
                        this.readOverlapped.StartAsyncOperation(AsyncReadBuffer, this.onAsyncReadComplete, this.isBoundToCompletionPort);
                        if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != UnsafeNativeMethods.ERROR_IO_PENDING && error != UnsafeNativeMethods.ERROR_MORE_DATA)
                            {
                                this.isReadOutstanding = false;
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
                            }
                        }
                    }
                    finally
                    {
                        if (!this.isReadOutstanding)
                        {
                            // Unbind the buffer.
                            this.readOverlapped.CancelAsyncOperation();
 
                            this.asyncReadCallback = null;
                            this.asyncReadCallbackState = null;
                            this.ReadTimer.Cancel();
                        }
                    }
 
                    if (!this.isReadOutstanding)
                    {
                        int bytesRead;
                        Exception readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
                        if (readException != null)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(readException);
                        }
                        asyncBytesRead = bytesRead;
                        HandleReadComplete(asyncBytesRead);
                    }
                    else
                    {
                        EnterReadingState();
                    }
 
                    return this.isReadOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
                }
                catch (PipeException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
                }
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public unsafe AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
            WaitCallback callback, object state)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            FinishPendingWrite(timeout);
 
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
 
            if (autoBindToCompletionPort && !isBoundToCompletionPort)
            {
                // Locks must be both taken, and in this order.
                lock (readLock)
                {
                    lock (writeLock)
                    {
                        ValidateEnterWritingState(true);
 
                        EnsureBoundToCompletionPort();
                    }
                }
            }
 
            lock (writeLock)
            {
                try
                {
                    ValidateEnterWritingState(true);
 
                    if (this.isWriteOutstanding)
                    {
                        throw Fx.AssertAndThrow("Write I/O already pending when BeginWrite called.");
                    }
 
                    try
                    {
                        this.writeTimeout = timeout;
                        this.WriteTimer.Set(timeoutHelper.RemainingTime());
 
                        this.asyncBytesToWrite = size;
                        this.asyncWriteException = null;
                        this.asyncWriteCallback = callback;
                        this.asyncWriteCallbackState = state;
 
                        this.isWriteOutstanding = true;
                        this.writeOverlapped.StartAsyncOperation(buffer, this.onAsyncWriteComplete, this.isBoundToCompletionPort);
                        if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
                        {
                            int error = Marshal.GetLastWin32Error();
                            if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
                            {
                                this.isWriteOutstanding = false;
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
                            }
                        }
                    }
                    finally
                    {
                        if (!this.isWriteOutstanding)
                        {
                            // Unbind the buffer.
                            this.writeOverlapped.CancelAsyncOperation();
 
                            this.ResetWriteState();
                            this.WriteTimer.Cancel();
                        }
                    }
 
                    if (!this.isWriteOutstanding)
                    {
                        int bytesWritten;
                        Exception writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
                        if (writeException == null && bytesWritten != size)
                        {
                            writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
                        }
                        if (writeException != null)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(writeException);
                        }
                    }
                    else
                    {
                        EnterWritingState();
                    }
 
                    return this.isWriteOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
                }
                catch (PipeException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
                }
            }
        }
 
        // CSDMain 112188: Note asyncAndLinger has no effect here. Async pooling for Tcp was
        // added and NamedPipes currently doesn't obey the async model.
        public void Close(TimeSpan timeout, bool asyncAndLinger)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            FinishPendingWrite(timeout);
 
            bool shouldCloseHandle = false;
            try
            {
                bool existingReadIsPending = false;
                bool shouldReadEOF = false;
                bool shouldWriteEOF = false;
 
                lock (readLock)
                {
                    lock (writeLock)
                    {
                        if (!isShutdownWritten && inWritingState)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                                new PipeException(SR.GetString(SR.PipeCantCloseWithPendingWrite)), ExceptionEventType);
                        }
 
                        if (closeState == CloseState.Closing || closeState == CloseState.HandleClosed)
                        {
                            // already closing or closed, so just return
                            return;
                        }
 
                        closeState = CloseState.Closing;
 
                        shouldCloseHandle = true;
 
                        if (!isAtEOF)
                        {
                            if (inReadingState)
                            {
                                existingReadIsPending = true;
                            }
                            else
                            {
                                shouldReadEOF = true;
                            }
                        }
 
                        if (!isShutdownWritten)
                        {
                            shouldWriteEOF = true;
                            isShutdownWritten = true;
                        }
                    }
                }
 
                if (shouldWriteEOF)
                {
                    StartWriteZero(timeoutHelper.RemainingTime());
                }
 
                if (shouldReadEOF)
                {
                    StartReadZero();
                }
 
                // wait for shutdown write to complete
                try
                {
                    WaitForWriteZero(timeoutHelper.RemainingTime(), true);
                }
                catch (TimeoutException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                        new TimeoutException(SR.GetString(SR.PipeShutdownWriteError), e), ExceptionEventType);
                }
 
                // ensure we have received EOF signal
                if (shouldReadEOF)
                {
                    try
                    {
                        WaitForReadZero(timeoutHelper.RemainingTime(), true);
                    }
                    catch (TimeoutException e)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                            new TimeoutException(SR.GetString(SR.PipeShutdownReadError), e), ExceptionEventType);
                    }
                }
                else if (existingReadIsPending)
                {
                    if (!TimeoutHelper.WaitOne(atEOFEvent, timeoutHelper.RemainingTime()))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                            new TimeoutException(SR.GetString(SR.PipeShutdownReadError)), ExceptionEventType);
                    }
                }
                // else we had already seen EOF.
 
                // at this point, we may get exceptions if the other side closes the handle first
                try
                {
                    // write an ack for eof
                    StartWriteZero(timeoutHelper.RemainingTime());
 
                    // read an ack for eof
                    StartReadZero();
 
                    // wait for write to complete/fail
                    WaitForWriteZero(timeoutHelper.RemainingTime(), false);
 
                    // wait for read to complete/fail
                    WaitForReadZero(timeoutHelper.RemainingTime(), false);
                }
                catch (PipeException e)
                {
                    if (!IsBrokenPipeError(e.ErrorCode))
                    {
                        throw;
                    }
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
                catch (CommunicationException e)
                {
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
                catch (TimeoutException e)
                {
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
            }
            catch (TimeoutException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                    new TimeoutException(SR.GetString(SR.PipeCloseFailed), e), ExceptionEventType);
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                    ConvertPipeException(SR.GetString(SR.PipeCloseFailed), e, TransferOperation.Undefined), ExceptionEventType);
            }
            finally
            {
                if (shouldCloseHandle)
                {
                    CloseHandle(false, null, TransferOperation.Undefined);
                }
            }
        }
 
        void CloseHandle(bool abort, string timeoutErrorString, TransferOperation transferOperation)
        {
            lock (readLock)
            {
                lock (writeLock)
                {
                    if (this.closeState == CloseState.HandleClosed)
                    {
                        return;
                    }
 
                    this.timeoutErrorString = timeoutErrorString;
                    this.timeoutErrorTransferOperation = transferOperation;
                    this.aborted = abort;
                    this.closeState = CloseState.HandleClosed;
                    this.pipe.Close();
                    this.readOverlapped.FreeOrDefer();
                    this.writeOverlapped.FreeOrDefer();
 
                    if (this.atEOFEvent != null)
                    {
                        this.atEOFEvent.Close();
                    }
 
                    // This should only do anything in the abort case.
                    try
                    {
                        FinishPendingWrite(TimeSpan.Zero);
                    }
                    catch (TimeoutException exception)
                    {
                        if (TD.CloseTimeoutIsEnabled())
                        {
                            TD.CloseTimeout(exception.Message);
                        }
                        DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
                    }
                    catch (CommunicationException exception)
                    {
                        DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
                    }
                }
            }
 
            if (abort)
            {
                TraceEventType traceEventType = TraceEventType.Warning;
 
                // we could be timing out a cached connection
                if (this.ExceptionEventType == TraceEventType.Information)
                {
                    traceEventType = this.ExceptionEventType;
                }
 
                if (DiagnosticUtility.ShouldTrace(traceEventType))
                {
                    TraceUtility.TraceEvent(traceEventType, TraceCode.PipeConnectionAbort, SR.GetString(SR.TraceCodePipeConnectionAbort), this);
                }
            }
        }
 
        CommunicationException CreatePipeDuplicationFailedException(int win32Error)
        {
            Exception innerException = new PipeException(SR.GetString(SR.PipeDuplicationFailed), win32Error);
            return new CommunicationException(innerException.Message, innerException);
        }
 
        public object DuplicateAndClose(int targetProcessId)
        {
            SafeCloseHandle targetProcessHandle = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE, false, targetProcessId);
            if (targetProcessHandle.IsInvalid)
            {
                targetProcessHandle.SetHandleAsInvalid();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                    CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
            }
            try
            {
                // no need to close this handle, it's a pseudo handle. expected value is -1.
                IntPtr sourceProcessHandle = ListenerUnsafeNativeMethods.GetCurrentProcess();
                if (sourceProcessHandle == IntPtr.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                        CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
                }
                IntPtr duplicatedHandle;
                bool success = UnsafeNativeMethods.DuplicateHandle(sourceProcessHandle, this.pipe, targetProcessHandle, out duplicatedHandle, 0, false, UnsafeNativeMethods.DUPLICATE_SAME_ACCESS);
                if (!success)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                        CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
                }
                this.Abort();
                return duplicatedHandle;
            }
            finally
            {
                targetProcessHandle.Close();
            }
        }
 
        public object GetCoreTransport()
        {
            return pipe;
        }
 
        void EnsureBoundToCompletionPort()
        {
            // Both read and write locks must be acquired before doing this
            if (!isBoundToCompletionPort)
            {
                ThreadPool.BindHandle(this.pipe);
                isBoundToCompletionPort = true;
            }
        }
 
        public int EndRead()
        {
            if (asyncReadException != null)
            {
                Exception exceptionToThrow = asyncReadException;
                asyncReadException = null;
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
            }
            return asyncBytesRead;
        }
 
        public void EndWrite()
        {
            if (this.asyncWriteException != null)
            {
                Exception exceptionToThrow = this.asyncWriteException;
                this.asyncWriteException = null;
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
            }
        }
 
        void EnterReadingState()
        {
            inReadingState = true;
        }
 
        void EnterWritingState()
        {
            inWritingState = true;
        }
 
        void ExitReadingState()
        {
            inReadingState = false;
        }
 
        void ExitWritingState()
        {
            inWritingState = false;
        }
 
        void ReadIOCompleted()
        {
            this.readOverlapped.FreeIfDeferred();
        }
 
        void WriteIOCompleted()
        {
            this.writeOverlapped.FreeIfDeferred();
        }
 
        void FinishPendingWrite(TimeSpan timeout)
        {
            if (this.pendingWriteBuffer == null)
            {
                return;
            }
 
            byte[] buffer;
            BufferManager bufferManager;
            lock (this.writeLock)
            {
                if (this.pendingWriteBuffer == null)
                {
                    return;
                }
 
                buffer = this.pendingWriteBuffer;
                this.pendingWriteBuffer = null;
 
                bufferManager = this.pendingWriteBufferManager;
                this.pendingWriteBufferManager = null;
            }
 
            try
            {
                bool success = false;
                try
                {
                    WaitForSyncWrite(timeout, true);
                    success = true;
                }
                finally
                {
                    lock (this.writeLock)
                    {
                        try
                        {
                            if (success)
                            {
                                FinishSyncWrite(true);
                            }
                        }
                        finally
                        {
                            ExitWritingState();
                            if (!this.isWriteOutstanding)
                            {
                                bufferManager.ReturnBuffer(buffer);
                                WriteIOCompleted();
                            }
                        }
                    }
                }
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
            }
        }
 
#if FUTURE
        ulong GetServerPid()
        {
            ulong id;
#pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
            if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
            {
                Win32Exception e = new Win32Exception();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
            }
            return id;
        }
 
        ulong GetClientPid()
        {
            ulong id;
#pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
            if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
            {
                Win32Exception e = new Win32Exception();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
            }
            return id;
        }
#endif
 
        void HandleReadComplete(int bytesRead)
        {
            if (bytesRead == 0)
            {
                isAtEOF = true;
                atEOFEvent.Set();
            }
        }
 
        bool IsBrokenPipeError(int error)
        {
            return error == UnsafeNativeMethods.ERROR_NO_DATA ||
                error == UnsafeNativeMethods.ERROR_BROKEN_PIPE;
        }
 
        Exception CreatePipeClosedException(TransferOperation transferOperation)
        {
            return ConvertPipeException(new PipeException(SR.GetString(SR.PipeClosed)), transferOperation);
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void OnAsyncReadComplete(bool haveResult, int error, int numBytes)
        {
            WaitCallback callback;
            object state;
 
            lock (readLock)
            {
                try
                {
                    try
                    {
                        if (this.readTimeout != TimeSpan.MaxValue && !this.ReadTimer.Cancel())
                        {
                            this.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
                        }
 
                        if (this.closeState == CloseState.HandleClosed)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Read));
                        }
                        if (!haveResult)
                        {
                            if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.readOverlapped.NativeOverlapped, out numBytes, 0) == 0)
                            {
                                error = Marshal.GetLastWin32Error();
                            }
                            else
                            {
                                error = 0;
                            }
                        }
 
                        if (error != 0 && error != UnsafeNativeMethods.ERROR_MORE_DATA)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException((int)error));
                        }
                        this.asyncBytesRead = numBytes;
                        HandleReadComplete(this.asyncBytesRead);
                    }
                    catch (PipeException e)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertPipeException(e, TransferOperation.Read));
                    }
                }
#pragma warning suppress 56500 // Microsoft, transferring exception to caller
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    this.asyncReadException = e;
                }
                finally
                {
                    this.isReadOutstanding = false;
                    ReadIOCompleted();
                    ExitReadingState();
                    callback = this.asyncReadCallback;
                    this.asyncReadCallback = null;
                    state = this.asyncReadCallbackState;
                    this.asyncReadCallbackState = null;
                }
            }
 
            callback(state);
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void OnAsyncWriteComplete(bool haveResult, int error, int numBytes)
        {
            WaitCallback callback;
            object state;
 
            Exception writeException = null;
 
            this.WriteTimer.Cancel();
            lock (writeLock)
            {
                try
                {
                    try
                    {
                        if (this.closeState == CloseState.HandleClosed)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Write));
                        }
                        if (!haveResult)
                        {
                            if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.writeOverlapped.NativeOverlapped, out numBytes, 0) == 0)
                            {
                                error = Marshal.GetLastWin32Error();
                            }
                            else
                            {
                                error = 0;
                            }
                        }
 
                        if (error != 0)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
                        }
                        else if (numBytes != this.asyncBytesToWrite)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PipeException(SR.GetString(SR.PipeWriteIncomplete)));
                        }
                    }
                    catch (PipeException e)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
                    }
                }
#pragma warning suppress 56500 // Microsoft, transferring exception to another thread
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    writeException = e;
                }
                finally
                {
                    this.isWriteOutstanding = false;
                    WriteIOCompleted();
                    ExitWritingState();
                    this.asyncWriteException = writeException;
                    callback = this.asyncWriteCallback;
                    state = this.asyncWriteCallbackState;
                    this.ResetWriteState();
                }
            }
 
            if (callback != null)
            {
                callback(state);
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
        {
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
 
            try
            {
                lock (readLock)
                {
                    ValidateEnterReadingState(true);
                    if (isAtEOF)
                    {
                        return 0;
                    }
 
                    StartSyncRead(buffer, offset, size);
                    EnterReadingState();
                }
 
                int bytesRead = -1;
                bool success = false;
                try
                {
                    WaitForSyncRead(timeout, true);
                    success = true;
                }
                finally
                {
                    lock (this.readLock)
                    {
                        try
                        {
                            if (success)
                            {
                                bytesRead = FinishSyncRead(true);
                                HandleReadComplete(bytesRead);
                            }
                        }
                        finally
                        {
                            ExitReadingState();
                            if (!this.isReadOutstanding)
                            {
                                ReadIOCompleted();
                            }
                        }
                    }
                }
 
                Fx.Assert(bytesRead >= 0, "Logic error in Read - bytesRead not set.");
                return bytesRead;
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
            }
        }
 
        public void Shutdown(TimeSpan timeout)
        {
            try
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                FinishPendingWrite(timeoutHelper.RemainingTime());
 
                lock (writeLock)
                {
                    ValidateEnterWritingState(true);
                    StartWriteZero(timeoutHelper.RemainingTime());
                    isShutdownWritten = true;
                }
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Undefined), ExceptionEventType);
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void StartReadZero()
        {
            lock (this.readLock)
            {
                ValidateEnterReadingState(false);
                StartSyncRead(ZeroBuffer, 0, 1);
                EnterReadingState();
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void StartWriteZero(TimeSpan timeout)
        {
            FinishPendingWrite(timeout);
 
            lock (this.writeLock)
            {
                ValidateEnterWritingState(false);
                StartSyncWrite(ZeroBuffer, 0, 0);
                EnterWritingState();
            }
        }
 
        void ResetWriteState()
        {
            this.asyncBytesToWrite = -1;
            this.asyncWriteCallback = null;
            this.asyncWriteCallbackState = null;
        }
 
        public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
        {
            return new CompletedAsyncResult<bool>(true, callback, state);
        }
 
        public bool EndValidate(IAsyncResult result)
        {
            return CompletedAsyncResult<bool>.End(result);
        }
 
        void WaitForReadZero(TimeSpan timeout, bool traceExceptionsAsErrors)
        {
            bool success = false;
            try
            {
                WaitForSyncRead(timeout, traceExceptionsAsErrors);
                success = true;
            }
            finally
            {
                lock (this.readLock)
                {
                    try
                    {
                        if (success)
                        {
                            if (FinishSyncRead(traceExceptionsAsErrors) != 0)
                            {
                                Exception exception = ConvertPipeException(new PipeException(SR.GetString(SR.PipeSignalExpected)), TransferOperation.Read);
                                TraceEventType traceEventType = TraceEventType.Information;
                                if (traceExceptionsAsErrors)
                                {
                                    traceEventType = TraceEventType.Error;
                                }
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exception, traceEventType);
                            }
                        }
                    }
                    finally
                    {
                        ExitReadingState();
                        if (!this.isReadOutstanding)
                        {
                            ReadIOCompleted();
                        }
                    }
                }
            }
        }
 
        void WaitForWriteZero(TimeSpan timeout, bool traceExceptionsAsErrors)
        {
            bool success = false;
            try
            {
                WaitForSyncWrite(timeout, traceExceptionsAsErrors);
                success = true;
            }
            finally
            {
                lock (this.writeLock)
                {
                    try
                    {
                        if (success)
                        {
                            FinishSyncWrite(traceExceptionsAsErrors);
                        }
                    }
                    finally
                    {
                        ExitWritingState();
                        if (!this.isWriteOutstanding)
                        {
                            WriteIOCompleted();
                        }
                    }
                }
            }
        }
 
        public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
        {
            WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
        }
 
        // The holder is a perf optimization that lets us avoid repeatedly indexing into the array.
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void WriteHelper(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, ref object holder)
        {
            try
            {
                FinishPendingWrite(timeout);
 
                ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
 
                int bytesToWrite = size;
                if (size > this.writeBufferSize)
                {
                    size = this.writeBufferSize;
                }
 
                while (bytesToWrite > 0)
                {
                    lock (this.writeLock)
                    {
                        ValidateEnterWritingState(true);
 
                        StartSyncWrite(buffer, offset, size, ref holder);
                        EnterWritingState();
                    }
 
                    bool success = false;
                    try
                    {
                        WaitForSyncWrite(timeout, true, ref holder);
                        success = true;
                    }
                    finally
                    {
                        lock (this.writeLock)
                        {
                            try
                            {
                                if (success)
                                {
                                    FinishSyncWrite(true);
                                }
                            }
                            finally
                            {
                                ExitWritingState();
                                if (!this.isWriteOutstanding)
                                {
                                    WriteIOCompleted();
                                }
                            }
                        }
                    }
 
                    bytesToWrite -= size;
                    offset += size;
                    if (size > bytesToWrite)
                    {
                        size = bytesToWrite;
                    }
                }
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public unsafe void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
        {
            bool shouldReturnBuffer = true;
 
            try
            {
                if (size > this.writeBufferSize)
                {
                    WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
                    return;
                }
 
                FinishPendingWrite(timeout);
 
                ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
 
                lock (this.writeLock)
                {
                    ValidateEnterWritingState(true);
 
                    // This method avoids the call to GetOverlappedResult for synchronous completions.  Perf?
                    bool success = false;
                    try
                    {
                        shouldReturnBuffer = false;
                        StartSyncWrite(buffer, offset, size);
                        success = true;
                    }
                    finally
                    {
                        if (!this.isWriteOutstanding)
                        {
                            shouldReturnBuffer = true;
                        }
                        else
                        {
                            if (success)
                            {
                                EnterWritingState();
 
                                Fx.Assert(this.pendingWriteBuffer == null, "Need to pend a write but one's already pending.");
                                this.pendingWriteBuffer = buffer;
                                this.pendingWriteBufferManager = bufferManager;
                            }
                        }
                    }
                }
            }
            catch (PipeException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
            }
            finally
            {
                if (shouldReturnBuffer)
                {
                    bufferManager.ReturnBuffer(buffer);
                }
            }
        }
 
        void ValidateEnterReadingState(bool checkEOF)
        {
            if (checkEOF)
            {
                if (closeState == CloseState.Closing)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
                }
            }
 
            if (inReadingState)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeReadPending)), ExceptionEventType);
            }
 
            if (closeState == CloseState.HandleClosed)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
            }
        }
 
        void ValidateEnterWritingState(bool checkShutdown)
        {
            if (checkShutdown)
            {
                if (isShutdownWritten)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyShuttingDown)), ExceptionEventType);
                }
 
                if (closeState == CloseState.Closing)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
                }
            }
 
            if (inWritingState)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeWritePending)), ExceptionEventType);
            }
 
            if (closeState == CloseState.HandleClosed)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
            }
        }
 
        void StartSyncRead(byte[] buffer, int offset, int size)
        {
            StartSyncRead(buffer, offset, size, ref this.readOverlapped.Holder[0]);
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void StartSyncRead(byte[] buffer, int offset, int size, ref object holder)
        {
            if (this.isReadOutstanding)
            {
                throw Fx.AssertAndThrow("StartSyncRead called when read I/O was already pending.");
            }
 
            try
            {
                this.isReadOutstanding = true;
                this.readOverlapped.StartSyncOperation(buffer, ref holder);
                if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
                {
                    int error = Marshal.GetLastWin32Error();
                    if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
                    {
                        this.isReadOutstanding = false;
                        if (error != UnsafeNativeMethods.ERROR_MORE_DATA)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
                        }
                    }
                }
                else
                {
                    this.isReadOutstanding = false;
                }
            }
            finally
            {
                if (!this.isReadOutstanding)
                {
                    this.readOverlapped.CancelSyncOperation(ref holder);
                }
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void WaitForSyncRead(TimeSpan timeout, bool traceExceptionsAsErrors)
        {
            if (this.isReadOutstanding)
            {
                if (!this.readOverlapped.WaitForSyncOperation(timeout))
                {
                    Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
 
                    Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeReadTimedOut, timeout));
                    TraceEventType traceEventType = TraceEventType.Information;
                    if (traceExceptionsAsErrors)
                    {
                        traceEventType = TraceEventType.Error;
                    }
 
                    // This intentionally doesn't reset isReadOutstanding, because technically it still is, and we need to not free the buffer.
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
                }
                else
                {
                    this.isReadOutstanding = false;
                }
            }
        }
 
        // Must be called in a lock.
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe int FinishSyncRead(bool traceExceptionsAsErrors)
        {
            int bytesRead = -1;
            Exception readException;
 
            if (this.closeState == CloseState.HandleClosed)
            {
                readException = CreatePipeClosedException(TransferOperation.Read);
            }
            else
            {
                readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
            }
            if (readException != null)
            {
                TraceEventType traceEventType = TraceEventType.Information;
                if (traceExceptionsAsErrors)
                {
                    traceEventType = TraceEventType.Error;
                }
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(readException, traceEventType);
            }
 
            return bytesRead;
        }
 
        void StartSyncWrite(byte[] buffer, int offset, int size)
        {
            StartSyncWrite(buffer, offset, size, ref this.writeOverlapped.Holder[0]);
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void StartSyncWrite(byte[] buffer, int offset, int size, ref object holder)
        {
            if (this.isWriteOutstanding)
            {
                throw Fx.AssertAndThrow("StartSyncWrite called when write I/O was already pending.");
            }
 
            try
            {
                this.syncWriteSize = size;
                this.isWriteOutstanding = true;
                this.writeOverlapped.StartSyncOperation(buffer, ref holder);
                if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
                {
                    int error = Marshal.GetLastWin32Error();
                    if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
                    {
                        this.isWriteOutstanding = false;
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
                    }
                }
                else
                {
                    this.isWriteOutstanding = false;
                }
            }
            finally
            {
                if (!this.isWriteOutstanding)
                {
                    this.writeOverlapped.CancelSyncOperation(ref holder);
                }
            }
        }
 
        void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors)
        {
            WaitForSyncWrite(timeout, traceExceptionsAsErrors, ref this.writeOverlapped.Holder[0]);
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors, ref object holder)
        {
            if (this.isWriteOutstanding)
            {
                if (!this.writeOverlapped.WaitForSyncOperation(timeout, ref holder))
                {
                    Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, this.writeTimeout), TransferOperation.Write);
 
                    Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeWriteTimedOut, timeout));
                    TraceEventType traceEventType = TraceEventType.Information;
                    if (traceExceptionsAsErrors)
                    {
                        traceEventType = TraceEventType.Error;
                    }
 
                    // This intentionally doesn't reset isWriteOutstanding, because technically it still is, and we need to not free the buffer.
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
                }
                else
                {
                    this.isWriteOutstanding = false;
                }
            }
        }
 
        // Must be called in a lock.
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        unsafe void FinishSyncWrite(bool traceExceptionsAsErrors)
        {
            int bytesWritten;
            Exception writeException;
 
            if (this.closeState == CloseState.HandleClosed)
            {
                writeException = CreatePipeClosedException(TransferOperation.Write);
            }
            else
            {
                writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
                if (writeException == null && bytesWritten != this.syncWriteSize)
                {
                    writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
                }
            }
 
            if (writeException != null)
            {
                TraceEventType traceEventType = TraceEventType.Information;
                if (traceExceptionsAsErrors)
                {
                    traceEventType = TraceEventType.Error;
                }
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(writeException, traceEventType);
            }
        }
 
        enum CloseState
        {
            Open,
            Closing,
            HandleClosed,
        }
 
        enum TransferOperation
        {
            Write,
            Read,
            Undefined,
        }
 
        static class Exceptions
        {
            static PipeException CreateException(string resourceString, int error)
            {
                return new PipeException(SR.GetString(resourceString, PipeError.GetErrorString(error)), error);
            }
 
            public static PipeException CreateReadException(int error)
            {
                return CreateException(SR.PipeReadError, error);
            }
 
            public static PipeException CreateWriteException(int error)
            {
                return CreateException(SR.PipeWriteError, error);
            }
 
            // Must be called in a lock, after checking for HandleClosed.
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            public static unsafe PipeException GetOverlappedWriteException(PipeHandle pipe,
                NativeOverlapped* nativeOverlapped, out int bytesWritten)
            {
                if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesWritten, 0) == 0)
                {
                    int error = Marshal.GetLastWin32Error();
                    return Exceptions.CreateWriteException(error);
                }
                else
                {
                    return null;
                }
            }
 
            // Must be called in a lock, after checking for HandleClosed.
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            public static unsafe PipeException GetOverlappedReadException(PipeHandle pipe,
                NativeOverlapped* nativeOverlapped, out int bytesRead)
            {
                if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesRead, 0) == 0)
                {
                    int error = Marshal.GetLastWin32Error();
                    if (error == UnsafeNativeMethods.ERROR_MORE_DATA)
                    {
                        return null;
                    }
 
                    else
                    {
                        return Exceptions.CreateReadException(error);
                    }
                }
                else
                {
                    return null;
                }
            }
        }
    }
 
 
    class PipeConnectionInitiator : IConnectionInitiator
    {
        int bufferSize;
        IPipeTransportFactorySettings pipeSettings;
 
        public PipeConnectionInitiator(int bufferSize, IPipeTransportFactorySettings pipeSettings)
        {
            this.bufferSize = bufferSize;
            this.pipeSettings = pipeSettings;
        }
 
        Exception CreateConnectFailedException(Uri remoteUri, PipeException innerException)
        {
            return new CommunicationException(
                SR.GetString(SR.PipeConnectFailed, remoteUri.AbsoluteUri), innerException);
        }
 
        public IConnection Connect(Uri remoteUri, TimeSpan timeout)
        {
            string resolvedAddress;
            BackoffTimeoutHelper backoffHelper;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            this.PrepareConnect(remoteUri, timeoutHelper.RemainingTime(), out resolvedAddress, out backoffHelper);
 
            IConnection connection = null;
            while (connection == null)
            {
                connection = this.TryConnect(remoteUri, resolvedAddress, backoffHelper);
                if (connection == null)
                {
                    backoffHelper.WaitAndBackoff();
 
                    if (DiagnosticUtility.ShouldTraceInformation)
                    {
                        TraceUtility.TraceEvent(
                            TraceEventType.Information,
                            TraceCode.FailedPipeConnect,
                            SR.GetString(
                                SR.TraceCodeFailedPipeConnect,
                                timeoutHelper.RemainingTime(),
                                remoteUri));
                    }
                }
            }
            return connection;
        }
 
        internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
        {
            AppContainerInfo appInfo = GetAppContainerInfo(transportFactorySettings);
 
            // for wildcard hostName support, we first try and connect to the StrongWildcard,
            // then the Exact HostName, and lastly the WeakWildcard
            string[] hostChoices = new string[] { "+", uri.Host, "*" };
            bool[] globalChoices = new bool[] { true, false };
            string matchPath = String.Empty;
            string matchPipeName = null;
 
            for (int i = 0; i < hostChoices.Length; i++)
            {
                for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++)
                {
 
                    if (appInfo != null && globalChoices[iGlobal])
                    {
                        // Don't look at shared memory to acces pipes 
                        // that are created in the local NamedObjectPath
                        continue;
                    }
 
                    // walk up the path hierarchy, looking for match
                    string path = PipeUri.GetPath(uri);
 
                    while (path.Length > 0)
                    {
 
                        string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal], appInfo);
                        try
                        {
                            PipeSharedMemory sharedMemory = PipeSharedMemory.Open(sharedMemoryName, uri);
                            if (sharedMemory != null)
                            {
                                try
                                {
                                    string pipeName = sharedMemory.GetPipeName(appInfo);
                                    if (pipeName != null)
                                    {
                                        // Found a matching pipe name. 
                                        // If the best match app setting is enabled, save the match if it is the best so far and continue.
                                        // Otherwise, just return the first match we find.
                                        if (ServiceModelAppSettings.UseBestMatchNamedPipeUri)
                                        {
                                            if (path.Length > matchPath.Length)
                                            {
                                                matchPath = path;
                                                matchPipeName = pipeName;
                                            }
                                        }
                                        else
                                        {
                                            return pipeName;
                                        }
                                    }
                                }
                                finally
                                {
                                    sharedMemory.Dispose();
                                }
                            }
                        }
                        catch (AddressAccessDeniedException exception)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(
                                SR.EndpointNotFound, uri.AbsoluteUri), exception));
                        }
 
                        path = PipeUri.GetParentPath(path);
                    }
                }
            }
 
            if (string.IsNullOrEmpty(matchPipeName))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
                    new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
            }
 
            return matchPipeName;
        }
 
        public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new ConnectAsyncResult(this, uri, timeout, callback, state);
        }
 
        public IConnection EndConnect(IAsyncResult result)
        {
            return ConnectAsyncResult.End(result);
        }
 
        void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolvedAddress, out BackoffTimeoutHelper backoffHelper)
        {
            PipeUri.Validate(remoteUri);
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingNamedPipeConnection,
                    SR.GetString(SR.TraceCodeInitiatingNamedPipeConnection),
                    new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
            }
            resolvedAddress = GetPipeName(remoteUri, this.pipeSettings);
            const int backoffBufferMilliseconds = 150;
            TimeSpan backoffTimeout;
            if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
            {
                backoffTimeout = TimeoutHelper.Add(timeout, TimeSpan.Zero - TimeSpan.FromMilliseconds(backoffBufferMilliseconds));
            }
            else
            {
                backoffTimeout = Ticks.ToTimeSpan((Ticks.FromMilliseconds(backoffBufferMilliseconds) / 2) + 1);
            }
 
            backoffHelper = new BackoffTimeoutHelper(backoffTimeout, TimeSpan.FromMinutes(5));
        }
 
        [ResourceConsumption(ResourceScope.Machine)]
        IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTimeoutHelper backoffHelper)
        {
            const int access = UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE;
            bool lastAttempt = backoffHelper.IsExpired();
 
            int flags = UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
 
            // By default Windows named pipe connection is created with impersonation, but we want
            // to create it with anonymous and let WCF take care of impersonation/identification.
            flags |= UnsafeNativeMethods.SECURITY_QOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS;
 
            PipeHandle pipeHandle = UnsafeNativeMethods.CreateFile(resolvedAddress, access, 0, IntPtr.Zero,
                UnsafeNativeMethods.OPEN_EXISTING, flags, IntPtr.Zero);
            int error = Marshal.GetLastWin32Error();
            if (pipeHandle.IsInvalid)
            {
                pipeHandle.SetHandleAsInvalid();
            }
            else
            {
                int mode = UnsafeNativeMethods.PIPE_READMODE_MESSAGE;
                if (UnsafeNativeMethods.SetNamedPipeHandleState(pipeHandle, ref mode, IntPtr.Zero, IntPtr.Zero) == 0)
                {
                    error = Marshal.GetLastWin32Error();
                    pipeHandle.Close();
                    PipeException innerException = new PipeException(SR.GetString(SR.PipeModeChangeFailed,
                        PipeError.GetErrorString(error)), error);
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        CreateConnectFailedException(remoteUri, innerException));
                }
                return new PipeConnection(pipeHandle, bufferSize, false, true);
            }
 
            if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND || error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
            {
                if (lastAttempt)
                {
                    Exception innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
                        resolvedAddress, PipeError.GetErrorString(error)), error);
 
                    TimeoutException timeoutException;
                    string endpoint = remoteUri.AbsoluteUri;
 
                    if (error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
                    {
                        timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOutServerTooBusy,
                            endpoint, backoffHelper.OriginalTimeout), innerException);
                    }
                    else
                    {
                        timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOut,
                            endpoint, backoffHelper.OriginalTimeout), innerException);
                    }
 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(timeoutException);
                }
 
                return null;
            }
            else
            {
                PipeException innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
                    resolvedAddress, PipeError.GetErrorString(error)), error);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    CreateConnectFailedException(remoteUri, innerException));
            }
        }
 
        static AppContainerInfo GetAppContainerInfo(IPipeTransportFactorySettings transportFactorySettings)
        {
            if (AppContainerInfo.IsAppContainerSupported &&
                transportFactorySettings != null &&
                transportFactorySettings.PipeSettings != null)
            {
                ApplicationContainerSettings appSettings = transportFactorySettings.PipeSettings.ApplicationContainerSettings;
                if (appSettings != null && appSettings.TargetingAppContainer)
                {
                    return AppContainerInfo.CreateAppContainerInfo(appSettings.PackageFullName, appSettings.SessionId);
                }
            }
 
            return null;
        }
 
        class ConnectAsyncResult : AsyncResult
        {
            PipeConnectionInitiator parent;
            Uri remoteUri;
            string resolvedAddress;
            BackoffTimeoutHelper backoffHelper;
            TimeoutHelper timeoutHelper;
            IConnection connection;
            static Action<object> waitCompleteCallback;
 
            public ConnectAsyncResult(PipeConnectionInitiator parent, Uri remoteUri, TimeSpan timeout,
                AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.parent = parent;
                this.remoteUri = remoteUri;
                this.timeoutHelper = new TimeoutHelper(timeout);
                parent.PrepareConnect(remoteUri, this.timeoutHelper.RemainingTime(), out this.resolvedAddress, out this.backoffHelper);
 
                if (this.ConnectAndWait())
                {
                    this.Complete(true);
                }
            }
 
            bool ConnectAndWait()
            {
                this.connection = this.parent.TryConnect(this.remoteUri, this.resolvedAddress, this.backoffHelper);
                bool completed = (this.connection != null);
                if (!completed)
                {
                    if (waitCompleteCallback == null)
                    {
                        waitCompleteCallback = new Action<object>(OnWaitComplete);
                    }
                    this.backoffHelper.WaitAndBackoff(waitCompleteCallback, this);
                }
                return completed;
            }
 
            public static IConnection End(IAsyncResult result)
            {
                ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
                return thisPtr.connection;
            }
 
            static void OnWaitComplete(object state)
            {
                Exception exception = null;
                ConnectAsyncResult thisPtr = (ConnectAsyncResult)state;
 
                bool completeSelf = true;
                try
                {
                    if (DiagnosticUtility.ShouldTraceInformation)
                    {
                        TraceUtility.TraceEvent(
                            TraceEventType.Information,
                            TraceCode.FailedPipeConnect,
                            SR.GetString(
                                SR.TraceCodeFailedPipeConnect,
                                thisPtr.timeoutHelper.RemainingTime(),
                                thisPtr.remoteUri));
                    }
 
                    completeSelf = thisPtr.ConnectAndWait();
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    exception = e;
                }
 
                if (completeSelf)
                {
                    thisPtr.Complete(false, exception);
                }
            }
        }
    }
 
    class PipeConnectionListener : IConnectionListener
    {
        Uri pipeUri;
        int bufferSize;
        HostNameComparisonMode hostNameComparisonMode;
        bool isDisposed;
        bool isListening;
        List<PendingAccept> pendingAccepts;
        bool anyPipesCreated;
        PipeSharedMemory sharedMemory;
        List<SecurityIdentifier> allowedSids;
        bool useCompletionPort;
        int maxInstances;
 
        public PipeConnectionListener(Uri pipeUri, HostNameComparisonMode hostNameComparisonMode, int bufferSize,
            List<SecurityIdentifier> allowedSids, bool useCompletionPort, int maxConnections)
        {
            PipeUri.Validate(pipeUri);
            this.pipeUri = pipeUri;
            this.hostNameComparisonMode = hostNameComparisonMode;
            this.allowedSids = allowedSids;
            this.bufferSize = bufferSize;
            pendingAccepts = new List<PendingAccept>();
            this.useCompletionPort = useCompletionPort;
            this.maxInstances = Math.Min(maxConnections, UnsafeNativeMethods.PIPE_UNLIMITED_INSTANCES);
        }
 
        object ThisLock
        {
            get { return this; }
        }
 
        public string PipeName { get { return sharedMemory.PipeName; } }
 
        public IAsyncResult BeginAccept(AsyncCallback callback, object state)
        {
            lock (ThisLock)
            {
                if (isDisposed)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException("", SR.GetString(SR.PipeListenerDisposed)));
                }
 
                if (!isListening)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PipeListenerNotListening)));
                }
 
                PipeHandle pipeHandle = CreatePipe();
                PendingAccept pendingAccept = new PendingAccept(this, pipeHandle, useCompletionPort, callback, state);
                if (!pendingAccept.CompletedSynchronously)
                {
                    this.pendingAccepts.Add(pendingAccept);
                }
                return pendingAccept;
            }
        }
 
        public IConnection EndAccept(IAsyncResult result)
        {
            PendingAccept pendingAccept = result as PendingAccept;
            if (pendingAccept == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("result", SR.GetString(SR.InvalidAsyncResult));
            }
 
            PipeHandle acceptedPipe = pendingAccept.End();
 
            if (acceptedPipe == null)
            {
                return null;
            }
            else
            {
                return new PipeConnection(acceptedPipe, bufferSize,
                    pendingAccept.IsBoundToCompletionPort, pendingAccept.IsBoundToCompletionPort);
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        [ResourceConsumption(ResourceScope.Machine)]
        unsafe PipeHandle CreatePipe()
        {
            int openMode = UnsafeNativeMethods.PIPE_ACCESS_DUPLEX | UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
            if (!anyPipesCreated)
            {
                openMode |= UnsafeNativeMethods.FILE_FLAG_FIRST_PIPE_INSTANCE;
            }
 
            byte[] binarySecurityDescriptor;
 
            try
            {
                binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
            }
            catch (Win32Exception e)
            {
                // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
                Exception innerException = new PipeException(e.Message, e);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
            }
 
            PipeHandle pipeHandle;
            int error;
            string pipeName = null;
            fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
            {
                UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
                securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
 
                pipeName = this.sharedMemory.PipeName;
                pipeHandle = UnsafeNativeMethods.CreateNamedPipe(
                                                    pipeName,
                                                    openMode,
                                                    UnsafeNativeMethods.PIPE_TYPE_MESSAGE | UnsafeNativeMethods.PIPE_READMODE_MESSAGE,
                                                    maxInstances, bufferSize, bufferSize, 0, securityAttributes);
                error = Marshal.GetLastWin32Error();
            }
 
            if (pipeHandle.IsInvalid)
            {
                pipeHandle.SetHandleAsInvalid();
 
                Exception innerException = new PipeException(SR.GetString(SR.PipeListenFailed,
                    pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
 
                if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
                }
                else if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(innerException.Message, innerException));
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
                }
            }
            else
            {
                if (TD.NamedPipeCreatedIsEnabled())
                {
                    TD.NamedPipeCreated(pipeName);
                }
            }
 
            bool closePipe = true;
            try
            {
                if (useCompletionPort)
                {
                    ThreadPool.BindHandle(pipeHandle);
                }
                anyPipesCreated = true;
                closePipe = false;
                return pipeHandle;
            }
            finally
            {
                if (closePipe)
                {
                    pipeHandle.Close();
                }
            }
        }
 
        public void Dispose()
        {
            lock (ThisLock)
            {
                if (!isDisposed)
                {
                    if (sharedMemory != null)
                    {
                        sharedMemory.Dispose();
                    }
                    for (int i = 0; i < pendingAccepts.Count; i++)
                    {
                        pendingAccepts[i].Abort();
                    }
                    isDisposed = true;
                }
            }
        }
 
        public void Listen()
        {
            lock (ThisLock)
            {
                if (!isListening)
                {
                    string sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, true);
                    if (!PipeSharedMemory.TryCreate(allowedSids, pipeUri, sharedMemoryName, out this.sharedMemory))
                    {
                        PipeSharedMemory tempSharedMemory = null;
 
                        // first see if we're in RANU by creating a unique Uri in the global namespace
                        Uri tempUri = new Uri(pipeUri, Guid.NewGuid().ToString());
                        string tempSharedMemoryName = PipeUri.BuildSharedMemoryName(tempUri, hostNameComparisonMode, true);
                        if (PipeSharedMemory.TryCreate(allowedSids, tempUri, tempSharedMemoryName, out tempSharedMemory))
                        {
                            // we're not RANU, throw PipeNameInUse
                            tempSharedMemory.Dispose();
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                PipeSharedMemory.CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
                        }
                        else
                        {
                            // try the session namespace since we're RANU
                            sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, false);
                            this.sharedMemory = PipeSharedMemory.Create(allowedSids, pipeUri, sharedMemoryName);
                        }
                    }
 
                    isListening = true;
                }
            }
        }
 
        void RemovePendingAccept(PendingAccept pendingAccept)
        {
            lock (ThisLock)
            {
                Fx.Assert(this.pendingAccepts.Contains(pendingAccept), "An unknown PendingAccept is removing itself.");
                this.pendingAccepts.Remove(pendingAccept);
            }
        }
 
        class PendingAccept : AsyncResult
        {
            PipeHandle pipeHandle;
            PipeHandle result;
            OverlappedIOCompleteCallback onAcceptComplete;
            static Action<object> onStartAccept;
            OverlappedContext overlapped;
            bool isBoundToCompletionPort;
            PipeConnectionListener listener;
            EventTraceActivity eventTraceActivity;
 
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            public unsafe PendingAccept(PipeConnectionListener listener, PipeHandle pipeHandle, bool isBoundToCompletionPort,
                AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.pipeHandle = pipeHandle;
                this.result = pipeHandle;
                this.listener = listener;
                onAcceptComplete = new OverlappedIOCompleteCallback(OnAcceptComplete);
                overlapped = new OverlappedContext();
                this.isBoundToCompletionPort = isBoundToCompletionPort;
 
                if (TD.PipeConnectionAcceptStartIsEnabled())
                {
                    this.eventTraceActivity = new EventTraceActivity();
                    TD.PipeConnectionAcceptStart(this.eventTraceActivity, this.listener.pipeUri != null ? this.listener.pipeUri.ToString() : string.Empty);
                }
 
                if (!Thread.CurrentThread.IsThreadPoolThread)
                {
                    if (onStartAccept == null)
                    {
                        onStartAccept = new Action<object>(OnStartAccept);
                    }
                    ActionItem.Schedule(onStartAccept, this);
                }
                else
                {
                    StartAccept(true);
                }
            }
 
            public bool IsBoundToCompletionPort
            {
                get { return this.isBoundToCompletionPort; }
            }
 
            static void OnStartAccept(object state)
            {
                PendingAccept pendingAccept = (PendingAccept)state;
                pendingAccept.StartAccept(false);
            }
 
            Exception CreatePipeAcceptFailedException(int errorCode)
            {
                Exception innerException = new PipeException(SR.GetString(SR.PipeAcceptFailed,
                    PipeError.GetErrorString(errorCode)), errorCode);
                return new CommunicationException(innerException.Message, innerException);
            }
 
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            unsafe void StartAccept(bool synchronous)
            {
                Exception completionException = null;
                bool completeSelf = false;
                try
                {
                    try
                    {
                        this.overlapped.StartAsyncOperation(null, onAcceptComplete, this.isBoundToCompletionPort);
                        while (true)
                        {
                            if (UnsafeNativeMethods.ConnectNamedPipe(pipeHandle, overlapped.NativeOverlapped) == 0)
                            {
                                int error = Marshal.GetLastWin32Error();
                                switch (error)
                                {
                                    case UnsafeNativeMethods.ERROR_NO_DATA:
                                        if (UnsafeNativeMethods.DisconnectNamedPipe(pipeHandle) != 0)
                                        {
                                            continue;
                                        }
                                        else
                                        {
                                            completeSelf = true;
                                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
                                        }
                                    case UnsafeNativeMethods.ERROR_PIPE_CONNECTED:
                                        completeSelf = true;
                                        break;
                                    case UnsafeNativeMethods.ERROR_IO_PENDING:
                                        break;
                                    default:
                                        completeSelf = true;
                                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
                                }
                            }
                            else
                            {
                                completeSelf = true;
                            }
 
                            break;
                        }
                    }
                    catch (ObjectDisposedException exception)
                    {
                        // A ---- with Abort can cause PipeHandle to throw this.
                        Fx.Assert(this.result == null, "Got an ObjectDisposedException but not an Abort!");
                        DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
                        completeSelf = true;
                    }
                    finally
                    {
                        if (completeSelf)
                        {
                            this.overlapped.CancelAsyncOperation();
                            this.overlapped.Free();
                        }
                    }
                }
#pragma warning suppress 56500 // Microsoft, transferring exception to another thread
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    completeSelf = true;
                    completionException = e;
                }
                if (completeSelf)
                {
                    if (!synchronous)
                    {
                        this.listener.RemovePendingAccept(this);
                    }
                    base.Complete(synchronous, completionException);
                }
            }
 
            // Must be called in PipeConnectionListener's lock.
            public void Abort()
            {
                this.result = null; // we need to return null after an abort
                pipeHandle.Close();
            }
 
            public PipeHandle End()
            {
                AsyncResult.End<PendingAccept>(this);
                return this.result;
            }
 
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            unsafe void OnAcceptComplete(bool haveResult, int error, int numBytes)
            {
                this.listener.RemovePendingAccept(this);
 
                if (!haveResult)
                {
                    // No ---- with Abort here since Abort can't be called once RemovePendingAccept happens.
                    if (this.result != null && UnsafeNativeMethods.GetOverlappedResult(this.pipeHandle,
                        this.overlapped.NativeOverlapped, out numBytes, 0) == 0)
                    {
                        error = Marshal.GetLastWin32Error();
                    }
                    else
                    {
                        error = 0;
                    }
                }
 
                this.overlapped.Free();
 
                if (TD.PipeConnectionAcceptStopIsEnabled())
                {
                    TD.PipeConnectionAcceptStop(this.eventTraceActivity);
                }
 
                if (error != 0)
                {
                    this.pipeHandle.Close();
                    base.Complete(false, CreatePipeAcceptFailedException(error));
                }
                else
                {
                    base.Complete(false);
                }
            }
        }
    }
 
    static class SecurityDescriptorHelper
    {
        static byte[] worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
        static byte[] worldCreatorOwnerWithReadDescriptorDenyNetwork;
 
        static SecurityDescriptorHelper()
        {
            worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
            worldCreatorOwnerWithReadDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ);
        }
 
        internal static byte[] FromSecurityIdentifiers(List<SecurityIdentifier> allowedSids, int accessRights)
        {
            if (allowedSids == null)
            {
                if (accessRights == (UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE))
                {
                    return worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
                }
 
                if (accessRights == UnsafeNativeMethods.GENERIC_READ)
                {
                    return worldCreatorOwnerWithReadDescriptorDenyNetwork;
                }
            }
 
            return FromSecurityIdentifiersFull(allowedSids, accessRights);
        }
 
        static byte[] FromSecurityIdentifiersFull(List<SecurityIdentifier> allowedSids, int accessRights)
        {
            int capacity = allowedSids == null ? 3 : 2 + allowedSids.Count;
            DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, capacity);
 
            // add deny ACE first so that we don't get short circuited
            dacl.AddAccess(AccessControlType.Deny, new SecurityIdentifier(WellKnownSidType.NetworkSid, null),
                UnsafeNativeMethods.GENERIC_ALL, InheritanceFlags.None, PropagationFlags.None);
 
            // clients get different rights, since they shouldn't be able to listen
            int clientAccessRights = GenerateClientAccessRights(accessRights);
 
            if (allowedSids == null)
            {
                dacl.AddAccess(AccessControlType.Allow, new SecurityIdentifier(WellKnownSidType.WorldSid, null),
                    clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
            }
            else
            {
                for (int i = 0; i < allowedSids.Count; i++)
                {
                    SecurityIdentifier allowedSid = allowedSids[i];
                    dacl.AddAccess(AccessControlType.Allow, allowedSid,
                        clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
                }
            }
 
            dacl.AddAccess(AccessControlType.Allow, GetProcessLogonSid(), accessRights, InheritanceFlags.None, PropagationFlags.None);
 
 
            if (AppContainerInfo.IsRunningInAppContainer)
            {
                // NamedPipeBinding requires dacl with current AppContainer SID
                // to setup multiple NamedPipes in the BeginAccept loop.                
                dacl.AddAccess(
                            AccessControlType.Allow,
                            AppContainerInfo.GetCurrentAppContainerSid(),
                            accessRights,
                            InheritanceFlags.None,
                            PropagationFlags.None);
            }
 
            CommonSecurityDescriptor securityDescriptor =
                new CommonSecurityDescriptor(false, false, ControlFlags.None, null, null, null, dacl);
            byte[] binarySecurityDescriptor = new byte[securityDescriptor.BinaryLength];
            securityDescriptor.GetBinaryForm(binarySecurityDescriptor, 0);
            return binarySecurityDescriptor;
        }
 
        // Security: We cannot grant rights for FILE_CREATE_PIPE_INSTANCE to clients, otherwise other apps can intercept server side pipes.
        // FILE_CREATE_PIPE_INSTANCE is granted in 2 ways, via GENERIC_WRITE or directly specified. Remove both.
        static int GenerateClientAccessRights(int accessRights)
        {
            int everyoneAccessRights = accessRights;
 
            if ((everyoneAccessRights & UnsafeNativeMethods.GENERIC_WRITE) != 0)
            {
                everyoneAccessRights &= ~UnsafeNativeMethods.GENERIC_WRITE;
 
                // Since GENERIC_WRITE grants the permissions to write to a file, we need to add it back.
                const int clientWriteAccess = UnsafeNativeMethods.FILE_WRITE_ATTRIBUTES | UnsafeNativeMethods.FILE_WRITE_DATA | UnsafeNativeMethods.FILE_WRITE_EA;
                everyoneAccessRights |= clientWriteAccess;
            }
 
            // Future proofing: FILE_CREATE_PIPE_INSTANCE isn't used currently but we need to ensure it is not granted.
            everyoneAccessRights &= ~UnsafeNativeMethods.FILE_CREATE_PIPE_INSTANCE;
 
            return everyoneAccessRights;
        }
 
        // The logon sid is generated on process start up so it is unique to this process.
        static SecurityIdentifier GetProcessLogonSid()
        {
            int pid = Process.GetCurrentProcess().Id;
            return System.ServiceModel.Activation.Utility.GetLogonSidForPid(pid);
        }
    }
 
    unsafe class PipeSharedMemory : IDisposable
    {
        internal const string PipePrefix = @"\\.\pipe\";
        internal const string PipeLocalPrefix = @"\\.\pipe\Local\";
        SafeFileMappingHandle fileMapping;
        string pipeName;
        string pipeNameGuidPart;
        Uri pipeUri;
 
        PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri)
            : this(fileMapping, pipeUri, null)
        {
        }
 
        PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri, string pipeName)
        {
            this.pipeName = pipeName;
            this.fileMapping = fileMapping;
            this.pipeUri = pipeUri;
        }
 
        public static PipeSharedMemory Create(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName)
        {
            PipeSharedMemory result;
            if (TryCreate(allowedSids, pipeUri, sharedMemoryName, out result))
            {
                return result;
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public unsafe static bool TryCreate(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName, out PipeSharedMemory result)
        {
            Guid pipeGuid = Guid.NewGuid();
            string pipeName = BuildPipeName(pipeGuid.ToString());
            byte[] binarySecurityDescriptor;
            try
            {
                binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ);
            }
            catch (Win32Exception e)
            {
                // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
                Exception innerException = new PipeException(e.Message, e);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
            }
 
            SafeFileMappingHandle fileMapping;
            int error;
            result = null;
            fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
            {
                UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
                securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
 
                fileMapping = UnsafeNativeMethods.CreateFileMapping((IntPtr)(-1), securityAttributes,
                    UnsafeNativeMethods.PAGE_READWRITE, 0, sizeof(SharedMemoryContents), sharedMemoryName);
                error = Marshal.GetLastWin32Error();
            }
 
            if (fileMapping.IsInvalid)
            {
                fileMapping.SetHandleAsInvalid();
                if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
                {
                    return false;
                }
                else
                {
                    Exception innerException = new PipeException(SR.GetString(SR.PipeNameCantBeReserved,
                        pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
                }
            }
 
            // now we have a valid file mapping handle
            if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
            {
                fileMapping.Close();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(error, pipeUri));
            }
            PipeSharedMemory pipeSharedMemory = new PipeSharedMemory(fileMapping, pipeUri, pipeName);
            bool disposeSharedMemory = true;
            try
            {
                pipeSharedMemory.InitializeContents(pipeGuid);
                disposeSharedMemory = false;
                result = pipeSharedMemory;
 
                if (TD.PipeSharedMemoryCreatedIsEnabled())
                {
                    TD.PipeSharedMemoryCreated(sharedMemoryName);
                }
                return true;
            }
            finally
            {
                if (disposeSharedMemory)
                {
                    pipeSharedMemory.Dispose();
                }
            }
        }
 
        [ResourceConsumption(ResourceScope.Machine)]
        public static PipeSharedMemory Open(string sharedMemoryName, Uri pipeUri)
        {
            SafeFileMappingHandle fileMapping = UnsafeNativeMethods.OpenFileMapping(
                UnsafeNativeMethods.FILE_MAP_READ, false, sharedMemoryName);
            if (fileMapping.IsInvalid)
            {
                int error = Marshal.GetLastWin32Error();
                fileMapping.SetHandleAsInvalid();
                if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
                {
                    fileMapping = UnsafeNativeMethods.OpenFileMapping(
                        UnsafeNativeMethods.FILE_MAP_READ, false, "Global\\" + sharedMemoryName);
                    if (fileMapping.IsInvalid)
                    {
                        error = Marshal.GetLastWin32Error();
                        fileMapping.SetHandleAsInvalid();
                        if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
                        {
                            return null;
                        }
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
                    }
                    return new PipeSharedMemory(fileMapping, pipeUri);
                }
 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
            }
            return new PipeSharedMemory(fileMapping, pipeUri);
        }
 
        public void Dispose()
        {
            if (fileMapping != null)
            {
                fileMapping.Close();
                fileMapping = null;
            }
        }
 
        public string PipeName
        {
            [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
            get
            {
                if (pipeName == null)
                {
                    SafeViewOfFileHandle view = GetView(false);
                    try
                    {
                        SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
                        if (contents->isInitialized)
                        {
                            Thread.MemoryBarrier();
                            this.pipeNameGuidPart = contents->pipeGuid.ToString();
                            this.pipeName = BuildPipeName(this.pipeNameGuidPart);
                        }
                    }
                    finally
                    {
                        view.Close();
                    }
                }
                return pipeName;
            }
        }
 
        internal string GetPipeName(AppContainerInfo appInfo)
        {
            if (appInfo == null)
            {
                return this.PipeName;
            }
            else if (this.PipeName != null)
            {
                // Build the PipeName for a pipe inside an AppContainer as follows
                // \\.\pipe\Sessions\<SessionId>\<NamedObjectPath>\<PipeGuid>
                return string.Format(
                            CultureInfo.InvariantCulture,
                            @"\\.\pipe\Sessions\{0}\{1}\{2}",
                            appInfo.SessionId,
                            appInfo.NamedObjectPath,
                            this.pipeNameGuidPart);
            }
 
            return null;
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        void InitializeContents(Guid pipeGuid)
        {
            SafeViewOfFileHandle view = GetView(true);
            try
            {
                SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
                contents->pipeGuid = pipeGuid;
                Thread.MemoryBarrier();
                contents->isInitialized = true;
            }
            finally
            {
                view.Close();
            }
        }
 
        public static Exception CreatePipeNameInUseException(int error, Uri pipeUri)
        {
            Exception innerException = new PipeException(SR.GetString(SR.PipeNameInUse, pipeUri.AbsoluteUri), error);
            return new AddressAlreadyInUseException(innerException.Message, innerException);
        }
 
        static Exception CreatePipeNameCannotBeAccessedException(int error, Uri pipeUri)
        {
            Exception innerException = new PipeException(SR.GetString(SR.PipeNameCanNotBeAccessed,
                PipeError.GetErrorString(error)), error);
            return new AddressAccessDeniedException(SR.GetString(SR.PipeNameCanNotBeAccessed2, pipeUri.AbsoluteUri), innerException);
        }
 
        SafeViewOfFileHandle GetView(bool writable)
        {
            SafeViewOfFileHandle handle = UnsafeNativeMethods.MapViewOfFile(fileMapping,
                writable ? UnsafeNativeMethods.FILE_MAP_WRITE : UnsafeNativeMethods.FILE_MAP_READ,
                0, 0, (IntPtr)sizeof(SharedMemoryContents));
            if (handle.IsInvalid)
            {
                int error = Marshal.GetLastWin32Error();
                handle.SetHandleAsInvalid();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
            }
            return handle;
        }
 
        static string BuildPipeName(string pipeGuid)
        {
            return (AppContainerInfo.IsRunningInAppContainer ? PipeLocalPrefix : PipePrefix) + pipeGuid;
        }
 
        [StructLayout(LayoutKind.Sequential)]
        struct SharedMemoryContents
        {
            public bool isInitialized;
            public Guid pipeGuid;
        }
    }
 
    static class PipeUri
    {
        public static string BuildSharedMemoryName(Uri uri, HostNameComparisonMode hostNameComparisonMode, bool global)
        {
            string path = PipeUri.GetPath(uri);
            string host = null;
 
            switch (hostNameComparisonMode)
            {
                case HostNameComparisonMode.StrongWildcard:
                    host = "+";
                    break;
                case HostNameComparisonMode.Exact:
                    host = uri.Host;
                    break;
                case HostNameComparisonMode.WeakWildcard:
                    host = "*";
                    break;
            }
 
            return PipeUri.BuildSharedMemoryName(host, path, global);
        }
 
        internal static string BuildSharedMemoryName(string hostName, string path, bool global, AppContainerInfo appContainerInfo)
        {
            if (appContainerInfo == null)
            {
                return BuildSharedMemoryName(hostName, path, global);
            }
            else
            {
                Fx.Assert(appContainerInfo.SessionId != ApplicationContainerSettingsDefaults.CurrentSession, "Session has not yet been initialized.");
                Fx.Assert(!String.IsNullOrEmpty(appContainerInfo.NamedObjectPath),
                    "NamedObjectPath cannot be empty when creating the SharedMemoryName when running in an AppContainer.");
 
                //We need to use a session symlink for the lowbox appcontainer.
                // Session\{0}\{1}\{2}\<SharedMemoryName>                
                return string.Format(
                            CultureInfo.InvariantCulture,
                            @"Session\{0}\{1}\{2}",
                            appContainerInfo.SessionId,
                            appContainerInfo.NamedObjectPath,
                            BuildSharedMemoryName(hostName, path, global));
            }
        }
 
        static string BuildSharedMemoryName(string hostName, string path, bool global)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(Uri.UriSchemeNetPipe);
            builder.Append("://");
            builder.Append(hostName.ToUpperInvariant());
            builder.Append(path);
            string canonicalName = builder.ToString();
 
            byte[] canonicalBytes = Encoding.UTF8.GetBytes(canonicalName);
            byte[] hashedBytes;
            string separator;
 
            if (canonicalBytes.Length >= 128)
            {
                using (HashAlgorithm hash = GetHashAlgorithm())
                {
                    hashedBytes = hash.ComputeHash(canonicalBytes);
                }
                separator = ":H";
            }
            else
            {
                hashedBytes = canonicalBytes;
                separator = ":E";
            }
 
            builder = new StringBuilder();
            if (global)
            {
                // we may need to create the shared memory in the global namespace so we work with terminal services+admin 
                builder.Append("Global\\");
            }
            else
            {
                builder.Append("Local\\");
            }
            builder.Append(Uri.UriSchemeNetPipe);
            builder.Append(separator);
            builder.Append(Convert.ToBase64String(hashedBytes));
            return builder.ToString();
        }
 
        [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. It will cause compatibility issue. Not used for cryptographic purposes.")]
        static HashAlgorithm GetHashAlgorithm()
        {
            if (!LocalAppContextSwitches.UseSha1InPipeConnectionGetHashAlgorithm)
            {
                if (SecurityUtilsEx.RequiresFipsCompliance)
                    return new SHA256CryptoServiceProvider();
                else
                    return new SHA256Managed();
            }
            else
            {
                if (SecurityUtilsEx.RequiresFipsCompliance)
                    return new SHA1CryptoServiceProvider();
                else
                    return new SHA1Managed();
            }
        }
 
        public static string GetPath(Uri uri)
        {
            string path = uri.LocalPath.ToUpperInvariant();
            if (!path.EndsWith("/", StringComparison.Ordinal))
                path = path + "/";
            return path;
        }
 
        public static string GetParentPath(string path)
        {
            if (path.EndsWith("/", StringComparison.Ordinal))
                path = path.Substring(0, path.Length - 1);
            if (path.Length == 0)
                return path;
            return path.Substring(0, path.LastIndexOf('/') + 1);
        }
 
        public static void Validate(Uri uri)
        {
            if (uri.Scheme != Uri.UriSchemeNetPipe)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("uri", SR.GetString(SR.PipeUriSchemeWrong));
        }
    }
 
    static class PipeError
    {
        public static string GetErrorString(int error)
        {
            StringBuilder stringBuilder = new StringBuilder(512);
            if (UnsafeNativeMethods.FormatMessage(UnsafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS |
                UnsafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | UnsafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY,
                IntPtr.Zero, error, CultureInfo.CurrentCulture.LCID, stringBuilder, stringBuilder.Capacity, IntPtr.Zero) != 0)
            {
                stringBuilder = stringBuilder.Replace("\n", "");
                stringBuilder = stringBuilder.Replace("\r", "");
                return SR.GetString(
                    SR.PipeKnownWin32Error,
                    stringBuilder.ToString(),
                    error.ToString(CultureInfo.InvariantCulture),
                    Convert.ToString(error, 16));
            }
            else
            {
                return SR.GetString(
                    SR.PipeUnknownWin32Error,
                    error.ToString(CultureInfo.InvariantCulture),
                    Convert.ToString(error, 16));
            }
        }
    }
}