protected override void HandleError(int errorCode) { TrySetException(Win32Marshal.GetExceptionForWin32Error(errorCode)); }
// Waits for a pipe instance to become available. This method may return before WaitForConnection is called // on the server end, but WaitForConnection will not return until we have returned. Any data written to the // pipe by us after we have connected but before the server has called WaitForConnection will be available // to the server after it calls WaitForConnection. private bool TryConnect(int timeout, CancellationToken cancellationToken) { Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability); // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag. // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to // CreateNamedPipeClient that were not defined in the enumeration. int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly); if (_impersonationLevel != TokenImpersonationLevel.None) { _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT; _pipeFlags |= (((int)_impersonationLevel - 1) << 16); } int access = 0; if ((PipeDirection.In & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_READ; } if ((PipeDirection.Out & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE; } SafePipeHandle handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access); if (handle.IsInvalid) { int errorCode = Marshal.GetLastPInvokeError(); // CreateFileW: "If the CreateNamedPipe function was not successfully called on the server prior to this operation, // a pipe will not exist and CreateFile will fail with ERROR_FILE_NOT_FOUND" // WaitNamedPipeW: "If no instances of the specified named pipe exist, // the WaitNamedPipe function returns immediately, regardless of the time-out value." // We know that no instances exist, so we just quit without calling WaitNamedPipeW. if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) { return(false); } if (errorCode != Interop.Errors.ERROR_PIPE_BUSY) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout)) { errorCode = Marshal.GetLastPInvokeError(); if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || // server has been closed errorCode == Interop.Errors.ERROR_SEM_TIMEOUT) { return(false); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } // Pipe server should be free. Let's try to connect to it. handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access); if (handle.IsInvalid) { errorCode = Marshal.GetLastPInvokeError(); // WaitNamedPipe: "A subsequent CreateFile call to the pipe can fail, // because the instance was closed by the server or opened by another client." if (errorCode == Interop.Errors.ERROR_PIPE_BUSY || // opened by another client errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) // server has been closed { return(false); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } // Success! InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0); State = PipeState.Connected; ValidateRemotePipeUser(); return(true);
// Waits for a pipe instance to become available. This method may return before WaitForConnection is called // on the server end, but WaitForConnection will not return until we have returned. Any data written to the // pipe by us after we have connected but before the server has called WaitForConnection will be available // to the server after it calls WaitForConnection. private bool TryConnect(int timeout, CancellationToken cancellationToken) { Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability); // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag. // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to // CreateNamedPipeClient that were not defined in the enumeration. int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly); if (_impersonationLevel != TokenImpersonationLevel.None) { _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT; _pipeFlags |= (((int)_impersonationLevel - 1) << 16); } int access = 0; if ((PipeDirection.In & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_READ; } if ((PipeDirection.Out & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE; } // Let's try to connect first SafePipeHandle handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath, access, // read and write access 0, // sharing: none ref secAttrs, // security attributes FileMode.Open, // open existing _pipeFlags, // impersonation flags IntPtr.Zero); // template file: null if (handle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.Errors.ERROR_PIPE_BUSY && errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout)) { errorCode = Marshal.GetLastWin32Error(); // Server is not yet created or a timeout occurred before a pipe instance was available. if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || errorCode == Interop.Errors.ERROR_SEM_TIMEOUT) { return(false); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } // Pipe server should be free. Let's try to connect to it. handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath, access, // read and write access 0, // sharing: none ref secAttrs, // security attributes FileMode.Open, // open existing _pipeFlags, // impersonation flags IntPtr.Zero); // template file: null if (handle.IsInvalid) { errorCode = Marshal.GetLastWin32Error(); // Handle the possible race condition of someone else connecting to the server // between our calls to WaitNamedPipe & CreateFile. if (errorCode == Interop.Errors.ERROR_PIPE_BUSY) { return(false); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } // Success! InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0); State = PipeState.Connected; ValidateRemotePipeUser(); return(true); }
private bool TryConnect(int timeout, CancellationToken cancellationToken) { Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability); int _pipeFlags = (int)_pipeOptions; if (_impersonationLevel != TokenImpersonationLevel.None) { _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT; _pipeFlags |= (((int)_impersonationLevel - 1) << 16); } int access = 0; if ((PipeDirection.In & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_READ; } if ((PipeDirection.Out & _direction) != 0) { access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE; } // Let's try to connect first SafePipeHandle handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath, access, // read and write access 0, // sharing: none ref secAttrs, // security attributes FileMode.Open, // open existing _pipeFlags, // impersonation flags IntPtr.Zero); // template file: null if (handle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.Errors.ERROR_PIPE_BUSY && errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout)) { errorCode = Marshal.GetLastWin32Error(); // Server is not yet created if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) { return(false); } // The timeout has expired. if (errorCode == Interop.Errors.ERROR_SUCCESS) { if (cancellationToken.CanBeCanceled) { // It may not be real timeout. return(false); } throw new TimeoutException(); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } // Pipe server should be free. Let's try to connect to it. handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath, access, // read and write access 0, // sharing: none ref secAttrs, // security attributes FileMode.Open, // open existing _pipeFlags, // impersonation flags IntPtr.Zero); // template file: null if (handle.IsInvalid) { errorCode = Marshal.GetLastWin32Error(); // Handle the possible race condition of someone else connecting to the server // between our calls to WaitNamedPipe & CreateFile. if (errorCode == Interop.Errors.ERROR_PIPE_BUSY) { return(false); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } // Success! InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0); State = PipeState.Connected; return(true); }
unsafe private PipeStreamAsyncResult BeginReadCore(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { Debug.Assert(_handle != null, "_handle is null"); Debug.Assert(!_handle.IsClosed, "_handle is closed"); Debug.Assert(CanRead, "can't read"); Debug.Assert(buffer != null, "buffer == null"); Debug.Assert(_isAsync, "BeginReadCore doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); // Create and store async stream class library specific data in the async result PipeStreamAsyncResult asyncResult = new PipeStreamAsyncResult(); asyncResult._handle = _handle; asyncResult._userCallback = callback; asyncResult._userStateObject = state; asyncResult._isWrite = false; // handle zero-length buffers separately; fixed keyword ReadFileNative doesn't like // 0-length buffers. Call user callback and we're done if (buffer.Length == 0) { asyncResult.CallUserCallback(); } else { // For Synchronous IO, I could go with either a userCallback and using // the managed Monitor class, or I could create a handle and wait on it. ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; // Create a managed overlapped class; set the file offsets later Overlapped overlapped = new Overlapped(); overlapped.OffsetLow = 0; overlapped.OffsetHigh = 0; overlapped.AsyncResult = asyncResult; // Pack the Overlapped class, and store it in the async result NativeOverlapped *intOverlapped; intOverlapped = overlapped.Pack(s_IOCallback, buffer); asyncResult._overlapped = intOverlapped; // Queue an async ReadFile operation and pass in a packed overlapped int errorCode = 0; int r = ReadFileNative(_handle, buffer, offset, count, intOverlapped, out errorCode); // ReadFile, the OS version, will return 0 on failure, but this ReadFileNative wrapper // returns -1. This will return the following: // - On error, r==-1. // - On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // - On async requests that completed sequentially, r==0 // // You will NEVER RELIABLY be able to get the number of buffer read back from this call // when using overlapped structures! You must not pass in a non-null lpNumBytesRead to // ReadFile when using overlapped structures! This is by design NT behavior. if (r == -1) { // One side has closed its handle or server disconnected. Set the state to Broken // and do some cleanup work if (errorCode == Interop.ERROR_BROKEN_PIPE || errorCode == Interop.ERROR_PIPE_NOT_CONNECTED) { State = PipeState.Broken; // Clear the overlapped status bit for this special case. Failure to do so looks // like we are freeing a pending overlapped. intOverlapped->InternalLow = IntPtr.Zero; // EndRead will free the Overlapped struct asyncResult.CallUserCallback(); } else if (errorCode != Interop.ERROR_IO_PENDING) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } ReadWriteAsyncParams readWriteParams = state as ReadWriteAsyncParams; if (readWriteParams != null) { if (readWriteParams.CancellationHelper != null) { readWriteParams.CancellationHelper.AllowCancellation(_handle, intOverlapped); } } } return(asyncResult); }
private unsafe void EndWaitForConnection(IAsyncResult asyncResult) { CheckConnectOperationsServerWithHandle(); if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } if (!IsAsync) { throw new InvalidOperationException(SR.InvalidOperation_PipeNotAsync); } PipeAsyncResult afsar = asyncResult as PipeAsyncResult; if (afsar == null) { throw __Error.GetWrongAsyncResult(); } // Ensure we can't get into any races by doing an interlocked // CompareExchange here. Avoids corrupting memory via freeing the // NativeOverlapped class or GCHandle twice. -- if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0)) { throw __Error.GetEndWaitForConnectionCalledTwice(); } IOCancellationHelper cancellationHelper = afsar.AsyncState as IOCancellationHelper; if (cancellationHelper != null) { cancellationHelper.SetOperationCompleted(); } // Obtain the WaitHandle, but don't use public property in case we // delay initialize the manual reset event in the future. WaitHandle wh = afsar._waitHandle; if (wh != null) { // We must block to ensure that ConnectionIOCallback has completed, // and we should close the WaitHandle in here. AsyncFSCallback // and the hand-ported imitation version in COMThreadPool.cpp // are the only places that set this event. using (wh) { wh.WaitOne(); Debug.Assert(afsar._isComplete == true, "NamedPipeServerStream::EndWaitForConnection - AsyncFSCallback didn't set _isComplete to true!"); } } // We should have freed the overlapped and set it to null either in the Begin // method (if ConnectNamedPipe completed synchronously) or in AsyncWaitForConnectionCallback. // If it is not nulled out, we should not be past the above wait: Debug.Assert(afsar._overlapped == null); // Now check for any error during the read. if (afsar._errorCode != 0) { if (afsar._errorCode == Interop.ERROR_OPERATION_ABORTED) { if (cancellationHelper != null) { cancellationHelper.ThrowIOOperationAborted(); } } throw Win32Marshal.GetExceptionForWin32Error(afsar._errorCode); } // Success State = PipeState.Connected; }
private unsafe IAsyncResult BeginWaitForConnection(AsyncCallback callback, Object state) { CheckConnectOperationsServerWithHandle(); if (!IsAsync) { throw new InvalidOperationException(SR.InvalidOperation_PipeNotAsync); } // Create and store async stream class library specific data in the // async result PipeAsyncResult asyncResult = new PipeAsyncResult(); asyncResult._handle = InternalHandle; asyncResult._userCallback = callback; asyncResult._userStateObject = state; IOCancellationHelper cancellationHelper = state as IOCancellationHelper; // Create wait handle and store in async result ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; // Create a managed overlapped class // We will set the file offsets later Overlapped overlapped = new Overlapped(); overlapped.OffsetLow = 0; overlapped.OffsetHigh = 0; overlapped.AsyncResult = asyncResult; // Pack the Overlapped class, and store it in the async result NativeOverlapped *intOverlapped = overlapped.Pack(s_WaitForConnectionCallback, null); asyncResult._overlapped = intOverlapped; if (!Interop.mincore.ConnectNamedPipe(InternalHandle, intOverlapped)) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_IO_PENDING) { if (cancellationHelper != null) { cancellationHelper.AllowCancellation(InternalHandle, intOverlapped); } return(asyncResult); } // WaitForConnectionCallback will not be called because we completed synchronously. // Either the pipe is already connected, or there was an error. Unpin and free the overlapped again. Overlapped.Free(intOverlapped); asyncResult._overlapped = null; // Did the client already connect to us? if (errorCode == Interop.ERROR_PIPE_CONNECTED) { if (State == PipeState.Connected) { throw new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected); } asyncResult.CallUserCallback(); return(asyncResult); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } // will set state to Connected when EndWait is called if (cancellationHelper != null) { cancellationHelper.AllowCancellation(InternalHandle, intOverlapped); } return(asyncResult); }
private Task <int> ReadAsyncCorePrivate(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { Debug.Assert(_handle != null, "_handle is null"); Debug.Assert(!_handle.IsClosed, "_handle is closed"); Debug.Assert(CanRead, "can't read"); Debug.Assert(buffer != null, "buffer == null"); Debug.Assert(_isAsync, "ReadAsyncCorePrivate doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); if (buffer.Length == 0) { UpdateMessageCompletion(false); return(s_zeroTask); } else { var completionSource = new ReadWriteCompletionSource(this, buffer, cancellationToken, isWrite: false); // Queue an async ReadFile operation and pass in a packed overlapped int errorCode = 0; int r; unsafe { r = ReadFileNative(_handle, buffer, offset, count, completionSource.Overlapped, out errorCode); } // ReadFile, the OS version, will return 0 on failure, but this ReadFileNative wrapper // returns -1. This will return the following: // - On error, r==-1. // - On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // - On async requests that completed sequentially, r==0 // // You will NEVER RELIABLY be able to get the number of buffer read back from this call // when using overlapped structures! You must not pass in a non-null lpNumBytesRead to // ReadFile when using overlapped structures! This is by design NT behavior. if (r == -1) { switch (errorCode) { // One side has closed its handle or server disconnected. // Set the state to Broken and do some cleanup work case Interop.mincore.Errors.ERROR_BROKEN_PIPE: case Interop.mincore.Errors.ERROR_PIPE_NOT_CONNECTED: State = PipeState.Broken; unsafe { // Clear the overlapped status bit for this special case. Failure to do so looks // like we are freeing a pending overlapped. completionSource.Overlapped->InternalLow = IntPtr.Zero; } completionSource.ReleaseResources(); UpdateMessageCompletion(true); return(s_zeroTask); case Interop.mincore.Errors.ERROR_IO_PENDING: break; default: throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } completionSource.RegisterForCancellation(); return(completionSource.Task); } }
protected override void HandleError(int errorCode) => TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(Win32Marshal.GetExceptionForWin32Error(errorCode)));