/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs
C# | 1350 lines | 1183 code | 139 blank | 28 comment | 154 complexity | 1dbb20ca4fe779a0d464122b34da925d MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
- //------------------------------------------------------------
- // 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.ThrowH