File: Resolver\DnsDataWriter.cs
Web Access
Project: src\src\Microsoft.Extensions.ServiceDiscovery.Dns\Microsoft.Extensions.ServiceDiscovery.Dns.csproj (Microsoft.Extensions.ServiceDiscovery.Dns)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Buffers.Binary;
using System.Diagnostics;
 
namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver;
 
internal sealed class DnsDataWriter
{
    private readonly Memory<byte> _buffer;
    private int _position;
 
    internal DnsDataWriter(Memory<byte> buffer)
    {
        _buffer = buffer;
        _position = 0;
    }
 
    public int Position => _position;
 
    internal bool TryWriteHeader(in DnsMessageHeader header)
    {
        if (!DnsPrimitives.TryWriteMessageHeader(_buffer.Span.Slice(_position), header, out int written))
        {
            return false;
        }
 
        _position += written;
        return true;
    }
 
    internal bool TryWriteQuestion(EncodedDomainName name, QueryType type, QueryClass @class)
    {
        if (!TryWriteDomainName(name) ||
            !TryWriteUInt16((ushort)type) ||
            !TryWriteUInt16((ushort)@class))
        {
            return false;
        }
 
        return true;
    }
 
    private bool TryWriteDomainName(EncodedDomainName name)
    {
        foreach (var label in name.Labels)
        {
            // this should be already validated by the caller
            Debug.Assert(label.Length <= 63, "Label length must not exceed 63 bytes.");
 
            if (!TryWriteByte((byte)label.Length) ||
                !TryWriteRawData(label.Span))
            {
                return false;
            }
        }
 
        // root label
        return TryWriteByte(0);
    }
 
    internal bool TryWriteDomainName(string name)
    {
        if (DnsPrimitives.TryWriteQName(_buffer.Span.Slice(_position), name, out int written))
        {
            _position += written;
            return true;
        }
 
        return false;
    }
 
    internal bool TryWriteByte(byte value)
    {
        if (_buffer.Length - _position < 1)
        {
            return false;
        }
 
        _buffer.Span[_position] = value;
        _position += 1;
        return true;
    }
 
    internal bool TryWriteUInt16(ushort value)
    {
        if (_buffer.Length - _position < 2)
        {
            return false;
        }
 
        BinaryPrimitives.WriteUInt16BigEndian(_buffer.Span.Slice(_position), value);
        _position += 2;
        return true;
    }
 
    internal bool TryWriteUInt32(uint value)
    {
        if (_buffer.Length - _position < 4)
        {
            return false;
        }
 
        BinaryPrimitives.WriteUInt32BigEndian(_buffer.Span.Slice(_position), value);
        _position += 4;
        return true;
    }
 
    internal bool TryWriteRawData(ReadOnlySpan<byte> value)
    {
        if (_buffer.Length - _position < value.Length)
        {
            return false;
        }
 
        value.CopyTo(_buffer.Span.Slice(_position));
        _position += value.Length;
        return true;
    }
}