XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Network;

/// <summary>Actual Ethernet frames without preamble/FCS; implementations own DMA and never fabricate packets.</summary>
public interface IEthernetDevice
{
    ReadOnlySpan<byte> MacAddress { get; }
    // Absolute deadline in the same monotonic millisecond domain as INetworkPlatform.
    // Implementations must not install a separate transmit timeout.
    bool Send(ReadOnlySpan<byte> frame, long deadlineMilliseconds);
    int Receive(Span<byte> frame);
}

public interface INetworkPlatform
{
    long Milliseconds { get; }
    void Wait(int milliseconds);
    uint Random32();
    void Trace(string text);
}

/// <summary>Explicit static configuration, not a DHCP lease or physical-network discovery.</summary>
public readonly record struct Ipv4Configuration(uint Address, uint Mask, uint Gateway, uint DnsServer)
{
    public static Ipv4Configuration QemuUserNat => new(0x0a00020f, 0xffffff00, 0x0a000202, 0x0a000203);
}

public static class NetworkPackets
{
    public static bool IsUnicastMac(ReadOnlySpan<byte> value)
    {
        if (value.Length != 6 || (value[0] & 1) != 0) return false;
        byte any = 0; foreach (byte octet in value) any |= octet; return any != 0;
    }
    public static ushort Read16(ReadOnlySpan<byte> value, int offset) => (ushort)((value[offset] << 8) | value[offset + 1]);
    public static uint Read32(ReadOnlySpan<byte> value, int offset) => ((uint)Read16(value, offset) << 16) | Read16(value, offset + 2);
    public static void Write16(Span<byte> value, int offset, ushort number)
    { value[offset] = (byte)(number >> 8); value[offset + 1] = (byte)number; }
    public static void Write32(Span<byte> value, int offset, uint number)
    { Write16(value, offset, (ushort)(number >> 16)); Write16(value, offset + 2, (ushort)number); }
    public static string Format(uint value) => $"{value >> 24}.{(value >> 16) & 255}.{(value >> 8) & 255}.{value & 255}";
    public static bool TryParseAddress(string text, out uint address)
    {
        address = 0; string[] parts = text.Split('.');
        if (parts.Length != 4) return false;
        foreach (string part in parts)
        {
            if (part.Length is 0 or > 3 || part.Any(c => c is < '0' or > '9') ||
                !uint.TryParse(part, out uint octet) || octet > 255) { address = 0; return false; }
            address = (address << 8) | octet;
        }
        return true;
    }
    static uint AddWords(ReadOnlySpan<byte> bytes, uint sum)
    {
        for (int i = 0; i + 1 < bytes.Length; i += 2) sum += Read16(bytes, i);
        if ((bytes.Length & 1) != 0) sum += (uint)bytes[^1] << 8;
        return sum;
    }
    static ushort Finish(uint sum)
    { while ((sum >> 16) != 0) sum = (sum & 65535) + (sum >> 16); return (ushort)~sum; }
    public static ushort Checksum(ReadOnlySpan<byte> bytes) => Finish(AddWords(bytes, 0));
    public static ushort TransportChecksum(uint source, uint destination, byte protocol, ReadOnlySpan<byte> bytes) =>
        Finish(AddWords(bytes, (source >> 16) + (source & 65535) + (destination >> 16) + (destination & 65535) + protocol + (uint)bytes.Length));
}