public async Task <int> ReadBytesAsync(ArraySegment <byte> buffer, CancellationToken cancellationToken) { var timer = new Stopwatch(); var totalBytesRead = 0; try { await _readSemaphore.LockAsync( // serialize receiving on a given transport async() => { var stream = _stream; // so if the socket is reconnected, we don't read partially from different sockets var socket = _tcpSocket; _configuration.OnReading?.Invoke(_endpoint, buffer.Count); timer.Start(); while (totalBytesRead < buffer.Count && !cancellationToken.IsCancellationRequested) { var bytesRemaining = buffer.Count - totalBytesRead; _log.Verbose(() => LogEvent.Create($"Reading ({bytesRemaining}? bytes) from {_endpoint}")); _configuration.OnReadingBytes?.Invoke(_endpoint, bytesRemaining); var bytesRead = await stream.ReadAsync(buffer.Array, buffer.Offset + totalBytesRead, bytesRemaining, cancellationToken).ConfigureAwait(false); totalBytesRead += bytesRead; _configuration.OnReadBytes?.Invoke(_endpoint, bytesRemaining, bytesRead, timer.Elapsed); _log.Verbose(() => LogEvent.Create($"Read {bytesRead} bytes from {_endpoint}")); if (bytesRead <= 0 && socket.Available == 0) { _socket.Disconnect(socket); var ex = new ConnectionException(_endpoint); _configuration.OnDisconnected?.Invoke(_endpoint, ex); throw ex; } } timer.Stop(); _configuration.OnRead?.Invoke(_endpoint, totalBytesRead, timer.Elapsed); }, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { timer.Stop(); _configuration.OnReadFailed?.Invoke(_endpoint, buffer.Count, timer.Elapsed, ex); if (_disposeCount > 0) { throw new ObjectDisposedException(nameof(SslTransport)); } throw; } return(totalBytesRead); }
private async Task ProcessReadTaskAsync(Stream stream, SocketPayloadReadTask readTask) { using (readTask) { var totalBytesRead = 0; var timer = new Stopwatch(); try { _configuration.OnReading?.Invoke(Endpoint, readTask.ReadSize); var buffer = new byte[readTask.ReadSize]; timer.Start(); while (totalBytesRead < readTask.ReadSize) { var readSize = readTask.ReadSize - totalBytesRead; _log.Debug(() => LogEvent.Create($"Reading ({readSize}? bytes) from {Endpoint}")); _configuration.OnReadingChunk?.Invoke(Endpoint, readTask.ReadSize, totalBytesRead, timer.Elapsed); var bytesRead = await stream.ReadAsync(buffer, totalBytesRead, readSize, readTask.CancellationToken).ConfigureAwait(false); totalBytesRead += bytesRead; var remainingBytes = readTask.ReadSize - totalBytesRead; _configuration.OnReadChunk?.Invoke(Endpoint, readTask.ReadSize, remainingBytes, bytesRead, timer.Elapsed); _log.Debug(() => LogEvent.Create($"Read {bytesRead} bytes from {Endpoint}{(readTask.CancellationToken.IsCancellationRequested ? " (cancelled)" : "")}")); if (bytesRead <= 0) { using (_client) { _client = null; if (_disposeToken.IsCancellationRequested) { _configuration.OnReadFailed?.Invoke(Endpoint, readTask.ReadSize, timer.Elapsed, new TaskCanceledException()); return; } throw new ConnectionException(Endpoint); } } } timer.Stop(); _configuration.OnRead?.Invoke(Endpoint, buffer, timer.Elapsed); readTask.Tcs.TrySetResult(buffer); totalBytesRead = 0; } catch (Exception ex) { timer.Stop(); _configuration.OnReadFailed?.Invoke(Endpoint, readTask.ReadSize, timer.Elapsed, ex); Exception exception = null; if (_disposeToken.IsCancellationRequested) { exception = new ObjectDisposedException($"Object is disposing (TcpSocket for {Endpoint})", ex); } else if ((_client == null || _client.Connected == false) && !(ex is ConnectionException)) { exception = new ConnectionException(Endpoint, ex); } if (totalBytesRead > 0) { readTask.Tcs.TrySetException(new PartialReadException(totalBytesRead, readTask.ReadSize, exception ?? ex)); } else { readTask.Tcs.TrySetException(exception ?? ex); } if (_disposeToken.IsCancellationRequested) { return; } if (exception != null) { throw exception; } throw; } } }