private async Task Publish(EventHubClient client, QuickBlockTransferSegment segment) { try { await client.SendAsync(new EventData(segment.Content) { PartitionKey = segment.GetKey(), Properties = { {nameof(segment.Header), segment.Header}, {nameof(segment.ReceivedAt), segment.ReceivedAt}, {nameof(segment.Filename), segment.Filename}, {nameof(segment.TimeStamp), segment.TimeStamp}, {nameof(segment.Checksum), segment.Checksum}, {nameof(segment.BlockNumber), segment.BlockNumber}, {nameof(segment.TotalBlocks), segment.TotalBlocks}, {nameof(segment.Version), segment.Version}, {nameof(segment.Source), segment.Source} } }); } catch (Exception ex) { _log.Error(ex.ToString()); } }
/// <summary> /// Parses the Quick Block Transfer V2 header. /// </summary> /// <param name="groups">The match from the regular expression parser.</param> /// <param name="packet">The packet to be populated.</param> private void ParseHeaderV2(GroupCollection groups, QuickBlockTransferSegment packet) { if (!groups["DL"].Success) { return; } packet.Version = 2; packet.Length = int.Parse(groups["DL"].Value); if (packet.Length <= 0 || packet.Length > 1024) { throw new IndexOutOfRangeException("DL (length) value " + packet.Length + " is out of range (1-1024)."); } }
/// <summary> /// Parses the Quick Block Transfer V1 header. /// </summary> /// <param name="groups">The match from the regular expression parser.</param> /// <param name="packet">The packet to be populated.</param> private static void ParseHeaderV1(GroupCollection groups, QuickBlockTransferSegment packet) { packet.Version = 1; packet.Length = QuickBlockV1BodySize; packet.Filename = groups["PF"].Value; packet.BlockNumber = int.Parse(groups["PN"].Value); packet.TotalBlocks = int.Parse(groups["PT"].Value); packet.Checksum = int.Parse(groups["CS"].Value); DateTimeOffset ts; var dateText = groups["FD"].Value; if (DateTimeOffset.TryParseExact(dateText, HeaderDateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out ts)) { packet.TimeStamp = ts; } else { ByteBlasterEventSource.Log.ParserWarning("Unable to parse header date", dateText); } }
/// <summary> /// Reads and parses the packet header. /// </summary> /// <param name="input">The input.</param> /// <returns>QuickBlockTransferPacket.</returns> private QuickBlockTransferSegment ParsePacketHeader(IByteBuffer input) { var header = ReadString(input, QuickBlockHeaderSize); ByteBlasterEventSource.Log.HeaderReceived(header); var match = HeaderRegex.Match(header); if (match.Success) { var packet = new QuickBlockTransferSegment { Header = header, Source = _remoteAddress }; ParseHeaderV1(match.Groups, packet); ParseHeaderV2(match.Groups, packet); return(packet); } throw new InvalidDataException("QuickBlockPacketDecoder Unknown header: " + header); }
/// <summary> /// Decodes the byte buffer and builds QuickBlockTransfer packets. /// </summary> /// <param name="context">The handler context.</param> /// <param name="input">The input byte buffer from the socket.</param> /// <param name="output">The output packets.</param> protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List <object> output) { switch (State) { case DecoderState.ReSync: if (!input.IsReadable(QuickBlockV1BodySize + FrameSyncBytes)) { break; } PerformanceCounters.FrameSyncTotal.Increment(); if (!SynchronizeFrame(input)) { break; } State = DecoderState.StartFrame; goto case DecoderState.StartFrame; case DecoderState.StartFrame: if (!SkipNullBytes(input)) { break; } State = DecoderState.FrameType; goto case DecoderState.FrameType; case DecoderState.FrameType: if (!input.IsReadable(QuickBlockHeaderSize)) { break; } if (IsDataBlockHeader(input)) { State = DecoderState.BlockHeader; goto case DecoderState.BlockHeader; } if (IsServerList(input)) { PerformanceCounters.ServerListReceivedTotal.Increment(); State = DecoderState.ServerList; goto case DecoderState.ServerList; } throw new InvalidOperationException("Unknown frame type"); case DecoderState.ServerList: var content = ReadString(input); if (content.Length == 0) { break; } context.FireUserEventTriggered(ParseServerList(content)); State = DecoderState.StartFrame; goto case DecoderState.StartFrame; case DecoderState.BlockHeader: Packet = ParsePacketHeader(input); PerformanceCounters.BlocksReceivedTotal.Increment(); if (Packet.Version == 2) { PerformanceCounters.CompressedBlocksReceivedTotal.Increment(); } State = DecoderState.BlockBody; goto case DecoderState.BlockBody; case DecoderState.BlockBody: if (!input.IsReadable(Packet.Length)) { break; } Packet.Content = ReadPacketBody(input, Packet.Length, Packet.Version); PerformanceCounters.BlocksProcessedPerSecond.Increment(); State = DecoderState.Validate; goto case DecoderState.Validate; case DecoderState.Validate: if (Packet.TotalBlocks <= 0 || Packet.BlockNumber <= 0) { PerformanceCounters.ChecksumErrorsTotal.Increment(); throw new InvalidDataException("Header block values out of range. " + Packet); } if (VerifyChecksum(Packet.Content, Packet.Checksum)) { ByteBlasterEventSource.Log.PacketCreated(Packet.ToString()); context.FireUserEventTriggered(Packet); } else { PerformanceCounters.ChecksumErrorsTotal.Increment(); throw new InvalidDataException("Block Checksum failed. " + Packet); } State = DecoderState.StartFrame; goto case DecoderState.StartFrame; default: throw new InvalidOperationException("Unknown Decoder State: " + State); } }
/// <summary> /// Reads and parses the packet header. /// </summary> /// <param name="input">The input.</param> /// <returns>QuickBlockTransferPacket.</returns> private QuickBlockTransferSegment ParsePacketHeader(IByteBuffer input) { var header = ReadString(input, QuickBlockHeaderSize); ByteBlasterEventSource.Log.HeaderReceived(header); var match = HeaderRegex.Match(header); if (match.Success) { var packet = new QuickBlockTransferSegment { Header = header, Source = _remoteAddress }; ParseHeaderV1(match.Groups, packet); ParseHeaderV2(match.Groups, packet); return packet; } throw new InvalidDataException("QuickBlockPacketDecoder Unknown header: " + header); }
/// <summary> /// Parses the Quick Block Transfer V2 header. /// </summary> /// <param name="groups">The match from the regular expression parser.</param> /// <param name="packet">The packet to be populated.</param> private void ParseHeaderV2(GroupCollection groups, QuickBlockTransferSegment packet) { if (!groups["DL"].Success) return; packet.Version = 2; packet.Length = int.Parse(groups["DL"].Value); if (packet.Length <= 0 || packet.Length > 1024) throw new IndexOutOfRangeException("DL (length) value " + packet.Length + " is out of range (1-1024)."); }
/// <summary> /// Decodes the byte buffer and builds QuickBlockTransfer packets. /// </summary> /// <param name="context">The handler context.</param> /// <param name="input">The input byte buffer from the socket.</param> /// <param name="output">The output packets.</param> protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output) { switch (State) { case DecoderState.ReSync: if (!input.IsReadable(QuickBlockV1BodySize + FrameSyncBytes)) break; PerformanceCounters.FrameSyncTotal.Increment(); if (!SynchronizeFrame(input)) break; State = DecoderState.StartFrame; goto case DecoderState.StartFrame; case DecoderState.StartFrame: if (!SkipNullBytes(input)) break; State = DecoderState.FrameType; goto case DecoderState.FrameType; case DecoderState.FrameType: if (!input.IsReadable(QuickBlockHeaderSize)) break; if (IsDataBlockHeader(input)) { State = DecoderState.BlockHeader; goto case DecoderState.BlockHeader; } if (IsServerList(input)) { PerformanceCounters.ServerListReceivedTotal.Increment(); State = DecoderState.ServerList; goto case DecoderState.ServerList; } throw new InvalidOperationException("Unknown frame type"); case DecoderState.ServerList: var content = ReadString(input); if (content.Length == 0) break; context.FireUserEventTriggered(ParseServerList(content)); State = DecoderState.StartFrame; goto case DecoderState.StartFrame; case DecoderState.BlockHeader: Packet = ParsePacketHeader(input); PerformanceCounters.BlocksReceivedTotal.Increment(); if (Packet.Version == 2) PerformanceCounters.CompressedBlocksReceivedTotal.Increment(); State = DecoderState.BlockBody; goto case DecoderState.BlockBody; case DecoderState.BlockBody: if (!input.IsReadable(Packet.Length)) break; Packet.Content = ReadPacketBody(input, Packet.Length, Packet.Version); PerformanceCounters.BlocksProcessedPerSecond.Increment(); State = DecoderState.Validate; goto case DecoderState.Validate; case DecoderState.Validate: if (Packet.TotalBlocks <= 0 || Packet.BlockNumber <= 0) { PerformanceCounters.ChecksumErrorsTotal.Increment(); throw new InvalidDataException("Header block values out of range. " + Packet); } if (VerifyChecksum(Packet.Content, Packet.Checksum)) { ByteBlasterEventSource.Log.PacketCreated(Packet.ToString()); context.FireUserEventTriggered(Packet); } else { PerformanceCounters.ChecksumErrorsTotal.Increment(); throw new InvalidDataException("Block Checksum failed. " + Packet); } State = DecoderState.StartFrame; goto case DecoderState.StartFrame; default: throw new InvalidOperationException("Unknown Decoder State: " + State); } }