// // internal IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) { BufferAsyncResult bufferResult = new BufferAsyncResult(this, buffer, offset, count, asyncState, asyncCallback); AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(bufferResult); ProcessRead(buffer, offset, count, asyncRequest ); return bufferResult; }
// // Combined [....]/async read method. For [....] requet asyncRequest==null // There is a little overheader because we need to pass buffer/offset/count used only in [....]. // Still the benefit is that we have a common [....]/async code path. // private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _NestedRead, 1) == 1) { throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginRead":"Read"), "read")); } bool failed = false; try { int copyBytes; if (InternalBufferCount != 0) { copyBytes = InternalBufferCount > count? count: InternalBufferCount; if (copyBytes != 0) { Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes); DecrementInternalBufferCount(copyBytes); } if (asyncRequest != null) { asyncRequest.CompleteUser((object)copyBytes); } return(copyBytes); } // going into real IO return(StartReading(buffer, offset, count, asyncRequest)); } catch (Exception e) { _SslState.FinishRead(null); failed = true; if (e is IOException) { throw; } throw new IOException(SR.GetString(SR.net_io_read), e); } finally { // if [....] request or exception if (asyncRequest == null || failed) { _NestedRead = 0; } } }
// // This is used in a rare situation when async Read is resumed from completed handshake // private static void ResumeAsyncReadCallback(AsyncProtocolRequest request) { try { ((_SslStream)request.AsyncObject).StartReading(request.Buffer, request.Offset, request.Count, request); } catch (Exception e) { if (request.IsUserCompleted) { // This will throw on a worker thread. throw; } ((_SslStream)request.AsyncObject)._SslState.FinishRead(null); request.CompleteWithError(e); } }
private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int num2; this.ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref this._NestedRead, 1) == 1) { throw new NotSupportedException(SR.GetString("net_io_invalidnestedcall", new object[] { (asyncRequest != null) ? "BeginRead" : "Read", "read" })); } bool flag = false; try { if (this.InternalBufferCount != 0) { int num = (this.InternalBufferCount > count) ? count : this.InternalBufferCount; if (num != 0) { Buffer.BlockCopy(this.InternalBuffer, this.InternalOffset, buffer, offset, num); this.DecrementInternalBufferCount(num); } if (asyncRequest != null) { asyncRequest.CompleteUser(num); } return(num); } num2 = this.StartReading(buffer, offset, count, asyncRequest); } catch (Exception exception) { this._SslState.FinishRead(null); flag = true; if (exception is IOException) { throw; } throw new IOException(SR.GetString("net_io_read"), exception); } finally { if ((asyncRequest == null) || flag) { this._NestedRead = 0; } } return(num2); }
// // Combined sync/async read method. For sync request asyncRequest==null. // private int ProcessRead(byte[] buffer, int offset, int count, BufferAsyncResult asyncResult) { ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncResult != null ? "BeginRead" : "Read"), "read")); } // If this is an async operation, get the AsyncProtocolRequest to use. // We do this only after we verify we're the sole write operation in flight. AsyncProtocolRequest asyncRequest = GetOrCreateProtocolRequest(ref _readProtocolRequest, asyncResult); bool failed = false; try { if (_decryptedBytesCount != 0) { int copyBytes = CopyDecryptedData(buffer, offset, count); asyncRequest?.CompleteUser(copyBytes); return(copyBytes); } return(StartReading(buffer, offset, count, asyncRequest)); } catch (Exception e) { _sslState.FinishRead(null); failed = true; if (e is IOException) { throw; } throw new IOException(SR.net_io_read, e); } finally { if (asyncRequest == null || failed) { _nestedRead = 0; } } }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. if (count >= 0) { byte[] outBuffer = null; do { int chunkBytes = Math.Min(count, NegoState.MaxWriteDataSize); int encryptedBytes; try { encryptedBytes = _negoState.EncryptData(buffer, offset, chunkBytes, ref outBuffer); } catch (Exception e) { throw new IOException(SR.net_io_encrypt, e); } if (asyncRequest != null) { // prepare for the next request asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, null); IAsyncResult ar = InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } InnerStream.EndWrite(ar); } else { InnerStream.Write(outBuffer, 0, encryptedBytes); } offset += chunkBytes; count -= chunkBytes; } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }
internal void StartReHandshake(AsyncProtocolRequest asyncRequest) { if (IsServer) { byte[] buffer = null; if (CheckEnqueueHandshakeRead(ref buffer, asyncRequest)) { return; } StartReceiveBlob(buffer, asyncRequest); return; } ForceAuthentication(false, null, asyncRequest); }
private static void CompleteFromCompletedTask(Task <int> task, AsyncProtocolRequest asyncRequest) { Debug.Assert(task.IsCompleted); if (task.IsCompletedSuccessfully) { asyncRequest.CompleteRequest(task.Result); } else if (task.IsFaulted) { asyncRequest.CompleteUserWithError(task.Exception.InnerException); } else { asyncRequest.CompleteUserWithError(new OperationCanceledException()); } }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, _ResumeAsyncWriteCallback); } if (count >= 0) { byte[] outBuffer = null; do { int num2; if (this._SslState.CheckEnqueueWrite(asyncRequest)) { return; } int num = Math.Min(count, this._SslState.MaxDataSize); SecurityStatus errorCode = this._SslState.EncryptData(buffer, offset, num, ref outBuffer, out num2); if (errorCode != SecurityStatus.OK) { ProtocolToken token = new ProtocolToken(null, errorCode); throw new IOException(SR.GetString("net_io_encrypt"), token.GetException()); } if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset + num, count - num, _ResumeAsyncWriteCallback); IAsyncResult asyncResult = this._SslState.InnerStream.BeginWrite(outBuffer, 0, num2, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this._SslState.InnerStream.EndWrite(asyncResult); } else { this._SslState.InnerStream.Write(outBuffer, 0, num2); } offset += num; count -= num; this._SslState.FinishWrite(); }while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }
private static void WriteCallback(IAsyncResult transportResult) { if (transportResult.CompletedSynchronously) { return; } if (!(transportResult.AsyncState is AsyncProtocolRequest)) { if (GlobalLog.IsEnabled) { GlobalLog.Assert("SslStream::WriteCallback | State type is wrong, expected AsyncProtocolRequest."); } Debug.Fail("SslStream::WriteCallback|State type is wrong, expected AsyncProtocolRequest."); } AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState; var sslStream = (SslStreamInternal)asyncRequest.AsyncObject; try { sslStream._sslState.InnerStreamAPM.EndWrite(transportResult); sslStream._sslState.FinishWrite(); if (asyncRequest.Count == 0) { // This was the last chunk. asyncRequest.Count = -1; } sslStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } sslStream._sslState.FinishWrite(); asyncRequest.CompleteWithError(e); } }
private static void PartialFrameCallback(AsyncProtocolRequest asyncRequest) { SslState asyncObject = (SslState)asyncRequest.AsyncObject; try { asyncObject.StartReadFrame(asyncRequest.Buffer, asyncRequest.Result, asyncRequest); } catch (Exception exception) { if (asyncRequest.IsUserCompleted) { throw; } asyncObject.FinishHandshake(exception, asyncRequest); } }
// // Combined sync/async read method. For sync request asyncRequest==null. // There is a little overhead because we need to pass buffer/offset/count used only in sync. // Still the benefit is that we have a common sync/async code path. // private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _NestedRead, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRead" : "Read"), "read")); } bool failed = false; try { if (InternalBufferCount != 0) { int copyBytes = InternalBufferCount > count ? count : InternalBufferCount; if (copyBytes != 0) { Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes); DecrementInternalBufferCount(copyBytes); } asyncRequest?.CompleteUser(copyBytes); return(copyBytes); } // Performing actual I/O. return(StartReading(buffer, offset, count, asyncRequest)); } catch (Exception e) { failed = true; if (e is IOException) { throw; } throw new IOException(SR.net_io_read, e); } finally { if (asyncRequest == null || failed) { _NestedRead = 0; } } }
private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (this._SslState.LastPayload != null) { BufferOffsetSize[] buffers = new BufferOffsetSize[] { new BufferOffsetSize(buffer, offset, count, false) }; if (asyncRequest != null) { this.ProcessWrite(buffers, new SplitWriteAsyncProtocolRequest(asyncRequest.UserAsyncResult)); } else { this.ProcessWrite(buffers, null); } } else { this.ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref this._NestedWrite, 1) == 1) { throw new NotSupportedException(SR.GetString("net_io_invalidnestedcall", new object[] { (asyncRequest != null) ? "BeginWrite" : "Write", "write" })); } bool flag = false; try { this.StartWriting(buffer, offset, count, asyncRequest); } catch (Exception exception) { this._SslState.FinishWrite(); flag = true; if (exception is IOException) { throw; } throw new IOException(SR.GetString("net_io_write"), exception); } finally { if ((asyncRequest == null) || flag) { this._NestedWrite = 0; } } } }
private void FinishHandshake(Exception e, AsyncProtocolRequest asyncRequest) { try { lock (this) { if (e != null) { this.SetException(e); } this.FinishHandshakeRead(0); if (Interlocked.CompareExchange(ref this._LockWriteState, 0, 2) == 3) { this._LockWriteState = 1; object state = this._QueuedWriteStateRequest; if (state != null) { this._QueuedWriteStateRequest = null; if (state is LazyAsyncResult) { ((LazyAsyncResult)state).InvokeCallback(); } else { ThreadPool.QueueUserWorkItem(new WaitCallback(this.CompleteRequestWaitCallback), state); } } } } } finally { if (asyncRequest != null) { if (e != null) { asyncRequest.CompleteWithError(e); } else { asyncRequest.CompleteUser(); } } } }
internal void ReplyOnReAuthentication(byte[] buffer) { lock (this) { this._LockReadState = 2; if (this._PendingReHandshake) { this.FinishRead(buffer); return; } } AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(new LazyAsyncResult(this, null, new AsyncCallback(this.RehandshakeCompleteCallback))) { Buffer = buffer }; this.ForceAuthentication(false, buffer, asyncRequest); }
// // This is used in a rare situation when async Write is resumed from completed handshake. // private static void ResumeAsyncWriteCallback(AsyncProtocolRequest asyncRequest) { try { ((SslStreamInternal)asyncRequest.AsyncObject).StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } ((SslStreamInternal)asyncRequest.AsyncObject)._sslState.FinishWrite(); asyncRequest.CompleteUserWithError(e); } }
// // To avoid recursion when decrypted 0 bytes this method will loop until a decrypted result at least 1 byte. // private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int result = 0; if (InternalBufferCount != 0) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("SslStream::StartReading()|Previous frame was not consumed. InternalBufferCount:{0}", InternalBufferCount); } Debug.Fail("SslStream::StartReading()|Previous frame was not consumed. InternalBufferCount:" + InternalBufferCount); } do { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncReadCallback); } int copyBytes = _sslState.CheckEnqueueRead(buffer, offset, count, asyncRequest); if (copyBytes == 0) { // Queued but not completed! return(0); } if (copyBytes != -1) { if (asyncRequest != null) { asyncRequest.CompleteUser((object)copyBytes); } return(copyBytes); } } // When we read -1 bytes means we have decrypted 0 bytes or rehandshaking, need looping. while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1); return(result); }
// // Need read frame size first // private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int readBytes = 0; if (asyncRequest != null) { asyncRequest.SetNextRequest(_ReadHeader, 0, _ReadHeader.Length, _ReadCallback); _FrameReader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return(0); } readBytes = asyncRequest.Result; } else { readBytes = _FrameReader.ReadPacket(_ReadHeader, 0, _ReadHeader.Length); } return(StartFrameBody(readBytes, buffer, offset, count, asyncRequest)); }
private static void ReadHeaderCallback(AsyncProtocolRequest asyncRequest) { try { _SslStream asyncObject = (_SslStream)asyncRequest.AsyncObject; BufferAsyncResult userAsyncResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; if (-1 == asyncObject.StartFrameBody(asyncRequest.Result, userAsyncResult.Buffer, userAsyncResult.Offset, userAsyncResult.Count, asyncRequest)) { asyncObject.StartReading(userAsyncResult.Buffer, userAsyncResult.Offset, userAsyncResult.Count, asyncRequest); } } catch (Exception exception) { if (asyncRequest.IsUserCompleted) { throw; } asyncRequest.CompleteWithError(exception); } }
private static void WriteCallback(IAsyncResult transportResult) { if (transportResult.CompletedSynchronously) { return; } if (!(transportResult.AsyncState is AsyncProtocolRequest)) { NetEventSource.Fail(transportResult, "State type is wrong, expected AsyncProtocolRequest."); } AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState; var sslStream = (SslStreamInternal)asyncRequest.AsyncObject; try { TaskToApm.End(transportResult); sslStream._sslState.FinishWrite(); if (asyncRequest.Count == 0) { // This was the last chunk. asyncRequest.Count = -1; } sslStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } sslStream._sslState.FinishWrite(); asyncRequest.CompleteUserWithError(e); } }
private void StartReadFrame(byte[] buffer, int readBytes, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { throw new IOException(SR.GetString("net_auth_eof")); } if (this._Framing == Framing.None) { this._Framing = this.DetectFraming(buffer, readBytes); } int remainingFrameSize = this.GetRemainingFrameSize(buffer, readBytes); if (remainingFrameSize < 0) { throw new IOException(SR.GetString("net_ssl_io_frame")); } if (remainingFrameSize == 0) { throw new AuthenticationException(SR.GetString("net_auth_eof"), null); } buffer = EnsureBufferSize(buffer, readBytes, readBytes + remainingFrameSize); if (asyncRequest == null) { remainingFrameSize = this._Reader.ReadPacket(buffer, readBytes, remainingFrameSize); } else { asyncRequest.SetNextRequest(buffer, readBytes, remainingFrameSize, _ReadFrameCallback); this._Reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return; } remainingFrameSize = asyncRequest.Result; if (remainingFrameSize == 0) { readBytes = 0; } } this.ProcessReceivedBlob(buffer, readBytes + remainingFrameSize, asyncRequest); }
private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) { SslState asyncObject = (SslState)asyncRequest.AsyncObject; try { if (asyncRequest.Result == 0) { asyncRequest.Offset = 0; } asyncObject.ProcessReceivedBlob(asyncRequest.Buffer, asyncRequest.Offset + asyncRequest.Result, asyncRequest); } catch (Exception exception) { if (asyncRequest.IsUserCompleted) { throw; } asyncObject.FinishHandshake(exception, asyncRequest); } }
private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int readBytes = 0; this.EnsureInternalBufferSize(0, this._SslState.HeaderSize); if (asyncRequest != null) { asyncRequest.SetNextRequest(this.InternalBuffer, 0, this._SslState.HeaderSize, _ReadHeaderCallback); this._Reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return(0); } readBytes = asyncRequest.Result; } else { readBytes = this._Reader.ReadPacket(this.InternalBuffer, 0, this._SslState.HeaderSize); } return(this.StartFrameBody(readBytes, buffer, offset, count, asyncRequest)); }
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) { #if DEBUG using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { #endif _NegoState.CheckThrow(true); if (!_NegoState.CanGetSecureStream) { return(InnerStream.BeginRead(buffer, offset, count, asyncCallback, asyncState)); } BufferAsyncResult bufferResult = new BufferAsyncResult(this, buffer, offset, count, asyncState, asyncCallback); AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(bufferResult); ProcessRead(buffer, offset, count, asyncRequest); return(bufferResult); #if DEBUG } #endif }
private AsyncProtocolRequest GetOrCreateProtocolRequest(ref AsyncProtocolRequest aprField, LazyAsyncResult asyncResult) { AsyncProtocolRequest request = null; if (asyncResult != null) { // SslStreamInternal supports only a single read and a single write operation at a time. // As such, we can cache and reuse the AsyncProtocolRequest object that's used throughout // the implementation. request = aprField; if (request != null) { request.Reset(asyncResult); } else { aprField = request = new AsyncProtocolRequest(asyncResult); } } return(request); }
// // Sync write method. // private void ProcessWrite(byte[] buffer, int offset, int count, LazyAsyncResult asyncResult) { _sslState.CheckThrow(authSuccessCheck: true, shutdownCheck: true); ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _nestedWrite, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, "Write", "write")); } // If this is an async operation, get the AsyncProtocolRequest to use. // We do this only after we verify we're the sole write operation in flight. AsyncProtocolRequest asyncRequest = GetOrCreateProtocolRequest(ref _writeProtocolRequest, asyncResult); bool failed = false; try { StartWriting(buffer, offset, count, asyncRequest); } catch (Exception e) { _sslState.FinishWrite(); failed = true; if (e is IOException) { throw; } throw new IOException(SR.net_io_write, e); } finally { if (asyncRequest == null || failed) { _nestedWrite = 0; } } }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (count >= 0) { byte[] outBuffer = null; do { int num2; int num = Math.Min(count, 0xfc00); try { num2 = this._NegoState.EncryptData(buffer, offset, num, ref outBuffer); } catch (Exception exception) { throw new IOException(SR.GetString("net_io_encrypt"), exception); } if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset + num, count - num, null); IAsyncResult asyncResult = base.InnerStream.BeginWrite(outBuffer, 0, num2, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } base.InnerStream.EndWrite(asyncResult); } else { base.InnerStream.Write(outBuffer, 0, num2); } offset += num; count -= num; }while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }
private void StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) { if ((message == null) || (message.Size == 0)) { throw exception; } if (asyncRequest == null) { this.InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = exception; IAsyncResult asyncResult = this.InnerStream.BeginWrite(message.Payload, 0, message.Size, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this.InnerStream.EndWrite(asyncResult); } throw exception; }
internal void FinishRead(byte[] renegotiateBuffer) { if (Interlocked.CompareExchange(ref this._LockReadState, 0, 4) == 2) { lock (this) { LazyAsyncResult result = this._QueuedReadStateRequest as LazyAsyncResult; if (result != null) { this._QueuedReadStateRequest = null; result.InvokeCallback(renegotiateBuffer); } else { AsyncProtocolRequest state = (AsyncProtocolRequest)this._QueuedReadStateRequest; state.Buffer = renegotiateBuffer; this._QueuedReadStateRequest = null; ThreadPool.QueueUserWorkItem(new WaitCallback(this.AsyncResumeHandshakeRead), state); } } } }
// // To avoid recursion when decrypted 0 bytes this method will loop until a decrypted result at least 1 byte. // private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int result = 0; if (InternalBufferCount != 0) { NetEventSource.Fail(this, $"Previous frame was not consumed. InternalBufferCount: {InternalBufferCount}"); } do { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncReadCallback); } int copyBytes = _sslState.CheckEnqueueRead(buffer, offset, count, asyncRequest); if (copyBytes == 0) { // Queued but not completed! return(0); } if (copyBytes != -1) { if (asyncRequest != null) { asyncRequest.CompleteUser((object)copyBytes); } return(copyBytes); } } // When we read -1 bytes means we have decrypted 0 bytes or rehandshaking, need looping. while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1); return(result); }
// // private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) { // Async ONLY completion try { _SslStream sslStream = (_SslStream)asyncRequest.AsyncObject; BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; if (-1 == sslStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest)) { // in case we decrypted 0 bytes start another reading. sslStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); } } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } asyncRequest.CompleteWithError(e); } }
// Returns: // true - operation queued // false - operation can proceed private bool CheckEnqueueHandshake(byte[] buffer, AsyncProtocolRequest asyncRequest) { LazyAsyncResult lazyResult = null; lock (this) { if (_lockWriteState == LockPendingWrite) { return false; } int lockState = Interlocked.Exchange(ref _lockWriteState, LockHandshake); if (lockState != LockWrite) { // Proceed with handshake. return false; } if (asyncRequest != null) { asyncRequest.Buffer = buffer; _queuedWriteStateRequest = asyncRequest; return true; } lazyResult = new LazyAsyncResult(null, null, /*must be*/null); _queuedWriteStateRequest = lazyResult; } lazyResult.InternalWaitForCompletion(); return false; }
// Returns: // true - operation queued // false - operation can proceed internal bool CheckEnqueueWrite(AsyncProtocolRequest asyncRequest) { // Clear previous request. _queuedWriteStateRequest = null; int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockWrite, LockNone); if (lockState != LockHandshake) { // Proceed with write. return false; } LazyAsyncResult lazyResult = null; lock (this) { if (_lockWriteState != LockHandshake) { // Handshake has completed before we grabbed the lock. CheckThrow(true); return false; } _lockWriteState = LockPendingWrite; // Still pending, wait or enqueue. if (asyncRequest != null) { _queuedWriteStateRequest = asyncRequest; return true; } lazyResult = new LazyAsyncResult(null, null, /*must be */null); _queuedWriteStateRequest = lazyResult; } // Need to exit from lock before waiting. lazyResult.InternalWaitForCompletion(); CheckThrow(true); return false; }
// Returns: // -1 - proceed // 0 - queued // X - some bytes are ready, no need for IO internal int CheckEnqueueRead(byte[] buffer, int offset, int count, AsyncProtocolRequest request) { int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone); if (lockState != LockHandshake) { // Proceed, no concurrent handshake is ongoing so no need for a lock. return CheckOldKeyDecryptedData(buffer, offset, count); } LazyAsyncResult lazyResult = null; lock (this) { int result = CheckOldKeyDecryptedData(buffer, offset, count); if (result != -1) { return result; } // Check again under lock. if (_lockReadState != LockHandshake) { // The other thread has finished before we grabbed the lock. _lockReadState = LockRead; return -1; } _lockReadState = LockPendingRead; if (request != null) { // Request queued. _queuedReadStateRequest = request; return 0; } lazyResult = new LazyAsyncResult(null, null, /*must be */ null); _queuedReadStateRequest = lazyResult; } // Need to exit from lock before waiting. lazyResult.InternalWaitForCompletion(); lock (this) { return CheckOldKeyDecryptedData(buffer, offset, count); } }
private bool CheckEnqueueHandshakeRead(ref byte[] buffer, AsyncProtocolRequest request) { LazyAsyncResult lazyResult = null; lock (this) { if (_lockReadState == LockPendingRead) { return false; } int lockState = Interlocked.Exchange(ref _lockReadState, LockHandshake); if (lockState != LockRead) { return false; } if (request != null) { _queuedReadStateRequest = request; return true; } lazyResult = new LazyAsyncResult(null, null, /*must be */ null); _queuedReadStateRequest = lazyResult; } // Need to exit from lock before waiting. lazyResult.InternalWaitForCompletion(); buffer = (byte[])lazyResult.Result; return false; }
// // private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslState::ReadFrameCallback()"); } // Async ONLY completion. SslState sslState = (SslState)asyncRequest.AsyncObject; try { if (asyncRequest.Result == 0) { //EOF received: will fail. asyncRequest.Offset = 0; } sslState.ProcessReceivedBlob(asyncRequest.Buffer, asyncRequest.Offset + asyncRequest.Result, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } sslState.FinishHandshake(e, asyncRequest); } }
private static void PartialFrameCallback(AsyncProtocolRequest asyncRequest) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SslState::PartialFrameCallback()"); } // Async ONLY completion. SslState sslState = (SslState)asyncRequest.AsyncObject; try { sslState.StartReadFrame(asyncRequest.Buffer, asyncRequest.Result, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } sslState.FinishHandshake(e, asyncRequest); } }
// // Client side starts here, but server also loops through this method. // private void StartSendBlob(byte[] incoming, int count, AsyncProtocolRequest asyncRequest) { ProtocolToken message = Context.NextMessage(incoming, 0, count); _securityStatus = message.Status; if (message.Size != 0) { if (Context.IsServer && _CachedSession == CachedSessionStatus.Unknown) { // //[Schannel] If the first call to ASC returns a token less than 200 bytes, // then it's a reconnect (a handshake based on a cache entry). // _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached; } if (_Framing == Framing.Unified) { _Framing = DetectFraming(message.Payload, message.Payload.Length); } if (asyncRequest == null) { InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = message; IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { #if DEBUG asyncRequest._DebugAsyncChain = ar; #endif return; } InnerStreamAPM.EndWrite(ar); } } CheckCompletionBeforeNextReceive(message, asyncRequest); }
// // This is used to reply on re-handshake when received SEC_I_RENEGOTIATE on Read(). // internal void ReplyOnReAuthentication(byte[] buffer) { lock (this) { // Note we are already inside the read, so checking for already going concurrent handshake. _lockReadState = LockHandshake; if (_pendingReHandshake) { // A concurrent handshake is pending, resume. FinishRead(buffer); return; } } // Start rehandshake from here. // Forcing async mode. The caller will queue another Read as soon as we return using its preferred // calling convention, which will be woken up when the handshake completes. The callback is just // to capture any SocketErrors that happen during the handshake so they can be surfaced from the Read. AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(new LazyAsyncResult(this, null, new AsyncCallback(RehandshakeCompleteCallback))); // Buffer contains a result from DecryptMessage that will be passed to ISC/ASC asyncRequest.Buffer = buffer; ForceAuthentication(false, buffer, asyncRequest); }
// // Combined sync/async read method. For sync requet asyncRequest==null. // private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { ValidateParameters(buffer, offset, count); if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest!=null? "BeginRead":"Read"), "read")); } bool failed = false; try { int copyBytes; if (InternalBufferCount != 0) { copyBytes = InternalBufferCount > count ? count : InternalBufferCount; if (copyBytes != 0) { Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes); SkipBytes(copyBytes); } if (asyncRequest != null) { asyncRequest.CompleteUser((object) copyBytes); } return copyBytes; } return StartReading(buffer, offset, count, asyncRequest); } catch (Exception e) { _sslState.FinishRead(null); failed = true; if (e is IOException) { throw; } throw new IOException(SR.net_io_read, e); } finally { if (asyncRequest == null || failed) { _nestedRead = 0; } } }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback); } // We loop to this method from the callback. // If the last chunk was just completed from async callback (count < 0), we complete user request. if (count >= 0 ) { byte[] outBuffer = null; if (_pinnableOutputBufferInUse == null) { if (_pinnableOutputBuffer == null) { _pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer(); } _pinnableOutputBufferInUse = buffer; outBuffer = _pinnableOutputBuffer; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } } else { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count); } } do { // Request a write IO slot. if (_sslState.CheckEnqueueWrite(asyncRequest)) { // Operation is async and has been queued, return. return; } int chunkBytes = Math.Min(count, _sslState.MaxDataSize); int encryptedBytes; SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { // Re-handshake status is not supported. ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.net_io_encrypt, message.GetException()); } if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer", this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer)); } if (asyncRequest != null) { // Prepare for the next request. asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback); IAsyncResult ar = _sslState.InnerStreamAPM.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _sslState.InnerStreamAPM.EndWrite(ar); } else { _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); } offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _sslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } if (buffer == _pinnableOutputBufferInUse) { _pinnableOutputBufferInUse = null; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } }
internal void StartReHandshake (AsyncProtocolRequest asyncRequest) { if (IsServer) { byte[] buffer = null; if (CheckEnqueueHandshakeRead (ref buffer, asyncRequest)) return; StartReceiveBlob (buffer, asyncRequest); return; } ForceAuthentication (false, null, asyncRequest); }
// // To avoid recursion when decrypted 0 bytes this method will loop until a decrypted result at least 1 byte. // private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int result = 0; if (InternalBufferCount != 0) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("SslStream::StartReading()|Previous frame was not consumed. InternalBufferCount:{0}", InternalBufferCount); } Debug.Fail("SslStream::StartReading()|Previous frame was not consumed. InternalBufferCount:" + InternalBufferCount); } do { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncReadCallback); } int copyBytes = _sslState.CheckEnqueueRead(buffer, offset, count, asyncRequest); if (copyBytes == 0) { // Queued but not completed! return 0; } if (copyBytes != -1) { if (asyncRequest != null) { asyncRequest.CompleteUser((object)copyBytes); } return copyBytes; } } // When we read -1 bytes means we have decrypted 0 bytes or rehandshaking, need looping. while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1); return result; }
private void ProcessReceivedBlob(byte[] buffer, int count, AsyncProtocolRequest asyncRequest) { if (count == 0) { // EOF received. throw new AuthenticationException(SR.net_auth_eof, null); } if (_pendingReHandshake) { int offset = 0; SecurityStatusPal status = PrivateDecryptData(buffer, ref offset, ref count); if (status.ErrorCode == SecurityStatusPalErrorCode.OK) { Exception e = EnqueueOldKeyDecryptedData(buffer, offset, count); if (e != null) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(e)); return; } _Framing = Framing.Unknown; StartReceiveBlob(buffer, asyncRequest); return; } else if (status.ErrorCode != SecurityStatusPalErrorCode.Renegotiate) { // Fail re-handshake. ProtocolToken message = new ProtocolToken(null, status); StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))); return; } // We expect only handshake messages from now. _pendingReHandshake = false; if (offset != 0) { Buffer.BlockCopy(buffer, offset, buffer, 0, count); } } StartSendBlob(buffer, count, asyncRequest); }
// // Server side starts here, but client also loops through this method. // private void StartReceiveBlob(byte[] buffer, AsyncProtocolRequest asyncRequest) { if (_pendingReHandshake) { if (CheckEnqueueHandshakeRead(ref buffer, asyncRequest)) { return; } if (!_pendingReHandshake) { // Renegotiate: proceed to the next step. ProcessReceivedBlob(buffer, buffer.Length, asyncRequest); return; } } //This is first server read. buffer = EnsureBufferSize(buffer, 0, SecureChannel.ReadHeaderSize); int readBytes = 0; if (asyncRequest == null) { readBytes = _reader.ReadPacket(buffer, 0, SecureChannel.ReadHeaderSize); } else { asyncRequest.SetNextRequest(buffer, 0, SecureChannel.ReadHeaderSize, s_partialFrameCallback); _reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return; } readBytes = asyncRequest.Result; } StartReadFrame(buffer, readBytes, asyncRequest); }
private void FinishHandshake(Exception e, AsyncProtocolRequest asyncRequest) { try { lock (this) { if (e != null) { SetException(e); } // Release read if any. FinishHandshakeRead(LockNone); // If there is a pending write we want to keep it's lock state. int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockNone, LockHandshake); if (lockState != LockPendingWrite) { return; } _lockWriteState = LockWrite; object obj = _queuedWriteStateRequest; if (obj == null) { // We finished before Write has grabbed the lock. return; } _queuedWriteStateRequest = null; if (obj is LazyAsyncResult) { // Sync write is waiting on other thread. ((LazyAsyncResult)obj).InvokeCallback(); } else { // Async write is pending, start it on other thread. // Consider: we could start it in on this thread but that will delay THIS handshake completion ThreadPool.QueueUserWorkItem(new WaitCallback(CompleteRequestWaitCallback), obj); } } } finally { if (asyncRequest != null) { if (e != null) { asyncRequest.CompleteWithError(e); } else { asyncRequest.CompleteUser(); } } } }
// // This method assumes that a SSPI context is already in a good shape. // For example it is either a fresh context or already authenticated context that needs renegotiation. // internal void ProcessAuthentication(LazyAsyncResult lazyResult) { if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) { throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, lazyResult == null ? "BeginAuthenticate" : "Authenticate", "authenticate")); } try { CheckThrow(false); AsyncProtocolRequest asyncRequest = null; if (lazyResult != null) { asyncRequest = new AsyncProtocolRequest(lazyResult); asyncRequest.Buffer = null; #if DEBUG lazyResult._debugAsyncChain = asyncRequest; #endif } // A trick to discover and avoid cached sessions. _CachedSession = CachedSessionStatus.Unknown; ForceAuthentication(Context.IsServer, null, asyncRequest); // Not aync so the connection is completed at this point. if (lazyResult == null && SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.SspiSelectedCipherSuite("ProcessAuthentication", SslProtocol, CipherAlgorithm, CipherStrength, HashAlgorithm, HashStrength, KeyExchangeAlgorithm, KeyExchangeStrength); } } catch (Exception) { // If an exception emerges synchronously, the asynchronous operation was not // initiated, so no operation is in progress. _nestedAuth = 0; throw; } finally { // For synchronous operations, the operation has completed. if (lazyResult == null) { _nestedAuth = 0; } } }
private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { int readBytes = 0; // // Always pass InternalBuffer for SSPI "in place" decryption. // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption. // // Reset internal buffer for a new frame. EnsureInternalBufferSize(0, SecureChannel.ReadHeaderSize); if (asyncRequest != null) { asyncRequest.SetNextRequest(InternalBuffer, 0, SecureChannel.ReadHeaderSize, s_readHeaderCallback); _reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return 0; } readBytes = asyncRequest.Result; } else { readBytes = _reader.ReadPacket(InternalBuffer, 0, SecureChannel.ReadHeaderSize); } return StartFrameBody(readBytes, buffer, offset, count, asyncRequest); }
// // This method attempts to start authentication. // Incoming buffer is either null or is the result of "renegotiate" decrypted message // If write is in progress the method will either wait or be put on hold // private void ForceAuthentication(bool receiveFirst, byte[] buffer, AsyncProtocolRequest asyncRequest) { if (CheckEnqueueHandshake(buffer, asyncRequest)) { // Async handshake is enqueued and will resume later. return; } // Either Sync handshake is ready to go or async handshake won the race over write. // This will tell that we don't know the framing yet (what SSL version is) _Framing = Framing.Unknown; try { if (receiveFirst) { // Listen for a client blob. StartReceiveBlob(buffer, asyncRequest); } else { // We start with the first blob. StartSendBlob(buffer, (buffer == null ? 0 : buffer.Length), asyncRequest); } } catch (Exception e) { // Failed auth, reset the framing if any. _Framing = Framing.Unknown; _handshakeCompleted = false; if (SetException(e).SourceException == e) { throw; } else { _exception.Throw(); } } finally { if (_exception != null) { // This a failed handshake. Release waiting IO if any. FinishHandshake(null, null); } } }
private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { //EOF : Reset the buffer as we did not read anything into it. SkipBytes(InternalBufferCount); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return 0; } // Now readBytes is a payload size. readBytes = _sslState.GetRemainingFrameSize(InternalBuffer, readBytes); if (readBytes < 0) { throw new IOException(SR.net_frame_read_size); } EnsureInternalBufferSize(SecureChannel.ReadHeaderSize, readBytes); if (asyncRequest != null) { asyncRequest.SetNextRequest(InternalBuffer, SecureChannel.ReadHeaderSize, readBytes, s_readFrameCallback); _reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return 0; } readBytes = asyncRequest.Result; } else { readBytes = _reader.ReadPacket(InternalBuffer, SecureChannel.ReadHeaderSize, readBytes); } return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest); }
// // This will check and logically complete / fail the auth handshake. // private void CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) { if (message.Failed) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))); return; } else if (message.Done && !_pendingReHandshake) { if (!CompleteHandshake()) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_validation, null))); return; } // Release waiting IO if any. Presumably it should not throw. // Otherwise application may get not expected type of the exception. FinishHandshake(null, asyncRequest); return; } StartReceiveBlob(message.Payload, asyncRequest); }
// // This is used in a rare situation when async Write is resumed from completed handshake. // private static void ResumeAsyncWriteCallback(AsyncProtocolRequest asyncRequest) { try { ((SslStreamInternal)asyncRequest.AsyncObject).StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest); } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } ((SslStreamInternal)asyncRequest.AsyncObject)._sslState.FinishWrite(); asyncRequest.CompleteWithError(e); } }
// private void StartReadFrame(byte[] buffer, int readBytes, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { // EOF received throw new IOException(SR.net_auth_eof); } if (_Framing == Framing.Unknown) { _Framing = DetectFraming(buffer, readBytes); } int restBytes = GetRemainingFrameSize(buffer, readBytes); if (restBytes < 0) { throw new IOException(SR.net_ssl_io_frame); } if (restBytes == 0) { // EOF received throw new AuthenticationException(SR.net_auth_eof, null); } buffer = EnsureBufferSize(buffer, readBytes, readBytes + restBytes); if (asyncRequest == null) { restBytes = _reader.ReadPacket(buffer, readBytes, restBytes); } else { asyncRequest.SetNextRequest(buffer, readBytes, restBytes, s_readFrameCallback); _reader.AsyncReadPacket(asyncRequest); if (!asyncRequest.MustCompleteSynchronously) { return; } restBytes = asyncRequest.Result; if (restBytes == 0) { //EOF received: fail. readBytes = 0; } } ProcessReceivedBlob(buffer, readBytes + restBytes, asyncRequest); }
private static void ReadFrameCallback(AsyncProtocolRequest asyncRequest) { try { SslStreamInternal sslStream = (SslStreamInternal)asyncRequest.AsyncObject; BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; if (-1 == sslStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest)) { // in case we decrypted 0 bytes start another reading. sslStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); } } catch (Exception e) { if (asyncRequest.IsUserCompleted) { // This will throw on a worker thread. throw; } asyncRequest.CompleteWithError(e); } }
// // This is to reset auth state on remote side. // If this write succeeds we will allow auth retrying. // private void StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) { if (message == null || message.Size == 0) { // // We don't have an alert to send so cannot retry and fail prematurely. // exception.Throw(); } if (asyncRequest == null) { InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = exception; IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } InnerStreamAPM.EndWrite(ar); } exception.Throw(); }
internal bool CheckEnqueueHandshakeWrite (byte[] buffer, AsyncProtocolRequest asyncRequest) { return CheckEnqueueHandshake (buffer, asyncRequest); }
// // readBytes == SSL Data Payload size on input or 0 on EOF. // private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (readBytes == 0) { // EOF throw new IOException(SR.net_io_eof); } // Set readBytes to total number of received bytes. readBytes += SecureChannel.ReadHeaderSize; // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_. int data_offset = 0; SecurityStatusPal status = _sslState.DecryptData(InternalBuffer, ref data_offset, ref readBytes); if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { byte[] extraBuffer = null; if (readBytes != 0) { extraBuffer = new byte[readBytes]; Buffer.BlockCopy(InternalBuffer, data_offset, extraBuffer, 0, readBytes); } // Reset internal buffer count. SkipBytes(InternalBufferCount); return ProcessReadErrorCode(status, buffer, offset, count, asyncRequest, extraBuffer); } if (readBytes == 0 && count != 0) { // Read again since remote side has sent encrypted 0 bytes. SkipBytes(InternalBufferCount); return -1; } // Decrypted data start from "data_offset" offset, the total count can be shrunk after decryption. EnsureInternalBufferSize(0, data_offset + readBytes); SkipBytes(data_offset); if (readBytes > count) { readBytes = count; } Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes); // This will adjust both the remaining internal buffer count and the offset. SkipBytes(readBytes); _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)readBytes); } return readBytes; }
// // This is used in a rare situation when async Read is resumed from completed handshake. // private static void ResumeAsyncReadCallback(AsyncProtocolRequest request) { try { ((SslStreamInternal)request.AsyncObject).StartReading(request.Buffer, request.Offset, request.Count, request); } catch (Exception e) { if (request.IsUserCompleted) { // This will throw on a worker thread. throw; } ((SslStreamInternal)request.AsyncObject)._sslState.FinishRead(null); request.CompleteWithError(e); } }
// // private IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) { #if DEBUG using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { #endif _negoState.CheckThrow(true); if (!_negoState.CanGetSecureStream) { return InnerStream.BeginWrite(buffer, offset, count, asyncCallback, asyncState); } BufferAsyncResult bufferResult = new BufferAsyncResult(this, buffer, offset, count, true, asyncState, asyncCallback); AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(bufferResult); ProcessWrite(buffer, offset, count, asyncRequest); return bufferResult; #if DEBUG } #endif }
// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken message = new ProtocolToken(null, status); if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString()); } if (message.Renegotiate) { _sslState.ReplyOnReAuthentication(extraBuffer); // Loop on read. return -1; } if (message.CloseConnection) { _sslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return 0; } throw new IOException(SR.net_io_decrypt, message.GetException()); }