private async Task EnsureDataAvailableOrReadAsync(int bytesNeeded, CancellationToken cancellationToken)
{
// Adequate buffer space?
Contract.Assert(bytesNeeded <= _receiveBuffer.Length);
// Insufficient buffered data
while (_receiveBufferBytes < bytesNeeded)
{
cancellationToken.ThrowIfCancellationRequested();
int spaceRemaining = _receiveBuffer.Length - (_receiveBufferOffset + _receiveBufferBytes);
if (_receiveBufferOffset > 0 && bytesNeeded > spaceRemaining)
{
// Some data in the buffer, shift down to make room
Array.Copy(_receiveBuffer, _receiveBufferOffset, _receiveBuffer, 0, _receiveBufferBytes);
_receiveBufferOffset = 0;
spaceRemaining = _receiveBuffer.Length - _receiveBufferBytes;
}
// Add to the end
int read = await _stream.ReadAsync(_receiveBuffer, _receiveBufferOffset + _receiveBufferBytes, spaceRemaining, cancellationToken);
if (read == 0)
{
throw new IOException("Unexpected end of stream");
}
_receiveBufferBytes += read;
}
}