public ReliableSamHelper( ISamHelper samHelper, ReliableSamHelperSettings settings ) { if (samHelper == null) { throw new ArgumentNullException( MyNameof.GetLocalVarName(() => samHelper)); } if (settings == null) { throw new ArgumentNullException( MyNameof.GetLocalVarName(() => settings)); } _samHelper = samHelper; _settings = settings; var rng = new Random(DateTime.UtcNow.Millisecond); _nextOutMessageId = (uint)rng.Next(int.MaxValue); RawDatagramReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe(args => _log.Trace( "{5} recv raw datagram of {0} bytes " + "from {1} id={2}, rid={3}, kind={6}, ansiS='{4}'", args.Data.Length, args.Destination.Substring(0, 20), args.MessageId, args.ReplyToMessageId, Encoding.ASCII.GetString(args.Data), _reliableSamHelperGuid.ToString().Substring(0, 5), args.MessageKind )); ReliableMessageReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe(args => _log.Trace( "{4} recv reliable message of {0} bytes " + "from {1} id={2}, rid={3}, kind={5}", args.Data.Length, args.Destination.Substring(0, 20), args.MessageId, args.ReplyToMessageId, _reliableSamHelperGuid.ToString().Substring(0, 5), args.MessageKind ) ); _subscriptions.AddRange( new[] { _samHelper.DatagramDataReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe( SamHelperOnDatagramDataReceived ), GetProtocolVersionReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe( OnGetProtocolVersionReceived ), HandshakeStartReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe( OnHandshakeStartReceived ), GetMessageStatusReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe( OnGetMessageStatusReceived ), BlockSendReceived.ObserveOn(TaskPoolScheduler.Default).Subscribe( OnBlockSendReceived ), Observable.Interval(TimeSpan.FromSeconds(20.0d)).ObserveOn(TaskPoolScheduler.Default).Subscribe( IntervalCleanupAction ) } ); _stateHelper.SetInitializedState(); }
private async void SamHelperOnDatagramDataReceived( DatagramDataReceivedArgs datagramDataReceivedArgs ) { try { using (_stateHelper.GetFuncWrapper()) { if ( datagramDataReceivedArgs.Data.Length > (_settings.MaxBlockSize + 1000) ) { return; } if ( _dropDestinations.Contains( datagramDataReceivedArgs.Destination ) ) { return; } string fromDestination = datagramDataReceivedArgs.Destination; using ( var reader = new EndianBinaryReader( _littleEndianConverter, new MemoryStream(datagramDataReceivedArgs.Data) ) ) { var blockType = (ReliableDatagramCodes)reader.ReadByte(); switch (blockType) { case ReliableDatagramCodes.RawDatagram: { uint messageId = reader.ReadUInt32(); uint replyToMessageId = reader.ReadUInt32(); byte messageKind = reader.ReadByte(); var messageHash = reader.ReadBytesOrThrow(32); var rawData = ReadBytesToEnd(reader); if ( messageHash.SequenceEqual( GetMessageHash( messageId, replyToMessageId, messageKind, rawData ) ) ) { RawDatagramReceived.OnNext( new ReliableMessageReceivedArgs() { Data = rawData, Destination = fromDestination, MessageId = messageId, ReplyToMessageId = replyToMessageId, MessageKind = messageKind } ); } return; } case ReliableDatagramCodes.HandshakeStart: { uint messageId = reader.ReadUInt32(); uint replyToMessageId = reader.ReadUInt32(); byte messageKind = reader.ReadByte(); uint totalMessageSize = reader.ReadUInt32(); if (totalMessageSize > _settings.MaxMesageLength) { return; } uint blockSize = reader.ReadUInt32(); if (blockSize > _settings.MaxBlockSize) { return; } var messageHash = reader.ReadBytesOrThrow(32); uint firstBlockSize = reader.ReadUInt32(); if ( firstBlockSize == 0 || firstBlockSize > _settings.MaxBlockSize ) { return; } byte[] firstBlockData = reader.ReadBytesOrThrow((int)firstBlockSize); HandshakeStartReceived.OnNext( new HandshakeStartArgs { Destination = fromDestination, BlockSize = blockSize, MessageId = messageId, ReplyToMessageId = replyToMessageId, MessageSize = totalMessageSize, MessageKind = messageKind, MessageHash = messageHash, FirstBlockData = firstBlockData } ); return; } case ReliableDatagramCodes.MessageStatus: { uint messageId = reader.ReadUInt32(); if (!await CheckExistOutMessage(fromDestination, messageId).ConfigureAwait(false)) { return; } var errorCode = (MessageStatusArgs.MessageStatusCode) reader.ReadByte(); uint blocksReceived = reader.ReadUInt32(); MessageStatusReceived.OnNext( new MessageStatusArgs() { Destination = datagramDataReceivedArgs .Destination, MessageId = messageId, StatusCode = errorCode, BlocksReceived = blocksReceived } ); return; } case ReliableDatagramCodes.BlockSend: { uint messageId = reader.ReadUInt32(); uint blockId = reader.ReadUInt32(); var blockData = ReadBytesToEnd(reader); if ( blockData.Length == 0 || blockData.Length > _settings.MaxBlockSize ) { return; } BlockSendReceived.OnNext(new BlockSendArgs() { Destination = fromDestination, MessageId = messageId, BlockId = blockId, BlockData = blockData }); return; } case ReliableDatagramCodes.BlockConfirmation: { uint messageId = reader.ReadUInt32(); if (!await CheckExistOutMessage(fromDestination, messageId).ConfigureAwait(false)) { return; } uint blockId = reader.ReadUInt32(); BlockConfirmationReceived.OnNext( new BlockConfirmationArgs() { Destination = fromDestination, MessageId = messageId, BlockId = blockId } ); return; } case ReliableDatagramCodes.GetMessageStatus: { uint messageId = reader.ReadUInt32(); GetMessageStatusReceived.OnNext( new GetMessageStatusArgs() { Destination = fromDestination, MessageId = messageId } ); return; } case ReliableDatagramCodes.GetProtocolVersion: { GetProtocolVersionReceived.OnNext( new GetProtocolVersionArgs() { Destination = fromDestination } ); return; } case ReliableDatagramCodes.ProtocolVersion: { uint protocolVersion = reader.ReadUInt32(); ProtocolVersionReceived.OnNext( new ProtocolVersionArgs() { Destination = fromDestination, ProtocolVersion = protocolVersion } ); return; } } } } } catch (EndOfStreamException exc) { _log.Error( "SamHelperOnDatagramDataReceived" + " EndOfStreamException '{0}'", exc.ToString() ); } catch (OperationCanceledException) { } catch (WrongDisposableObjectStateException) { } catch (Exception exc) { _log.Error( "SamHelperOnDatagramDataReceived" + " unexpected error '{0}'", exc.ToString() ); } }