// // Loops while subsequent completions are sync. // private void StartReading() { while (true) { IAsyncResult ar = _transportAPM.BeginRead(_request.Buffer, _request.Offset + _totalRead, _request.Count - _totalRead, s_readCallback, this); if (!ar.CompletedSynchronously) { #if DEBUG _request._DebugAsyncChain = ar; #endif break; } int bytes = _transportAPM.EndRead(ar); if (CheckCompletionBeforeNextRead(bytes)) { break; } } }
// IO COMPLETION CALLBACK // // This callback is responsible for getting the complete protocol frame. // 1. it reads the header. // 2. it determines the frame size. // 3. loops while not all frame received or an error. // private void ReadFrameComplete(IAsyncResult transportResult) { do { if (!(transportResult.AsyncState is WorkerAsyncResult)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("StreamFramer::ReadFrameComplete|The state expected to be WorkerAsyncResult, received:{0}.", transportResult.GetType().FullName); } Debug.Fail("StreamFramer::ReadFrameComplete|The state expected to be WorkerAsyncResult, received:" + transportResult.GetType().FullName + "."); } WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState; int bytesRead = _transportAPM.EndRead(transportResult); workerResult.Offset += bytesRead; if (!(workerResult.Offset <= workerResult.End)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("StreamFramer::ReadFrameCallback|WRONG: offset - end = {0}", workerResult.Offset - workerResult.End); } Debug.Fail("StreamFramer::ReadFrameCallback|WRONG: offset - end = " + (workerResult.Offset - workerResult.End)); } if (bytesRead <= 0) { // (by design) This indicates the stream has receives EOF // If we are in the middle of a Frame - fail, otherwise - produce EOF object result = null; if (!workerResult.HeaderDone && workerResult.Offset == 0) { result = (object)-1; } else { result = new System.IO.IOException(SR.net_frame_read_io); } workerResult.InvokeCallback(result); return; } if (workerResult.Offset >= workerResult.End) { if (!workerResult.HeaderDone) { workerResult.HeaderDone = true; // This indicates the header has been read succesfully _curReadHeader.CopyFrom(workerResult.Buffer, 0, _readVerifier); int payloadSize = _curReadHeader.PayloadSize; if (payloadSize < 0) { // Let's call user callback and he call us back and we will throw workerResult.InvokeCallback(new System.IO.IOException(SR.Format(SR.net_frame_read_size))); } if (payloadSize == 0) { // report emtpy frame (NOT eof!) to the caller, he might be interested in workerResult.InvokeCallback(0); return; } if (payloadSize > _curReadHeader.MaxMessageSize) { throw new InvalidOperationException(SR.Format(SR.net_frame_size, _curReadHeader.MaxMessageSize.ToString(NumberFormatInfo.InvariantInfo), payloadSize.ToString(NumberFormatInfo.InvariantInfo))); } // Start reading the remaining frame data (note header does not count). byte[] frame = new byte[payloadSize]; // Save the ref of the data block workerResult.Buffer = frame; workerResult.End = frame.Length; workerResult.Offset = 0; // Transport.BeginRead below will pickup those changes. } else { workerResult.HeaderDone = false; // Reset for optional object reuse. workerResult.InvokeCallback(workerResult.End); return; } } // This means we need more data to complete the data block. transportResult = _transportAPM.BeginRead(workerResult.Buffer, workerResult.Offset, workerResult.End - workerResult.Offset, _readFrameCallback, workerResult); } while (transportResult.CompletedSynchronously); }