private async Task SendProtocolVersion(
     string destination,
     int protocolId
     )
 {
     if (!SamHelper.IsDestinationStringValid(destination))
     {
         throw new ArgumentOutOfRangeException(
                   "destination"
                   );
     }
     using (
         var ms = new MemoryStream(
             sizeof(byte) + sizeof(int)
             )
         )
     {
         using (
             var binaryWriter = new EndianBinaryWriter(
                 _littleEndianConverter,
                 ms
                 )
             )
         {
             binaryWriter.Write(
                 (byte)ReliableDatagramCodes.ProtocolVersion
                 );
             binaryWriter.Write(protocolId);
             await _samHelper.SendDatagram(
                 destination,
                 ms.ToArray()
                 ).ThrowIfCancelled(_cts.Token).ConfigureAwait(false);
         }
     }
 }
 private async Task SendMessageStatus(
     string destination,
     uint messageId,
     MessageStatusArgs.MessageStatusCode statusCode,
     uint blocksReceived
     )
 {
     if (!SamHelper.IsDestinationStringValid(destination))
     {
         throw new ArgumentOutOfRangeException("destination");
     }
     using (
         var ms = new MemoryStream(
             sizeof(byte)
             + sizeof(uint)
             + sizeof(byte)
             + sizeof(uint)
             )
         )
     {
         using (
             var binaryWriter
                 = new EndianBinaryWriter(
                       _littleEndianConverter,
                       ms
                       )
                 )
         {
             binaryWriter.Write(
                 (byte)ReliableDatagramCodes.MessageStatus
                 );
             binaryWriter.Write(messageId);
             binaryWriter.Write((byte)statusCode);
             binaryWriter.Write(blocksReceived);
             await _samHelper.SendDatagram(
                 destination,
                 ms.ToArray()
                 ).ThrowIfCancelled(_cts.Token).ConfigureAwait(false);
         }
     }
 }
 private async Task SendBlockConfirmation(
     string destination,
     uint messageId,
     uint blockId
     )
 {
     if (!SamHelper.IsDestinationStringValid(destination))
     {
         throw new ArgumentOutOfRangeException(
                   MyNameof.GetLocalVarName(() => destination));
     }
     using (
         var ms = new MemoryStream(
             sizeof(byte)
             + sizeof(uint)
             + sizeof(uint)
             )
         )
     {
         using (
             var binaryWriter
                 = new EndianBinaryWriter(
                       _littleEndianConverter,
                       ms
                       )
                 )
         {
             binaryWriter.Write(
                 (byte)ReliableDatagramCodes.BlockConfirmation
                 );
             binaryWriter.Write(messageId);
             binaryWriter.Write(blockId);
             await _samHelper.SendDatagram(
                 destination,
                 ms.ToArray()
                 ).ThrowIfCancelled(_cts.Token).ConfigureAwait(false);
         }
     }
 }
 private async void OnGetProtocolVersionReceived(
     GetProtocolVersionArgs getProtocolVersionArgs
     )
 {
     try
     {
         using (_stateHelper.GetFuncWrapper())
         {
             string fromDestination = getProtocolVersionArgs.Destination;
             if (_dropDestinations.Contains(fromDestination))
             {
                 return;
             }
             if (!SamHelper.IsDestinationStringValid(fromDestination))
             {
                 return;
             }
             await SendProtocolVersion(
                 fromDestination,
                 _settings.ProtocolVersion
                 ).ConfigureAwait(false);
         }
     }
     catch (OperationCanceledException)
     {
     }
     catch (WrongDisposableObjectStateException)
     {
     }
     catch (Exception exc)
     {
         _log.Error(
             "OnGetProtocolVersionReceived" +
             " unexpected error '{0}'",
             exc.ToString()
             );
     }
 }
        public async Task <uint> SendReliableMessage(
            string destination,
            byte[] data,
            IProgress <OutMessageProgressInfo> progress = null,
            uint messageId          = 0,
            uint replyToMessageId   = 0,
            byte messageKind        = 0,
            CancellationToken token = default(CancellationToken)
            )
        {
            using (_stateHelper.GetFuncWrapper())
            {
                try
                {
                    Assert.True(SamHelper.IsDestinationStringValid(destination));
                    Assert.NotNull(data);
                    Assert.InRange(data.Length, 1, _settings.MaxMesageLength);
                    if (messageId == 0)
                    {
                        messageId = await GetNextOutMessageId().ConfigureAwait(false);
                    }
                    DestinationInfo destinationInfo;
                    using (await _destinationDbLockSem.GetDisposable(token: token).ConfigureAwait(false))
                    {
                        if (!_destinationDb.ContainsKey(destination))
                        {
                            _destinationDb.Add(destination, new DestinationInfo());
                        }
                        destinationInfo = _destinationDb[destination];
                    }
                    OutMessageInfo outMessageInfo;
                    using (await destinationInfo.OutMessagesDbLockSem.GetDisposable(token: token).ConfigureAwait(false))
                    {
                        if (
                            destinationInfo.OutMessagesDb.ContainsKey(messageId)
                            )
                        {
                            throw new EnumException <SendReliableMessageExcs>(
                                      SendReliableMessageExcs.ExistMessageId
                                      );
                        }
                        outMessageInfo = new OutMessageInfo(
                            data,
                            replyToMessageId,
                            _settings.MaxBlockSize,
                            progress
                            );
                        destinationInfo.OutMessagesDb.Add(messageId, outMessageInfo);
                    }
                    try
                    {
                        uint blocksCount = outMessageInfo.BlockCount;

                        /*
                         * Handshake
                         */
                        using (
                            var compositeTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
                                _cts.Token,
                                token
                                )
                            )
                        {
                            try
                            {
                                var messageStatusTask =
                                    MessageStatusReceived
                                    .Where(
                                        x =>
                                        x.Destination == destination &&
                                        x.MessageId == messageId
                                        )
                                    .FirstAsync()
                                    .ToTask(compositeTokenSource.Token);
                                byte[] messageHash = GetMessageHash(
                                    messageId,
                                    replyToMessageId,
                                    messageKind,
                                    data
                                    );
                                for (
                                    outMessageInfo.HandshakeAttemptNo = 0;
                                    outMessageInfo.HandshakeAttemptNo
                                    <= _settings.HandshakeAttemptCount;
                                    outMessageInfo.HandshakeAttemptNo++
                                    )
                                {
                                    if (
                                        outMessageInfo.HandshakeAttemptNo
                                        == _settings.HandshakeAttemptCount
                                        )
                                    {
                                        throw new EnumException <SendReliableMessageExcs>(
                                                  SendReliableMessageExcs.HandshakeTimeout
                                                  );
                                    }
                                    await SendHandshakeStart(
                                        destination,
                                        messageId,
                                        replyToMessageId,
                                        (uint)data.Length,
                                        outMessageInfo.BlockSize,
                                        messageHash,
                                        outMessageInfo.Data[0],
                                        messageKind
                                        ).ConfigureAwait(false);

                                    var waitTasks = await Task.WhenAny(
                                        messageStatusTask,
                                        Task.Delay(
                                            TimeSpan.FromSeconds(
                                                _settings.HandshakeTimeoutSeconds
                                                ),
                                            compositeTokenSource.Token
                                            )
                                        ).ConfigureAwait(false);

                                    if (waitTasks == messageStatusTask)
                                    {
                                        var messageStatus = await messageStatusTask.ConfigureAwait(false);

                                        if (
                                            !(
                                                messageStatus.StatusCode ==
                                                MessageStatusArgs.MessageStatusCode.HandshakeOk
                                                ||
                                                (
                                                    messageStatus.StatusCode ==
                                                    MessageStatusArgs.MessageStatusCode.AllBlocksReceived &&
                                                    outMessageInfo.BlockCount == 1
                                                )
                                                )
                                            )
                                        {
                                            throw new EnumException <SendReliableMessageExcs>(
                                                      SendReliableMessageExcs.HandshakeError,
                                                      messageStatus.WriteObjectToJson()
                                                      );
                                        }
                                        break;
                                    }
                                }
                                outMessageInfo.Status            = OutMessageStatus.HandshakeOk;
                                outMessageInfo.BlockConfirmed[0] = true;
                                if (outMessageInfo.BlockCount > 1)
                                {
                                    // Handshake established, start sending blocks
                                    DateTime lastBlockConfirmationTime = DateTime.UtcNow;
                                    var      blocksInProgress          = new SortedSet <uint>();
                                    var      blocksInProgressLockSem   = new SemaphoreSlim(1);
                                    var      blockSentTimes            = new DateTime[blocksCount];
                                    using (
                                        BlockConfirmationReceived
                                        .Where(_ =>
                                               _.Destination == destination &&
                                               _.MessageId == messageId
                                               )
                                        .ObserveOn(TaskPoolScheduler.Default)
                                        .Subscribe(async x =>
                                    {
                                        if (
                                            x.BlockId < blocksCount &&
                                            !outMessageInfo.BlockConfirmed[x.BlockId]
                                            )
                                        {
                                            await outMessageInfo.ConfirmBlock(x.BlockId).ConfigureAwait(false);
                                            lastBlockConfirmationTime = DateTime.UtcNow;
                                            using (await blocksInProgressLockSem.GetDisposable().ConfigureAwait(false))
                                            {
                                                blocksInProgress.Remove(x.BlockId);
                                            }
                                        }
                                    }
                                                   )
                                        )
                                    {
                                        while (true)
                                        {
                                            compositeTokenSource.Token.ThrowIfCancellationRequested();
                                            IEnumerable <int> blocksToSend;
                                            using (
                                                await
                                                blocksInProgressLockSem.GetDisposable(token: compositeTokenSource.Token)
                                                .ConfigureAwait(false))
                                            {
                                                if (
                                                    blocksInProgress.Count == 0 &&
                                                    outMessageInfo.BlockConfirmed.All(x => x)
                                                    )
                                                {
                                                    break;
                                                }
                                                blocksInProgress.RemoveWhere(
                                                    i =>
                                                    DateTime.UtcNow >
                                                    (
                                                        blockSentTimes[i]
                                                        + TimeSpan.FromSeconds(
                                                            _settings
                                                            .ConfirmationOneBlockTimeoutSeconds
                                                            )
                                                    )
                                                    );
                                                blocksToSend = Enumerable.Range(0, (int)blocksCount)
                                                               .Where(
                                                    i =>
                                                    !blocksInProgress.Contains((uint)i) &&
                                                    !outMessageInfo.BlockConfirmed[i]
                                                    )
                                                               .Take(
                                                    Math.Max(
                                                        0,
                                                        _settings.WindowSize
                                                        - blocksInProgress.Count
                                                        )
                                                    );
                                            }
                                            foreach (int blockId in blocksToSend)
                                            {
                                                await SendBlock(
                                                    destination,
                                                    messageId,
                                                    (uint)blockId
                                                    ).ConfigureAwait(false);

                                                await outMessageInfo.SendBlock(
                                                    (uint)blockId
                                                    ).ConfigureAwait(false);

                                                using (
                                                    await
                                                    blocksInProgressLockSem.GetDisposable(token: compositeTokenSource.Token)
                                                    .ConfigureAwait(false))
                                                {
                                                    blocksInProgress.Add((uint)blockId);
                                                }
                                                blockSentTimes[blockId] = DateTime.UtcNow;
                                            }
                                            if (
                                                DateTime.UtcNow >
                                                lastBlockConfirmationTime +
                                                TimeSpan.FromSeconds(
                                                    _settings.ConfirmationTimeoutSeconds
                                                    )
                                                )
                                            {
                                                throw new EnumException <SendReliableMessageExcs>(
                                                          SendReliableMessageExcs.SendBlocksTimeout
                                                          );
                                            }
                                            await Task.Delay(50, compositeTokenSource.Token).ConfigureAwait(false);
                                        }
                                    }
                                }
                                outMessageInfo.Status = OutMessageStatus.AllBlocksSent;
                                // all blocks sent and confirmed
                                _log.Trace(
                                    "{4}, send reliable message of {0} bytes " +
                                    "to {1} id={2},rid={3},kind={5}",
                                    data.Length,
                                    destination.Substring(0, 20),
                                    messageId,
                                    replyToMessageId,
                                    _reliableSamHelperGuid.ToString().Substring(0, 5),
                                    messageKind
                                    );
                                return(messageId);
                            }
                            finally
                            {
                                compositeTokenSource.Cancel();
                            }
                        }
                    }
                    finally
                    {
                        TryRemoveOutMessageInfo(destinationInfo, messageId);
                    }
                }
                catch (EnumException <SendReliableMessageExcs> )
                {
                    throw;
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (TimeoutException)
                {
                    throw;
                }
                catch (Exception exc)
                {
                    throw new EnumException <SendReliableMessageExcs>(
                              SendReliableMessageExcs.UnexpectedError,
                              innerException: exc
                              );
                }
            }
        }
        private async Task SendBlock(
            string destination,
            uint messageId,
            uint blockId
            )
        {
            if (string.IsNullOrWhiteSpace(destination))
            {
                throw new ArgumentNullException("destination");
            }
            if (!SamHelper.IsDestinationStringValid(destination))
            {
                throw new ArgumentOutOfRangeException("destination");
            }
            DestinationInfo destinationInfo;

            using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
            {
                if (!_destinationDb.ContainsKey(destination))
                {
                    throw new ArgumentException("destination");
                }
                destinationInfo = _destinationDb[destination];
            }
            OutMessageInfo outMessageInfo;

            using (await destinationInfo.OutMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
            {
                if (!destinationInfo.OutMessagesDb.ContainsKey(messageId))
                {
                    throw new ArgumentOutOfRangeException("messageId");
                }
                outMessageInfo = destinationInfo.OutMessagesDb[messageId];
            }
            if (blockId >= outMessageInfo.Data.Count)
            {
                throw new ArgumentOutOfRangeException("blockId");
            }
            var dataToSend = outMessageInfo.Data[(int)blockId];

            using (
                var ms = new MemoryStream(
                    sizeof(byte)
                    + sizeof(uint)
                    + sizeof(uint)
                    + dataToSend.Length
                    )
                )
            {
                using (
                    var binaryWriter
                        = new EndianBinaryWriter(
                              _littleEndianConverter,
                              ms
                              )
                        )
                {
                    binaryWriter.Write(
                        (byte)ReliableDatagramCodes.BlockSend
                        );
                    binaryWriter.Write(messageId);
                    binaryWriter.Write(blockId);
                    binaryWriter.Write(dataToSend);
                    await _samHelper.SendDatagram(
                        destination,
                        ms.ToArray()
                        ).ThrowIfCancelled(_cts.Token).ConfigureAwait(false);
                }
            }
        }
        private async void OnHandshakeStartReceived(
            HandshakeStartArgs handshakeStartArgs
            )
        {
            try
            {
                using (_stateHelper.GetFuncWrapper())
                {
                    string fromDestination
                        = handshakeStartArgs.Destination;
                    if (_dropDestinations.Contains(fromDestination))
                    {
                        return;
                    }
                    if (!SamHelper.IsDestinationStringValid(fromDestination))
                    {
                        return;
                    }
                    DestinationInfo destinationInfo;
                    using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        if (
                            !_destinationDb.ContainsKey(
                                handshakeStartArgs.Destination
                                )
                            )
                        {
                            destinationInfo = new DestinationInfo();
                            _destinationDb.Add(
                                handshakeStartArgs.Destination,
                                destinationInfo
                                );
                        }
                        else
                        {
                            destinationInfo =
                                _destinationDb[
                                    handshakeStartArgs.Destination
                                ];
                        }
                    }
                    using (await destinationInfo.InMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        if (
                            destinationInfo.InMessagesDb.ContainsKey(
                                handshakeStartArgs.MessageId
                                )
                            )
                        {
                            var inMessageInfo
                                = destinationInfo.InMessagesDb[
                                      handshakeStartArgs.MessageId
                                  ];
                            if (
                                inMessageInfo.Status
                                == InMessageStatus.HandshakeReceived
                                )
                            {
                                await
                                SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs.MessageStatusCode.HandshakeOk,
                                    0
                                    ).ConfigureAwait(false);

                                return;
                            }
                            else if (
                                inMessageInfo.Status
                                == InMessageStatus.AllBlocksReceived
                                )
                            {
                                await SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs.MessageStatusCode.AllBlocksReceived,
                                    inMessageInfo.BlocksReceivedCount
                                    ).ConfigureAwait(false);

                                return;
                            }
                            else
                            {
                                await SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs
                                    .MessageStatusCode
                                    .HandshakeErrorDuplicatedId,
                                    inMessageInfo.BlocksReceivedCount
                                    ).ConfigureAwait(false);

                                return;
                            }
                        }
                        else
                        {
                            if (
                                handshakeStartArgs.MessageSize
                                > _settings.MaxMesageLength
                                )
                            {
                                await SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs.MessageStatusCode
                                    .HandshakeErrorWrongTotalSize,
                                    0
                                    ).ConfigureAwait(false);

                                return;
                            }
                            if (handshakeStartArgs.BlockSize > _settings.MaxBlockSize)
                            {
                                await SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs.MessageStatusCode
                                    .HandshakeErrorWrongBlockSize,
                                    0
                                    ).ConfigureAwait(false);

                                return;
                            }
                            var inMessageInfo = new InMessageInfo(
                                handshakeStartArgs.MessageSize,
                                handshakeStartArgs.BlockSize,
                                handshakeStartArgs.ReplyToMessageId,
                                handshakeStartArgs.MessageKind,
                                handshakeStartArgs.MessageHash
                                );
                            if (
                                inMessageInfo.ReceivedDataChunkSizes[0]
                                != handshakeStartArgs.FirstBlockData.Length
                                )
                            {
                                await SendMessageStatus(
                                    fromDestination,
                                    handshakeStartArgs.MessageId,
                                    MessageStatusArgs.MessageStatusCode
                                    .HandshakeErrorWrongBlockSize,
                                    0
                                    ).ConfigureAwait(false);

                                return;
                            }
                            destinationInfo.InMessagesDb.Add(
                                handshakeStartArgs.MessageId,
                                inMessageInfo
                                );
                            await SendMessageStatus(
                                fromDestination,
                                handshakeStartArgs.MessageId,
                                MessageStatusArgs.MessageStatusCode.HandshakeOk,
                                0
                                ).ConfigureAwait(false);

                            OnBlockSendReceived(
                                new BlockSendArgs()
                            {
                                BlockData   = handshakeStartArgs.FirstBlockData,
                                BlockId     = 0,
                                Destination = handshakeStartArgs.Destination,
                                MessageId   = handshakeStartArgs.MessageId
                            }
                                );
                            return;
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (WrongDisposableObjectStateException)
            {
            }
            catch (Exception exc)
            {
                _log.Error(
                    "OnHandshakeStartReceive" +
                    " unexpected error '{0}'",
                    exc.ToString()
                    );
            }
        }
        private async void OnGetMessageStatusReceived(
            GetMessageStatusArgs getMessageStatusArgs
            )
        {
            try
            {
                using (_stateHelper.GetFuncWrapper())
                {
                    string fromDestination
                        = getMessageStatusArgs.Destination;
                    if (_dropDestinations.Contains(fromDestination))
                    {
                        return;
                    }
                    if (!SamHelper.IsDestinationStringValid(fromDestination))
                    {
                        return;
                    }
                    bool destinationDbContainsKey;
                    using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        destinationDbContainsKey
                            = _destinationDb.ContainsKey(
                                  fromDestination
                                  );
                    }
                    if (
                        !destinationDbContainsKey
                        )
                    {
                        await SendMessageStatus(
                            fromDestination,
                            getMessageStatusArgs.MessageId,
                            MessageStatusArgs
                            .MessageStatusCode
                            .UnknownMessageId,
                            0
                            ).ConfigureAwait(false);

                        return;
                    }

                    DestinationInfo destinationInfo;
                    using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        destinationInfo =
                            _destinationDb[fromDestination];
                    }
                    bool inMessagesDbContainsKey;
                    using (await destinationInfo.InMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        inMessagesDbContainsKey =
                            destinationInfo.InMessagesDb.ContainsKey(
                                getMessageStatusArgs.MessageId
                                );
                    }
                    if (
                        !inMessagesDbContainsKey
                        )
                    {
                        await SendMessageStatus(
                            fromDestination,
                            getMessageStatusArgs.MessageId,
                            MessageStatusArgs
                            .MessageStatusCode
                            .UnknownMessageId,
                            0
                            ).ConfigureAwait(false);

                        return;
                    }
                    InMessageInfo inMessageInfo;
                    using (await destinationInfo.InMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
                    {
                        inMessageInfo
                            = destinationInfo.InMessagesDb[
                                  getMessageStatusArgs.MessageId
                              ];
                    }
                    int blocksReceivedCount
                        = inMessageInfo.BlocksReceived.Count(x => x);
                    if (
                        inMessageInfo.Status
                        == InMessageStatus.HandshakeReceived
                        )
                    {
                        await SendMessageStatus(
                            fromDestination,
                            getMessageStatusArgs.MessageId,
                            MessageStatusArgs
                            .MessageStatusCode
                            .HandshakeOk,
                            (uint)blocksReceivedCount
                            ).ConfigureAwait(false);

                        return;
                    }
                    if (
                        inMessageInfo.Status
                        == InMessageStatus.AllBlocksReceived
                        )
                    {
                        await SendMessageStatus(
                            fromDestination,
                            getMessageStatusArgs.MessageId,
                            MessageStatusArgs
                            .MessageStatusCode
                            .AllBlocksReceived,
                            (uint)inMessageInfo.BlocksReceived.Length
                            ).ConfigureAwait(false);
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (WrongDisposableObjectStateException)
            {
            }
            catch (Exception exc)
            {
                _log.Error(
                    "OnGetMessageStatusReceived" +
                    " unexpected error '{0}'",
                    exc.ToString()
                    );
            }
        }
 private async void OnBlockSendReceived(
     BlockSendArgs blockSendArgs
     )
 {
     try
     {
         using (_stateHelper.GetFuncWrapper())
         {
             string fromDestination = blockSendArgs.Destination;
             if (_dropDestinations.Contains(fromDestination))
             {
                 return;
             }
             if (!SamHelper.IsDestinationStringValid(fromDestination))
             {
                 return;
             }
             DestinationInfo destinationInfo;
             using (await _destinationDbLockSem.GetDisposable().ConfigureAwait(false))
             {
                 if (
                     !_destinationDb.ContainsKey(
                         blockSendArgs.Destination
                         )
                     )
                 {
                     return;
                 }
                 destinationInfo
                     = _destinationDb[blockSendArgs.Destination];
             }
             InMessageInfo inMessageInfo;
             using (await destinationInfo.InMessagesDbLockSem.GetDisposable().ConfigureAwait(false))
             {
                 if (
                     !destinationInfo.InMessagesDb.ContainsKey(
                         blockSendArgs.MessageId
                         )
                     )
                 {
                     return;
                 }
                 inMessageInfo
                     = destinationInfo.InMessagesDb[
                           blockSendArgs.MessageId
                       ];
             }
             if (
                 inMessageInfo.Status
                 == InMessageStatus.AllBlocksReceived
                 )
             {
                 return;
             }
             if (inMessageInfo.BlockCount > 1)
             {
                 await SendBlockConfirmation(
                     fromDestination,
                     blockSendArgs.MessageId,
                     blockSendArgs.BlockId
                     ).ConfigureAwait(false);
             }
             if (
                 await inMessageInfo.ReceiveBlock(
                     blockSendArgs.BlockId,
                     blockSendArgs.BlockData
                     ).ConfigureAwait(false)
                 )
             {
                 var allData = new List <byte>(
                     (int)inMessageInfo.MessageSize
                     );
                 foreach (
                     byte[] blockData
                     in inMessageInfo.ReceivedData
                     )
                 {
                     allData.AddRange(blockData);
                 }
                 var dataArray = allData.ToArray();
                 if (
                     inMessageInfo.MessageHash.SequenceEqual(
                         GetMessageHash(
                             blockSendArgs.MessageId,
                             inMessageInfo.ReplyToMessageId,
                             inMessageInfo.MessageKind,
                             dataArray
                             )
                         )
                     )
                 {
                     ReliableMessageReceived.OnNext(
                         new ReliableMessageReceivedArgs()
                     {
                         Destination = fromDestination,
                         Data        = allData.ToArray(),
                         MessageId   = blockSendArgs.MessageId,
                         ReplyToMessageId
                                     = inMessageInfo.ReplyToMessageId,
                         MessageKind = inMessageInfo.MessageKind
                     }
                         );
                 }
                 await inMessageInfo.FlushBlocks().ConfigureAwait(false);
             }
         }
     }
     catch (OperationCanceledException)
     {
     }
     catch (WrongDisposableObjectStateException)
     {
     }
     catch (Exception exc)
     {
         _log.Error(
             "OnBlockSendReceived" +
             " unexpected error '{0}'",
             exc.ToString()
             );
     }
 }