File: DiagnosticsIpc\IpcHeader.cs
Web Access
Project: src\src\diagnostics\src\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.csproj (Microsoft.Diagnostics.NETCore.Client)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Diagnostics.NETCore.Client
{
    internal class IpcHeader
    {
        private IpcHeader() { }

        public IpcHeader(DiagnosticsServerCommandSet commandSet, byte commandId)
        {
            CommandSet = (byte)commandSet;
            CommandId = commandId;
        }

        // the number of bytes for the DiagnosticsIpc::IpcHeader type in native code
        public const ushort HeaderSizeInBytes = 20;
        private const ushort MagicSizeInBytes = 14;

        public byte[] Magic = DotnetIpcV1; // byte[14] in native code
        public ushort Size = HeaderSizeInBytes;
        public byte CommandSet;
        public byte CommandId;
        public ushort Reserved;


        // Helper expression to quickly get V1 magic string for comparison
        // should be 14 bytes long
        public static byte[] DotnetIpcV1 => Encoding.ASCII.GetBytes("DOTNET_IPC_V1" + '\0');

        public byte[] Serialize()
        {
            using (MemoryStream stream = new())
            using (BinaryWriter writer = new(stream))
            {
                writer.Write(Magic);
                Debug.Assert(Magic.Length == MagicSizeInBytes);
                writer.Write(Size);
                writer.Write(CommandSet);
                writer.Write(CommandId);
                writer.Write((ushort)0x0000);
                writer.Flush();
                return stream.ToArray();
            }
        }

        public static IpcHeader Parse(BinaryReader reader)
        {
            IpcHeader header = new()
            {
                Magic = reader.ReadBytes(14),
                Size = reader.ReadUInt16(),
                CommandSet = reader.ReadByte(),
                CommandId = reader.ReadByte(),
                Reserved = reader.ReadUInt16()
            };

            return header;
        }

        public static async Task<IpcHeader> ParseAsync(Stream stream, CancellationToken cancellationToken)
        {
            byte[] buffer = await stream.ReadBytesAsync(HeaderSizeInBytes, cancellationToken).ConfigureAwait(false);
            using MemoryStream bufferStream = new(buffer);
            using BinaryReader bufferReader = new(bufferStream);
            IpcHeader header = Parse(bufferReader);
            Debug.Assert(bufferStream.Position == bufferStream.Length);
            return header;
        }

        public override string ToString()
        {
            return $"{{ Magic={Magic}; Size={Size}; CommandSet={CommandSet}; CommandId={CommandId}; Reserved={Reserved} }}";
        }
    }
}