private void StartReading() { try { while (!cancellationToken.IsCancellationRequested) { log.LogInformation("Start message reader"); byte[] header = new byte[HeaderSize]; int headerResult = readStream.Read(header, 0, header.Length); try { if (headerResult == 0) { throw new ClientDisconnectedException(); } (int messageLength, bool isSplit, Guid messageGuid, byte confirmation) = ParseHeader(header); if (messageLength > 0) { ReadMessage(messageLength, isSplit, messageGuid, confirmation); } else { ProcessConfirmationFlag(confirmation, messageGuid); } } catch (ClientDisconnectedException) { communicationProtocol.Disconnect(); } } log.LogInformation("Shutdown reader thread."); } catch (Exception) { //Do not log anything as any log will lead to another exception } void ReadMessage(int messageLength, bool isSplit, Guid messageGuid, byte confirmation) { Stream messageStream = streamFactory.Create(messageLength); int intervals = messageLength / BufferSize; int remaining = messageLength % BufferSize; byte[] buffer = new byte[BufferSize]; IncomingMessage message = new IncomingMessage(messageGuid, messageStream, log); try { ReadIntervals(); int result = Extensions.ExecutesWithTimeout(() => readStream.Read(buffer, 0, remaining), MaxConfirmationResponseTime); if (result == 0) { throw new ClientDisconnectedException(); } if (result != remaining) { throw new PartialMessageException(messageGuid); } AppendBuffer(messageStream, buffer, remaining); messageStream.Seek(0, SeekOrigin.Begin); if (splitMessages.ContainsKey(messageGuid) && splitMessages.TryGetValue(messageGuid, out IncomingMessage splitMessage)) { MergeWithSplitMessage(splitMessage, messageStream); message.Dispose(); message = splitMessage; } if (isSplit) { EnqueueSplitMessage(messageGuid, message); } if (!isSplit) { splitMessages.TryRemove(messageGuid, out _); CompleteMessage(message, messageGuid, confirmation); } } catch (ClientDisconnectedException disconnectedException) { log.LogError($"Client disconnected during communication.{Environment.NewLine}" + $"{disconnectedException}"); messageStream?.Dispose(); message?.Dispose(); throw; } catch (TaskCanceledException c) { log.LogError($"Exception during message read.{Environment.NewLine}" + $"{new MessageTimeoutException(messageGuid.GetHashCode(), MaxConfirmationResponseTime, c)}"); } catch (OperationCanceledException oc) { log.LogError($"Exception during message read.{Environment.NewLine}" + $"{new MessageTimeoutException(messageGuid.GetHashCode(), MaxConfirmationResponseTime, oc)}"); } catch (PartialMessageException) { messageStream?.Dispose(); message?.Dispose(); outgoingMessageQueue.SendMessageConfirmation(messageGuid, false); } catch (Exception e) { log.LogError($"Exception during message read.{Environment.NewLine}" + $"{e}"); messageStream?.Dispose(); message?.Dispose(); throw new ClientDisconnectedException(e); } log.LogVerbose("Finished reading message."); void ReadIntervals() { while (intervals > 0) { intervals--; ReadInterval(); } void ReadInterval() { int result = Extensions.ExecutesWithTimeout(() => readStream.Read(buffer, 0, BufferSize), MaxConfirmationResponseTime); if (result == 0) { throw new ClientDisconnectedException(); } if (result != BufferSize) { throw new PartialMessageException(messageGuid); } AppendBuffer(messageStream, buffer, BufferSize); } } } }