/// <summary> /// Validates the data packet by CRC check /// </summary> /// <param name="dataPacket">Data packet to check.</param> /// <exception cref="CrcCheckFailedSerializationException"> /// Throws when CRC check fails. /// </exception> public static void ValidateCrc(byte[] dataPacket) { var version = (ushort)(dataPacket[0] | dataPacket[1] << 8); if (version < 5) { // No CRC is added for versions less than 5. return; } var crc = (uint)(dataPacket[2] | dataPacket[3] << 8 | dataPacket[4] << 16 | dataPacket[5] << 24); var computedCrc = Crc.ComputeCrc(0, dataPacket, 6); if (crc != computedCrc) { throw new CrcCheckFailedSerializationException($"Crc check failed. Computed CRC : {crc}, Packet CRC: {computedCrc}"); } }
/// <summary> /// Serializes counter (metric) data to the stream. /// </summary> /// <param name="stream">Stream to which data should be serialized. Stream should be writable and provide random access.</param> /// <param name="metricData">Collection of metric data to be serialized.</param> public void Serialize(Stream stream, IEnumerable <IReadOnlyMetric> metricData) { if (!stream.CanWrite || !stream.CanSeek) { throw new ArgumentException("Stream should be writable and provide random access.", nameof(stream)); } try { using (var writer = new NoCloseBinaryWriter(stream, Encoding.UTF8)) { var startStreamPosition = stream.Position; // Write version and type serializers info writer.Write(this.version); long crcOffSet = 0; long crcBodyOffSet = 0; if (this.version >= 5) { // Add CRC crcOffSet = stream.Position; writer.Write((uint)0); crcBodyOffSet = stream.Position; } writer.Write(TypeSerializerFlags); // Reserve place to write type serializers data sections offsets var offsetsPosition = stream.Position; stream.Position += 2 * sizeof(long); // Write metrics data this.WriteMetricsData(writer, metricData); // Write cached metrics metadata and offset var serializerDataPosition = stream.Position; stream.Position = offsetsPosition; writer.Write(serializerDataPosition - startStreamPosition); offsetsPosition = stream.Position; stream.Position = serializerDataPosition; SerializationUtils.WriteUInt32AsBase128(writer, (uint)this.metadatas.Count); this.metadatas.ForEach(m => this.WriteMetricMetadata(writer, m)); // Write cached strings and offset serializerDataPosition = stream.Position; stream.Position = offsetsPosition; writer.Write(serializerDataPosition - startStreamPosition); stream.Position = serializerDataPosition; SerializationUtils.WriteUInt32AsBase128(writer, (uint)this.strings.Count); this.strings.ForEach(writer.Write); var endOfStream = stream.Position; if (this.version >= 5) { stream.Position = crcBodyOffSet; var crc = Crc.ComputeCrc(0, stream, stream.Length - crcBodyOffSet); stream.Position = crcOffSet; writer.Write(crc); } stream.Position = endOfStream; } } catch (IOException ioException) { throw new MetricSerializationException("Failed to serialize data.", ioException); } finally { this.nextStringIndex = 0; this.stringIndexes.Clear(); this.strings.Clear(); this.nextMetadataIndex = 0; this.metadataIndexes.Clear(); this.metadatas.Clear(); this.currentMetricDataBlockSize = 0; this.currentMetadataDictionaryBlockSize = 0; this.currentStringDictionaryBlockSize = 0; } }